X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6746dc89c47ed01b165cc1152533605f97eb8e8d..HEAD:/src/core/src/dom/Element-more.js diff --git a/src/core/src/dom/Element-more.js b/src/core/src/dom/Element-more.js index d1bc8503..634c28a2 100644 --- a/src/core/src/dom/Element-more.js +++ b/src/core/src/dom/Element-more.js @@ -13,256 +13,288 @@ If you are unsure which license is appropriate for your use, please contact the */ /** - * @class Ext.core.Element + * @class Ext.Element */ -Ext.core.Element.addMethods({ - - /** - * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if - * the mouse was not moved back into the Element within the delay. If the mouse was moved - * back in, the function is not called. - * @param {Number} delay The delay in milliseconds to wait for possible mouse re-entry before calling the handler function. - * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time. - * @param {Object} scope The scope (this reference) in which the handler function executes. Defaults to this Element. - * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage: +Ext.Element.addMethods((function(){ + var focusRe = /button|input|textarea|select|object/; + return { + /** + * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if + * the mouse was not moved back into the Element within the delay. If the mouse was moved + * back in, the function is not called. + * @param {Number} delay The delay in milliseconds to wait for possible mouse re-entry before calling the handler function. + * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time. + * @param {Object} scope The scope (this reference) in which the handler function executes. Defaults to this Element. + * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:

 // Hide the menu if the mouse moves out for 250ms or more
 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
 
 ...
 // Remove mouseleave monitor on menu destroy
 this.menuEl.un(this.mouseLeaveMonitor);
-
- */ - monitorMouseLeave: function(delay, handler, scope) { - var me = this, - timer, - listeners = { - mouseleave: function(e) { - timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay); - }, - mouseenter: function() { - clearTimeout(timer); - }, - freezeEvent: true - }; +
+ */ + monitorMouseLeave: function(delay, handler, scope) { + var me = this, + timer, + listeners = { + mouseleave: function(e) { + timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay); + }, + mouseenter: function() { + clearTimeout(timer); + }, + freezeEvent: true + }; - me.on(listeners); - return listeners; - }, + me.on(listeners); + return listeners; + }, - /** - * Stops the specified event(s) from bubbling and optionally prevents the default action - * @param {String/Array} eventName an event / array of events to stop from bubbling - * @param {Boolean} preventDefault (optional) true to prevent the default action too - * @return {Ext.core.Element} this - */ - swallowEvent : function(eventName, preventDefault) { - var me = this; - function fn(e) { - e.stopPropagation(); - if (preventDefault) { - e.preventDefault(); + /** + * Stops the specified event(s) from bubbling and optionally prevents the default action + * @param {String/String[]} eventName an event / array of events to stop from bubbling + * @param {Boolean} preventDefault (optional) true to prevent the default action too + * @return {Ext.Element} this + */ + swallowEvent : function(eventName, preventDefault) { + var me = this; + function fn(e) { + e.stopPropagation(); + if (preventDefault) { + e.preventDefault(); + } } - } - - if (Ext.isArray(eventName)) { - Ext.each(eventName, function(e) { - me.on(e, fn); - }); - return me; - } - me.on(eventName, fn); - return me; - }, - /** - * Create an event handler on this element such that when the event fires and is handled by this element, - * it will be relayed to another object (i.e., fired again as if it originated from that object instead). - * @param {String} eventName The type of event to relay - * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context - * for firing the relayed event - */ - relayEvent : function(eventName, observable) { - this.on(eventName, function(e) { - observable.fireEvent(eventName, e); - }); - }, + if (Ext.isArray(eventName)) { + Ext.each(eventName, function(e) { + me.on(e, fn); + }); + return me; + } + me.on(eventName, fn); + return me; + }, - /** - * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes. - * @param {Boolean} forceReclean (optional) By default the element - * keeps track if it has been cleaned already so - * you can call this over and over. However, if you update the element and - * need to force a reclean, you can pass true. - */ - clean : function(forceReclean) { - var me = this, - dom = me.dom, - n = dom.firstChild, - nx, - ni = -1; + /** + * Create an event handler on this element such that when the event fires and is handled by this element, + * it will be relayed to another object (i.e., fired again as if it originated from that object instead). + * @param {String} eventName The type of event to relay + * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context + * for firing the relayed event + */ + relayEvent : function(eventName, observable) { + this.on(eventName, function(e) { + observable.fireEvent(eventName, e); + }); + }, - if (Ext.core.Element.data(dom, 'isCleaned') && forceReclean !== true) { - return me; - } + /** + * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes. + * @param {Boolean} forceReclean (optional) By default the element + * keeps track if it has been cleaned already so + * you can call this over and over. However, if you update the element and + * need to force a reclean, you can pass true. + */ + clean : function(forceReclean) { + var me = this, + dom = me.dom, + n = dom.firstChild, + nx, + ni = -1; + + if (Ext.Element.data(dom, 'isCleaned') && forceReclean !== true) { + return me; + } - while (n) { - nx = n.nextSibling; - if (n.nodeType == 3) { - // Remove empty/whitespace text nodes - if (!(/\S/.test(n.nodeValue))) { - dom.removeChild(n); - // Combine adjacent text nodes - } else if (nx && nx.nodeType == 3) { - n.appendData(Ext.String.trim(nx.data)); - dom.removeChild(nx); - nx = n.nextSibling; + while (n) { + nx = n.nextSibling; + if (n.nodeType == 3) { + // Remove empty/whitespace text nodes + if (!(/\S/.test(n.nodeValue))) { + dom.removeChild(n); + // Combine adjacent text nodes + } else if (nx && nx.nodeType == 3) { + n.appendData(Ext.String.trim(nx.data)); + dom.removeChild(nx); + nx = n.nextSibling; + n.nodeIndex = ++ni; + } + } else { + // Recursively clean + Ext.fly(n).clean(); n.nodeIndex = ++ni; } - } else { - // Recursively clean - Ext.fly(n).clean(); - n.nodeIndex = ++ni; + n = nx; } - n = nx; - } - Ext.core.Element.data(dom, 'isCleaned', true); - return me; - }, - - /** - * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object - * parameter as {@link Ext.ElementLoader#load} - * @return {Ext.core.Element} this - */ - load : function(options) { - this.getLoader().load(options); - return this; - }, + Ext.Element.data(dom, 'isCleaned', true); + return me; + }, - /** - * Gets this element's {@link Ext.ElementLoader ElementLoader} - * @return {Ext.ElementLoader} The loader - */ - getLoader : function() { - var dom = this.dom, - data = Ext.core.Element.data, - loader = data(dom, 'loader'); - - if (!loader) { - loader = Ext.create('Ext.ElementLoader', { - target: this - }); - data(dom, 'loader', loader); - } - return loader; - }, + /** + * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object + * parameter as {@link Ext.ElementLoader#load} + * @return {Ext.Element} this + */ + load : function(options) { + this.getLoader().load(options); + return this; + }, - /** - * Update the innerHTML of this element, optionally searching for and processing scripts - * @param {String} html The new HTML - * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false) - * @param {Function} callback (optional) For async script loading you can be notified when the update completes - * @return {Ext.core.Element} this - */ - update : function(html, loadScripts, callback) { - var me = this, - id, - dom, - interval; - - if (!me.dom) { - return me; - } - html = html || ''; - dom = me.dom; + /** + * Gets this element's {@link Ext.ElementLoader ElementLoader} + * @return {Ext.ElementLoader} The loader + */ + getLoader : function() { + var dom = this.dom, + data = Ext.Element.data, + loader = data(dom, 'loader'); + + if (!loader) { + loader = Ext.create('Ext.ElementLoader', { + target: this + }); + data(dom, 'loader', loader); + } + return loader; + }, - if (loadScripts !== true) { - dom.innerHTML = html; - Ext.callback(callback, me); - return me; - } + /** + * Update the innerHTML of this element, optionally searching for and processing scripts + * @param {String} html The new HTML + * @param {Boolean} [loadScripts=false] True to look for and process scripts + * @param {Function} [callback] For async script loading you can be notified when the update completes + * @return {Ext.Element} this + */ + update : function(html, loadScripts, callback) { + var me = this, + id, + dom, + interval; - id = Ext.id(); - html += ''; + if (!me.dom) { + return me; + } + html = html || ''; + dom = me.dom; - interval = setInterval(function(){ - if (!document.getElementById(id)) { - return false; + if (loadScripts !== true) { + dom.innerHTML = html; + Ext.callback(callback, me); + return me; } - clearInterval(interval); - var DOC = document, - hd = DOC.getElementsByTagName("head")[0], - re = /(?:]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig, - srcRe = /\ssrc=([\'\"])(.*?)\1/i, - typeRe = /\stype=([\'\"])(.*?)\1/i, - match, - attrs, - srcMatch, - typeMatch, - el, - s; - while ((match = re.exec(html))) { - attrs = match[1]; - srcMatch = attrs ? attrs.match(srcRe) : false; - if (srcMatch && srcMatch[2]) { - s = DOC.createElement("script"); - s.src = srcMatch[2]; - typeMatch = attrs.match(typeRe); - if (typeMatch && typeMatch[2]) { - s.type = typeMatch[2]; - } - hd.appendChild(s); - } else if (match[2] && match[2].length > 0) { - if (window.execScript) { - window.execScript(match[2]); - } else { - window.eval(match[2]); + id = Ext.id(); + html += ''; + + interval = setInterval(function(){ + if (!document.getElementById(id)) { + return false; + } + clearInterval(interval); + var DOC = document, + hd = DOC.getElementsByTagName("head")[0], + re = /(?:]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig, + srcRe = /\ssrc=([\'\"])(.*?)\1/i, + typeRe = /\stype=([\'\"])(.*?)\1/i, + match, + attrs, + srcMatch, + typeMatch, + el, + s; + + while ((match = re.exec(html))) { + attrs = match[1]; + srcMatch = attrs ? attrs.match(srcRe) : false; + if (srcMatch && srcMatch[2]) { + s = DOC.createElement("script"); + s.src = srcMatch[2]; + typeMatch = attrs.match(typeRe); + if (typeMatch && typeMatch[2]) { + s.type = typeMatch[2]; + } + hd.appendChild(s); + } else if (match[2] && match[2].length > 0) { + if (window.execScript) { + window.execScript(match[2]); + } else { + window.eval(match[2]); + } } } - } - - el = DOC.getElementById(id); - if (el) { - Ext.removeNode(el); - } - Ext.callback(callback, me); - }, 20); - dom.innerHTML = html.replace(/(?:)((\n|\r|.)*?)(?:<\/script>)/ig, ''); - return me; - }, - // inherit docs, overridden so we can add removeAnchor - removeAllListeners : function() { - this.removeAnchor(); - Ext.EventManager.removeAll(this.dom); - return this; - }, + el = DOC.getElementById(id); + if (el) { + Ext.removeNode(el); + } + Ext.callback(callback, me); + }, 20); + dom.innerHTML = html.replace(/(?:)((\n|\r|.)*?)(?:<\/script>)/ig, ''); + return me; + }, + + // inherit docs, overridden so we can add removeAnchor + removeAllListeners : function() { + this.removeAnchor(); + Ext.EventManager.removeAll(this.dom); + return this; + }, + + /** + * Gets the parent node of the current element taking into account Ext.scopeResetCSS + * @protected + * @return {HTMLElement} The parent element + */ + getScopeParent: function(){ + var parent = this.dom.parentNode; + return Ext.scopeResetCSS ? parent.parentNode : parent; + }, - /** - * Creates a proxy element of this element - * @param {String/Object} config The class name of the proxy element or a DomHelper config object - * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body) - * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false) - * @return {Ext.core.Element} The new proxy element - */ - createProxy : function(config, renderTo, matchBox) { - config = (typeof config == 'object') ? config : {tag : "div", cls: config}; + /** + * Creates a proxy element of this element + * @param {String/Object} config The class name of the proxy element or a DomHelper config object + * @param {String/HTMLElement} [renderTo] The element or element id to render the proxy to (defaults to document.body) + * @param {Boolean} [matchBox=false] True to align and size the proxy to this element now. + * @return {Ext.Element} The new proxy element + */ + createProxy : function(config, renderTo, matchBox) { + config = (typeof config == 'object') ? config : {tag : "div", cls: config}; - var me = this, - proxy = renderTo ? Ext.core.DomHelper.append(renderTo, config, true) : - Ext.core.DomHelper.insertBefore(me.dom, config, true); + var me = this, + proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) : + Ext.DomHelper.insertBefore(me.dom, config, true); - proxy.setVisibilityMode(Ext.core.Element.DISPLAY); - proxy.hide(); - if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded - proxy.setBox(me.getBox()); - } - return proxy; - } -}); -Ext.core.Element.prototype.clearListeners = Ext.core.Element.prototype.removeAllListeners; + proxy.setVisibilityMode(Ext.Element.DISPLAY); + proxy.hide(); + if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded + proxy.setBox(me.getBox()); + } + return proxy; + }, + + /** + * Checks whether this element can be focused. + * @return {Boolean} True if the element is focusable + */ + focusable: function(){ + var dom = this.dom, + nodeName = dom.nodeName.toLowerCase(), + canFocus = false, + hasTabIndex = !isNaN(dom.tabIndex); + + if (!dom.disabled) { + if (focusRe.test(nodeName)) { + canFocus = true; + } else { + canFocus = nodeName == 'a' ? dom.href || hasTabIndex : hasTabIndex; + } + } + return canFocus && this.isVisible(true); + } + }; +})()); +Ext.Element.prototype.clearListeners = Ext.Element.prototype.removeAllListeners;