/* * Based on: * Ext JS Library 1.1.1 * Copyright(c) 2006-2007, Ext JS, LLC. * * Originally Released Under LGPL - original licence link has changed is not relivant. * * Fork - LGPL * <script type="text/javascript"> */ // for old browsers window["undefined"] = window["undefined"]; /** * @class Roo * Roo core utilities and functions. * @singleton */ var Roo = {}; /** * Copies all the properties of config to obj. * @param {Object} obj The receiver of the properties * @param {Object} config The source of the properties * @param {Object} defaults A different object that will also be applied for default values * @return {Object} returns obj * @member Roo apply */ Roo.apply = function(o, c, defaults){ if(defaults){ // no "this" reference for friendly out of scope calls Roo.apply(o, defaults); } if(o && c && typeof c == 'object'){ for(var p in c){ o[p] = c[p]; } } return o; }; (function(){ var idSeed = 0; var ua = navigator.userAgent.toLowerCase(); var isStrict = document.compatMode == "CSS1Compat", isOpera = ua.indexOf("opera") > -1, isSafari = (/webkit|khtml/).test(ua), isFirefox = ua.indexOf("firefox") > -1, isIE = ua.indexOf("msie") > -1, isIE7 = ua.indexOf("msie 7") > -1, isIE11 = /trident.*rv\:11\./.test(ua), isEdge = ua.indexOf("edge") > -1, isGecko = !isSafari && ua.indexOf("gecko") > -1, isBorderBox = isIE && !isStrict, isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1), isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1), isLinux = (ua.indexOf("linux") != -1), isSecure = window.location.href.toLowerCase().indexOf("https") === 0, isIOS = /iphone|ipad/.test(ua), isAndroid = /android/.test(ua), isTouch = (function() { try { if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) { window.addEventListener('touchstart', function __set_has_touch__ () { Roo.isTouch = true; window.removeEventListener('touchstart', __set_has_touch__); }); return false; // no touch on chrome!? } document.createEvent("TouchEvent"); return true; } catch (e) { return false; } })(); // remove css image flicker if(isIE && !isIE7){ try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){} } Roo.apply(Roo, { /** * True if the browser is in strict mode * @type Boolean */ isStrict : isStrict, /** * True if the page is running over SSL * @type Boolean */ isSecure : isSecure, /** * True when the document is fully initialized and ready for action * @type Boolean */ isReady : false, /** * Turn on debugging output (currently only the factory uses this) * @type Boolean */ debug: false, /** * True to automatically uncache orphaned Roo.Elements periodically (defaults to true) * @type Boolean */ enableGarbageCollector : true, /** * True to automatically purge event listeners after uncaching an element (defaults to false). * Note: this only happens if enableGarbageCollector is true. * @type Boolean */ enableListenerCollection:false, /** * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent * the IE insecure content warning (defaults to javascript:false). * @type String */ SSL_SECURE_URL : "javascript:false", /** * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to * "http://Roojs.com/s.gif" and you should change this to a URL on your server). * @type String */ BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif", emptyFn : function(){}, /** * Copies all the properties of config to obj if they don't already exist. * @param {Object} obj The receiver of the properties * @param {Object} config The source of the properties * @return {Object} returns obj */ applyIf : function(o, c){ if(o && c){ for(var p in c){ if(typeof o[p] == "undefined"){ o[p] = c[p]; } } } return o; }, /** * Applies event listeners to elements by selectors when the document is ready. * The event name is specified with an @ suffix. <pre><code> Roo.addBehaviors({ // add a listener for click on all anchors in element with id foo '#foo a@click' : function(e, t){ // do something }, // add the same listener to multiple selectors (separated by comma BEFORE the @) '#foo a, #bar span.some-class@mouseover' : function(){ // do something } }); </code></pre> * @param {Object} obj The list of behaviors to apply */ addBehaviors : function(o){ if(!Roo.isReady){ Roo.onReady(function(){ Roo.addBehaviors(o); }); return; } var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times for(var b in o){ var parts = b.split('@'); if(parts[1]){ // for Object prototype breakers var s = parts[0]; if(!cache[s]){ cache[s] = Roo.select(s); } cache[s].on(parts[1], o[b]); } } cache = null; }, /** * Generates unique ids. If the element already has an id, it is unchanged * @param {String/HTMLElement/Element} el (optional) The element to generate an id for * @param {String} prefix (optional) Id prefix (defaults "Roo-gen") * @return {String} The generated Id. */ id : function(el, prefix){ prefix = prefix || "roo-gen"; el = Roo.getDom(el); var id = prefix + (++idSeed); return el ? (el.id ? el.id : (el.id = id)) : id; }, /** * Extends one class with another class and optionally overrides members with the passed literal. This class * also adds the function "override()" to the class that can be used to override * members on an instance. * @param {Object} subclass The class inheriting the functionality * @param {Object} superclass The class being extended * @param {Object} overrides (optional) A literal with members * @method extend */ extend : function(){ // inline overrides var io = function(o){ for(var m in o){ this[m] = o[m]; } }; return function(sb, sp, overrides){ if(typeof sp == 'object'){ // eg. prototype, rather than function constructor.. overrides = sp; sp = sb; sb = function(){sp.apply(this, arguments);}; } var F = function(){}, sbp, spp = sp.prototype; F.prototype = spp; sbp = sb.prototype = new F(); sbp.constructor=sb; sb.superclass=spp; if(spp.constructor == Object.prototype.constructor){ spp.constructor=sp; } sb.override = function(o){ Roo.override(sb, o); }; sbp.override = io; Roo.override(sb, overrides); return sb; }; }(), /** * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name. * Usage:<pre><code> Roo.override(MyClass, { newMethod1: function(){ // etc. }, newMethod2: function(foo){ // etc. } }); </code></pre> * @param {Object} origclass The class to override * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal * containing one or more methods. * @method override */ override : function(origclass, overrides){ if(overrides){ var p = origclass.prototype; for(var method in overrides){ p[method] = overrides[method]; } } }, /** * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage: * <pre><code> Roo.namespace('Company', 'Company.data'); Company.Widget = function() { ... } Company.data.CustomStore = function(config) { ... } </code></pre> * @param {String} namespace1 * @param {String} namespace2 * @param {String} etc * @method namespace */ namespace : function(){ var a=arguments, o=null, i, j, d, rt; for (i=0; i<a.length; ++i) { d=a[i].split("."); rt = d[0]; /** eval:var:o */ eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';'); for (j=1; j<d.length; ++j) { o[d[j]]=o[d[j]] || {}; o=o[d[j]]; } } }, /** * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage: * <pre><code> Roo.factory({ xns: Roo.data, xtype : 'Store', .....}); Roo.factory(conf, Roo.data); </code></pre> * @param {String} classname * @param {String} namespace (optional) * @method factory */ factory : function(c, ns) { // no xtype, no ns or c.xns - or forced off by c.xns if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info... return c; } ns = c.xns ? c.xns : ns; // if c.xns is set, then use that.. if (c.constructor == ns[c.xtype]) {// already created... return c; } if (ns[c.xtype]) { if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); } var ret = new ns[c.xtype](c); ret.xns = false; return ret; } c.xns = false; // prevent recursion.. return c; }, /** * Logs to console if it can. * * @param {String|Object} string * @method log */ log : function(s) { if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) { return; // alerT? } console.log(s); }, /** * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value. * @param {Object} o * @return {String} */ urlEncode : function(o){ if(!o){ return ""; } var buf = []; for(var key in o){ var ov = o[key], k = Roo.encodeURIComponent(key); var type = typeof ov; if(type == 'undefined'){ buf.push(k, "=&"); }else if(type != "function" && type != "object"){ buf.push(k, "=", Roo.encodeURIComponent(ov), "&"); }else if(ov instanceof Array){ if (ov.length) { for(var i = 0, len = ov.length; i < len; i++) { buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&"); } } else { buf.push(k, "=&"); } } } buf.pop(); return buf.join(""); }, /** * Safe version of encodeURIComponent * @param {String} data * @return {String} */ encodeURIComponent : function (data) { try { return encodeURIComponent(data); } catch(e) {} // should be an uri encode error. if (data == '' || data == null){ return ''; } // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript function nibble_to_hex(nibble){ var chars = '0123456789ABCDEF'; return chars.charAt(nibble); } data = data.toString(); var buffer = ''; for(var i=0; i<data.length; i++){ var c = data.charCodeAt(i); var bs = new Array(); if (c > 0x10000){ // 4 bytes bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18); bs[1] = 0x80 | ((c & 0x3F000) >>> 12); bs[2] = 0x80 | ((c & 0xFC0) >>> 6); bs[3] = 0x80 | (c & 0x3F); }else if (c > 0x800){ // 3 bytes bs[0] = 0xE0 | ((c & 0xF000) >>> 12); bs[1] = 0x80 | ((c & 0xFC0) >>> 6); bs[2] = 0x80 | (c & 0x3F); }else if (c > 0x80){ // 2 bytes bs[0] = 0xC0 | ((c & 0x7C0) >>> 6); bs[1] = 0x80 | (c & 0x3F); }else{ // 1 byte bs[0] = c; } for(var j=0; j<bs.length; j++){ var b = bs[j]; var hex = nibble_to_hex((b & 0xF0) >>> 4) + nibble_to_hex(b &0x0F); buffer += '%'+hex; } } return buffer; }, /** * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}. * @param {String} string * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false). * @return {Object} A literal with members */ urlDecode : function(string, overwrite){ if(!string || !string.length){ return {}; } var obj = {}; var pairs = string.split('&'); var pair, name, value; for(var i = 0, len = pairs.length; i < len; i++){ pair = pairs[i].split('='); name = decodeURIComponent(pair[0]); value = decodeURIComponent(pair[1]); if(overwrite !== true){ if(typeof obj[name] == "undefined"){ obj[name] = value; }else if(typeof obj[name] == "string"){ obj[name] = [obj[name]]; obj[name].push(value); }else{ obj[name].push(value); } }else{ obj[name] = value; } } return obj; }, /** * Iterates an array calling the passed function with each item, stopping if your function returns false. If the * passed array is not really an array, your function is called once with it. * The supplied function is called with (Object item, Number index, Array allItems). * @param {Array/NodeList/Mixed} array * @param {Function} fn * @param {Object} scope */ each : function(array, fn, scope){ if(typeof array.length == "undefined" || typeof array == "string"){ array = [array]; } for(var i = 0, len = array.length; i < len; i++){ if(fn.call(scope || array[i], array[i], i, array) === false){ return i; }; } }, // deprecated combine : function(){ var as = arguments, l = as.length, r = []; for(var i = 0; i < l; i++){ var a = as[i]; if(a instanceof Array){ r = r.concat(a); }else if(a.length !== undefined && !a.substr){ r = r.concat(Array.prototype.slice.call(a, 0)); }else{ r.push(a); } } return r; }, /** * Escapes the passed string for use in a regular expression * @param {String} str * @return {String} */ escapeRe : function(s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1"); }, // internal callback : function(cb, scope, args, delay){ if(typeof cb == "function"){ if(delay){ cb.defer(delay, scope, args || []); }else{ cb.apply(scope, args || []); } } }, /** * Return the dom node for the passed string (id), dom node, or Roo.Element * @param {String/HTMLElement/Roo.Element} el * @return HTMLElement */ getDom : function(el){ if(!el){ return null; } return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el); }, /** * Shorthand for {@link Roo.ComponentMgr#get} * @param {String} id * @return Roo.Component */ getCmp : function(id){ return Roo.ComponentMgr.get(id); }, num : function(v, defaultValue){ if(typeof v != 'number'){ return defaultValue; } return v; }, destroy : function(){ for(var i = 0, a = arguments, len = a.length; i < len; i++) { var as = a[i]; if(as){ if(as.dom){ as.removeAllListeners(); as.remove(); continue; } if(typeof as.purgeListeners == 'function'){ as.purgeListeners(); } if(typeof as.destroy == 'function'){ as.destroy(); } } } }, // inpired by a similar function in mootools library /** * Returns the type of object that is passed in. If the object passed in is null or undefined it * return false otherwise it returns one of the following values:<ul> * <li><b>string</b>: If the object passed is a string</li> * <li><b>number</b>: If the object passed is a number</li> * <li><b>boolean</b>: If the object passed is a boolean value</li> * <li><b>function</b>: If the object passed is a function reference</li> * <li><b>object</b>: If the object passed is an object</li> * <li><b>array</b>: If the object passed is an array</li> * <li><b>regexp</b>: If the object passed is a regular expression</li> * <li><b>element</b>: If the object passed is a DOM Element</li> * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li> * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li> * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li> * @param {Mixed} object * @return {String} */ type : function(o){ if(o === undefined || o === null){ return false; } if(o.htmlElement){ return 'element'; } var t = typeof o; if(t == 'object' && o.nodeName) { switch(o.nodeType) { case 1: return 'element'; case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace'; } } if(t == 'object' || t == 'function') { switch(o.constructor) { case Array: return 'array'; case RegExp: return 'regexp'; } if(typeof o.length == 'number' && typeof o.item == 'function') { return 'nodelist'; } } return t; }, /** * Returns true if the passed value is null, undefined or an empty string (optional). * @param {Mixed} value The value to test * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty * @return {Boolean} */ isEmpty : function(v, allowBlank){ return v === null || v === undefined || (!allowBlank ? v === '' : false); }, /** @type Boolean */ isOpera : isOpera, /** @type Boolean */ isSafari : isSafari, /** @type Boolean */ isFirefox : isFirefox, /** @type Boolean */ isIE : isIE, /** @type Boolean */ isIE7 : isIE7, /** @type Boolean */ isIE11 : isIE11, /** @type Boolean */ isEdge : isEdge, /** @type Boolean */ isGecko : isGecko, /** @type Boolean */ isBorderBox : isBorderBox, /** @type Boolean */ isWindows : isWindows, /** @type Boolean */ isLinux : isLinux, /** @type Boolean */ isMac : isMac, /** @type Boolean */ isIOS : isIOS, /** @type Boolean */ isAndroid : isAndroid, /** @type Boolean */ isTouch : isTouch, /** * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash, * you may want to set this to true. * @type Boolean */ useShims : ((isIE && !isIE7) || (isGecko && isMac)), /** * Selects a single element as a Roo Element * This is about as close as you can get to jQuery's $('do crazy stuff') * @param {String} selector The selector/xpath query * @param {Node} root (optional) The start of the query (defaults to document). * @return {Roo.Element} */ selectNode : function(selector, root) { var node = Roo.DomQuery.selectNode(selector,root); return node ? Roo.get(node) : new Roo.Element(false); } }); })(); Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data", "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux", "Roo.bootstrap", "Roo.bootstrap.dash");