[Checkins] SVN: z3c.listjs/trunk/ * make sure javascript is executed when doing a renumbering.

Martijn Faassen faassen at startifact.com
Thu Jun 4 09:51:51 EDT 2009


Log message for revision 100632:
  * make sure javascript is executed when doing a renumbering.
  
  * renumber javascript. Scary but will mostly be reliable.
  
  * disconnect TinyMCE editors in things being moved.
  

Changed:
  U   z3c.listjs/trunk/CHANGES.txt
  U   z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js

-=-
Modified: z3c.listjs/trunk/CHANGES.txt
===================================================================
--- z3c.listjs/trunk/CHANGES.txt	2009-06-04 11:46:22 UTC (rev 100631)
+++ z3c.listjs/trunk/CHANGES.txt	2009-06-04 13:51:51 UTC (rev 100632)
@@ -4,6 +4,19 @@
 1.0b1 (unreleased)
 ==================
 
+* Javascript in ``<script>`` blocks and ``onclick`` handlers are also
+  renumbered so that references to the element id in question are
+  updated. This won't be reliable in the (assumed to uncommon) case
+  where a widget id is referenced within the HTML that is *not* the
+  field of the widget being rendered.
+
+* If TinyMCE is installed, care is taken to disconnect TinyMCE editors
+  before moving. Reconnection of the moved editors is assumed to take
+  place in the included HTML for the new element, using something
+  like::
+
+    tinyMCE.execCommand('mceAddControl', false, 'id_of_element');
+
 * A few small bugfixes:
 
   * prefix is passed along to update_numbers

Modified: z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js	2009-06-04 11:46:22 UTC (rev 100631)
+++ z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js	2009-06-04 13:51:51 UTC (rev 100632)
@@ -20,7 +20,9 @@
 
 (function() {
     Z3C.namespace('listjs');
-        
+
+    var disconnected_editor_ids = [];
+
     // return true if string starts with a prefix
     var startswith = function(s, prefix) {
         return (s.substring(0, prefix.length) == prefix);
@@ -51,7 +53,17 @@
         return result.join('.');
     };
 
-    
+    var renumberScript = function(s, nr, prefix) {
+        var tomatch = new RegExp(prefix + '[^"\']*', 'g');
+        var potentials = s.match(tomatch);
+        if (potentials == null) {
+            return s; // nothing to replace
+        }
+        var original = potentials[0];
+        var renumbered = renumber(original, nr);
+        return s.replace(original, renumbered);
+    };
+
     // simplistic implementation that doesn't understand 
     // multiple classes per element
     var getElementsByClassName = function(class_name, root_el, tag) {
@@ -74,6 +86,13 @@
         if (el.nodeType != 1) {
             return;
         }
+
+        // if this is a script tag, do textual replace
+        if (el.tagName.toLowerCase() == 'script') {
+            el.text = renumberScript(el.text, nr, prefix);
+            return;
+        }
+
         var i;
         var attributes = ['id', 'name', 'for'];
         for (i = 0; i < attributes.length; i++) {
@@ -82,6 +101,12 @@
                 el.setAttribute(attributes[i], renumber(attr, nr));
             }
         }
+        
+        var onclick_attr = el.getAttribute('onclick');
+        if (onclick_attr) {
+            el.setAttribute('onclick', renumberScript(onclick_attr, nr, prefix));
+        }
+
         // recursion
         var node = el.firstChild;
         while (node) {
@@ -98,12 +123,97 @@
         var i;
         for (i = 0; i < els.length; i++) {
             updateNumbers(els[i], i, prefix);
+            runScripts(els[i]);
         }
         // update count
         var count_el = document.getElementById(prefix + '.count');
         count_el.value = els.length;
     };
+    
+    // disconnect all editors in affected elements
+    var disconnectEditors = function(affected_elements) {
+       // if tinyMCE is installed, disconnect all editors
+        if (tinyMCE) {
+            //tinyMCE.triggerSave();
+            disconnected_editor_ids = [];
+            for (var n in tinyMCE.editors) {
+                var inst = tinyMCE.editors[n];
+                if (!inAffectedElements(inst.getElement(), 
+                                        affected_elements)) {
+                    continue;
+                }
+                disconnected_editor_ids.push(inst.id);
+                tinyMCE.execCommand('mceFocus', false, inst.id);
+                tinyMCE.execCommand('mceRemoveControl', false, inst.id);
+            }
+        }
+    };
 
+    // reconnect all editors that aren't reconnected already
+    var reconnectEditors = function() {
+        // reconnect all editors
+        if (tinyMCE) {
+           for (i = 0; i < disconnected_editor_ids.length; i++) {
+               var editor_id = disconnected_editor_ids[i];
+               if (!tinyMCE.get(editor_id)) {
+                   tinyMCE.execCommand('mceAddControl', false, editor_id);
+               }
+           }
+        }
+    };
+
+    // return true if el is inside one of affected_elements
+    var inAffectedElements = function(el, affected_elements) {
+        for (var i = 0; i < affected_elements.length; i++) {
+            if (isAncestor(affected_elements[i], el)) {
+                return true;
+            }
+        }
+        return false;
+    };
+
+    // return true if a is an ancestor of b
+    var isAncestor = function(a, b) {
+        while (b) {
+            if (a === b) {
+                return true;
+            }
+            b = b.parentNode;
+        }
+        return false;
+    }
+
+
+    // run all embedded scripts (after setting innerHTML)
+    // see http://brightbyte.de/page/Loading_script_tags_via_AJAX
+    // combined with 
+    // http://caih.org/open-source-software/loading-javascript-execscript-and-testing/
+    // to eval in the global scope
+    var runScripts  = function(e) { 
+        if (e.nodeType != 1) {
+            return;
+        }
+        
+        // run any script tag
+        if (e.tagName.toLowerCase() == 'script') {
+            if (window.execScript) {
+                window.execScript(e.text);
+            } else {
+                with (window) {
+                    window.eval(e.text);
+                }
+            }
+        } else {
+            var n = e.firstChild;
+            while (n) {
+                if (n.nodeType == 1) {
+                    runScripts(n);
+                }
+                n = n.nextSibling;
+            }
+        }
+    };
+
     // add a new repeating element to the list
     Z3C.listjs.add = function(prefix) {
         var table_el = document.getElementById(prefix + '.table');
@@ -186,8 +296,13 @@
         if (previous_el == null) {
             return;
         }
+
+        disconnectEditors([el, previous_el]);
+
         previous_el.parentNode.insertBefore(el, previous_el);
         updateAllNumbers(prefix);
+
+        reconnectEditors();
     };
 
     Z3C.listjs.down = function(prefix, el) {
@@ -202,8 +317,12 @@
         if (next_el == null) {
             return;
         }
+        disconnectEditors([el, next_el]);
+
         next_el.parentNode.insertBefore(el, next_el.nextSibling);
         updateAllNumbers(prefix);
+
+        reconnectEditors();
     };
     
 })();



More information about the Checkins mailing list