Eloy Duran
2006-Apr-14 13:19 UTC
Script.aculo.us Effects with callbacks not working as it should.
Hello all! I''m having a problem which is driving me insane. It''s probably related to the fact that I''m new to javascript.... :) Here''s the thing, I have a couple of effects which are all being put in the queue. Some of these effects have callbacks; e.g. "afterFinish". But the calback is being made directly instead of after the effect is done. The same happens with "beforeUpdate" etc. The weird thing here is that it used to work when I was using global variables for all the content_elements. I now converted the global variables to come from a hash, so I can dynamically call the functions. But the effects still work, so obviously the correct strings (content_elements) are being passed to the effects calls, only the timing of the callbacks don''t work anymore. For completeness I''ll just paste the whole beast :) (Which btw is the first time I present my javascript skills to the world, so any advice is greatly appreciated!) Thanks in advance. Kind regards, Eloy. PS: Being the good little boy I am, I also downloaded the latest versions of prototype/scriptaculous. CODE: <html> <head> <%= javascript_include_tag("prototype", "effects") %> <script language="javascript" type="text/javascript" src="/javascripts/tiny_mce/tiny_mce.js"></script> <script language="javascript" type="text/javascript"> tinyMCE.init({ mode : "textareas", theme : "advanced", theme_advanced_toolbar_location : "top", theme_advanced_buttons1 : "bold, italic, underline, strikethrough, separator, bullist, numlist", theme_advanced_buttons2 : "", theme_advanced_buttons3 : "" }); </script> <script language="javascript" type="text/javascript"> function printfire() { if (document.createEvent) { printfire.args = arguments; var ev = document.createEvent("Events"); ev.initEvent("printfire", false, true); dispatchEvent(ev); } } function set_content_and_editor_variables(content_id) { // First create the object that we will turn into a hash. var content_and_editor_variables = { content_container: "content_container_" + content_id, content_or_editor: "content_or_editor_" + content_id, content_editor: "content_editor_" + content_id, content_node: "content_node_" + content_id, editor_textarea: "editor_textarea_" + content_id, editor: "editor_" + content_id, edit_button: "edit_text_" + content_id, save_button: "save_text_" + content_id, busy_indicator: "busy_indicator_" + content_id }; // Then turn the object into a hash. var content_and_editor_variables_hash $H(content_and_editor_variables); // Return the hash. return content_and_editor_variables_hash; } function edit_content(content_id) { var content_elements = set_content_and_editor_variables(content_id); // VERY VERY IMPORTANT!!!!! // At the moment you can''t use multiple editors at the same time.... // Fix should be something along the lines of: // // All the global variables that get declared below, // should be put in a array, which should be returned by a function based on the id of the content. // This variable is used in the resize_content_or_editor function // to check if we resized the content_or_editor to the new content size. //content_or_editor_resized = ''false''; //content_container = "content_container_" + content_id; //content_or_editor = "content_or_editor_" + content_id; //content_editor = "content_editor_" + content_id; //content_node = "content_node_" + content_id; //editor_textarea = "editor_textarea_" + content_id; //editor = "editor_" + content_id; //edit_button = "edit_text_" + content_id; //save_button = "save_text_" + content_id; //busy_indicator = "busy_indicator_" + content_id; // Set the div content_or_editor to the height of the current content. // We do this so the div doesn''t get very small and flashes when the content_node is completely faded. // For some reason if the height is lower than approx. 190px, // the toolbar of the editor overlaps the content_controls div....?? var content_or_editor_height = ''height: '' + Element.getHeight($(content_elements[''content_or_editor''])) + ''px;''; $(content_elements[''content_or_editor'']).setAttribute(''style'', content_or_editor_height); // First let''s hide the div holding everything content/editor related. new Effect.Fade(content_elements[''content_node''], { queue: ''end'', duration: 1.5}); // Create the new textarea element that will be used by the editor. var editor_content = document.createElement(''textarea''); // Set the attributes. editor_content.setAttribute(''id'', content_elements[''editor_textarea'']); editor_content.setAttribute(''style'', ''width: 100%; height: 100%;''); // Fill the content of the textarea with the content of the content_node div. editor_content.innerHTML $(content_elements[''content_node'']).innerHTML; // And insert the textarea we created earlier. $(content_elements[''content_editor'']).appendChild(editor_content); // And finally hook the editor up to the textarea we created. tinyMCE.addMCEControl($(content_elements[''editor_textarea'']), $(content_elements[''editor''])); // And then let''s fade in the div holding everything content/editor related. // It''s important that when the div has appeared we set the focus to the new editor, // otherwise we can''t drag in anything until we set the cursor in the editor ourself. // Therefor we do a callback after the effect to set the focus for us! new Effect.Appear( content_elements[''content_editor''], { queue: ''end'', duration: 1.5, afterFinish: set_focus_to_editor(content_elements[''editor'']) }); // We''ve entered edit mode, so disable edit button. $(content_elements[''edit_button'']).disabled = true; // and enable the save button. $(content_elements[''save_button'']).disabled = false; } function set_focus_to_editor(editor_id) { // After we added the hash with all the content variables, this doesn''t work anymore.... // // We have to call this function to be able to start dragging images and links into the editor. // If we wouldn''t do this we would not be able to drag anything in, // unless you first set the cursor in the editor. // I guess it doesn''t work directly because of the javascript effects, // that''s why we call this function as a callback from a effect. tinyMCE.execCommand(''mceFocus'', $(editor_id)); } function save_content(content_id) { var content_elements = set_content_and_editor_variables(content_id); // First disable the buttons and show that we''re busy. $(content_elements[''edit_button'']).disabled = true; $(content_elements[''save_button'']).disabled = true; Element.show(content_elements[''busy_indicator'']); // Get the contents of the editor and escape any html. var content tinyMCE.getContent($(content_elements[''editor''])).escapeHTML(); // Escape all the nasty characters. var content = content.replace(/=/g,"*equals*"); var content = content.replace(/&/g,"*ampersand*"); var content = content.replace(/\+/g,"*plus*"); var content = content.replace(/;/g,"*semicolon*"); // Create the query string for the ajax request. var content = "content=" + content; var url = "<%= url_for(:controller => "test", :action => "rich_text_editor_save_tinymce") %>"; // Create the ajax request, that sends the edited content by POST. // When the response has been returned call the function show_new_content. var content_ajax = new Ajax.Request( url, { method: ''post'', parameters: content, onComplete: function(request) { show_new_content(content_id, request.responseText); } }); } function show_new_content(content_id, response_text) { var content_elements = set_content_and_editor_variables(content_id); // First update the original content_node div with the new content. Element.update(content_elements[''content_node''], response_text); // Than add the effects to the queue that will hide the editor and show the new content. new Effect.Fade( content_elements[''content_editor''], { queue: ''end'', duration: 2.0, afterFinish: clean_up_editor(content_elements[''editor''], content_elements[''editor_textarea'']) }); new Effect.Appear( content_elements[''content_node''], { queue: ''end'', duration: 2.0, afterUpdate: resize_content_or_editor(content_elements[''content_or_editor''], content_elements[''content_node'']) }); new Effect.Highlight( content_elements[''content_node''], { queue: ''end'', duration: 2.0 }); // Then we really should scale the content_or_editor div to the size that the new content has. // Something like below, but it doesn''t work yet :( // So to at least do some resizing we added the function resize_content_node // //new Effect.Scale(content_or_editor, // { // queue: ''end'', // scaleMode: { originalHeight: 100, originalWidth: 100} // }); $(content_elements[''edit_button'']).disabled = false; $(content_elements[''save_button'']).disabled = true; Element.hide(content_elements[''busy_indicator'']); } function clean_up_editor(editor, editor_textarea) { // Clean up the editor, which is faded out by now. Element.remove(editor_textarea); tinyMCE.removeMCEControl($(editor)); } function resize_content_or_editor(content_or_editor, content_node) { // Because there''s a possibility that the user has created content // longer than the original content, we should set the height of the div content_or_editor // to the height of the new updated div content_node. // Off course we should do this only once, so we added the variable content_node_resized to check // if we already updated it. I''m not sure if this is the best way, but it works. printfire(Element.getHeight($(content_node))); //if (Element.getHeight($(content_node)) > 0) { // alert(Element.getHeight($(content_or_editor)) + ", " + Element.getHeight($(content_node))); // var content_node_height = ''height: '' + Element.getHeight($(content_node)) + ''px;''; // $(content_or_editor).setAttribute(''style'', content_node_height); // content_or_editor_resized = ''true''; //} //if (Element.getHeight($(content_or_editor)) !Element.getHeight($(content_node))) { // alert(Element.getHeight($(content_or_editor)) + ", " + Element.getHeight($(content_node))); // var content_node_height = ''height: '' + Element.getHeight($(content_node)) + ''px;''; // $(content_or_editor).setAttribute(''style'', content_node_height); //} } </script> <title>Zukunft Tests - Rich Text Editor</title> </head> <body> <div id="content_container_1" style="width: 400px; border-style: outset;"> <strong>CONTENT 1</strong> <div id="content_or_editor_1"> <div id="content_editor_1" style="display: none;"> </div> <div id="content_node_1"> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed at sapien volutpat leo euismod varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus justo. Pellentesque molestie, enim at ullamcorper tempor, eros ipsum fermentum odio, vitae facilisis lacus nulla vel nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis eget lacus. Mauris porta. Duis eros neque, cursus ut, lobortis eu, porta vitae, nibh. Sed et eros non mauris tempus bibendum. Nullam augue.<br /> <br /> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed at sapien volutpat leo euismod varius. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus justo. Pellentesque molestie, enim at ullamcorper tempor, eros ipsum fermentum odio, vitae facilisis lacus nulla vel nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis eget lacus. Mauris porta. Duis eros neque, cursus ut, lobortis eu, porta vitae, nibh. Sed et eros non mauris tempus bibendum. Nullam augue. </div> </div> <div id="content_controls_1"> <input type="submit" id="edit_text_1" value="Edit" onclick="edit_content(''1'')"> <input type="submit" id="save_text_1" value="Save" onclick="save_content(''1'')"> <span id="busy_indicator_1" style="display: none;"> <%= image_tag("indicator.gif") %> Saving content, one moment please... </span> </div> </div> </body> </html>
Eloy Duran
2006-Apr-14 14:30 UTC
Re: Script.aculo.us Effects with callbacks not working as it
DO! RTFM, that''s what you get from not sleeping enough :) What I did was: new Effect.Appear( content_elements[''content_node''], { queue: ''end'', duration: 2.0, afterUpdate: resize_content_or_editor(content_elements[''content_or_editor''], content_elements[''content_node'']) }); What I should have done is: new Effect.Appear( content_elements[''content_node''], { queue: ''end'', duration: 2.0, afterUpdate: function callback(obj) { resize_content_or_editor(content_elements[''content_or_editor''], content_elements[''content_node'']); } }); Thanks anyway! Cheers, Eloy. -- Posted via http://www.ruby-forum.com/.