UNPKG

alpaca

Version:

Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices. It runs simply as HTML5 or more elaborately using Bootstrap, jQuery Mobile or jQuery UI. Alpaca uses Handlebars to process JSON schema and provide

2,070 lines (1,748 loc) 950 kB
// 4.1.7 (2014-11-27) /** * Compiled inline version. (Library mode) */ /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ /*globals $code */ (function(exports, undefined) { "use strict"; var modules = {}; function require(ids, callback) { var module, defs = []; for (var i = 0; i < ids.length; ++i) { module = modules[ids[i]] || resolve(ids[i]); if (!module) { throw 'module definition dependecy not found: ' + ids[i]; } defs.push(module); } callback.apply(null, defs); } function define(id, dependencies, definition) { if (typeof id !== 'string') { throw 'invalid module definition, module id must be defined and be a string'; } if (dependencies === undefined) { throw 'invalid module definition, dependencies must be specified'; } if (definition === undefined) { throw 'invalid module definition, definition function must be specified'; } require(dependencies, function() { modules[id] = definition.apply(null, arguments); }); } function defined(id) { return !!modules[id]; } function resolve(id) { var target = exports; var fragments = id.split(/[.\/]/); for (var fi = 0; fi < fragments.length; ++fi) { if (!target[fragments[fi]]) { return; } target = target[fragments[fi]]; } return target; } function expose(ids) { for (var i = 0; i < ids.length; i++) { var target = exports; var id = ids[i]; var fragments = id.split(/[.\/]/); for (var fi = 0; fi < fragments.length - 1; ++fi) { if (target[fragments[fi]] === undefined) { target[fragments[fi]] = {}; } target = target[fragments[fi]]; } target[fragments[fragments.length - 1]] = modules[id]; } } // Included from: js/tinymce/classes/dom/EventUtils.js /** * EventUtils.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*jshint loopfunc:true*/ /*eslint no-loop-func:0 */ /** * This class wraps the browsers native event logic with more convenient methods. * * @class tinymce.dom.EventUtils */ define("tinymce/dom/EventUtils", [], function() { "use strict"; var eventExpandoPrefix = "mce-data-"; var mouseEventRe = /^(?:mouse|contextmenu)|click/; var deprecated = {keyLocation: 1, layerX: 1, layerY: 1, returnValue: 1}; /** * Binds a native event to a callback on the speified target. */ function addEvent(target, name, callback, capture) { if (target.addEventListener) { target.addEventListener(name, callback, capture || false); } else if (target.attachEvent) { target.attachEvent('on' + name, callback); } } /** * Unbinds a native event callback on the specified target. */ function removeEvent(target, name, callback, capture) { if (target.removeEventListener) { target.removeEventListener(name, callback, capture || false); } else if (target.detachEvent) { target.detachEvent('on' + name, callback); } } /** * Normalizes a native event object or just adds the event specific methods on a custom event. */ function fix(originalEvent, data) { var name, event = data || {}, undef; // Dummy function that gets replaced on the delegation state functions function returnFalse() { return false; } // Dummy function that gets replaced on the delegation state functions function returnTrue() { return true; } // Copy all properties from the original event for (name in originalEvent) { // layerX/layerY is deprecated in Chrome and produces a warning if (!deprecated[name]) { event[name] = originalEvent[name]; } } // Normalize target IE uses srcElement if (!event.target) { event.target = event.srcElement || document; } // Calculate pageX/Y if missing and clientX/Y available if (originalEvent && mouseEventRe.test(originalEvent.type) && originalEvent.pageX === undef && originalEvent.clientX !== undef) { var eventDoc = event.target.ownerDocument || document; var doc = eventDoc.documentElement; var body = eventDoc.body; event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); } // Add preventDefault method event.preventDefault = function() { event.isDefaultPrevented = returnTrue; // Execute preventDefault on the original event object if (originalEvent) { if (originalEvent.preventDefault) { originalEvent.preventDefault(); } else { originalEvent.returnValue = false; // IE } } }; // Add stopPropagation event.stopPropagation = function() { event.isPropagationStopped = returnTrue; // Execute stopPropagation on the original event object if (originalEvent) { if (originalEvent.stopPropagation) { originalEvent.stopPropagation(); } else { originalEvent.cancelBubble = true; // IE } } }; // Add stopImmediatePropagation event.stopImmediatePropagation = function() { event.isImmediatePropagationStopped = returnTrue; event.stopPropagation(); }; // Add event delegation states if (!event.isDefaultPrevented) { event.isDefaultPrevented = returnFalse; event.isPropagationStopped = returnFalse; event.isImmediatePropagationStopped = returnFalse; } return event; } /** * Bind a DOMContentLoaded event across browsers and executes the callback once the page DOM is initialized. * It will also set/check the domLoaded state of the event_utils instance so ready isn't called multiple times. */ function bindOnReady(win, callback, eventUtils) { var doc = win.document, event = {type: 'ready'}; if (eventUtils.domLoaded) { callback(event); return; } // Gets called when the DOM is ready function readyHandler() { if (!eventUtils.domLoaded) { eventUtils.domLoaded = true; callback(event); } } function waitForDomLoaded() { // Check complete or interactive state if there is a body // element on some iframes IE 8 will produce a null body if (doc.readyState === "complete" || (doc.readyState === "interactive" && doc.body)) { removeEvent(doc, "readystatechange", waitForDomLoaded); readyHandler(); } } function tryScroll() { try { // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author. // http://javascript.nwbox.com/IEContentLoaded/ doc.documentElement.doScroll("left"); } catch (ex) { setTimeout(tryScroll, 0); return; } readyHandler(); } // Use W3C method if (doc.addEventListener) { if (doc.readyState === "complete") { readyHandler(); } else { addEvent(win, 'DOMContentLoaded', readyHandler); } } else { // Use IE method addEvent(doc, "readystatechange", waitForDomLoaded); // Wait until we can scroll, when we can the DOM is initialized if (doc.documentElement.doScroll && win.self === win.top) { tryScroll(); } } // Fallback if any of the above methods should fail for some odd reason addEvent(win, 'load', readyHandler); } /** * This class enables you to bind/unbind native events to elements and normalize it's behavior across browsers. */ function EventUtils() { var self = this, events = {}, count, expando, hasFocusIn, hasMouseEnterLeave, mouseEnterLeave; expando = eventExpandoPrefix + (+new Date()).toString(32); hasMouseEnterLeave = "onmouseenter" in document.documentElement; hasFocusIn = "onfocusin" in document.documentElement; mouseEnterLeave = {mouseenter: 'mouseover', mouseleave: 'mouseout'}; count = 1; // State if the DOMContentLoaded was executed or not self.domLoaded = false; self.events = events; /** * Executes all event handler callbacks for a specific event. * * @private * @param {Event} evt Event object. * @param {String} id Expando id value to look for. */ function executeHandlers(evt, id) { var callbackList, i, l, callback, container = events[id]; callbackList = container && container[evt.type]; if (callbackList) { for (i = 0, l = callbackList.length; i < l; i++) { callback = callbackList[i]; // Check if callback exists might be removed if a unbind is called inside the callback if (callback && callback.func.call(callback.scope, evt) === false) { evt.preventDefault(); } // Should we stop propagation to immediate listeners if (evt.isImmediatePropagationStopped()) { return; } } } } /** * Binds a callback to an event on the specified target. * * @method bind * @param {Object} target Target node/window or custom object. * @param {String} names Name of the event to bind. * @param {function} callback Callback function to execute when the event occurs. * @param {Object} scope Scope to call the callback function on, defaults to target. * @return {function} Callback function that got bound. */ self.bind = function(target, names, callback, scope) { var id, callbackList, i, name, fakeName, nativeHandler, capture, win = window; // Native event handler function patches the event and executes the callbacks for the expando function defaultNativeHandler(evt) { executeHandlers(fix(evt || win.event), id); } // Don't bind to text nodes or comments if (!target || target.nodeType === 3 || target.nodeType === 8) { return; } // Create or get events id for the target if (!target[expando]) { id = count++; target[expando] = id; events[id] = {}; } else { id = target[expando]; } // Setup the specified scope or use the target as a default scope = scope || target; // Split names and bind each event, enables you to bind multiple events with one call names = names.split(' '); i = names.length; while (i--) { name = names[i]; nativeHandler = defaultNativeHandler; fakeName = capture = false; // Use ready instead of DOMContentLoaded if (name === "DOMContentLoaded") { name = "ready"; } // DOM is already ready if (self.domLoaded && name === "ready" && target.readyState == 'complete') { callback.call(scope, fix({type: name})); continue; } // Handle mouseenter/mouseleaver if (!hasMouseEnterLeave) { fakeName = mouseEnterLeave[name]; if (fakeName) { nativeHandler = function(evt) { var current, related; current = evt.currentTarget; related = evt.relatedTarget; // Check if related is inside the current target if it's not then the event should // be ignored since it's a mouseover/mouseout inside the element if (related && current.contains) { // Use contains for performance related = current.contains(related); } else { while (related && related !== current) { related = related.parentNode; } } // Fire fake event if (!related) { evt = fix(evt || win.event); evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter'; evt.target = current; executeHandlers(evt, id); } }; } } // Fake bubbeling of focusin/focusout if (!hasFocusIn && (name === "focusin" || name === "focusout")) { capture = true; fakeName = name === "focusin" ? "focus" : "blur"; nativeHandler = function(evt) { evt = fix(evt || win.event); evt.type = evt.type === 'focus' ? 'focusin' : 'focusout'; executeHandlers(evt, id); }; } // Setup callback list and bind native event callbackList = events[id][name]; if (!callbackList) { events[id][name] = callbackList = [{func: callback, scope: scope}]; callbackList.fakeName = fakeName; callbackList.capture = capture; //callbackList.callback = callback; // Add the nativeHandler to the callback list so that we can later unbind it callbackList.nativeHandler = nativeHandler; // Check if the target has native events support if (name === "ready") { bindOnReady(target, nativeHandler, self); } else { addEvent(target, fakeName || name, nativeHandler, capture); } } else { if (name === "ready" && self.domLoaded) { callback({type: name}); } else { // If it already has an native handler then just push the callback callbackList.push({func: callback, scope: scope}); } } } target = callbackList = 0; // Clean memory for IE return callback; }; /** * Unbinds the specified event by name, name and callback or all events on the target. * * @method unbind * @param {Object} target Target node/window or custom object. * @param {String} names Optional event name to unbind. * @param {function} callback Optional callback function to unbind. * @return {EventUtils} Event utils instance. */ self.unbind = function(target, names, callback) { var id, callbackList, i, ci, name, eventMap; // Don't bind to text nodes or comments if (!target || target.nodeType === 3 || target.nodeType === 8) { return self; } // Unbind event or events if the target has the expando id = target[expando]; if (id) { eventMap = events[id]; // Specific callback if (names) { names = names.split(' '); i = names.length; while (i--) { name = names[i]; callbackList = eventMap[name]; // Unbind the event if it exists in the map if (callbackList) { // Remove specified callback if (callback) { ci = callbackList.length; while (ci--) { if (callbackList[ci].func === callback) { var nativeHandler = callbackList.nativeHandler; var fakeName = callbackList.fakeName, capture = callbackList.capture; // Clone callbackList since unbind inside a callback would otherwise break the handlers loop callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1)); callbackList.nativeHandler = nativeHandler; callbackList.fakeName = fakeName; callbackList.capture = capture; eventMap[name] = callbackList; } } } // Remove all callbacks if there isn't a specified callback or there is no callbacks left if (!callback || callbackList.length === 0) { delete eventMap[name]; removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); } } } } else { // All events for a specific element for (name in eventMap) { callbackList = eventMap[name]; removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); } eventMap = {}; } // Check if object is empty, if it isn't then we won't remove the expando map for (name in eventMap) { return self; } // Delete event object delete events[id]; // Remove expando from target try { // IE will fail here since it can't delete properties from window delete target[expando]; } catch (ex) { // IE will set it to null target[expando] = null; } } return self; }; /** * Fires the specified event on the specified target. * * @method fire * @param {Object} target Target node/window or custom object. * @param {String} name Event name to fire. * @param {Object} args Optional arguments to send to the observers. * @return {EventUtils} Event utils instance. */ self.fire = function(target, name, args) { var id; // Don't bind to text nodes or comments if (!target || target.nodeType === 3 || target.nodeType === 8) { return self; } // Build event object by patching the args args = fix(null, args); args.type = name; args.target = target; do { // Found an expando that means there is listeners to execute id = target[expando]; if (id) { executeHandlers(args, id); } // Walk up the DOM target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow; } while (target && !args.isPropagationStopped()); return self; }; /** * Removes all bound event listeners for the specified target. This will also remove any bound * listeners to child nodes within that target. * * @method clean * @param {Object} target Target node/window object. * @return {EventUtils} Event utils instance. */ self.clean = function(target) { var i, children, unbind = self.unbind; // Don't bind to text nodes or comments if (!target || target.nodeType === 3 || target.nodeType === 8) { return self; } // Unbind any element on the specificed target if (target[expando]) { unbind(target); } // Target doesn't have getElementsByTagName it's probably a window object then use it's document to find the children if (!target.getElementsByTagName) { target = target.document; } // Remove events from each child element if (target && target.getElementsByTagName) { unbind(target); children = target.getElementsByTagName('*'); i = children.length; while (i--) { target = children[i]; if (target[expando]) { unbind(target); } } } return self; }; /** * Destroys the event object. Call this on IE to remove memory leaks. */ self.destroy = function() { events = {}; }; // Legacy function for canceling events self.cancel = function(e) { if (e) { e.preventDefault(); e.stopImmediatePropagation(); } return false; }; } EventUtils.Event = new EventUtils(); EventUtils.Event.bind(window, 'ready', function() {}); return EventUtils; }); // Included from: js/tinymce/classes/dom/Sizzle.jQuery.js /** * Sizzle.jQuery.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*global jQuery:true */ /* * Fake Sizzle using jQuery. */ define("tinymce/dom/Sizzle", [], function() { // Detect if jQuery is loaded if (!window.jQuery) { throw new Error("Load jQuery first"); } return jQuery.find; }); // Included from: js/tinymce/classes/Env.js /** * Env.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This class contains various environment constants like browser versions etc. * Normally you don't want to sniff specific browser versions but sometimes you have * to when it's impossible to feature detect. So use this with care. * * @class tinymce.Env * @static */ define("tinymce/Env", [], function() { var nav = navigator, userAgent = nav.userAgent; var opera, webkit, ie, ie11, gecko, mac, iDevice; opera = window.opera && window.opera.buildNumber; webkit = /WebKit/.test(userAgent); ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName); ie = ie && /MSIE (\w+)\./.exec(userAgent)[1]; ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false; ie = ie || ie11; gecko = !webkit && !ie11 && /Gecko/.test(userAgent); mac = userAgent.indexOf('Mac') != -1; iDevice = /(iPad|iPhone)/.test(userAgent); // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions // says it has contentEditable support but there is no visible caret. var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534; return { /** * Constant that is true if the browser is Opera. * * @property opera * @type Boolean * @final */ opera: opera, /** * Constant that is true if the browser is WebKit (Safari/Chrome). * * @property webKit * @type Boolean * @final */ webkit: webkit, /** * Constant that is more than zero if the browser is IE. * * @property ie * @type Boolean * @final */ ie: ie, /** * Constant that is true if the browser is Gecko. * * @property gecko * @type Boolean * @final */ gecko: gecko, /** * Constant that is true if the os is Mac OS. * * @property mac * @type Boolean * @final */ mac: mac, /** * Constant that is true if the os is iOS. * * @property iOS * @type Boolean * @final */ iOS: iDevice, /** * Constant that is true if the browser supports editing. * * @property contentEditable * @type Boolean * @final */ contentEditable: contentEditable, /** * Transparent image data url. * * @property transparentSrc * @type Boolean * @final */ transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", /** * Returns true/false if the browser can or can't place the caret after a inline block like an image. * * @property noCaretAfter * @type Boolean * @final */ caretAfter: ie != 8, /** * Constant that is true if the browser supports native DOM Ranges. IE 9+. * * @property range * @type Boolean */ range: window.getSelection && "Range" in window, /** * Returns the IE document mode for non IE browsers this will fake IE 10. * * @property documentMode * @type Number */ documentMode: ie ? (document.documentMode || 7) : 10 }; }); // Included from: js/tinymce/classes/util/Tools.js /** * Tools.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This class contains various utlity functions. These are also exposed * directly on the tinymce namespace. * * @class tinymce.util.Tools */ define("tinymce/util/Tools", [ "tinymce/Env" ], function(Env) { /** * Removes whitespace from the beginning and end of a string. * * @method trim * @param {String} s String to remove whitespace from. * @return {String} New string with removed whitespace. */ var whiteSpaceRegExp = /^\s*|\s*$/g; function trim(str) { return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, ''); } /** * Returns true/false if the object is an array or not. * * @method isArray * @param {Object} obj Object to check. * @return {boolean} true/false state if the object is an array or not. */ var isArray = Array.isArray || function(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; }; /** * Checks if a object is of a specific type for example an array. * * @method is * @param {Object} o Object to check type of. * @param {string} t Optional type to check for. * @return {Boolean} true/false if the object is of the specified type. */ function is(o, t) { if (!t) { return o !== undefined; } if (t == 'array' && isArray(o)) { return true; } return typeof(o) == t; } /** * Converts the specified object into a real JavaScript array. * * @method toArray * @param {Object} obj Object to convert into array. * @return {Array} Array object based in input. */ function toArray(obj) { var array = obj, i, l; if (!isArray(obj)) { array = []; for (i = 0, l = obj.length; i < l; i++) { array[i] = obj[i]; } } return array; } /** * Makes a name/object map out of an array with names. * * @method makeMap * @param {Array/String} items Items to make map out of. * @param {String} delim Optional delimiter to split string by. * @param {Object} map Optional map to add items to. * @return {Object} Name/value map of items. */ function makeMap(items, delim, map) { var i; items = items || []; delim = delim || ','; if (typeof(items) == "string") { items = items.split(delim); } map = map || {}; i = items.length; while (i--) { map[items[i]] = {}; } return map; } /** * Performs an iteration of all items in a collection such as an object or array. This method will execure the * callback function for each item in the collection, if the callback returns false the iteration will terminate. * The callback has the following format: cb(value, key_or_index). * * @method each * @param {Object} o Collection to iterate. * @param {function} cb Callback function to execute for each item. * @param {Object} s Optional scope to execute the callback in. * @example * // Iterate an array * tinymce.each([1,2,3], function(v, i) { * console.debug("Value: " + v + ", Index: " + i); * }); * * // Iterate an object * tinymce.each({a: 1, b: 2, c: 3], function(v, k) { * console.debug("Value: " + v + ", Key: " + k); * }); */ function each(o, cb, s) { var n, l; if (!o) { return 0; } s = s || o; if (o.length !== undefined) { // Indexed arrays, needed for Safari for (n = 0, l = o.length; n < l; n++) { if (cb.call(s, o[n], n, o) === false) { return 0; } } } else { // Hashtables for (n in o) { if (o.hasOwnProperty(n)) { if (cb.call(s, o[n], n, o) === false) { return 0; } } } } return 1; } /** * Creates a new array by the return value of each iteration function call. This enables you to convert * one array list into another. * * @method map * @param {Array} array Array of items to iterate. * @param {function} callback Function to call for each item. It's return value will be the new value. * @return {Array} Array with new values based on function return values. */ function map(array, callback) { var out = []; each(array, function(item) { out.push(callback(item)); }); return out; } /** * Filters out items from the input array by calling the specified function for each item. * If the function returns false the item will be excluded if it returns true it will be included. * * @method grep * @param {Array} a Array of items to loop though. * @param {function} f Function to call for each item. Include/exclude depends on it's return value. * @return {Array} New array with values imported and filtered based in input. * @example * // Filter out some items, this will return an array with 4 and 5 * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;}); */ function grep(a, f) { var o = []; each(a, function(v) { if (!f || f(v)) { o.push(v); } }); return o; } /** * Creates a class, subclass or static singleton. * More details on this method can be found in the Wiki. * * @method create * @param {String} s Class name, inheritage and prefix. * @param {Object} p Collection of methods to add to the class. * @param {Object} root Optional root object defaults to the global window object. * @example * // Creates a basic class * tinymce.create('tinymce.somepackage.SomeClass', { * SomeClass: function() { * // Class constructor * }, * * method: function() { * // Some method * } * }); * * // Creates a basic subclass class * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', { * SomeSubClass: function() { * // Class constructor * this.parent(); // Call parent constructor * }, * * method: function() { * // Some method * this.parent(); // Call parent method * }, * * 'static': { * staticMethod: function() { * // Static method * } * } * }); * * // Creates a singleton/static class * tinymce.create('static tinymce.somepackage.SomeSingletonClass', { * method: function() { * // Some method * } * }); */ function create(s, p, root) { var self = this, sp, ns, cn, scn, c, de = 0; // Parse : <prefix> <class>:<super class> s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name // Create namespace for new class ns = self.createNS(s[3].replace(/\.\w+$/, ''), root); // Class already exists if (ns[cn]) { return; } // Make pure static class if (s[2] == 'static') { ns[cn] = p; if (this.onCreate) { this.onCreate(s[2], s[3], ns[cn]); } return; } // Create default constructor if (!p[cn]) { p[cn] = function() {}; de = 1; } // Add constructor and methods ns[cn] = p[cn]; self.extend(ns[cn].prototype, p); // Extend if (s[5]) { sp = self.resolve(s[5]).prototype; scn = s[5].match(/\.(\w+)$/i)[1]; // Class name // Extend constructor c = ns[cn]; if (de) { // Add passthrough constructor ns[cn] = function() { return sp[scn].apply(this, arguments); }; } else { // Add inherit constructor ns[cn] = function() { this.parent = sp[scn]; return c.apply(this, arguments); }; } ns[cn].prototype[cn] = ns[cn]; // Add super methods self.each(sp, function(f, n) { ns[cn].prototype[n] = sp[n]; }); // Add overridden methods self.each(p, function(f, n) { // Extend methods if needed if (sp[n]) { ns[cn].prototype[n] = function() { this.parent = sp[n]; return f.apply(this, arguments); }; } else { if (n != cn) { ns[cn].prototype[n] = f; } } }); } // Add static methods /*jshint sub:true*/ self.each(p['static'], function(f, n) { ns[cn][n] = f; }); } /** * Returns the index of a value in an array, this method will return -1 if the item wasn't found. * * @method inArray * @param {Array} a Array/Object to search for value in. * @param {Object} v Value to check for inside the array. * @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found. * @example * // Get index of value in array this will alert 1 since 2 is at that index * alert(tinymce.inArray([1,2,3], 2)); */ function inArray(a, v) { var i, l; if (a) { for (i = 0, l = a.length; i < l; i++) { if (a[i] === v) { return i; } } } return -1; } function extend(obj, ext) { var i, l, name, args = arguments, value; for (i = 1, l = args.length; i < l; i++) { ext = args[i]; for (name in ext) { if (ext.hasOwnProperty(name)) { value = ext[name]; if (value !== undefined) { obj[name] = value; } } } } return obj; } /** * Executed the specified function for each item in a object tree. * * @method walk * @param {Object} o Object tree to walk though. * @param {function} f Function to call for each item. * @param {String} n Optional name of collection inside the objects to walk for example childNodes. * @param {String} s Optional scope to execute the function in. */ function walk(o, f, n, s) { s = s || this; if (o) { if (n) { o = o[n]; } each(o, function(o, i) { if (f.call(s, o, i, n) === false) { return false; } walk(o, f, n, s); }); } } /** * Creates a namespace on a specific object. * * @method createNS * @param {String} n Namespace to create for example a.b.c.d. * @param {Object} o Optional object to add namespace to, defaults to window. * @return {Object} New namespace object the last item in path. * @example * // Create some namespace * tinymce.createNS('tinymce.somepackage.subpackage'); * * // Add a singleton * var tinymce.somepackage.subpackage.SomeSingleton = { * method: function() { * // Some method * } * }; */ function createNS(n, o) { var i, v; o = o || window; n = n.split('.'); for (i = 0; i < n.length; i++) { v = n[i]; if (!o[v]) { o[v] = {}; } o = o[v]; } return o; } /** * Resolves a string and returns the object from a specific structure. * * @method resolve * @param {String} n Path to resolve for example a.b.c.d. * @param {Object} o Optional object to search though, defaults to window. * @return {Object} Last object in path or null if it couldn't be resolved. * @example * // Resolve a path into an object reference * var obj = tinymce.resolve('a.b.c.d'); */ function resolve(n, o) { var i, l; o = o || window; n = n.split('.'); for (i = 0, l = n.length; i < l; i++) { o = o[n[i]]; if (!o) { break; } } return o; } /** * Splits a string but removes the whitespace before and after each value. * * @method explode * @param {string} s String to split. * @param {string} d Delimiter to split by. * @example * // Split a string into an array with a,b,c * var arr = tinymce.explode('a, b, c'); */ function explode(s, d) { if (!s || is(s, 'array')) { return s; } return map(s.split(d || ','), trim); } function _addCacheSuffix(url) { var cacheSuffix = Env.cacheSuffix; if (cacheSuffix) { url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix; } return url; } return { trim: trim, isArray: isArray, is: is, toArray: toArray, makeMap: makeMap, each: each, map: map, grep: grep, inArray: inArray, extend: extend, create: create, walk: walk, createNS: createNS, resolve: resolve, explode: explode, _addCacheSuffix: _addCacheSuffix }; }); // Included from: js/tinymce/classes/dom/DomQuery.js /** * DomQuery.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This class mimics most of the jQuery API: * * This is whats currently implemented: * - Utility functions * - DOM traversial * - DOM manipulation * - Event binding * * This is not currently implemented: * - Dimension * - Ajax * - Animation * - Advanced chaining * * @example * var $ = tinymce.dom.DomQuery; * $('p').attr('attr', 'value').addClass('class'); * * @class tinymce.dom.DomQuery */ define("tinymce/dom/DomQuery", [ "tinymce/dom/EventUtils", "tinymce/dom/Sizzle", "tinymce/util/Tools", "tinymce/Env" ], function(EventUtils, Sizzle, Tools, Env) { var doc = document, push = Array.prototype.push, slice = Array.prototype.slice; var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/; var Event = EventUtils.Event, undef; function isDefined(obj) { return typeof obj !== 'undefined'; } function isString(obj) { return typeof obj === 'string'; } function isWindow(obj) { return obj && obj == obj.window; } function createFragment(html, fragDoc) { var frag, node, container; fragDoc = fragDoc || doc; container = fragDoc.createElement('div'); frag = fragDoc.createDocumentFragment(); container.innerHTML = html; while ((node = container.firstChild)) { frag.appendChild(node); } return frag; } function domManipulate(targetNodes, sourceItem, callback, reverse) { var i; if (isString(sourceItem)) { sourceItem = createFragment(sourceItem, getElementDocument(targetNodes[0])); } else if (sourceItem.length && !sourceItem.nodeType) { sourceItem = DomQuery.makeArray(sourceItem); if (reverse) { for (i = sourceItem.length - 1; i >= 0; i--) { domManipulate(targetNodes, sourceItem[i], callback, reverse); } } else { for (i = 0; i < sourceItem.length; i++) { domManipulate(targetNodes, sourceItem[i], callback, reverse); } } return targetNodes; } if (sourceItem.nodeType) { i = targetNodes.length; while (i--) { callback.call(targetNodes[i], sourceItem); } } return targetNodes; } function hasClass(node, className) { return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1; } function wrap(elements, wrapper, all) { var lastParent, newWrapper; wrapper = DomQuery(wrapper)[0]; elements.each(function() { var self = this; if (!all || lastParent != self.parentNode) { lastParent = self.parentNode; newWrapper = wrapper.cloneNode(false); self.parentNode.insertBefore(newWrapper, self); newWrapper.appendChild(self); } else { newWrapper.appendChild(self); } }); return elements; } var numericCssMap = Tools.makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom', ' '); var booleanMap = Tools.makeMap('checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected', ' '); var propFix = { 'for': 'htmlFor', 'class': 'className', 'readonly': 'readOnly' }; var cssFix = { 'float': 'cssFloat' }; var attrHooks = {}, cssHooks = {}; function DomQuery(selector, context) { /*eslint new-cap:0 */ return new DomQuery.fn.init(selector, context); } function inArray(item, array) { var i; if (array.indexOf) { return array.indexOf(item); } i = array.length; while (i--) { if (array[i] === item) { return i; } } return -1; } var whiteSpaceRegExp = /^\s*|\s*$/g; function trim(str) { return (str === null || str === undef) ? '' : ("" + str).replace(whiteSpaceRegExp, ''); } function each(obj, callback) { var length, key, i, undef, value; if (obj) { length = obj.length; if (length === undef) { // Loop object items for (key in obj) { if (obj.hasOwnProperty(key)) { value = obj[key]; if (callback.call(value, key, value) === false) { break; } } } } else { // Loop array items for (i = 0; i < length; i++) { value = obj[i]; if (callback.call(value, i, value) === false) { break; } } } } return obj; } function grep(array, callback) { var out = []; each(array, function(i, item) { if (callback(item, i)) { out.push(item); } }); return out; } function getElementDocument(element) { if (!element) { return doc; } if (element.nodeType == 9) { return element; } return element.ownerDocument; } DomQuery.fn = DomQuery.prototype = { constructor: DomQuery, /** * Selector for the current set. * * @property selector * @type String */ selector: "", /** * Context used to create the set. * * @property context * @type Element */ context: null, /** * Number of items in the current set. * * @property length * @type Number */ length: 0, /** * Constructs a new DomQuery instance with the specified selector or context. * * @constructor * @method init * @param {String/Array/DomQuery} selector Optional CSS selector/Array or array like object or HTML string. * @param {Document/Element} context Optional context to search in. */ init: function(selector, context) { var self = this, match, node; if (!selector) { return self; } if (selector.nodeType) { self.context = self[0] = selector; self.length = 1; return self; } if (context && context.nodeType) { self.context = context; } else { if (context) { return DomQuery(selector).attr(context); } else { self.context = context = document; } } if (isString(selector)) { self.selector = selector; if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) { match = [null, selector, null]; } else { match = rquickExpr.exec(selector); } if (match) { if (match[1]) { node = createFragment(selector, getElementDocument(context)).firstChild; while (node) { push.call(self, node); node = node.nextSibling; } } else { node = getElementDocument(context).getElementById(match[2]); if (!node) { return self; } if (node.id !== match[2]) { return self.find(selector); } self.length = 1; self[0] = node; } } else { return DomQuery(context).find(selector); } } else { this.add(selector, false); } return self; }, /** * Converts the current set to an array. * * @method toArray * @param {Array} Array of all nodes in set. */ toArray: function() { return Tools.toArray(this); }, /** * Adds new nodes to the set. * * @method add * @param {Array/tinymce.dom.DomQuery} items Array of all nodes to add to set. * @return {tinymce.dom.DomQuery} New instance with nodes added. */ add: function(items, sort) { var self = this, nodes, i; if (isString(items)) { return self.add(DomQuery(items)); } if (sort !== false) { nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items))); self.length = nodes.length; for (i = 0; i < nodes.length; i++) { self[i] = nodes[i]; } } else { push.apply(self, DomQuery.makeArray(items)); } return self; }, /** * Sets/gets attributes on the elements in the current set. * * @method attr * @param {String/Object} name Name of attribute to get or an object with attributes to set. * @param {String} value Optional value to set. * @return {tinymce.dom.DomQuery/String} Current set or the specified attribute when only the name is specified. */ attr: function(name, value) { var self = this, hook; if (typeof name === "object") { each(name, function(name, value) { self.attr(name, value); }); } else if (isDefined(value)) { this.each(function() { var hook; if (this.nodeType === 1) { hook = attrHooks[name]; if (hook && hook.set) { hook.set(this, value); return; } if (value === null) { this.removeAttribute(name, 2); } else { this.setAttribute(name, value, 2); } } }); } else { if (self[0] && self[0].nodeType === 1) { hook = attrHooks[name]; if (hook && hook.get) { return hook.get(self[0], name); } if (booleanMap[name]) { return self.prop(name) ? name : undef; } value = self[0].getAttribute(name, 2); if (value === null) { value = undef; } } return value; } return self; }, /** * Removes attributse on the elements in the current set. * * @method removeAttr * @param {String/Object} name Name of attribute to remove. * @return {tinymce.dom.DomQuery/String} Current set. */ removeAttr: function(name) { return this.attr(name, null); }, /** * Sets/gets properties on the elements in the current set. * * @method attr * @param {String/Object} name Name of property to get or an object with properties to set. * @param {String} value Optional value to set. * @return {tinymce.dom.DomQuery/String} Current set or the specified property when only the name is specified. */ prop: function(name, value) { var self = this; name = propFix[name] || name; if (typeof name === "object") { each(name, function(name, value) { self.prop(name, value); }); } else if (isDefined(value)) { this.each(function() { if (this.nodeType == 1) { this[name] = value; } }); } else { if (self[0] && self[0].nodeType && name in self[0]) { return self[0][name]; } return value; } return self; }, /** * Sets/gets styles on the elements in the current set. * * @method css * @param {String/Object} name Name of style to get or an object with styles to set. * @param {String} value Optional value to set. * @return {tinymce.dom.DomQuery/String} Current set or the specified style when only the name is specified. */ css: function(name, value) { var self = this, elm, hook; function camel(name) { return name.replace(/-(\D)/g, function(a, b) { return b.toUpperCase(); }); } function dashed(name) { return name.replace(/[A-Z]/g, function(a) { return '-' + a; }); } if (typeof name === "object") { each(name, function(name, value) { self.css(name, value); }); } else { if (isDefined(value)) { name = camel(name); // Default px suffix on these if (typeof(value) === 'number' && !numericCssMap[name]) { value += 'px'; } self.each(function() { var style = this.style; hook = cssHooks[name]; if (hook && hook.set) { hook.set(this, value); return; } try { this.style[cssFix[name] || name] = value; } catch (ex) { // Ignore } if (value === null || value === '') { if (style.removeProperty) { style.removeProperty(dashed(name)); } else { style.removeAttribute(name); } } }); } else { elm = self[0]; hook = cssHooks[name]; if (hook && hook.get) { return hook.get(elm); } if (elm.ownerDocument.defaultView) { try { return elm.ownerDocument.defaultView.getComputedStyle(elm, null).getPropertyValue(dashed(name)); } catch (ex) { return undef; } } else if (elm.currentStyle) { return elm.currentStyle[camel(name)]; } } } return self; }, /** * Removes all nodes in set from the document. * * @method remove * @return {tinymce.dom.DomQuery} Current set with the removed nodes. */ remove: function() { var self = this, node, i = this.length; while (i--) { node = self[i]; Event.clean(node); if (node.parentNode) { node.parentNode.removeChild(node); } } return this; }, /** * Empties all elements in set. * * @method empty * @return {tinymce.dom.DomQuery} Current set with the empty nodes. */ empty: function() { var self = this, node, i = this.length; while (i--) { node = self[i]; while (node.firstChild) { node.removeChild(node.firstChild); } } return this; }, /** * Sets or gets the HTML of the current set or first set node. * * @method html * @param {String} value Optional innerHTML value to set on each element. * @return {tinymce.dom.DomQuery/String} Current set or the innerHTML of the first element. */ html: function(value) { var self = this, i; if (isDefined(value)) { i = self.length; try { while (i--) { self[i].innerHTML = value; } } catch (ex) { // Workaround for "Unknown runtime error" when DIV is added to P on IE DomQuery(self[i]).empty().append(value); } return self; } return self[0] ? self[0].innerHTML : ''; }, /** * Sets or gets the text of the current set or first set node. * * @method text * @param {String} value Optional innerText value to set on each element. * @return {tinymce.dom.DomQuery/String} Current set or the innerText of the first element. */ text: function(value) { var self = this, i; if (isDefined(value)) { i = self.length; while (i--) { if ("innerText" in self[i]) { self[i].innerText = value; } else { self[0].textContent = value; } } return self; } return self[0] ? (self[0].innerText || self[0].textContent) : ''; }, /** * Appends the specified node/html or node set to the current set nodes. * * @method append * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to append to each element in set. * @return {tinymce.dom.DomQuery} Current set. */ append: function() { return domManipulate(this, arguments, function(node) { if (this.nodeType === 1) { this.appendChild(node); } }); }, /** * Prepends the specified node/html or node set to the current set nodes. * * @method prepend * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to prepend to each element in set. * @return {tinymce.dom.DomQuery} Current set. */ prepend: function() { return domManipulate(this, arguments, function(node) { if (this.nodeType === 1) { this.insertBefore(node, this.firstChild); } }, true); }, /** * Adds the specified elements before current set nodes. * * @method before * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add before to each element in set. * @return {tinymce.dom.DomQuery} Current set. */ before: function() { var self = this; if (self[0] && self[0].parentNode) { return domManipulate(self, arguments, function(node) { this.parentNode.insertBefore(node, this); }); } return self; }, /** * Adds the specified elements after current set nodes. * * @method after * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add after to each element in set. * @return {tinymce.dom.DomQuery} Current set. */ after: function() { var self = this; if (self[0] && self[0].parentNode) { return domManipulate(self, arguments, function(node) { this.parentNode.insertBefore(node, this.nextSibling); }, true); } return self; }, /** * Appends the specified set nodes to the specified selector/instance. * * @method appendTo * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to append the current set to. * @return {tinymce.dom.DomQuery} Current set with the appended nodes. */ appendTo: function(val) { DomQuery(val).append(this); return this; }, /** * Prepends the specified set nodes to the specified selector/instance. * * @method prependTo * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to prepend the current set to. * @return {tinymce.dom.DomQuery} Current set with the prepended nodes. */ prependTo: function(val) { DomQuery(val).prepend(this); return this; }, /** * Replaces the nodes in set with the specified content. *