UNPKG

modulex-util

Version:

common utilities from modulex

243 lines (224 loc) 6.94 kB
/** * this code can only run at browser environment * @ignore * @author lifesinger@gmail.com, yiminghe@gmail.com */ var util = require('./base'); var win = typeof window !== 'undefined' ? window : {}, doc = win.document || {}, docElem = doc.documentElement, EMPTY = '', domReady = 0, callbacks = [], // The number of poll times. POLL_RETIRES = 500, // The poll interval in milliseconds. POLL_INTERVAL = 40, // #id or id RE_ID_STR = /^#?([\w-]+)$/, RE_NOT_WHITESPACE = /\S/, standardEventModel = doc.addEventListener, supportEvent = doc.attachEvent || standardEventModel, DOM_READY_EVENT = 'DOMContentLoaded', READY_STATE_CHANGE_EVENT = 'readystatechange', LOAD_EVENT = 'load', COMPLETE = 'complete', /*global addEventListener:true, removeEventListener:true*/ addEventListener = standardEventModel ? function (el, type, fn) { el.addEventListener(type, fn, false); } : function (el, type, fn) { el.attachEvent('on' + type, fn); }, removeEventListener = standardEventModel ? function (el, type, fn) { el.removeEventListener(type, fn, false); } : function (el, type, fn) { el.detachEvent('on' + type, fn); }; util.mix(util, { /** * A crude way of determining if an object is a window * @member util */ isWindow: function (obj) { // must use == for ie8 /*jshint eqeqeq:false*/ return obj != null && obj == obj.window; }, /** * get xml representation of data * @param {String} data * @member util */ parseXml: function (data) { // already a xml if (data.documentElement) { return data; } var xml; // Standard if (win.DOMParser) { xml = new DOMParser().parseFromString(data, 'text/xml'); } else { // IE /*global ActiveXObject*/ xml = new ActiveXObject('Microsoft.XMLDOM'); xml.async = false; xml.loadXML(data); } if (!xml || !xml.documentElement || xml.getElementsByTagName('parsererror').length) { throw new Error('Invalid XML: ' + data); } return xml; }, /** * Evaluates a script in a global context. * @member util */ globalEval: function (data) { if (data && RE_NOT_WHITESPACE.test(data)) { // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context // http://msdn.microsoft.com/en-us/library/ie/ms536420(v=vs.85).aspx always return null /*jshint evil:true*/ if (win.execScript) { win.execScript(data); } else { (function (data) { win['eval'].call(win, data); })(data); } } }, /** * Specify a function to execute when the Dom is fully loaded. * @param fn {Function} A function to execute after the Dom is ready * @chainable * @member util */ ready: function (fn) { if (domReady) { if ('@DEBUG@') { fn(); } else { try { fn(); } catch (e) { setTimeout(function () { throw e; }, 0); } } } else { callbacks.push(fn); } return this; }, /** * Executes the supplied callback when the item with the supplied id is found. * @param id {String} The id of the element, or an array of ids to look for. * @param fn {Function} What to execute when the element is found. * @member util */ available: function (id, fn) { id = (id + EMPTY).match(RE_ID_STR)[1]; var retryCount = 1; var timer = util.later(function () { if (++retryCount > POLL_RETIRES) { timer.cancel(); return; } var node = doc.getElementById(id); if (node) { fn(node); timer.cancel(); } }, POLL_INTERVAL, true); } }); util.parseXML = util.parseXml; function fireReady() { if (domReady) { return; } // nodejs if (win && win.setTimeout) { removeEventListener(win, LOAD_EVENT, fireReady); } domReady = 1; for (var i = 0; i < callbacks.length; i++) { if ('@DEBUG@') { callbacks[i](); } else { try { callbacks[i](); } catch (e) { /*jshint loopfunc:true*/ setTimeout(function () { throw e; }, 0); } } } } // Binds ready events. function bindReady() { // Catch cases where ready() is called after the // browser event has already occurred. if (!doc || doc.readyState === COMPLETE) { fireReady(); return; } // A fallback to window.onload, that will always work addEventListener(win, LOAD_EVENT, fireReady); // w3c mode if (standardEventModel) { var domReady = function () { removeEventListener(doc, DOM_READY_EVENT, domReady); fireReady(); }; addEventListener(doc, DOM_READY_EVENT, domReady); } else { var stateChange = function () { if (doc.readyState === COMPLETE) { removeEventListener(doc, READY_STATE_CHANGE_EVENT, stateChange); fireReady(); } }; // ensure firing before onload (but completed after all inner iframes is loaded) // maybe late but safe also for iframes addEventListener(doc, READY_STATE_CHANGE_EVENT, stateChange); // If IE and not a frame // continually check to see if the document is ready var notframe, doScroll = docElem && docElem.doScroll; try { notframe = (win.frameElement === null); } catch (e) { notframe = false; } // can not use in iframe,parent window is dom ready so doScroll is ready too if (doScroll && notframe) { var readyScroll = function () { try { // Ref: http://javascript.nwbox.com/IEContentLoaded/ doScroll('left'); fireReady(); } catch (ex) { setTimeout(readyScroll, POLL_INTERVAL); } }; readyScroll(); } } } // bind on start // in case when you bind but the DOMContentLoaded has triggered // then you has to wait onload // worst case no callback at all if (supportEvent) { bindReady(); } try { if (doc.execCommand) { doc.execCommand('BackgroundImageCache', false, true); } } catch (e) { }