[KSS-checkins] r42420 - kukit/kukit.js/branch/performance_improvement/kukit
reebalazs at codespeak.net
reebalazs at codespeak.net
Sun Apr 29 14:17:11 CEST 2007
Author: reebalazs
Date: Sun Apr 29 14:17:10 2007
New Revision: 42420
Modified:
kukit/kukit.js/branch/performance_improvement/kukit/dom.js
kukit/kukit.js/branch/performance_improvement/kukit/eventreg.js
kukit/kukit.js/branch/performance_improvement/kukit/oper.js
kukit/kukit.js/branch/performance_improvement/kukit/plugin.js
kukit/kukit.js/branch/performance_improvement/kukit/utils.js
Log:
Merge in changes from the ree-load-event-cleanup branch -r41967:42418
Modified: kukit/kukit.js/branch/performance_improvement/kukit/dom.js
==============================================================================
--- kukit/kukit.js/branch/performance_improvement/kukit/dom.js (original)
+++ kukit/kukit.js/branch/performance_improvement/kukit/dom.js Sun Apr 29 14:17:10 2007
@@ -1,9 +1,6 @@
/*
-* Copyright (c) 2005-2006
-* Authors:
-* Godefroid Chapelle <gotcha at bubblenet.be>
-* Florian Schulze <florian.schulze at gmx.net>
-* Balázs Reé <ree at greenfinity.hu>
+* Copyright (c) 2005-2007
+* Authors: KSS Project Contributors (see docs/CREDITS.txt)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
@@ -343,12 +340,12 @@
*
* Scheduler for embedded window content loaded
*/
-kukit.dom.EmbeddedContentLoadedScheduler = function(framename, func) {
+kukit.dom.EmbeddedContentLoadedScheduler = function(framename, func, autodetect) {
this.framename = framename;
this.func = func;
+ this.autodetect = autodetect;
var self = this;
var f = function() {
- kukit.logDebug('Is iframe loaded ?');
self.check();
};
this.counter = new kukit.ut.TimerCounter(250, f, true);
@@ -373,35 +370,50 @@
};
kukit.dom.EmbeddedContentLoadedScheduler.prototype.check = function() {
- // quit if the init function has already been called
+
+ kukit.logDebug('Is iframe loaded ?');
+
var doc = kukit.dom.getIframeDocument(this.framename);
+
+ // quit if the init function has already been called
+ // XXX I believe we want to call the function too, then
if (doc._embeddedContentLoadedInitDone) {
- return;
+ kukit.logWarning('Iframe already initialized, but we execute the action enyway, as requested.');
+ this.counter.restart = false;
}
- // obviously we are not there... this happens on FF
-
- /*Commented out by GC
- if (doc.location.href == 'about:blank') {
- return;
- }*/
-
+ // autodetect=false implements a more reliable detection method
+ // that involves cooperation from the internal document. In this
+ // case the internal document sets the _kssReadyForLoadEvent attribute
+ // on the document, when loaded. It is safe to check for this in any
+ // case, however if this option is selected, we rely only on this,
+ // and skip the otherwise problematic default checking.
if (typeof doc._kssReadyForLoadEvent != 'undefined') {
this.counter.restart = false;
}
- // First check for Safari or
- //if DOM methods are supported, and the body element exists
- //(using a double-check including document.body, for the benefit of older moz builds [eg ns7.1]
- //in which getElementsByTagName('body')[0] is undefined, unless this script is in the body section)
-
- /*Commented out by GC
- if(/KHTML|WebKit/i.test(navigator.userAgent)) {
- if(/loaded|complete/.test(doc.readyState)) {
+
+ if (this.autodetect && this.counter.restart) {
+
+ // obviously we are not there... this happens on FF
+ if (doc.location.href == 'about:blank') {
+ return;
+ } /* */
+
+ // First check for Safari or
+ //if DOM methods are supported, and the body element exists
+ //(using a double-check including document.body, for the benefit of older moz builds [eg ns7.1]
+ //in which getElementsByTagName('body')[0] is undefined, unless this script is in the body section)
+
+ if(/KHTML|WebKit/i.test(navigator.userAgent)) {
+ if(/loaded|complete/.test(doc.readyState)) {
+ this.counter.restart = false;
+ }
+ } else if(typeof doc.getElementsByTagName != 'undefined' && (doc.getElementsByTagName('body')[0] != null || doc.body != null)) {
this.counter.restart = false;
- }
- } else if(typeof doc.getElementsByTagName != 'undefined' && (doc.getElementsByTagName('body')[0] != null || doc.body != null)) {
- this.counter.restart = false;
- }*/
+ } /* */
+
+ }
+
if ( ! this.counter.restart) {
kukit.logDebug('Yes, iframe is loaded.');
doc._embeddedContentLoadedInitDone = true;
Modified: kukit/kukit.js/branch/performance_improvement/kukit/eventreg.js
==============================================================================
--- kukit/kukit.js/branch/performance_improvement/kukit/eventreg.js (original)
+++ kukit/kukit.js/branch/performance_improvement/kukit/eventreg.js Sun Apr 29 14:17:10 2007
@@ -1,9 +1,6 @@
/*
-* Copyright (c) 2005-2006
-* Authors:
-* Godefroid Chapelle <gotcha at bubblenet.be>
-* Florian Schulze <florian.schulze at gmx.net>
-* Balázs Reé <ree at greenfinity.hu>
+* Copyright (c) 2005-2007
+* Authors: KSS Project Contributors (see docs/CREDITS.txt)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
@@ -81,7 +78,7 @@
/* events (methods) registration helpers (not to be called directly) */
kukit.er.EventRegistry.prototype._register = function(namespace, eventname, klass,
- bindmethodname, defaultactionmethodname, bindmethodapi) {
+ bindmethodname, defaultactionmethodname, itername) {
if (typeof(defaultactionmethodname) == 'undefined') {
throw 'some arguments are not passed when calling EventRegistry.register';
}
@@ -105,42 +102,55 @@
}
throw 'In EventRegistry.register double registration of key "' + key + '"';
}
+ // check bindmethodname and defaultactionmethodname
+ if (bindmethodname && ! klass.prototype[bindmethodname])
+ throw 'In EventRegistry.register bind method "' + bindmethodname + '" is undefined for event "' + eventname + '" namespace "' + namespace + '"';
+ if (defaultactionmethodname && ! klass.prototype[defaultactionmethodname])
+ throw 'In EventRegistry.register default action method "' + defaultactionmethodname + '" is undefined for event "' + eventname + '" namespace "' + namespace + '"';
+ // check the iterator.
+ if (! kukit.er.getBindIterator(itername)) {
+ throw 'In EventRegistry.register unknown bind iterator "' + itername + '"';
+ }
// register it
this.content[key] = {
'classname': classname,
'bindmethodname': bindmethodname,
'defaultactionmethodname': defaultactionmethodname,
- 'bindmethodapi': bindmethodapi
+ 'itername': itername
};
};
/* events (methods) binding "ForAll" registration */
-kukit.er.EventRegistry.prototype._registerEventSet = function(namespace, names) {
- // At this name the class and event should be checked already. so this should
+kukit.er.EventRegistry.prototype._registerEventSet = function(namespace, names, itername, bindmethodname) {
+ // At this name the values should be checked already. so this should
// be called _after_ _register.
- this.eventsets.push({'namespace': namespace, 'names': names});
+ this.eventsets.push({
+ 'namespace': namespace,
+ 'names': names,
+ 'itername': itername,
+ 'bindmethodname': bindmethodname
+ });
};
-
/* there are the actual registration methods, to be called from plugins */
kukit.er.EventRegistry.prototype.register = function(namespace, eventname, klass,
bindmethodname, defaultactionmethodname) {
- this._register(namespace, eventname, klass, bindmethodname, defaultactionmethodname, 'old');
- this._registerEventSet(namespace, [eventname]);
+ this._register(namespace, eventname, klass, bindmethodname, defaultactionmethodname, 'each_legacy');
+ this._registerEventSet(namespace, [eventname], 'each_legacy', bindmethodname);
};
kukit.er.EventRegistry.prototype.registerForAllEvents = function(namespace, eventnames, klass,
- bindmethodname, defaultactionmethodname) {
+ bindmethodname, defaultactionmethodname, itername) {
if (typeof(eventnames) == 'string') {
eventnames = [eventnames];
}
for (var i=0; i<eventnames.length; i++) {
var eventname = eventnames[i];
- this._register(namespace, eventname, klass, bindmethodname, defaultactionmethodname, 'new');
+ this._register(namespace, eventname, klass, bindmethodname, defaultactionmethodname, itername);
}
- this._registerEventSet(namespace, eventnames);
+ this._registerEventSet(namespace, eventnames, itername, bindmethodname);
};
kukit.er.EventRegistry.prototype._getKey = function(namespace, eventname) {
@@ -502,7 +512,7 @@
// We mark a given oper. This means a binding on the binderinstance
// for given event, node and eventrule (containing event namespace,
// name, and evt- parms.)
-
+ //
// first see if it can go to already bound ones
this.bound.checkOperBindable(oper);
// then register it properly to the binding events
@@ -512,70 +522,13 @@
kukit.er.BinderInfo.prototype.processBindingEvents = function () {
// We came to the end of the binding phase. Now we process all our binding
// events, This will do the actual binding on the browser side.
- var eventRegistry = kukit.eventsGlobalRegistry;
- for (var i=0; i < eventRegistry.eventsets.length; i++) {
- var eventset = eventRegistry.eventsets[i];
- if (this.binderinstance.__event_namespace__ == eventset.namespace) {
- this._processBindingEventSet(eventset.names);
- }
- }
+ this.binding.processBindingEvents(this.binderinstance)
// Now we to add these to the new ones.
this.binding.propagateTo(this.bound);
// Delete them from the registry, to protect against accidents.
this.binding = null;
};
-kukit.er.BinderInfo.prototype._processBindingEventSet = function (names) {
- // Bind finally for all the opers collected
- var opers = this.binding.getBoundOpersForEventSet(names);
- if (opers.length == 0) {
- return;
- }
- // find the bind method
- // (We use the name and namespace from the first oper, as the bindmethod
- // should be identical anyway.
- var kss_selector = opers[0].eventrule.kss_selector;
- var namespace = kss_selector.namespace;
- var name = kss_selector.name;
- var reg = kukit.eventsGlobalRegistry.get(namespace, name);
- var methodname = reg.bindmethodname;
- // XXX this is now disabled. We want to allow these events to "bind" on different nodes,
- // however there is no actual event bound.
- if (! methodname) {
- return;
- //throw new kukit.err.rd.EventBindError('Method is not defined as bindable', name, namespace);
- }
- var method = this.binderinstance[methodname];
- if (typeof(method) == 'undefined' ) {
- throw new kukit.err.rd.EventBindError('Method "' + methodname + '" does not exist', name, namespace);
- }
- // Ok. Now decide if we go with the new or the old api.
- if (reg.bindmethodapi == 'new') {
- // Protect the binding for better logging
- try {
- method.call(binderinstance, opers);
- } catch(e) {
- throw new kukit.err.rd.EventBindError('Error during binding, reason: [' + e + ']', name, namespace);
- }
- } else { // old
- for (var i=0; i<opers.length; i++) {
- var oper = opers[i];
- var func_to_bind = oper.makeExecuteActionsHook();
- if (this.binderinstance != oper.binderinstance) {
- throw new kukit.err.rd.EventBindError('fatal: wrong binder instance');
- }
- var binderinstance = oper.binderinstance;
- var eventname = oper.getEventName();
- // Protect the binding for better logging
- try {
- method.call(binderinstance, eventname, func_to_bind, oper);
- } catch(e) {
- throw new kukit.err.rd.EventBindError('Error during binding, reason: [' + e + ']', eventname, oper.getEventNamespace());
- }
- }
- }
-};
-
/*
* class OperRegistry
@@ -588,12 +541,14 @@
*/
kukit.er.OperRegistry = function () {
- this.info = {};
+ this.infopername = {};
+ this.infopernode = {};
};
+// XXX XXX XXX we can do this without full cloning, more efficiently.
kukit.er.OperRegistry.prototype.propagateTo = function (newreg) {
- for (var key in this.info) {
- var rules_per_name = this.info[key];
+ for (var key in this.infopername) {
+ var rules_per_name = this.infopername[key];
for (var name in rules_per_name) {
var oper = rules_per_name[name];
newreg.bindOper(oper);
@@ -601,12 +556,18 @@
}
};
-kukit.er.OperRegistry.prototype.checkOperBindable = function (oper) {
+kukit.er.OperRegistry.prototype.checkOperBindable = function (oper, name, nodehash) {
// Check if the binding with this oper could be done.
// Throw exception otherwise.
- var info = this.info;
- var name = oper.eventrule.kss_selector.name;
- var nodehash = kukit.rd.hashnode(oper.node);
+ //
+ // Remark. We need different check and bind method, because we need to bind to the currently
+ // processed nodes, but we need to check duplication in all the previously bound nodes.
+ var info = this.infopername;
+ // name and nodehash are for speedup.
+ if (typeof(nodehash) == 'undefined') {
+ name = oper.eventrule.kss_selector.name;
+ nodehash = kukit.rd.hashnode(oper.node);
+ }
var rules_per_name = info[name];
if (typeof(rules_per_name) == 'undefined') {
// Create an empty list.
@@ -619,15 +580,43 @@
kukit.er.OperRegistry.prototype.bindOper = function (oper) {
// Marks binding between binderinstance, eventname, node.
+ var name = oper.eventrule.kss_selector.name;
var nodehash = kukit.rd.hashnode(oper.node);
- var rules_per_name = this.checkOperBindable(oper);
+ var rules_per_name = this.checkOperBindable(oper, name, nodehash);
rules_per_name[nodehash] = oper;
+ // also store per node info
+ var rules_per_node = this.infopernode[nodehash];
+ if (typeof(rules_per_node) == 'undefined') {
+ // Create an empty list.
+ rules_per_node = this.infopernode[nodehash] = {};
+ }
+ rules_per_node[name] = oper;
};
+// XXX This will need refactoring.
+/// We would only want to lookup from our registry and not the other way around.
+kukit.er.OperRegistry.prototype.processBindingEvents = function (binderinstance) {
+ var eventRegistry = kukit.eventsGlobalRegistry;
+ for (var i=0; i < eventRegistry.eventsets.length; i++) {
+ var eventset = eventRegistry.eventsets[i];
+ // Only process binding events (and ignore non-binding ones)
+ if (eventset.bindmethodname) {
+ if (binderinstance.__event_namespace__ == eventset.namespace) {
+ // Process the binding event set. This will call the actual bindmethods
+ // according to the specified iterator.
+ var iterator = kukit.er.getBindIterator(eventset.itername);
+ iterator.call(this, eventset, binderinstance);
+ }
+ }
+ }
+};
+
+// XXX The following methods will probably disappear as iterators replace their functionality.
+
kukit.er.OperRegistry.prototype.getBoundOperForNode = function (name, node) {
// Get the oper that is bound to a given eventname to a node in this binderinstance
// returns null, if there is no such oper.
- var rules_per_name = this.info[name];
+ var rules_per_name = this.infopername[name];
if (typeof(rules_per_name) == 'undefined') {
return null;
}
@@ -643,7 +632,7 @@
kukit.er.OperRegistry.prototype.getBoundOpers = function (name) {
// Get the opers bound to a given eventname (to any node) in this binderinstance
var opers = [];
- var rules_per_name = this.info[name];
+ var rules_per_name = this.infopername[name];
if (typeof(rules_per_name) != 'undefined') {
// take the values as a list
for (var nodehash in rules_per_name) {
@@ -654,12 +643,94 @@
return opers;
};
-kukit.er.OperRegistry.prototype.getBoundOpersForEventSet = function (names) {
- // Returns all opers for a given eventset.
+// Iterators
+// The getBindIterator returns a function that gets executed on
+// the oper registry.
+//
+// Iterators receive the eventset as a parameter
+// plus a binderinstance and a method. They need to iterate by calling this
+// as method.call(binderinstance, ...); where ... can be any parameters this
+// given iteration specifies.
+//
+
+kukit.er.getBindIterator = function(itername) {
+ return kukit.er.OperRegistry.prototype['iter_' + itername];
+};
+
+kukit.er.OperRegistry.prototype.call_bind_method = function (eventset, binderinstance, p1, p2, p3, p4, p5, p6) {
+ var method = binderinstance[eventset.bindmethodname];
+ // Protect the binding for better logging
+ try {
+ method.call(binderinstance, p1, p2, p3, p4, p5, p6);
+ } catch(e) {
+ throw new kukit.err.rd.EventBindError('Error during binding, reason: [' + e + ']', eventset.names, eventset.namespace);
+ }
+};
+
+// This calls the bind method by each bound oper one by one. Eventname and func_to_bind are passed too.
+// this is the legacy ("each_legacy") way
+kukit.er.OperRegistry.prototype.iter_each_legacy = function (eventset, binderinstance) {
+ for (var i=0; i<eventset.names.length; i++) {
+ var rules_per_name = this.infopername[eventset.names[i]];
+ if (typeof(rules_per_name) != 'undefined') {
+ for (var nodehash in rules_per_name) {
+ var oper = rules_per_name[nodehash];
+ var eventname = oper.getEventName();
+ var func_to_bind = oper.makeExecuteActionsHook();
+ this.call_bind_method(eventset, binderinstance, eventname, func_to_bind, oper);
+ }
+ }
+ }
+};
+
+
+// This calls the bind method by each bound oper one by one. Eventname and func_to_bind are passed too.
+// this is the preferred ("each") way. Parameters are different from each_legacy.
+kukit.er.OperRegistry.prototype.iter_each = function (eventset, binderinstance) {
+ for (var i=0; i<eventset.names.length; i++) {
+ var rules_per_name = this.infopername[eventset.names[i]];
+ if (typeof(rules_per_name) != 'undefined') {
+ for (var nodehash in rules_per_name) {
+ var oper = rules_per_name[nodehash];
+ this.call_bind_method(eventset, binderinstance, oper);
+ }
+ }
+ }
+};
+
+// This calls the bind method by the list of bound opers
+kukit.er.OperRegistry.prototype.iter_opers = function (eventset, binderinstance) {
var opers = [];
- for (var i=0; i<names.length; i++) {
- var name = names[i];
- opers = opers.concat(this.getBoundOpers(name));
+ for (var i=0; i<eventset.names.length; i++) {
+ var rules_per_name = this.infopername[eventset.names[i]];
+ if (typeof(rules_per_name) != 'undefined') {
+ for (var nodehash in rules_per_name) {
+ opers.push(rules_per_name[nodehash]);
+ }
+ }
}
- return opers;
+ this.call_bind_method(eventset, binderinstance, opers);
};
+
+// This calls the bind method by a mapping eventname:oper per each bound node individually
+kukit.er.OperRegistry.prototype.iter_node = function (eventset, binderinstance) {
+ for (var nodehash in this.infopernode) {
+ var rules_per_node = this.infopernode[nodehash];
+ // filter only the events we are interested in
+ var filtered_rules = {};
+ var found = false;
+ for (var i=0; i<eventset.names.length; i++) {
+ var name = eventset.names[i];
+ var oper = rules_per_node[name];
+ if (typeof(oper) != 'undefined') {
+ filtered_rules[name] = oper;
+ found = true;
+ }
+ }
+ // call it
+ if (found) {
+ this.call_bind_method(eventset, binderinstance, filtered_rules);
+ }
+ }
+};
+
Modified: kukit/kukit.js/branch/performance_improvement/kukit/oper.js
==============================================================================
--- kukit/kukit.js/branch/performance_improvement/kukit/oper.js (original)
+++ kukit/kukit.js/branch/performance_improvement/kukit/oper.js Sun Apr 29 14:17:10 2007
@@ -199,14 +199,26 @@
return this.eventrule.kss_selector.namespace;
};
-kukit.op.Oper.prototype.makeExecuteActionsHook = function () {
+kukit.op.Oper.prototype.makeExecuteActionsHook = function (filter) {
// Factory that creates the function that executes the actions.
// The function may take a dict that is updated on the oper
+ // If filter is specified, it will we called with a function and
+ // the event will only be triggered if the filter returned true.
+ // THe return value of func_to_bind will show if the event
+ // has executed or not.
var eventname = this.getEventName();
var self = this;
var func_to_bind = function(dict) {
+ // (XXX XXX TODO it should happen here, that we change to a different
+ // oper class. This is for the future when we separate the BindOper
+ // from the ActionOper.)
var newoper = self.clone(dict, true);
+ // call the filter and if it says skip it, we are done
+ if (filter && ! filter(newoper)) return false;
+ // execute the event's actions
newoper.binderinstance._EventBinder_triggerevent(eventname, newoper);
+ // show that the event's actions have been executed
+ return true;
};
return func_to_bind;
};
Modified: kukit/kukit.js/branch/performance_improvement/kukit/plugin.js
==============================================================================
--- kukit/kukit.js/branch/performance_improvement/kukit/plugin.js (original)
+++ kukit/kukit.js/branch/performance_improvement/kukit/plugin.js Sun Apr 29 14:17:10 2007
@@ -1,9 +1,6 @@
/*
-* Copyright (c) 2005-2006
-* Authors:
-* Godefroid Chapelle <gotcha at bubblenet.be>
-* Florian Schulze <florian.schulze at gmx.net>
-* Balázs Reé <ree at greenfinity.hu>
+* Copyright (c) 2005-2007
+* Authors: KSS Project Contributors (see docs/CREDITS.txt)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
@@ -59,6 +56,77 @@
};
/*
+* function registerBrowserEvent
+*
+* This can be used to register native events in a way that
+* they handle allowbubbling, preventdefault and preventbubbling as needed.
+* (THe handling of these parms are optional, it is allowed not to have them
+* in the oper.parms.)
+*
+* THe register function can also take a filter function as parameter.
+* This function needs to receive oper as a parameter,
+* where 'browserevent' will be set on oper too as the native browser event.
+* The function must return true if it wants the event to execure, false otherwise.
+* If it returns false, the event will not be prevented and counts as if
+* were not called.
+* This allows for certain event binder like key handlers, to put an extra condition
+* on the triggering of event.
+*
+* The eventname parameter is entirely optional and can be used to set up a different
+* event from the desired one.
+*/
+
+kukit.pl.registerBrowserEvent = function(oper, filter, eventname) {
+ var func_to_bind = oper.makeExecuteActionsHook(filter);
+ var func = function(e) {
+ target = kukit.pl.getTargetForBrowserEvent(e);
+ if (oper.parms.allowbubbling || target == oper.node) {
+ // Execute the action, provide browserevent on oper
+ // ... however, do it protected. We want the preventdefault
+ // in any case!
+ var exc;
+ var success;
+ try {
+ success = func_to_bind({'browserevent': e});
+ } catch(exc1) {
+ exc = exc1;
+ }
+ if (success || exc) {
+ // This should only be skipped, if the filter told
+ // us that we don't need this event to be executed.
+ // If an exception happened during the event execution,
+ // we do yet want to proceed with the prevents.
+ //
+ // Cancel default event ?
+ if (oper.parms.preventdefault) {
+ // W3C style
+ if (e.preventDefault)
+ e.preventDefault();
+ // MS style
+ try { e.returnValue = false; } catch (exc2) {}
+ }
+ // Prevent bubbling to other kss events ?
+ if (oper.parms.preventbubbling) {
+ if (!e) var e = window.event;
+ e.cancelBubble = true;
+ if (e.stopPropagation) e.stopPropagation();
+ }
+ }
+ //
+ if (exc != null) {
+ // throw the original exception
+ throw exc;
+ }
+ } else {
+ kukit.log('Ignored bubbling event for "' + name + '" (target =' + target.tagName + '), EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid);
+ }
+ };
+ if (! eventname)
+ eventname = oper.getEventName();
+ kukit.ut.registerEventListener(oper.node, eventname, func);
+};
+
+/*
* class NativeEventBinder
*/
kukit.pl.NativeEventBinder = function() {
@@ -103,52 +171,17 @@
throw 'In native events only the click event can have preventdefault.';
}
}
- var allowbubbling = oper.parms.allowbubbling;
- var preventdefault = oper.parms.preventdefault;
- var node = oper.node;
- var func = function(e) {
- target = kukit.pl.getTargetForBrowserEvent(e);
- if (allowbubbling || target == node) {
-
- // Execute the action, provide browserevent on oper
- // ... however, do it protected. We want the preventdefault
- // in any case!
- var exc;
- try {
- func_to_bind({'browserevent': e});
- } catch(exc1) {
- exc = exc1;
- }
- // Cancel default event ?
- if (preventdefault) {
- // W3C style
- if (e.preventDefault)
- e.preventDefault();
- // MS style
- try { e.returnValue = false; } catch (exc2) {}
- }
- // Prevent bubbling to other kss events ?
- if (oper.parms.preventbubbling) {
- if (!e) var e = window.event;
- e.cancelBubble = true;
- if (e.stopPropagation) e.stopPropagation();
- }
- //
- if (exc != null) {
- // throw the original exception
- throw exc;
- }
- } else {
- kukit.log('Ignored bubbling event for "' + name + '" (target =' + target.tagName + '), EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid);
- }
- };
- kukit.ut.registerEventListener(node, name, func);
+ kukit.pl.registerBrowserEvent(oper);
+ //
// XXX Safari hack
// necessary since Safari does not prevent the <a href...> following
// (in case of allowbubbling we have to apply it to all clicks, as there
// might be a link inside that we cannot detect on the current node)
- if (preventdefault && kukit.HAVE_SAFARI
- && (allowbubbling || name == 'click' && node.tagName.toLowerCase() == 'a')) {
+ //
+ // XXX not needed since we have the legacy name parameter:
+ // var name = oper.getEventName();
+ if (oper.parms.preventdefault && kukit.HAVE_SAFARI
+ && (oper.parms.allowbubbling || name == 'click' && oper.node.tagName.toLowerCase() == 'a')) {
function cancelClickSafari() {
return false;
}
@@ -157,49 +190,32 @@
};
kukit.pl.NativeEventBinder.prototype.__bind_key__ = function(name, func_to_bind, oper) {
- oper.completeParms([], {'preventdefault': 'true', 'allowbubbling': '', 'keycodes': ''}, 'native key event binding');
+ oper.completeParms([], {'preventdefault': 'true', 'allowbubbling': '', 'preventbubbling': '', 'keycodes': ''}, 'native key event binding');
oper.evalList('keycodes', 'native key event binding');
oper.evalBool('preventdefault', 'native key event binding');
oper.evalBool('allowbubbling', 'native key event binding');
- var allowbubbling = oper.parms.allowbubbling;
- var preventdefault = oper.parms.preventdefault;
- var node = oper.node;
- // Convert keyCode to dict
- var keycodes = {};
- for (var i=0; i<oper.parms.keycodes.length; i++) {
- keyCode = oper.parms.keycodes[i];
- keycodes[keyCode] = true;
- }
- var func = function(e) {
- target = kukit.pl.getTargetForBrowserEvent(e);
- if (allowbubbling || target == node) {
- var keyCode = e.keyCode.toString();
- if (oper.parms.keycodes.length == 0 || keycodes[keyCode]) {
- // Execute the action, provide browserevent on oper
- func_to_bind({'browserevent': e});
- // Cancel default event
- if (preventdefault) {
- // W3C style
- if (e.preventDefault)
- e.preventDefault();
- // MS style
- try { e.returnValue = false; } catch (exc) {}
- }
- } else {
- kukit.log('Ignored event for "' + name + '", keycode ' + e.keyCode + ' not in ' + oper.parms.keycodes);
- }
- } else {
- kukit.log('Ignored bubbling event for "' + name + '" (target =' + target.tagName + '), EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid);
+ var filter;
+ if (oper.parms.keycodes.length >= 0) {
+ // Convert keyCode to dict
+ var keycodes = {};
+ for (var i=0; i<oper.parms.keycodes.length; i++) {
+ keyCode = oper.parms.keycodes[i];
+ keycodes[keyCode] = true;
}
- };
- kukit.ut.registerEventListener(node, name, func);
+ // Set filter so that only the specified keys should trigger.
+ filter = function(oper) {
+ var keyCode = oper.browserevent.keyCode.toString();
+ return keycodes[keyCode];
+ };
+ }
+ kukit.pl.registerBrowserEvent(oper, filter);
};
/*
* Registration of all the native events that can bound to a node or to document
* (= document or window, depending on the event specs)
* Unsupported are those with absolute no hope to work in a cross browser way
-* Preventdefault is only allowed for click, currently
+* Preventdefault is only allowed for click and key events, currently
*/
kukit.eventsGlobalRegistry.register(null, 'blur', kukit.pl.NativeEventBinder, '__bind__nodeorwindow', null);
kukit.eventsGlobalRegistry.register(null, 'focus', kukit.pl.NativeEventBinder, '__bind__nodeorwindow', null);
@@ -271,14 +287,21 @@
kukit.pl.LoadEventBinder = function() {
};
-kukit.pl.LoadEventBinder.prototype.__bind__ = function(name, func_to_bind, oper) {
- oper.completeParms([], {'initial': 'true', 'insert': 'true'}, 'load event binding');
- oper.evalBool('initial', 'load event binding');
- oper.evalBool('insert', 'load event binding');
- // Bind the function to the onload event of the node.
- // If this is an iframe node, we have the possibility
- // to wait until the execution totally finishes, so we load the real load event.
- // node._kukitmark contains the binding phase.
+kukit.pl.LoadEventBinder.prototype.process_parms = function(oper, iload) {
+ if (! oper) {
+ return;
+ }
+ if (iload) {
+ oper.completeParms(['autodetect'], {'initial': 'true', 'insert': 'true'}, 'iload event binding');
+ // autodetect=false changes the iload autosense method to one that requires the iframe set
+ // the _kssReadyForLoadEvent attribute on the document. Setting this attribute is explicitely required
+ // if autodetect is off, since otherwise in this case we would never notice if the document has arrived.
+ oper.evalBool('autodetect', 'iload event binding');
+ } else {
+ oper.completeParms([], {'initial': 'true', 'insert': 'true'}, 'load event binding');
+ }
+ oper.evalBool('initial', 'load/iload event binding');
+ oper.evalBool('insert', 'load/iload event binding');
var phase = oper.node._kukitmark;
if (phase == 1 && ! oper.parms.initial) {
kukit.logDebug('EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid + ' event ignored, oninitial=false.');
@@ -288,23 +311,78 @@
kukit.logDebug('EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid + ' event ignored, oninsert=false.');
return;
}
- if (oper.node != null && oper.node.tagName.toLowerCase() == 'iframe' &&
- (phase == 2 || (phase == 1 && kukit.engine.initializedOnDOMLoad))) {
- kukit.logDebug('EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid + ' event selected delayed execution (when iframe loaded)');
- // We want the event execute once the iframe is loaded.
- var f = function() {
- kukit.engine.bindScheduler.addPost(func_to_bind, 'Execute load event for iframe ' + oper.node.name);
- };
- new kukit.dom.EmbeddedContentLoadedScheduler(oper.node.id, f);
+ return oper;
+};
+kukit.pl.LoadEventBinder.prototype.__bind__ = function(opers_by_eventname) {
+ // This bind method handles load and iload events together, and opers_by_eventname is
+ // a dictionary of opers which can contain a load and an iload key, either one or both.
+ var loadoper = opers_by_eventname.load;
+ var iloadoper = opers_by_eventname.iload;
+ loadoper = this.process_parms(loadoper);
+ iloadoper = this.process_parms(iloadoper, true);
+ var anyoper = loadoper || iloadoper;
+ if (! anyoper) {
+ return;
+ }
+ if (anyoper.node != null && anyoper.node.tagName.toLowerCase() == 'iframe') {
+ // In an iframe.
+ //
+ // BBB If there is only a load (and no iload) event bound to this node,
+ // we interpret it as an iload event, but issue deprecation warning.
+ // This conserves legacy behaviour when the load event was actually doing an iload,
+ // when it was bound to an iframe node.
+ // The deprecation tells that the event should be changed from load to iload.
+ if (loadoper && ! iloadoper) {
+ iloadoper = loadoper;
+ loadoper = null;
+ // with the legacy loads we suppose autodetect=false
+ iloadoper.parms.autodetect = false;
+ kukit.logWarning('Deprecated the use of "load" event for iframes. It will behave differently in the future. Use the "iload" event (maybe with evt-iload-autodetect: false) instead!');
+ }
} else {
- kukit.logDebug('EventRule #' + oper.eventrule.getNr() + ' mergeid ' + oper.eventrule.kss_selector.mergeid + ' event selected normal postponed execution.');
+ // Not an iframe. So iload is not usable.
+ if (iloadoper) {
+ throw 'iload event can only be bound on an iframe node.';
+ }
+ }
+ // Now, bind the events.
+ if (loadoper) {
+ kukit.logDebug('EventRule #' + loadoper.eventrule.getNr() + ' mergeid ' + loadoper.eventrule.kss_selector.mergeid + ' event selected normal postponed execution.');
// for any other node than iframe, or even for iframe in phase1, we need to execute immediately.
- kukit.engine.bindScheduler.addPost(func_to_bind, 'Execute load event for node ' + oper.node.tagName.toLowerCase());
+ var func_to_bind = loadoper.makeExecuteActionsHook();
+ kukit.engine.bindScheduler.addPost(func_to_bind, 'Execute load event for node ' + loadoper.node.tagName.toLowerCase());
+ }
+ if (iloadoper) {
+ var phase = iloadoper.node._kukitmark;
+ // For phase 2 we need to execute posponed, for phase1 immediately.
+ // XXX it would be better not need this and do always postponed.
+ if (phase == 2 || (phase == 1 && kukit.engine.initializedOnDOMLoad)) {
+ kukit.logDebug('EventRule #' + iloadoper.eventrule.getNr() + ' mergeid ' + iloadoper.eventrule.kss_selector.mergeid + ' event selected delayed execution (when iframe loaded)');
+ // We want the event execute once the iframe is loaded.
+ // In a somewhat tricky way, we start the scheduler only from the normal delayed execution. This will enable that in
+ // case we had a load event on the same node, it could modify the name and id parameters and we only start
+ // the autosense loop (which is based on name and id) after the load event's action executed.
+ // (Note, oper.node.id may lie in the log then and show the original, unchanged id but we ignore this for the time.)
+ var g = function() {
+ var f = function() {
+ var func_to_bind = iloadoper.makeExecuteActionsHook();
+ kukit.engine.bindScheduler.addPost(func_to_bind, 'Execute iload event for iframe ' + iloadoper.node.name);
+ };
+ new kukit.dom.EmbeddedContentLoadedScheduler(iloadoper.node.id, f, iloadoper.parms.autodetect);
+ }
+ kukit.engine.bindScheduler.addPost(g, 'Schedule iload event for iframe ' + iloadoper.node.name);
+ } else {
+ kukit.logDebug('EventRule #' + iloadoper.eventrule.getNr() + ' mergeid ' + iloadoper.eventrule.kss_selector.mergeid + ' event selected normal postponed execution.');
+ var func_to_bind = iloadoper.makeExecuteActionsHook();
+ kukit.engine.bindScheduler.addPost(func_to_bind, 'Execute iload event for iframe ' + iloadoper.node.name);
+ }
}
};
-kukit.eventsGlobalRegistry.register(null, 'load', kukit.pl.LoadEventBinder, '__bind__', null);
+// Use the "node" iterator to provide expected invocation and call signature of the bind method.
+kukit.eventsGlobalRegistry.registerForAllEvents(null, ['load', 'iload'], kukit.pl.LoadEventBinder, '__bind__', null, 'node');
+
/*
* class SpinnerEventBinder
@@ -499,7 +577,7 @@
kukit.commandsGlobalRegistry.registerFromAction('addClassName', kukit.cr.makeSelectorCommand);
kukit.actionsGlobalRegistry.register('removeClassName', function(oper) {
- oper.completeParms(['name'], {}, 'addClassName action');
+ oper.completeParms(['name'], {}, 'removeClassName action');
removeClassName(oper.node, oper.parms.name);
});
kukit.commandsGlobalRegistry.registerFromAction('removeClassName', kukit.cr.makeSelectorCommand);
@@ -635,6 +713,16 @@
});
kukit.commandsGlobalRegistry.registerFromAction('moveNodeAfter', kukit.cr.makeSelectorCommand);
+kukit.actionsGlobalRegistry.register('moveNodeBefore', function(oper) {
+ oper.completeParms(['html_id'], {}, 'moveNodeBefore action');
+ var node = oper.node;
+ var parentNode = node.parentNode;
+ parentNode.removeChild(node);
+ var toNode = document.getElementById(oper.parms.html_id);
+ parentNode.insertBefore(node, toNode);
+});
+kukit.commandsGlobalRegistry.registerFromAction('moveNodeBefore', kukit.cr.makeSelectorCommand);
+
kukit.actionsGlobalRegistry.register('copyChildNodesFrom', function(oper) {
oper.completeParms(['html_id'], {}, 'copyChildNodesFrom action');
var fromNode = document.getElementById(oper.parms.html_id);
@@ -740,4 +828,4 @@
kukit.commandsGlobalRegistry.registerFromAction('copyChildNodesFrom', kukit.cr.makeSelectorCommand, 'copyChildrenFrom');
kukit.commandsGlobalRegistry.registerFromAction('copyChildNodesTo', kukit.cr.makeSelectorCommand, 'copyChildrenTo');
kukit.commandsGlobalRegistry.registerFromAction('setStateVar', kukit.cr.makeGlobalCommand, 'setStatevar');
-
+
Modified: kukit/kukit.js/branch/performance_improvement/kukit/utils.js
==============================================================================
--- kukit/kukit.js/branch/performance_improvement/kukit/utils.js (original)
+++ kukit/kukit.js/branch/performance_improvement/kukit/utils.js Sun Apr 29 14:17:10 2007
@@ -282,6 +282,7 @@
kukit.ut.TimerCounter.prototype.clear = function() {
if (this.timer) {
window.clearTimeout(this.timer);
+ this.timer = null;
}
this.restart = false;
};
More information about the Kukit-checkins
mailing list