assets/scripts/api.simile-widgets.org/ajax/2.2.1.fake/simile-ajax-api-debug.js (3,115 lines of code) (raw):

(function(root, factory) { if (typeof define === "function" && define.amd) { define(factory); } else { root.SimileAjax = factory(); } }(this, function() { /** * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/almond for details */ //Going sloppy to avoid 'use strict' string cost, but strict practices should //be followed. /*jslint sloppy: true */ /*global setTimeout: false */ var requirejs, require, define; (function (undef) { var main, req, makeMap, handlers, defined = {}, waiting = {}, config = {}, defining = {}, hasOwn = Object.prototype.hasOwnProperty, aps = [].slice; function hasProp(obj, prop) { return hasOwn.call(obj, prop); } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @returns {String} normalized name */ function normalize(name, baseName) { var nameParts, nameSegment, mapValue, foundMap, foundI, foundStarMap, starI, i, j, part, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {}; //Adjust any relative paths. if (name && name.charAt(0) === ".") { //If have a base name, try to normalize against it, //otherwise, assume it is a top-level require that will //be relative to baseUrl in the end. if (baseName) { //Convert baseName to array, and lop off the last part, //so that . matches that "directory" and not name of the baseName's //module. For instance, baseName of "one/two/three", maps to //"one/two/three.js", but we want the directory, "one/two" for //this normalization. baseParts = baseParts.slice(0, baseParts.length - 1); name = baseParts.concat(name.split("/")); //start trimDots for (i = 0; i < name.length; i += 1) { part = name[i]; if (part === ".") { name.splice(i, 1); i -= 1; } else if (part === "..") { if (i === 1 && (name[2] === '..' || name[0] === '..')) { //End of the line. Keep at least one non-dot //path segment at the front so it can be mapped //correctly to disk. Otherwise, there is likely //no path mapping for a path starting with '..'. //This can still fail, but catches the most reasonable //uses of .. break; } else if (i > 0) { name.splice(i - 1, 2); i -= 2; } } } //end trimDots name = name.join("/"); } else if (name.indexOf('./') === 0) { // No baseName, so this is ID is resolved relative // to baseUrl, pull off the leading dot. name = name.substring(2); } } //Apply map config if available. if ((baseParts || starMap) && map) { nameParts = name.split('/'); for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join("/"); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = map[baseParts.slice(0, j).join('/')]; //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = mapValue[nameSegment]; if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break; } } } } if (foundMap) { break; } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && starMap[nameSegment]) { foundStarMap = starMap[nameSegment]; starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join('/'); } } return name; } function makeRequire(relName, forceSync) { return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync])); }; } function makeNormalize(relName) { return function (name) { return normalize(name, relName); }; } function makeLoad(depName) { return function (value) { defined[depName] = value; }; } function callDep(name) { if (hasProp(waiting, name)) { var args = waiting[name]; delete waiting[name]; defining[name] = true; main.apply(undef, args); } if (!hasProp(defined, name) && !hasProp(defining, name)) { throw new Error('No ' + name); } return defined[name]; } //Turns a plugin!resource to [plugin, resource] //with the plugin being undefined if the name //did not have a plugin prefix. function splitPrefix(name) { var prefix, index = name ? name.indexOf('!') : -1; if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } return [prefix, name]; } /** * Makes a name map, normalizing the name, and using a plugin * for normalization if necessary. Grabs a ref to plugin * too, as an optimization. */ makeMap = function (name, relName) { var plugin, parts = splitPrefix(name), prefix = parts[0]; name = parts[1]; if (prefix) { prefix = normalize(prefix, relName); plugin = callDep(prefix); } //Normalize according if (prefix) { if (plugin && plugin.normalize) { name = plugin.normalize(name, makeNormalize(relName)); } else { name = normalize(name, relName); } } else { name = normalize(name, relName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; if (prefix) { plugin = callDep(prefix); } } //Using ridiculous property names for space reasons return { f: prefix ? prefix + '!' + name : name, //fullName n: name, pr: prefix, p: plugin }; }; function makeConfig(name) { return function () { return (config && config.config && config.config[name]) || {}; }; } handlers = { require: function (name) { return makeRequire(name); }, exports: function (name) { var e = defined[name]; if (typeof e !== 'undefined') { return e; } else { return (defined[name] = {}); } }, module: function (name) { return { id: name, uri: '', exports: defined[name], config: makeConfig(name) }; } }; main = function (name, deps, callback, relName) { var cjsModule, depName, ret, map, i, args = [], usingExports; //Use name if no relName relName = relName || name; //Call the callback to define the module, if necessary. if (typeof callback === 'function') { //Pull out the defined dependencies and pass the ordered //values to the callback. //Default to [require, exports, module] if no deps deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; for (i = 0; i < deps.length; i += 1) { map = makeMap(deps[i], relName); depName = map.f; //Fast path CommonJS standard dependencies. if (depName === "require") { args[i] = handlers.require(name); } else if (depName === "exports") { //CommonJS module spec 1.1 args[i] = handlers.exports(name); usingExports = true; } else if (depName === "module") { //CommonJS module spec 1.1 cjsModule = args[i] = handlers.module(name); } else if (hasProp(defined, depName) || hasProp(waiting, depName) || hasProp(defining, depName)) { args[i] = callDep(depName); } else if (map.p) { map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); args[i] = defined[depName]; } else { throw new Error(name + ' missing ' + depName); } } ret = callback.apply(defined[name], args); if (name) { //If setting exports via "module" is in play, //favor that over return value and exports. After that, //favor a non-undefined return value over exports use. if (cjsModule && cjsModule.exports !== undef && cjsModule.exports !== defined[name]) { defined[name] = cjsModule.exports; } else if (ret !== undef || !usingExports) { //Use the return value from the function. defined[name] = ret; } } } else if (name) { //May just be an object definition for the module. Only //worry about defining if have a module name. defined[name] = callback; } }; requirejs = require = req = function (deps, callback, relName, forceSync, alt) { if (typeof deps === "string") { if (handlers[deps]) { //callback in this case is really relName return handlers[deps](callback); } //Just return the module wanted. In this scenario, the //deps arg is the module name, and second arg (if passed) //is just the relName. //Normalize module name, if it contains . or .. return callDep(makeMap(deps, callback).f); } else if (!deps.splice) { //deps is a config object, not an array. config = deps; if (callback.splice) { //callback is an array, which means it is a dependency list. //Adjust args if there are dependencies deps = callback; callback = relName; relName = null; } else { deps = undef; } } //Support require(['a']) callback = callback || function () {}; //If relName is a function, it is an errback handler, //so remove it. if (typeof relName === 'function') { relName = forceSync; forceSync = alt; } //Simulate async callback; if (forceSync) { main(undef, deps, callback, relName); } else { //Using a non-zero value because of concern for what old browsers //do, and latest browsers "upgrade" to 4 if lower value is used: //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: //If want a value immediately, use require('id') instead -- something //that works in almond on the global level, but not guaranteed and //unlikely to work in other AMD implementations. setTimeout(function () { main(undef, deps, callback, relName); }, 4); } return req; }; /** * Just drops the config on the floor, but returns req in case * the config return value is used. */ req.config = function (cfg) { config = cfg; if (config.deps) { req(config.deps, config.callback); } return req; }; define = function (name, deps, callback) { //This module may not have dependencies if (!deps.splice) { //deps is not an array, so probably means //an object literal or factory function for //the value. Adjust args. callback = deps; deps = []; } if (!hasProp(defined, name) && !hasProp(waiting, name)) { waiting[name] = [name, deps, callback]; } }; define.amd = { jQuery: true }; }()); define("lib/almond", function(){}); define('scripts/simile-ajax-base',[],function() { var SimileAjax = { loaded: false, loadingScriptsCount: 0, error: null, params: { "bundle": true }, paramTypes: { "bundle": Boolean }, version: "3.0.0", jQuery: null, // use jQuery directly urlPrefix: null }; return SimileAjax; }); /*================================================== * Platform Utility Functions and Constants *================================================== */ define('scripts/platform',[],function() { var Platform = {}; Platform.os = { isMac: false, isWin: false, isWin32: false, isUnix: false }; Platform.browser = { isIE: false, isNetscape: false, isMozilla: false, isFirefox: false, isOpera: false, isSafari: false, majorVersion: 0, minorVersion: 0 }; (function() { var an = navigator.appName.toLowerCase(); var ua = navigator.userAgent.toLowerCase(); /* * Operating system */ Platform.os.isMac = (ua.indexOf('mac') != -1); Platform.os.isWin = (ua.indexOf('win') != -1); Platform.os.isWin32 = Platform.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 ); Platform.os.isUnix = (ua.indexOf('x11') != -1); /* * Browser */ Platform.browser.isIE = (an.indexOf("microsoft") != -1); Platform.browser.isNetscape = (an.indexOf("netscape") != -1); Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1); Platform.browser.isFirefox = (ua.indexOf("firefox") != -1); Platform.browser.isOpera = (an.indexOf("opera") != -1); Platform.browser.isSafari = (an.indexOf("safari") != -1); var parseVersionString = function(s) { var a = s.split("."); Platform.browser.majorVersion = parseInt(a[0]); Platform.browser.minorVersion = parseInt(a[1]); }; var indexOf = function(s, sub, start) { var i = s.indexOf(sub, start); return i >= 0 ? i : s.length; }; if (Platform.browser.isMozilla) { var offset = ua.indexOf("mozilla/"); if (offset >= 0) { parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset))); } } if (Platform.browser.isIE) { var offset = ua.indexOf("msie "); if (offset >= 0) { parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset))); } } if (Platform.browser.isNetscape) { var offset = ua.indexOf("rv:"); if (offset >= 0) { parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset))); } } if (Platform.browser.isFirefox) { var offset = ua.indexOf("firefox/"); if (offset >= 0) { parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset))); } } if (!("localeCompare" in String.prototype)) { String.prototype.localeCompare = function (s) { if (this < s) return -1; else if (this > s) return 1; else return 0; }; } })(); Platform.getDefaultLocale = function() { return Platform.clientLocale; }; return Platform; }); /*================================================== * Debug Utility Functions *================================================== */ define('scripts/debug',["./simile-ajax-base"], function(SimileAjax) { var Debug = { silent: false }; Debug.log = function(msg) { var f; if ("console" in window && "log" in window.console) { // FireBug installed f = function(msg2) { console.log(msg2); } } else { f = function(msg2) { if (!Debug.silent) { alert(msg2); } } } Debug.log = f; f(msg); }; Debug.warn = function(msg) { var f; if ("console" in window && "warn" in window.console) { // FireBug installed f = function(msg2) { console.warn(msg2); } } else { f = function(msg2) { if (!Debug.silent) { alert(msg2); } } } Debug.warn = f; f(msg); }; Debug.exception = function(e, msg) { var f, params = SimileAjax.parseURLParameters(); if (params.errors == "throw" || SimileAjax.params.errors == "throw") { f = function(e2, msg2) { throw(e2); // do not hide from browser's native debugging features }; } else if ("console" in window && "error" in window.console) { // FireBug installed f = function(e2, msg2) { if (msg2 != null) { console.error(msg2 + " %o", e2); } else { console.error(e2); } throw(e2); // do not hide from browser's native debugging features }; } else { f = function(e2, msg2) { if (!Debug.silent) { alert("Caught exception: " + msg2 + "\n\nDetails: " + ("description" in e2 ? e2.description : e2)); } throw(e2); // do not hide from browser's native debugging features }; } Debug.exception = f; f(e, msg); }; Debug.objectToString = function(o) { return Debug._objectToString(o, ""); }; Debug._objectToString = function(o, indent) { var indent2 = indent + " "; if (typeof o == "object") { var s = "{"; for (n in o) { s += indent2 + n + ": " + Debug._objectToString(o[n], indent2) + "\n"; } s += indent + "}"; return s; } else if (typeof o == "array") { var s = "["; for (var n = 0; n < o.length; n++) { s += Debug._objectToString(o[n], indent2) + "\n"; } s += indent + "]"; return s; } else { return o; } }; return Debug; }); /** * @fileOverview XmlHttp utility functions * @name SimileAjax.XmlHttp */ define('scripts/xmlhttp',["./debug", "./platform"], function(Debug, Platform) { var XmlHttp = new Object(); /** * Callback for XMLHttp onRequestStateChange. */ XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) { switch (xmlhttp.readyState) { // 1: Request not yet made // 2: Contact established with server but nothing downloaded yet // 3: Called multiple while downloading in progress // Download complete case 4: try { if (xmlhttp.status == 0 // file:// urls, works on Firefox || xmlhttp.status == 200 // http:// urls ) { if (fDone) { fDone(xmlhttp); } } else { if (fError) { fError( xmlhttp.statusText, xmlhttp.status, xmlhttp ); } } } catch (e) { Debug.exception("XmlHttp: Error handling onReadyStateChange", e); } break; } }; /** * Creates an XMLHttpRequest object. On the first run, this * function creates a platform-specific function for * instantiating an XMLHttpRequest object and then replaces * itself with that function. */ XmlHttp._createRequest = function() { if (Platform.browser.isIE) { var programIDs = [ "Msxml2.XMLHTTP", "Microsoft.XMLHTTP", "Msxml2.XMLHTTP.4.0" ]; for (var i = 0; i < programIDs.length; i++) { try { var programID = programIDs[i]; var f = function() { return new ActiveXObject(programID); }; var o = f(); // We are replacing the _createXmlHttpRequest // function with this inner function as we've // found out that it works. This is so that we // don't have to do all the testing over again // on subsequent calls. XmlHttp._createRequest = f; return o; } catch (e) { // silent } } // fall through to try new XMLHttpRequest(); } try { var f = function() { return new XMLHttpRequest(); }; var o = f(); // We are replacing the _createXmlHttpRequest // function with this inner function as we've // found out that it works. This is so that we // don't have to do all the testing over again // on subsequent calls. XmlHttp._createRequest = f; return o; } catch (e) { throw new Error("Failed to create an XMLHttpRequest object"); } }; /** * Performs an asynchronous HTTP GET. * * @param {Function} fError a function of the form function(statusText, statusCode, xmlhttp) * @param {Function} fDone a function of the form function(xmlhttp) */ XmlHttp.get = function(url, fError, fDone) { var xmlhttp = XmlHttp._createRequest(); xmlhttp.open("GET", url, true); xmlhttp.onreadystatechange = function() { XmlHttp._onReadyStateChange(xmlhttp, fError, fDone); }; xmlhttp.send(null); }; /** * Performs an asynchronous HTTP POST. * * @param {Function} fError a function of the form function(statusText, statusCode, xmlhttp) * @param {Function} fDone a function of the form function(xmlhttp) */ XmlHttp.post = function(url, body, fError, fDone) { var xmlhttp = XmlHttp._createRequest(); xmlhttp.open("POST", url, true); xmlhttp.onreadystatechange = function() { XmlHttp._onReadyStateChange(xmlhttp, fError, fDone); }; xmlhttp.send(body); }; XmlHttp._forceXML = function(xmlhttp) { try { xmlhttp.overrideMimeType("text/xml"); } catch (e) { xmlhttp.setrequestheader("Content-Type", "text/xml"); } }; return XmlHttp; }); /*================================================== * DOM Utility Functions *================================================== */ define('scripts/dom',["./platform"], function(Platform) { var DOM = new Object(); DOM.registerEventWithObject = function(elmt, eventName, obj, handlerName) { DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) { return obj[handlerName].call(obj, elmt2, evt, target); }); }; DOM.registerEvent = function(elmt, eventName, handler) { var handler2 = function(evt) { evt = (evt) ? evt : ((event) ? event : null); if (evt) { var target = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null); if (target) { target = (target.nodeType == 1 || target.nodeType == 9) ? target : target.parentNode; } return handler(elmt, evt, target); } return true; } if (Platform.browser.isIE) { elmt.attachEvent("on" + eventName, handler2); } else { elmt.addEventListener(eventName, handler2, false); } }; DOM.getPageCoordinates = function(elmt) { var left = 0; var top = 0; if (elmt.nodeType != 1) { elmt = elmt.parentNode; } var elmt2 = elmt; while (elmt2 != null) { left += elmt2.offsetLeft; top += elmt2.offsetTop; elmt2 = elmt2.offsetParent; } var body = document.body; while (elmt != null && elmt != body) { if ("scrollLeft" in elmt) { left -= elmt.scrollLeft; top -= elmt.scrollTop; } elmt = elmt.parentNode; } return { left: left, top: top }; }; DOM.getSize = function(elmt) { var w = this.getStyle(elmt,"width"); var h = this.getStyle(elmt,"height"); if (w.indexOf("px") > -1) w = w.replace("px",""); if (h.indexOf("px") > -1) h = h.replace("px",""); return { w: w, h: h } } DOM.getStyle = function(elmt, styleProp) { if (elmt.currentStyle) { // IE var style = elmt.currentStyle[styleProp]; } else if (window.getComputedStyle) { // standard DOM var style = document.defaultView.getComputedStyle(elmt, null).getPropertyValue(styleProp); } else { var style = ""; } return style; } DOM.getEventRelativeCoordinates = function(evt, elmt) { if (Platform.browser.isIE) { if (evt.type == "mousewheel") { var coords = DOM.getPageCoordinates(elmt); return { x: evt.clientX - coords.left, y: evt.clientY - coords.top }; } else { return { x: evt.offsetX, y: evt.offsetY }; } } else { var coords = DOM.getPageCoordinates(elmt); if ((evt.type == "DOMMouseScroll") && Platform.browser.isFirefox && (Platform.browser.majorVersion == 2)) { // Due to: https://bugzilla.mozilla.org/show_bug.cgi?id=352179 return { x: evt.screenX - coords.left, y: evt.screenY - coords.top }; } else { return { x: evt.pageX - coords.left, y: evt.pageY - coords.top }; } } }; DOM.getEventPageCoordinates = function(evt) { if (Platform.browser.isIE) { var scrOfY = 0; var scrOfX = 0; if (document.body && (document.body.scrollLeft || document.body.scrollTop)) { //DOM compliant scrOfY = document.body.scrollTop; scrOfX = document.body.scrollLeft; } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { //IE6 standards compliant mode scrOfY = document.documentElement.scrollTop; scrOfX = document.documentElement.scrollLeft; } return { x: evt.clientX + scrOfX, y: evt.clientY + scrOfY }; } else { return { x: evt.pageX, y: evt.pageY }; } }; DOM.hittest = function(x, y, except) { return DOM._hittest(document.body, x, y, except); }; DOM._hittest = function(elmt, x, y, except) { var childNodes = elmt.childNodes; outer: for (var i = 0; i < childNodes.length; i++) { var childNode = childNodes[i]; for (var j = 0; j < except.length; j++) { if (childNode == except[j]) { continue outer; } } if (childNode.offsetWidth == 0 && childNode.offsetHeight == 0) { /* * Sometimes SPAN elements have zero width and height but * they have children like DIVs that cover non-zero areas. */ var hitNode = DOM._hittest(childNode, x, y, except); if (hitNode != childNode) { return hitNode; } } else { var top = 0; var left = 0; var node = childNode; while (node) { top += node.offsetTop; left += node.offsetLeft; node = node.offsetParent; } if (left <= x && top <= y && (x - left) < childNode.offsetWidth && (y - top) < childNode.offsetHeight) { return DOM._hittest(childNode, x, y, except); } else if (childNode.nodeType == 1 && childNode.tagName == "TR") { /* * Table row might have cells that span several rows. */ var childNode2 = DOM._hittest(childNode, x, y, except); if (childNode2 != childNode) { return childNode2; } } } } return elmt; }; DOM.cancelEvent = function(evt) { evt.returnValue = false; evt.cancelBubble = true; if ("preventDefault" in evt) { evt.preventDefault(); } }; DOM.appendClassName = function(elmt, className) { var classes = elmt.className.split(" "); for (var i = 0; i < classes.length; i++) { if (classes[i] == className) { return; } } classes.push(className); elmt.className = classes.join(" "); }; DOM.createInputElement = function(type) { var div = document.createElement("div"); div.innerHTML = "<input type='" + type + "' />"; return div.firstChild; }; DOM.createDOMFromTemplate = function(template) { var result = {}; result.elmt = DOM._createDOMFromTemplate(template, result, null); return result; }; DOM._createDOMFromTemplate = function(templateNode, result, parentElmt) { if (templateNode == null) { /* var node = doc.createTextNode("--null--"); if (parentElmt != null) { parentElmt.appendChild(node); } return node; */ return null; } else if (typeof templateNode != "object") { var node = document.createTextNode(templateNode); if (parentElmt != null) { parentElmt.appendChild(node); } return node; } else { var elmt = null; if ("tag" in templateNode) { var tag = templateNode.tag; if (parentElmt != null) { if (tag == "tr") { elmt = parentElmt.insertRow(parentElmt.rows.length); } else if (tag == "td") { elmt = parentElmt.insertCell(parentElmt.cells.length); } } if (elmt == null) { elmt = tag == "input" ? DOM.createInputElement(templateNode.type) : document.createElement(tag); if (parentElmt != null) { parentElmt.appendChild(elmt); } } } else { elmt = templateNode.elmt; if (parentElmt != null) { parentElmt.appendChild(elmt); } } for (var attribute in templateNode) { var value = templateNode[attribute]; if (attribute == "field") { result[value] = elmt; } else if (attribute == "className") { elmt.className = value; } else if (attribute == "id") { elmt.id = value; } else if (attribute == "title") { elmt.title = value; } else if (attribute == "type" && elmt.tagName == "input") { // do nothing } else if (attribute == "style") { for (n in value) { var v = value[n]; if (n == "float") { n = Platform.browser.isIE ? "styleFloat" : "cssFloat"; } elmt.style[n] = v; } } else if (attribute == "children") { for (var i = 0; i < value.length; i++) { DOM._createDOMFromTemplate(value[i], result, elmt); } } else if (attribute != "tag" && attribute != "elmt") { elmt.setAttribute(attribute, value); } } return elmt; } } DOM._cachedParent = null; DOM.createElementFromString = function(s) { if (DOM._cachedParent == null) { DOM._cachedParent = document.createElement("div"); } DOM._cachedParent.innerHTML = s; return DOM._cachedParent.firstChild; }; DOM.createDOMFromString = function(root, s, fieldElmts) { var elmt = typeof root == "string" ? document.createElement(root) : root; elmt.innerHTML = s; var dom = { elmt: elmt }; DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts != null ? fieldElmts : {} ); return dom; }; DOM._processDOMConstructedFromString = function(dom, elmt, fieldElmts) { var id = elmt.id; if (id != null && id.length > 0) { elmt.removeAttribute("id"); if (id in fieldElmts) { var parentElmt = elmt.parentNode; parentElmt.insertBefore(fieldElmts[id], elmt); parentElmt.removeChild(elmt); dom[id] = fieldElmts[id]; return; } else { dom[id] = elmt; } } if (elmt.hasChildNodes()) { DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts); } }; DOM._processDOMChildrenConstructedFromString = function(dom, elmt, fieldElmts) { var node = elmt.firstChild; while (node != null) { var node2 = node.nextSibling; if (node.nodeType == 1) { DOM._processDOMConstructedFromString(dom, node, fieldElmts); } node = node2; } }; return DOM; }); /** * @fileOverview Graphics utility functions and constants * @name SimileAjax.Graphics */ define('scripts/graphics',[ "./simile-ajax-base", "./platform" ], function(SimileAjax, Platform) { var Graphics = { "pngIsTranslucent": undefined, "createTranslucentImage": undefined, "createTranslucentImageHTML": undefined }; /*================================================== * Opacity, translucency *================================================== */ Graphics._createTranslucentImage1 = function(url, verticalAlign) { var elmt = document.createElement("img"); elmt.setAttribute("src", url); if (verticalAlign != null) { elmt.style.verticalAlign = verticalAlign; } return elmt; }; Graphics._createTranslucentImage2 = function(url, verticalAlign) { var elmt = document.createElement("img"); elmt.style.width = "1px"; // just so that IE will calculate the size property elmt.style.height = "1px"; elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')"; elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle"; return elmt; }; Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) { return "<img src=\"" + url + "\"" + (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") + " />"; }; Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) { var style = "width: 1px; height: 1px; " + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" + (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : ""); return "<img src='" + url + "' style=\"" + style + "\" />"; }; /** * Consolidate graphics constant setting into a function dependent on * SimileAjax loading. * @param {Object} g Object to modify functions for. */ Graphics.initialize = function(g) { /** * A boolean value indicating whether PNG translucency is supported on the * user's browser or not. * * @type Boolean */ g.pngIsTranslucent = (!Platform.browser.isIE) || (Platform.browser.majorVersion > 6); if (!g.pngIsTranslucent) { includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css"); } /** * Creates a DOM element for an <code>img</code> tag using the URL given. * This is a convenience method that automatically includes the necessary * CSS to allow for translucency, even on IE. * * @function * @param {String} url the URL to the image * @param {String} verticalAlign the CSS value for the image's * vertical-align * @return {Element} a DOM element containing the <code>img</code> tag */ g.createTranslucentImage = g.pngIsTranslucent ? g._createTranslucentImage1 : g._createTranslucentImage2; /** * Creates an HTML string for an <code>img</code> tag using the URL given. * This is a convenience method that automatically includes the necessary * CSS to allow for translucency, even on IE. * * @function * @param {String} url the URL to the image * @param {String} verticalAlign the CSS value for the image's * vertical-align * @return {String} a string containing the <code>img</code> tag */ g.createTranslucentImageHTML = g.pngIsTranslucent ? g._createTranslucentImageHTML1 : g._createTranslucentImageHTML2; return g; }; /** * Sets the opacity on the given DOM element. * * @param {Element} elmt the DOM element to set the opacity on * @param {Number} opacity an integer from 0 to 100 specifying the opacity */ Graphics.setOpacity = function(elmt, opacity) { if (Platform.browser.isIE) { elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")"; } else { var o = (opacity / 100).toString(); elmt.style.opacity = o; elmt.style.MozOpacity = o; } }; /*================================================== * Bubble *================================================== */ Graphics.bubbleConfig = { containerCSSClass: "simileAjax-bubble-container", innerContainerCSSClass: "simileAjax-bubble-innerContainer", contentContainerCSSClass: "simileAjax-bubble-contentContainer", borderGraphicSize: 50, borderGraphicCSSClassPrefix: "simileAjax-bubble-border-", arrowGraphicTargetOffset: 33, // from tip of arrow to the side of the graphic that touches the content of the bubble arrowGraphicLength: 100, // dimension of arrow graphic along the direction that the arrow points arrowGraphicWidth: 49, // dimension of arrow graphic perpendicular to the direction that the arrow points arrowGraphicCSSClassPrefix: "simileAjax-bubble-arrow-", closeGraphicCSSClass: "simileAjax-bubble-close", extraPadding: 20 }; Graphics.getWindowDimensions = function() { if (typeof window.innerHeight == 'number') { return { w:window.innerWidth, h:window.innerHeight }; // Non-IE } else if (document.documentElement && document.documentElement.clientHeight) { return { // IE6+, in "standards compliant mode" w:document.documentElement.clientWidth, h:document.documentElement.clientHeight }; } else if (document.body && document.body.clientHeight) { return { // IE 4 compatible w:document.body.clientWidth, h:document.body.clientHeight }; } }; /** * Creates a floating, rounded message bubble in the center of the window for * displaying modal information, e.g. "Loading..." * * @param {Document} doc the root document for the page to render on * @param {Object} an object with two properties, contentDiv and containerDiv, * consisting of the newly created DOM elements */ Graphics.createMessageBubble = function(doc) { var containerDiv = doc.createElement("div"); var prefix = "simileAjax-messageBubble"; if (Graphics.pngIsTranslucent) { var topDiv = doc.createElement("div"); topDiv.className = prefix + "-top"; containerDiv.appendChild(topDiv); var topRightDiv = doc.createElement("div"); topRightDiv.className = prefix + "-top-right"; topDiv.appendChild(topRightDiv); var middleDiv = doc.createElement("div"); middleDiv.className = prefix + "-middle"; containerDiv.appendChild(middleDiv); var middleRightDiv = doc.createElement("div"); middleRightDiv.className = prefix + "-middle-right"; middleDiv.appendChild(middleRightDiv); var contentDiv = doc.createElement("div"); middleRightDiv.appendChild(contentDiv); var bottomDiv = doc.createElement("div"); bottomDiv.className = prefix + "-bottom"; containerDiv.appendChild(bottomDiv); var bottomRightDiv = doc.createElement("div"); bottomRightDiv.className = prefix + "-bottom-right"; bottomDiv.appendChild(bottomRightDiv); } else { containerDiv.style.border = "2px solid #7777AA"; containerDiv.style.padding = "20px"; containerDiv.style.background = "white"; Graphics.setOpacity(containerDiv, 90); var contentDiv = doc.createElement("div"); containerDiv.appendChild(contentDiv); } return { containerDiv: containerDiv, contentDiv: contentDiv }; }; /*================================================== * Animation *================================================== */ /** * Creates an animation for a function, and an interval of values. The word * "animation" here is used in the sense of repeatedly calling a function with * a current value from within an interval, and a delta value. * * @param {Function} f a function to be called every 50 milliseconds throughout * the animation duration, of the form f(current, delta), where current is * the current value within the range and delta is the current change. * @param {Number} from a starting value * @param {Number} to an ending value * @param {Number} duration the duration of the animation in milliseconds * @param {Function} [cont] an optional function that is called at the end of * the animation, i.e. a continuation. * @return {Graphics._Animation} a new animation object */ Graphics.createAnimation = function(f, from, to, duration, cont) { return new Graphics._Animation(f, from, to, duration, cont); }; Graphics._Animation = function(f, from, to, duration, cont) { this.f = f; this.cont = (typeof cont == "function") ? cont : function() {}; this.from = from; this.to = to; this.current = from; this.duration = duration; this.start = new Date().getTime(); this.timePassed = 0; }; /** * Runs this animation. */ Graphics._Animation.prototype.run = function() { var a = this; window.setTimeout(function() { a.step(); }, 50); }; /** * Increments this animation by one step, and then continues the animation with * <code>run()</code>. */ Graphics._Animation.prototype.step = function() { this.timePassed += 50; var timePassedFraction = this.timePassed / this.duration; var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5; var current = parameterFraction * (this.to - this.from) + this.from; try { this.f(current, current - this.current); } catch (e) { } this.current = current; if (this.timePassed < this.duration) { this.run(); } else { this.f(this.to, 0); this["cont"](); } }; /*================================================== * CopyPasteButton * * Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html. *================================================== */ /** * Creates a button and textarea for displaying structured data and copying it * to the clipboard. The data is dynamically generated by the given * createDataFunction parameter. * * @param {String} image an image URL to use as the background for the * generated box * @param {Number} width the width in pixels of the generated box * @param {Number} height the height in pixels of the generated box * @param {Function} createDataFunction a function that is called with no * arguments to generate the structured data * @return a new DOM element */ Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) { var div = document.createElement("div"); div.style.position = "relative"; div.style.display = "inline"; div.style.width = width + "px"; div.style.height = height + "px"; div.style.overflow = "hidden"; div.style.margin = "2px"; if (Graphics.pngIsTranslucent) { div.style.background = "url(" + image + ") no-repeat"; } else { div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')"; } var style; if (Platform.browser.isIE) { style = "filter:alpha(opacity=0)"; } else { style = "opacity: 0"; } div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />"; var textarea = div.firstChild; textarea.style.width = width + "px"; textarea.style.height = height + "px"; textarea.onmousedown = function(evt) { evt = (evt) ? evt : ((event) ? event : null); if (evt.button == 2) { textarea.value = createDataFunction(); textarea.select(); } }; return div; }; /*================================================== * getWidthHeight *================================================== */ Graphics.getWidthHeight = function(el) { // RETURNS hash {width: w, height: h} in pixels var w, h; // offsetWidth rounds on FF, so doesn't work for us. // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617 if (el.getBoundingClientRect == null) { // use offsetWidth w = el.offsetWidth; h = el.offsetHeight; } else { // use getBoundingClientRect var rect = el.getBoundingClientRect(); w = Math.ceil(rect.right - rect.left); h = Math.ceil(rect.bottom - rect.top); } return { width: w, height: h }; }; /*================================================== * FontRenderingContext *================================================== */ Graphics.getFontRenderingContext = function(elmt, width) { return new Graphics._FontRenderingContext(elmt, width); }; Graphics._FontRenderingContext = function(elmt, width) { this._elmt = elmt; this._elmt.style.visibility = "hidden"; if (typeof width == "string") { this._elmt.style.width = width; } else if (typeof width == "number") { this._elmt.style.width = width + "px"; } }; Graphics._FontRenderingContext.prototype.dispose = function() { this._elmt = null; }; Graphics._FontRenderingContext.prototype.update = function() { this._elmt.innerHTML = "A"; this._lineHeight = this._elmt.offsetHeight; }; Graphics._FontRenderingContext.prototype.computeSize = function(text, className) { // className arg is optional var el = this._elmt; el.innerHTML = text; el.className = className === undefined ? '' : className; var wh = Graphics.getWidthHeight(el); el.className = ''; // reset for the next guy return wh; }; Graphics._FontRenderingContext.prototype.getLineHeight = function() { return this._lineHeight; }; return Graphics; }); /** * @fileOverview UI layers and window-wide dragging * @name SimileAjax.WindowManager */ /** * This is a singleton that keeps track of UI layers (modal and * modeless) and enables/disables UI elements based on which layers * they belong to. It also provides window-wide dragging * implementation. */ define('scripts/window-manager',[ "./dom", "./debug", "./graphics", "./simile-ajax-base" ], function(DOM, Debug, Graphics, SimileAjax) { var WindowManager = { _initialized: false, _listeners: [], _draggedElement: null, _draggedElementCallback: null, _dropTargetHighlightElement: null, _lastCoords: null, _ghostCoords: null, _draggingMode: "", _dragging: false, _layers: [] }; WindowManager.initialize = function() { if (WindowManager._initialized) { return; } DOM.registerEvent(document.body, "mousedown", WindowManager._onBodyMouseDown); DOM.registerEvent(document.body, "mousemove", WindowManager._onBodyMouseMove); DOM.registerEvent(document.body, "mouseup", WindowManager._onBodyMouseUp); DOM.registerEvent(document, "keydown", WindowManager._onBodyKeyDown); DOM.registerEvent(document, "keyup", WindowManager._onBodyKeyUp); WindowManager._layers.push({index: 0}); // @@@ There were pieces here to assemble a no-op history listener // and add it to the SimileAjax.History listener stack, but I // suspect it was only here to make sure history initialized // before window manager. I've simply put calls to init both // in the overall SimileAjax.load() method. This breaks a // terrible dependency cycle that sat between them. If I'm // wrong, another solution needs to be found. WindowManager._initialized = true; }; WindowManager.getBaseLayer = function() { return WindowManager._layers[0]; }; WindowManager.getHighestLayer = function() { return WindowManager._layers[WindowManager._layers.length - 1]; }; WindowManager.registerEventWithObject = function(elmt, eventName, obj, handlerName, layer) { WindowManager.registerEvent( elmt, eventName, function(elmt2, evt, target) { return obj[handlerName].call(obj, elmt2, evt, target); }, layer ); }; WindowManager.registerEvent = function(elmt, eventName, handler, layer) { if (layer == null) { layer = WindowManager.getHighestLayer(); } var handler2 = function(elmt, evt, target) { if (WindowManager._canProcessEventAtLayer(layer)) { WindowManager._popToLayer(layer.index); try { handler(elmt, evt, target); } catch (e) { Debug.exception(e); } } DOM.cancelEvent(evt); return false; } DOM.registerEvent(elmt, eventName, handler2); }; WindowManager.pushLayer = function(f, ephemeral, elmt) { var layer = { onPop: f, index: WindowManager._layers.length, ephemeral: (ephemeral), elmt: elmt }; WindowManager._layers.push(layer); return layer; }; WindowManager.popLayer = function(layer) { for (var i = 1; i < WindowManager._layers.length; i++) { if (WindowManager._layers[i] == layer) { WindowManager._popToLayer(i - 1); break; } } }; WindowManager.popAllLayers = function() { WindowManager._popToLayer(0); }; WindowManager.registerForDragging = function(elmt, callback, layer) { WindowManager.registerEvent( elmt, "mousedown", function(elmt, evt, target) { WindowManager._handleMouseDown(elmt, evt, callback); }, layer ); }; WindowManager._popToLayer = function(level) { while (level+1 < WindowManager._layers.length) { try { var layer = WindowManager._layers.pop(); if (layer.onPop != null) { layer.onPop(); } } catch (e) { } } }; WindowManager._canProcessEventAtLayer = function(layer) { if (layer.index == (WindowManager._layers.length - 1)) { return true; } for (var i = layer.index + 1; i < WindowManager._layers.length; i++) { if (!WindowManager._layers[i].ephemeral) { return false; } } return true; }; WindowManager.cancelPopups = function(evt) { var evtCoords = (evt) ? DOM.getEventPageCoordinates(evt) : { x: -1, y: -1 }; var i = WindowManager._layers.length - 1; while (i > 0 && WindowManager._layers[i].ephemeral) { var layer = WindowManager._layers[i]; if (layer.elmt != null) { // if event falls within main element of layer then don't cancel var elmt = layer.elmt; var elmtCoords = DOM.getPageCoordinates(elmt); if (evtCoords.x >= elmtCoords.left && evtCoords.x < (elmtCoords.left + elmt.offsetWidth) && evtCoords.y >= elmtCoords.top && evtCoords.y < (elmtCoords.top + elmt.offsetHeight)) { break; } } i--; } WindowManager._popToLayer(i); }; WindowManager._onBodyMouseDown = function(elmt, evt, target) { if (!("eventPhase" in evt) || evt.eventPhase == evt.BUBBLING_PHASE) { WindowManager.cancelPopups(evt); } }; WindowManager._handleMouseDown = function(elmt, evt, callback) { WindowManager._draggedElement = elmt; WindowManager._draggedElementCallback = callback; WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY }; DOM.cancelEvent(evt); return false; }; WindowManager._onBodyKeyDown = function(elmt, evt, target) { if (WindowManager._dragging) { if (evt.keyCode == 27) { // esc WindowManager._cancelDragging(); } else if ((evt.keyCode == 17 || evt.keyCode == 16) && WindowManager._draggingMode != "copy") { WindowManager._draggingMode = "copy"; var img = Graphics.createTranslucentImage(SimileAjax.urlPrefix + "images/copy.png"); img.style.position = "absolute"; img.style.left = (WindowManager._ghostCoords.left - 16) + "px"; img.style.top = (WindowManager._ghostCoords.top) + "px"; document.body.appendChild(img); WindowManager._draggingModeIndicatorElmt = img; } } }; WindowManager._onBodyKeyUp = function(elmt, evt, target) { if (WindowManager._dragging) { if (evt.keyCode == 17 || evt.keyCode == 16) { WindowManager._draggingMode = ""; if (WindowManager._draggingModeIndicatorElmt != null) { document.body.removeChild(WindowManager._draggingModeIndicatorElmt); WindowManager._draggingModeIndicatorElmt = null; } } } }; WindowManager._onBodyMouseMove = function(elmt, evt, target) { if (WindowManager._draggedElement != null) { var callback = WindowManager._draggedElementCallback; var lastCoords = WindowManager._lastCoords; var diffX = evt.clientX - lastCoords.x; var diffY = evt.clientY - lastCoords.y; if (!WindowManager._dragging) { if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) { try { if ("onDragStart" in callback) { callback.onDragStart(); } if ("ghost" in callback && callback.ghost) { var draggedElmt = WindowManager._draggedElement; WindowManager._ghostCoords = DOM.getPageCoordinates(draggedElmt); WindowManager._ghostCoords.left += diffX; WindowManager._ghostCoords.top += diffY; var ghostElmt = draggedElmt.cloneNode(true); ghostElmt.style.position = "absolute"; ghostElmt.style.left = WindowManager._ghostCoords.left + "px"; ghostElmt.style.top = WindowManager._ghostCoords.top + "px"; ghostElmt.style.zIndex = 1000; Graphics.setOpacity(ghostElmt, 50); document.body.appendChild(ghostElmt); callback._ghostElmt = ghostElmt; } WindowManager._dragging = true; WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY }; document.body.focus(); } catch (e) { Debug.exception("WindowManager: Error handling mouse down", e); WindowManager._cancelDragging(); } } } else { try { WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY }; if ("onDragBy" in callback) { callback.onDragBy(diffX, diffY); } if ("_ghostElmt" in callback) { var ghostElmt = callback._ghostElmt; WindowManager._ghostCoords.left += diffX; WindowManager._ghostCoords.top += diffY; ghostElmt.style.left = WindowManager._ghostCoords.left + "px"; ghostElmt.style.top = WindowManager._ghostCoords.top + "px"; if (WindowManager._draggingModeIndicatorElmt != null) { var indicatorElmt = WindowManager._draggingModeIndicatorElmt; indicatorElmt.style.left = (WindowManager._ghostCoords.left - 16) + "px"; indicatorElmt.style.top = WindowManager._ghostCoords.top + "px"; } if ("droppable" in callback && callback.droppable) { var coords = DOM.getEventPageCoordinates(evt); var target = DOM.hittest( coords.x, coords.y, [ WindowManager._ghostElmt, WindowManager._dropTargetHighlightElement ] ); target = WindowManager._findDropTarget(target); if (target != WindowManager._potentialDropTarget) { if (WindowManager._dropTargetHighlightElement != null) { document.body.removeChild(WindowManager._dropTargetHighlightElement); WindowManager._dropTargetHighlightElement = null; WindowManager._potentialDropTarget = null; } var droppable = false; if (target != null) { if ((!("canDropOn" in callback) || callback.canDropOn(target)) && (!("canDrop" in target) || target.canDrop(WindowManager._draggedElement))) { droppable = true; } } if (droppable) { var border = 4; var targetCoords = DOM.getPageCoordinates(target); var highlight = document.createElement("div"); highlight.style.border = border + "px solid yellow"; highlight.style.backgroundColor = "yellow"; highlight.style.position = "absolute"; highlight.style.left = targetCoords.left + "px"; highlight.style.top = targetCoords.top + "px"; highlight.style.width = (target.offsetWidth - border * 2) + "px"; highlight.style.height = (target.offsetHeight - border * 2) + "px"; Graphics.setOpacity(highlight, 30); document.body.appendChild(highlight); WindowManager._potentialDropTarget = target; WindowManager._dropTargetHighlightElement = highlight; } } } } } catch (e) { Debug.exception("WindowManager: Error handling mouse move", e); WindowManager._cancelDragging(); } } DOM.cancelEvent(evt); return false; } }; WindowManager._onBodyMouseUp = function(elmt, evt, target) { if (WindowManager._draggedElement != null) { try { if (WindowManager._dragging) { var callback = WindowManager._draggedElementCallback; if ("onDragEnd" in callback) { callback.onDragEnd(); } if ("droppable" in callback && callback.droppable) { var dropped = false; var target = WindowManager._potentialDropTarget; if (target != null) { if ((!("canDropOn" in callback) || callback.canDropOn(target)) && (!("canDrop" in target) || target.canDrop(WindowManager._draggedElement))) { if ("onDropOn" in callback) { callback.onDropOn(target); } target.ondrop(WindowManager._draggedElement, WindowManager._draggingMode); dropped = true; } } if (!dropped) { // TODO: do holywood explosion here } } } } finally { WindowManager._cancelDragging(); } DOM.cancelEvent(evt); return false; } }; WindowManager._cancelDragging = function() { var callback = WindowManager._draggedElementCallback; if ("_ghostElmt" in callback) { var ghostElmt = callback._ghostElmt; document.body.removeChild(ghostElmt); delete callback._ghostElmt; } if (WindowManager._dropTargetHighlightElement != null) { document.body.removeChild(WindowManager._dropTargetHighlightElement); WindowManager._dropTargetHighlightElement = null; } if (WindowManager._draggingModeIndicatorElmt != null) { document.body.removeChild(WindowManager._draggingModeIndicatorElmt); WindowManager._draggingModeIndicatorElmt = null; } WindowManager._draggedElement = null; WindowManager._draggedElementCallback = null; WindowManager._potentialDropTarget = null; WindowManager._dropTargetHighlightElement = null; WindowManager._lastCoords = null; WindowManager._ghostCoords = null; WindowManager._draggingMode = ""; WindowManager._dragging = false; }; WindowManager._findDropTarget = function(elmt) { while (elmt != null) { if ("ondrop" in elmt && (typeof elmt.ondrop) == "function") { break; } elmt = elmt.parentNode; } return elmt; }; return WindowManager; }); define('scripts/bubble',[ "./graphics", "./window-manager" ], function(Graphics, WindowManager) { /** * Creates a nice, rounded bubble popup with the given page coordinates and * content dimensions. The bubble will point to the location on the page * as described by pageX and pageY. All measurements should be given in * pixels. * * @param {Number} pageX the x coordinate of the point to point to * @param {Number} pageY the y coordinate of the point to point to * @param {Number} contentWidth the width of the content box in the bubble * @param {Number} contentHeight the height of the content box in the bubble * @param {String} orientation a string ("top", "bottom", "left", or "right") * that describes the orientation of the arrow on the bubble * @return {Element} a DOM element for the newly created bubble */ Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) { contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings var bubbleConfig = Graphics.bubbleConfig; var pngTransparencyClassSuffix = Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent"; var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize; var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize; var generatePngSensitiveClass = function(className) { return className + " " + className + "-" + pngTransparencyClassSuffix; }; /* * Render container divs */ var div = document.createElement("div"); div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass); div.style.width = contentWidth + "px"; div.style.height = contentHeight + "px"; var divInnerContainer = document.createElement("div"); divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass); div.appendChild(divInnerContainer); /* * Create layer for bubble */ var close = function() { if (!bubble._closed) { document.body.removeChild(bubble._div); bubble._doc = null; bubble._div = null; bubble._content = null; bubble._closed = true; } } var bubble = { _closed: false }; var layer = WindowManager.pushLayer(close, true, div); bubble._div = div; bubble.close = function() { WindowManager.popLayer(layer); } /* * Render border graphics */ var createBorder = function(classNameSuffix) { var divBorderGraphic = document.createElement("div"); divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix); divInnerContainer.appendChild(divBorderGraphic); }; createBorder("top-left"); createBorder("top-right"); createBorder("bottom-left"); createBorder("bottom-right"); createBorder("left"); createBorder("right"); createBorder("top"); createBorder("bottom"); /* * Render content */ var divContentContainer = document.createElement("div"); divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass); divInnerContainer.appendChild(divContentContainer); bubble.content = divContentContainer; /* * Render close button */ var divClose = document.createElement("div"); divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass); divInnerContainer.appendChild(divClose); WindowManager.registerEventWithObject(divClose, "click", bubble, "close"); (function() { var dims = Graphics.getWindowDimensions(); var docWidth = dims.w; var docHeight = dims.h; var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2); var createArrow = function(classNameSuffix) { var divArrowGraphic = document.createElement("div"); divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix); divInnerContainer.appendChild(divArrowGraphic); return divArrowGraphic; }; if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 && pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) { /* * Bubble can be positioned above or below the target point. */ var left = pageX - Math.round(contentWidth / 2); left = pageX < (docWidth / 2) ? Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) : Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth); if ((orientation && orientation == "top") || (!orientation && (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0))) { /* * Position bubble above the target point. */ var divArrow = createArrow("down"); divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px"; div.style.left = left + "px"; div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px"; return; } else if ((orientation && orientation == "bottom") || (!orientation && (pageY + bubbleConfig.arrowGraphicTargetOffset + contentHeight + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docHeight))) { /* * Position bubble below the target point. */ var divArrow = createArrow("up"); divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px"; div.style.left = left + "px"; div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px"; return; } } var top = pageY - Math.round(contentHeight / 2); top = pageY < (docHeight / 2) ? Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) : Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight); if ((orientation && orientation == "left") || (!orientation && (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0))) { /* * Position bubble left of the target point. */ var divArrow = createArrow("right"); divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px"; div.style.top = top + "px"; div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px"; } else { /* * Position bubble right of the target point, as the last resort. */ var divArrow = createArrow("left"); divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px"; div.style.top = top + "px"; div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px"; } })(); document.body.appendChild(div); return bubble; }; /** * Creates a nice, rounded bubble popup with the given content in a div, * page coordinates and a suggested width. The bubble will point to the * location on the page as described by pageX and pageY. All measurements * should be given in pixels. * * @param {Element} the content div * @param {Number} pageX the x coordinate of the point to point to * @param {Number} pageY the y coordinate of the point to point to * @param {Number} contentWidth a suggested width of the content * @param {String} orientation a string ("top", "bottom", "left", or "right") * that describes the orientation of the arrow on the bubble * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall. * Default of 0 or null means no maximum */ Graphics.createBubbleForContentAndPoint = function( div, pageX, pageY, contentWidth, orientation, maxHeight) { if (typeof contentWidth != "number") { contentWidth = 300; } if (typeof maxHeight != "number") { maxHeight = 0; } div.style.position = "absolute"; div.style.left = "-5000px"; div.style.top = "0px"; div.style.width = contentWidth + "px"; document.body.appendChild(div); window.setTimeout(function() { var width = div.scrollWidth + 10; var height = div.scrollHeight + 10; var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling if (maxHeight > 0 && height > maxHeight) { height = maxHeight; scrollDivW = width - 25; } var bubble = Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation); document.body.removeChild(div); div.style.position = "static"; div.style.left = ""; div.style.top = ""; // create a scroll div if needed if (scrollDivW > 0) { var scrollDiv = document.createElement("div"); div.style.width = ""; scrollDiv.style.width = scrollDivW + "px"; scrollDiv.appendChild(div); bubble.content.appendChild(scrollDiv); } else { div.style.width = width + "px"; bubble.content.appendChild(div); } }, 200); }; return Graphics; }); /** * @fileOverview A collection of date/time utility functions * @name SimileAjax.DateTime */ define('scripts/date-time',["./debug"], function(Debug) { var DateTime = new Object(); DateTime.MILLISECOND = 0; DateTime.SECOND = 1; DateTime.MINUTE = 2; DateTime.HOUR = 3; DateTime.DAY = 4; DateTime.WEEK = 5; DateTime.MONTH = 6; DateTime.YEAR = 7; DateTime.DECADE = 8; DateTime.CENTURY = 9; DateTime.MILLENNIUM = 10; DateTime.EPOCH = -1; DateTime.ERA = -2; /** * An array of unit lengths, expressed in milliseconds, of various lengths of * time. The array indices are predefined and stored as properties of the * DateTime object, e.g. DateTime.YEAR. * @type Array */ DateTime.gregorianUnitLengths = []; (function() { var d = DateTime; var a = d.gregorianUnitLengths; a[d.MILLISECOND] = 1; a[d.SECOND] = 1000; a[d.MINUTE] = a[d.SECOND] * 60; a[d.HOUR] = a[d.MINUTE] * 60; a[d.DAY] = a[d.HOUR] * 24; a[d.WEEK] = a[d.DAY] * 7; a[d.MONTH] = a[d.DAY] * 31; a[d.YEAR] = a[d.DAY] * 365; a[d.DECADE] = a[d.YEAR] * 10; a[d.CENTURY] = a[d.YEAR] * 100; a[d.MILLENNIUM] = a[d.YEAR] * 1000; })(); DateTime._dateRegexp = new RegExp( "^(-?)([0-9]{4})(" + [ "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth "(-?([0-9]{3}))", // -dayOfYear "(-?W([0-9]{2})(-?([1-7]))?)" // -Wweek-dayOfWeek ].join("|") + ")?$" ); DateTime._timezoneRegexp = new RegExp( "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$" ); DateTime._timeRegexp = new RegExp( "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$" ); /** * Takes a date object and a string containing an ISO 8601 date and sets the * the date using information parsed from the string. Note that this method * does not parse any time information. * * @param {Date} dateObject the date object to modify * @param {String} string an ISO 8601 string to parse * @return {Date} the modified date object */ DateTime.setIso8601Date = function(dateObject, string) { /* * This function has been adapted from dojo.date, v.0.3.0 * http://dojotoolkit.org/. */ var d = string.match(DateTime._dateRegexp); if(!d) { throw new Error("Invalid date string: " + string); } var sign = (d[1] == "-") ? -1 : 1; // BC or AD var year = sign * d[2]; var month = d[5]; var date = d[7]; var dayofyear = d[9]; var week = d[11]; var dayofweek = (d[13]) ? d[13] : 1; dateObject.setUTCFullYear(year); if (dayofyear) { dateObject.setUTCMonth(0); dateObject.setUTCDate(Number(dayofyear)); } else if (week) { dateObject.setUTCMonth(0); dateObject.setUTCDate(1); var gd = dateObject.getUTCDay(); var day = (gd) ? gd : 7; var offset = Number(dayofweek) + (7 * Number(week)); if (day <= 4) { dateObject.setUTCDate(offset + 1 - day); } else { dateObject.setUTCDate(offset + 8 - day); } } else { if (month) { dateObject.setUTCDate(1); dateObject.setUTCMonth(month - 1); } if (date) { dateObject.setUTCDate(date); } } return dateObject; }; /** * Takes a date object and a string containing an ISO 8601 time and sets the * the time using information parsed from the string. Note that this method * does not parse any date information. * * @param {Date} dateObject the date object to modify * @param {String} string an ISO 8601 string to parse * @return {Date} the modified date object */ DateTime.setIso8601Time = function (dateObject, string) { /* * This function has been adapted from dojo.date, v.0.3.0 * http://dojotoolkit.org/. */ var d = string.match(DateTime._timeRegexp); if(!d) { Debug.warn("Invalid time string: " + string); return false; } var hours = d[1]; var mins = Number((d[3]) ? d[3] : 0); var secs = (d[5]) ? d[5] : 0; var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0; dateObject.setUTCHours(hours); dateObject.setUTCMinutes(mins); dateObject.setUTCSeconds(secs); dateObject.setUTCMilliseconds(ms); return dateObject; }; /** * The timezone offset in minutes in the user's browser. * @type Number */ DateTime.timezoneOffset = new Date().getTimezoneOffset(); /** * Takes a date object and a string containing an ISO 8601 date and time and * sets the date object using information parsed from the string. * * @param {Date} dateObject the date object to modify * @param {String} string an ISO 8601 string to parse * @return {Date} the modified date object */ DateTime.setIso8601 = function (dateObject, string){ /* * This function has been adapted from dojo.date, v.0.3.0 * http://dojotoolkit.org/. */ var offset = null; var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T"); DateTime.setIso8601Date(dateObject, comps[0]); if (comps.length == 2) { // first strip timezone info from the end var d = comps[1].match(DateTime._timezoneRegexp); if (d) { if (d[0] == 'Z') { offset = 0; } else { offset = (Number(d[3]) * 60) + Number(d[5]); offset *= ((d[2] == '-') ? 1 : -1); } comps[1] = comps[1].substr(0, comps[1].length - d[0].length); } DateTime.setIso8601Time(dateObject, comps[1]); } if (offset == null) { offset = dateObject.getTimezoneOffset(); // local time zone if no tz info } dateObject.setTime(dateObject.getTime() + offset * 60000); return dateObject; }; /** * Takes a string containing an ISO 8601 date and returns a newly instantiated * date object with the parsed date and time information from the string. * * @param {String} string an ISO 8601 string to parse * @return {Date} a new date object created from the string */ DateTime.parseIso8601DateTime = function (string) { try { return DateTime.setIso8601(new Date(0), string); } catch (e) { return null; } }; /** * Takes a string containing a Gregorian date and time and returns a newly * instantiated date object with the parsed date and time information from the * string. If the param is actually an instance of Date instead of a string, * simply returns the given date instead. * * @param {Object} o an object, to either return or parse as a string * @return {Date} the date object */ DateTime.parseGregorianDateTime = function(o) { if (o == null) { return null; } else if (o instanceof Date) { return o; } var s = o.toString(); if (s.length > 0 && s.length < 8) { var space = s.indexOf(" "); if (space > 0) { var year = parseInt(s.substr(0, space)); var suffix = s.substr(space + 1); if (suffix.toLowerCase() == "bc") { year = 1 - year; } } else { var year = parseInt(s); } var d = new Date(0); d.setUTCFullYear(year); return d; } try { return new Date(Date.parse(s)); } catch (e) { return null; } }; /** * Rounds date objects down to the nearest interval or multiple of an interval. * This method modifies the given date object, converting it to the given * timezone if specified. * * @param {Date} date the date object to round * @param {Number} intervalUnit a constant, integer index specifying an * interval, e.g. DateTime.HOUR * @param {Number} timeZone a timezone shift, given in hours * @param {Number} multiple a multiple of the interval to round by * @param {Number} firstDayOfWeek an integer specifying the first day of the * week, 0 corresponds to Sunday, 1 to Monday, etc. */ DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) { var timeShift = timeZone * DateTime.gregorianUnitLengths[DateTime.HOUR]; var date2 = new Date(date.getTime() + timeShift); var clearInDay = function(d) { d.setUTCMilliseconds(0); d.setUTCSeconds(0); d.setUTCMinutes(0); d.setUTCHours(0); }; var clearInYear = function(d) { clearInDay(d); d.setUTCDate(1); d.setUTCMonth(0); }; switch(intervalUnit) { case DateTime.MILLISECOND: var x = date2.getUTCMilliseconds(); date2.setUTCMilliseconds(x - (x % multiple)); break; case DateTime.SECOND: date2.setUTCMilliseconds(0); var x = date2.getUTCSeconds(); date2.setUTCSeconds(x - (x % multiple)); break; case DateTime.MINUTE: date2.setUTCMilliseconds(0); date2.setUTCSeconds(0); var x = date2.getUTCMinutes(); date2.setTime(date2.getTime() - (x % multiple) * DateTime.gregorianUnitLengths[DateTime.MINUTE]); break; case DateTime.HOUR: date2.setUTCMilliseconds(0); date2.setUTCSeconds(0); date2.setUTCMinutes(0); var x = date2.getUTCHours(); date2.setUTCHours(x - (x % multiple)); break; case DateTime.DAY: clearInDay(date2); break; case DateTime.WEEK: clearInDay(date2); var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7; date2.setTime(date2.getTime() - d * DateTime.gregorianUnitLengths[DateTime.DAY]); break; case DateTime.MONTH: clearInDay(date2); date2.setUTCDate(1); var x = date2.getUTCMonth(); date2.setUTCMonth(x - (x % multiple)); break; case DateTime.YEAR: clearInYear(date2); var x = date2.getUTCFullYear(); date2.setUTCFullYear(x - (x % multiple)); break; case DateTime.DECADE: clearInYear(date2); date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10); break; case DateTime.CENTURY: clearInYear(date2); date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100); break; case DateTime.MILLENNIUM: clearInYear(date2); date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000); break; } date.setTime(date2.getTime() - timeShift); }; /** * Rounds date objects up to the nearest interval or multiple of an interval. * This method modifies the given date object, converting it to the given * timezone if specified. * * @param {Date} date the date object to round * @param {Number} intervalUnit a constant, integer index specifying an * interval, e.g. DateTime.HOUR * @param {Number} timeZone a timezone shift, given in hours * @param {Number} multiple a multiple of the interval to round by * @param {Number} firstDayOfWeek an integer specifying the first day of the * week, 0 corresponds to Sunday, 1 to Monday, etc. * @see DateTime.roundDownToInterval */ DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) { var originalTime = date.getTime(); DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek); if (date.getTime() < originalTime) { date.setTime(date.getTime() + DateTime.gregorianUnitLengths[intervalUnit] * multiple); } }; /** * Increments a date object by a specified interval, taking into * consideration the timezone. * * @param {Date} date the date object to increment * @param {Number} intervalUnit a constant, integer index specifying an * interval, e.g. DateTime.HOUR * @param {Number} timeZone the timezone offset in hours */ DateTime.incrementByInterval = function(date, intervalUnit, timeZone) { timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone; var timeShift = timeZone * DateTime.gregorianUnitLengths[DateTime.HOUR]; var date2 = new Date(date.getTime() + timeShift); switch(intervalUnit) { case DateTime.MILLISECOND: date2.setTime(date2.getTime() + 1) break; case DateTime.SECOND: date2.setTime(date2.getTime() + 1000); break; case DateTime.MINUTE: date2.setTime(date2.getTime() + DateTime.gregorianUnitLengths[DateTime.MINUTE]); break; case DateTime.HOUR: date2.setTime(date2.getTime() + DateTime.gregorianUnitLengths[DateTime.HOUR]); break; case DateTime.DAY: date2.setUTCDate(date2.getUTCDate() + 1); break; case DateTime.WEEK: date2.setUTCDate(date2.getUTCDate() + 7); break; case DateTime.MONTH: date2.setUTCMonth(date2.getUTCMonth() + 1); break; case DateTime.YEAR: date2.setUTCFullYear(date2.getUTCFullYear() + 1); break; case DateTime.DECADE: date2.setUTCFullYear(date2.getUTCFullYear() + 10); break; case DateTime.CENTURY: date2.setUTCFullYear(date2.getUTCFullYear() + 100); break; case DateTime.MILLENNIUM: date2.setUTCFullYear(date2.getUTCFullYear() + 1000); break; } date.setTime(date2.getTime() - timeShift); }; /** * Returns a new date object with the given time offset removed. * * @param {Date} date the starting date * @param {Number} timeZone a timezone specified in an hour offset to remove * @return {Date} a new date object with the offset removed */ DateTime.removeTimeZoneOffset = function(date, timeZone) { return new Date(date.getTime() + timeZone * DateTime.gregorianUnitLengths[DateTime.HOUR]); }; /** * Returns the timezone of the user's browser. * * @return {Number} the timezone in the user's locale in hours */ DateTime.getTimezone = function() { var d = new Date().getTimezoneOffset(); return d / -60; }; return DateTime; }); /*================================================== * String Utility Functions and Constants *================================================== */ define('scripts/string',[],function() { var StringUtils = {}; StringUtils.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }; StringUtils.startsWith = function(s, prefix) { return s.length >= prefix.length && s.substr(0, prefix.length) === prefix; }; StringUtils.endsWith = function(s, suffix) { return s.length >= suffix.length && s.substr(s.length - suffix.length) === suffix; }; StringUtils.substitute = function(s, objects) { var result, start, percent, n; result = ""; start = 0; while (start < s.length - 1) { percent = s.indexOf("%", start); if (percent < 0 || percent === s.length - 1) { break; } else if (percent > start && s.charAt(percent - 1) === "\\") { result += s.substring(start, percent - 1) + "%"; start = percent + 1; } else { n = parseInt(s.charAt(percent + 1)); if (isNaN(n) || n >= objects.length) { result += s.substring(start, percent + 2); } else { result += s.substring(start, percent) + objects[n].toString(); } start = percent + 2; } } if (start < s.length) { result += s.substring(start); } return result; }; return StringUtils; }); /*================================================== * HTML Utility Functions *================================================== */ define('scripts/html',[],function() { var HTML = new Object(); HTML._e2uHash = {}; (function() { var e2uHash = HTML._e2uHash; e2uHash['nbsp']= '\u00A0'; e2uHash['iexcl']= '\u00A1'; e2uHash['cent']= '\u00A2'; e2uHash['pound']= '\u00A3'; e2uHash['curren']= '\u00A4'; e2uHash['yen']= '\u00A5'; e2uHash['brvbar']= '\u00A6'; e2uHash['sect']= '\u00A7'; e2uHash['uml']= '\u00A8'; e2uHash['copy']= '\u00A9'; e2uHash['ordf']= '\u00AA'; e2uHash['laquo']= '\u00AB'; e2uHash['not']= '\u00AC'; e2uHash['shy']= '\u00AD'; e2uHash['reg']= '\u00AE'; e2uHash['macr']= '\u00AF'; e2uHash['deg']= '\u00B0'; e2uHash['plusmn']= '\u00B1'; e2uHash['sup2']= '\u00B2'; e2uHash['sup3']= '\u00B3'; e2uHash['acute']= '\u00B4'; e2uHash['micro']= '\u00B5'; e2uHash['para']= '\u00B6'; e2uHash['middot']= '\u00B7'; e2uHash['cedil']= '\u00B8'; e2uHash['sup1']= '\u00B9'; e2uHash['ordm']= '\u00BA'; e2uHash['raquo']= '\u00BB'; e2uHash['frac14']= '\u00BC'; e2uHash['frac12']= '\u00BD'; e2uHash['frac34']= '\u00BE'; e2uHash['iquest']= '\u00BF'; e2uHash['Agrave']= '\u00C0'; e2uHash['Aacute']= '\u00C1'; e2uHash['Acirc']= '\u00C2'; e2uHash['Atilde']= '\u00C3'; e2uHash['Auml']= '\u00C4'; e2uHash['Aring']= '\u00C5'; e2uHash['AElig']= '\u00C6'; e2uHash['Ccedil']= '\u00C7'; e2uHash['Egrave']= '\u00C8'; e2uHash['Eacute']= '\u00C9'; e2uHash['Ecirc']= '\u00CA'; e2uHash['Euml']= '\u00CB'; e2uHash['Igrave']= '\u00CC'; e2uHash['Iacute']= '\u00CD'; e2uHash['Icirc']= '\u00CE'; e2uHash['Iuml']= '\u00CF'; e2uHash['ETH']= '\u00D0'; e2uHash['Ntilde']= '\u00D1'; e2uHash['Ograve']= '\u00D2'; e2uHash['Oacute']= '\u00D3'; e2uHash['Ocirc']= '\u00D4'; e2uHash['Otilde']= '\u00D5'; e2uHash['Ouml']= '\u00D6'; e2uHash['times']= '\u00D7'; e2uHash['Oslash']= '\u00D8'; e2uHash['Ugrave']= '\u00D9'; e2uHash['Uacute']= '\u00DA'; e2uHash['Ucirc']= '\u00DB'; e2uHash['Uuml']= '\u00DC'; e2uHash['Yacute']= '\u00DD'; e2uHash['THORN']= '\u00DE'; e2uHash['szlig']= '\u00DF'; e2uHash['agrave']= '\u00E0'; e2uHash['aacute']= '\u00E1'; e2uHash['acirc']= '\u00E2'; e2uHash['atilde']= '\u00E3'; e2uHash['auml']= '\u00E4'; e2uHash['aring']= '\u00E5'; e2uHash['aelig']= '\u00E6'; e2uHash['ccedil']= '\u00E7'; e2uHash['egrave']= '\u00E8'; e2uHash['eacute']= '\u00E9'; e2uHash['ecirc']= '\u00EA'; e2uHash['euml']= '\u00EB'; e2uHash['igrave']= '\u00EC'; e2uHash['iacute']= '\u00ED'; e2uHash['icirc']= '\u00EE'; e2uHash['iuml']= '\u00EF'; e2uHash['eth']= '\u00F0'; e2uHash['ntilde']= '\u00F1'; e2uHash['ograve']= '\u00F2'; e2uHash['oacute']= '\u00F3'; e2uHash['ocirc']= '\u00F4'; e2uHash['otilde']= '\u00F5'; e2uHash['ouml']= '\u00F6'; e2uHash['divide']= '\u00F7'; e2uHash['oslash']= '\u00F8'; e2uHash['ugrave']= '\u00F9'; e2uHash['uacute']= '\u00FA'; e2uHash['ucirc']= '\u00FB'; e2uHash['uuml']= '\u00FC'; e2uHash['yacute']= '\u00FD'; e2uHash['thorn']= '\u00FE'; e2uHash['yuml']= '\u00FF'; e2uHash['quot']= '\u0022'; e2uHash['amp']= '\u0026'; e2uHash['lt']= '\u003C'; e2uHash['gt']= '\u003E'; e2uHash['OElig']= ''; e2uHash['oelig']= '\u0153'; e2uHash['Scaron']= '\u0160'; e2uHash['scaron']= '\u0161'; e2uHash['Yuml']= '\u0178'; e2uHash['circ']= '\u02C6'; e2uHash['tilde']= '\u02DC'; e2uHash['ensp']= '\u2002'; e2uHash['emsp']= '\u2003'; e2uHash['thinsp']= '\u2009'; e2uHash['zwnj']= '\u200C'; e2uHash['zwj']= '\u200D'; e2uHash['lrm']= '\u200E'; e2uHash['rlm']= '\u200F'; e2uHash['ndash']= '\u2013'; e2uHash['mdash']= '\u2014'; e2uHash['lsquo']= '\u2018'; e2uHash['rsquo']= '\u2019'; e2uHash['sbquo']= '\u201A'; e2uHash['ldquo']= '\u201C'; e2uHash['rdquo']= '\u201D'; e2uHash['bdquo']= '\u201E'; e2uHash['dagger']= '\u2020'; e2uHash['Dagger']= '\u2021'; e2uHash['permil']= '\u2030'; e2uHash['lsaquo']= '\u2039'; e2uHash['rsaquo']= '\u203A'; e2uHash['euro']= '\u20AC'; e2uHash['fnof']= '\u0192'; e2uHash['Alpha']= '\u0391'; e2uHash['Beta']= '\u0392'; e2uHash['Gamma']= '\u0393'; e2uHash['Delta']= '\u0394'; e2uHash['Epsilon']= '\u0395'; e2uHash['Zeta']= '\u0396'; e2uHash['Eta']= '\u0397'; e2uHash['Theta']= '\u0398'; e2uHash['Iota']= '\u0399'; e2uHash['Kappa']= '\u039A'; e2uHash['Lambda']= '\u039B'; e2uHash['Mu']= '\u039C'; e2uHash['Nu']= '\u039D'; e2uHash['Xi']= '\u039E'; e2uHash['Omicron']= '\u039F'; e2uHash['Pi']= '\u03A0'; e2uHash['Rho']= '\u03A1'; e2uHash['Sigma']= '\u03A3'; e2uHash['Tau']= '\u03A4'; e2uHash['Upsilon']= '\u03A5'; e2uHash['Phi']= '\u03A6'; e2uHash['Chi']= '\u03A7'; e2uHash['Psi']= '\u03A8'; e2uHash['Omega']= '\u03A9'; e2uHash['alpha']= '\u03B1'; e2uHash['beta']= '\u03B2'; e2uHash['gamma']= '\u03B3'; e2uHash['delta']= '\u03B4'; e2uHash['epsilon']= '\u03B5'; e2uHash['zeta']= '\u03B6'; e2uHash['eta']= '\u03B7'; e2uHash['theta']= '\u03B8'; e2uHash['iota']= '\u03B9'; e2uHash['kappa']= '\u03BA'; e2uHash['lambda']= '\u03BB'; e2uHash['mu']= '\u03BC'; e2uHash['nu']= '\u03BD'; e2uHash['xi']= '\u03BE'; e2uHash['omicron']= '\u03BF'; e2uHash['pi']= '\u03C0'; e2uHash['rho']= '\u03C1'; e2uHash['sigmaf']= '\u03C2'; e2uHash['sigma']= '\u03C3'; e2uHash['tau']= '\u03C4'; e2uHash['upsilon']= '\u03C5'; e2uHash['phi']= '\u03C6'; e2uHash['chi']= '\u03C7'; e2uHash['psi']= '\u03C8'; e2uHash['omega']= '\u03C9'; e2uHash['thetasym']= '\u03D1'; e2uHash['upsih']= '\u03D2'; e2uHash['piv']= '\u03D6'; e2uHash['bull']= '\u2022'; e2uHash['hellip']= '\u2026'; e2uHash['prime']= '\u2032'; e2uHash['Prime']= '\u2033'; e2uHash['oline']= '\u203E'; e2uHash['frasl']= '\u2044'; e2uHash['weierp']= '\u2118'; e2uHash['image']= '\u2111'; e2uHash['real']= '\u211C'; e2uHash['trade']= '\u2122'; e2uHash['alefsym']= '\u2135'; e2uHash['larr']= '\u2190'; e2uHash['uarr']= '\u2191'; e2uHash['rarr']= '\u2192'; e2uHash['darr']= '\u2193'; e2uHash['harr']= '\u2194'; e2uHash['crarr']= '\u21B5'; e2uHash['lArr']= '\u21D0'; e2uHash['uArr']= '\u21D1'; e2uHash['rArr']= '\u21D2'; e2uHash['dArr']= '\u21D3'; e2uHash['hArr']= '\u21D4'; e2uHash['forall']= '\u2200'; e2uHash['part']= '\u2202'; e2uHash['exist']= '\u2203'; e2uHash['empty']= '\u2205'; e2uHash['nabla']= '\u2207'; e2uHash['isin']= '\u2208'; e2uHash['notin']= '\u2209'; e2uHash['ni']= '\u220B'; e2uHash['prod']= '\u220F'; e2uHash['sum']= '\u2211'; e2uHash['minus']= '\u2212'; e2uHash['lowast']= '\u2217'; e2uHash['radic']= '\u221A'; e2uHash['prop']= '\u221D'; e2uHash['infin']= '\u221E'; e2uHash['ang']= '\u2220'; e2uHash['and']= '\u2227'; e2uHash['or']= '\u2228'; e2uHash['cap']= '\u2229'; e2uHash['cup']= '\u222A'; e2uHash['int']= '\u222B'; e2uHash['there4']= '\u2234'; e2uHash['sim']= '\u223C'; e2uHash['cong']= '\u2245'; e2uHash['asymp']= '\u2248'; e2uHash['ne']= '\u2260'; e2uHash['equiv']= '\u2261'; e2uHash['le']= '\u2264'; e2uHash['ge']= '\u2265'; e2uHash['sub']= '\u2282'; e2uHash['sup']= '\u2283'; e2uHash['nsub']= '\u2284'; e2uHash['sube']= '\u2286'; e2uHash['supe']= '\u2287'; e2uHash['oplus']= '\u2295'; e2uHash['otimes']= '\u2297'; e2uHash['perp']= '\u22A5'; e2uHash['sdot']= '\u22C5'; e2uHash['lceil']= '\u2308'; e2uHash['rceil']= '\u2309'; e2uHash['lfloor']= '\u230A'; e2uHash['rfloor']= '\u230B'; e2uHash['lang']= '\u2329'; e2uHash['rang']= '\u232A'; e2uHash['loz']= '\u25CA'; e2uHash['spades']= '\u2660'; e2uHash['clubs']= '\u2663'; e2uHash['hearts']= '\u2665'; e2uHash['diams']= '\u2666'; })(); HTML.deEntify = function(s) { var e2uHash = HTML._e2uHash; var re = /&(\w+?);/; while (re.test(s)) { var m = s.match(re); s = s.replace(re, e2uHash[m[1]]); } return s; }; return HTML; }); define('scripts/set',[],function() { /** * A basic set (in the mathematical sense) data structure * * @constructor * @param {Array or Set} [a] an initial collection */ var Set = function(a) { this._hash = {}; this._count = 0; if (a instanceof Array) { for (var i = 0; i < a.length; i++) { this.add(a[i]); } } else if (a instanceof Set) { this.addSet(a); } } /** * Adds the given object to this set, assuming there it does not already exist * * @param {Object} o the object to add * @return {Boolean} true if the object was added, false if not */ Set.prototype.add = function(o) { if (!(o in this._hash)) { this._hash[o] = true; this._count++; return true; } return false; } /** * Adds each element in the given set to this set * * @param {Set} set the set of elements to add */ Set.prototype.addSet = function(set) { for (var o in set._hash) { this.add(o); } } /** * Removes the given element from this set * * @param {Object} o the object to remove * @return {Boolean} true if the object was successfully removed, * false otherwise */ Set.prototype.remove = function(o) { if (o in this._hash) { delete this._hash[o]; this._count--; return true; } return false; } /** * Removes the elements in this set that correspond to the elements in the * given set * * @param {Set} set the set of elements to remove */ Set.prototype.removeSet = function(set) { for (var o in set._hash) { this.remove(o); } } /** * Removes all elements in this set that are not present in the given set, i.e. * modifies this set to the intersection of the two sets * * @param {Set} set the set to intersect */ Set.prototype.retainSet = function(set) { for (var o in this._hash) { if (!set.contains(o)) { delete this._hash[o]; this._count--; } } } /** * Returns whether or not the given element exists in this set * * @param {Set} o the object to test for * @return {Boolean} true if the object is present, false otherwise */ Set.prototype.contains = function(o) { return (o in this._hash); } /** * Returns the number of elements in this set * * @return {Number} the number of elements in this set */ Set.prototype.size = function() { return this._count; } /** * Returns the elements of this set as an array * * @return {Array} a new array containing the elements of this set */ Set.prototype.toArray = function() { var a = []; for (var o in this._hash) { a.push(o); } return a; } /** * Iterates through the elements of this set, order unspecified, executing the * given function on each element until the function returns true * * @param {Function} f a function of form f(element) */ Set.prototype.visit = function(f) { for (var o in this._hash) { if (f(o) == true) { break; } } } return Set; }); define('scripts/sorted-array',[],function() { /** * A sorted array data structure * * @constructor */ var SortedArray = function(compare, initialArray) { this._a = (initialArray instanceof Array) ? initialArray : []; this._compare = compare; }; SortedArray.prototype.add = function(elmt) { var sa = this; var index = this.find(function(elmt2) { return sa._compare(elmt2, elmt); }); if (index < this._a.length) { this._a.splice(index, 0, elmt); } else { this._a.push(elmt); } }; SortedArray.prototype.remove = function(elmt) { var sa = this; var index = this.find(function(elmt2) { return sa._compare(elmt2, elmt); }); while (index < this._a.length && this._compare(this._a[index], elmt) == 0) { if (this._a[index] == elmt) { this._a.splice(index, 1); return true; } else { index++; } } return false; }; SortedArray.prototype.removeAll = function() { this._a = []; }; SortedArray.prototype.elementAt = function(index) { return this._a[index]; }; SortedArray.prototype.length = function() { return this._a.length; }; SortedArray.prototype.find = function(compare) { var a = 0; var b = this._a.length; while (a < b) { var mid = Math.floor((a + b) / 2); var c = compare(this._a[mid]); if (mid == a) { return c < 0 ? a+1 : a; } else if (c < 0) { a = mid; } else { b = mid; } } return a; }; SortedArray.prototype.getFirst = function() { return (this._a.length > 0) ? this._a[0] : null; }; SortedArray.prototype.getLast = function() { return (this._a.length > 0) ? this._a[this._a.length - 1] : null; }; return SortedArray; }); define('scripts/units',["./date-time"], function(DateTime) { /*================================================== * Default Unit *================================================== */ var NativeDateUnit = new Object(); NativeDateUnit.makeDefaultValue = function() { return new Date(); }; NativeDateUnit.cloneValue = function(v) { return new Date(v.getTime()); }; NativeDateUnit.getParser = function(format) { if (typeof format == "string") { format = format.toLowerCase(); } var parser = (format == "iso8601" || format == "iso 8601") ? DateTime.parseIso8601DateTime : DateTime.parseGregorianDateTime; return function(d) { if (typeof d != 'undefined' && d !== null && typeof d.toUTCString == "function") { return d; } else { return parser(d); } }; }; NativeDateUnit.parseFromObject = function(o) { return DateTime.parseGregorianDateTime(o); }; NativeDateUnit.toNumber = function(v) { return v.getTime(); }; NativeDateUnit.fromNumber = function(n) { return new Date(n); }; NativeDateUnit.compare = function(v1, v2) { var n1, n2; if (typeof v1 == "object") { n1 = v1.getTime(); } else { n1 = Number(v1); } if (typeof v2 == "object") { n2 = v2.getTime(); } else { n2 = Number(v2); } return n1 - n2; }; NativeDateUnit.earlier = function(v1, v2) { return NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2; }; NativeDateUnit.later = function(v1, v2) { return NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2; }; NativeDateUnit.change = function(v, n) { return new Date(v.getTime() + n); }; return NativeDateUnit; }); define('scripts/event-index',["./units", "./sorted-array"], function(NativeDateUnit, SortedArray) { /*================================================== * Event Index *================================================== */ var EventIndex = function(unit) { var eventIndex = this; this._unit = (unit != null) ? unit : NativeDateUnit; this._events = new SortedArray( function(event1, event2) { return eventIndex._unit.compare(event1.getStart(), event2.getStart()); } ); this._idToEvent = {}; this._indexed = true; }; EventIndex.prototype.getUnit = function() { return this._unit; }; EventIndex.prototype.getEvent = function(id) { return this._idToEvent[id]; }; EventIndex.prototype.add = function(evt) { this._events.add(evt); this._idToEvent[evt.getID()] = evt; this._indexed = false; }; EventIndex.prototype.removeAll = function() { this._events.removeAll(); this._idToEvent = {}; this._indexed = false; }; EventIndex.prototype.getCount = function() { return this._events.length(); }; EventIndex.prototype.getIterator = function(startDate, endDate) { if (!this._indexed) { this._index(); } return new EventIndex._Iterator(this._events, startDate, endDate, this._unit); }; EventIndex.prototype.getReverseIterator = function(startDate, endDate) { if (!this._indexed) { this._index(); } return new EventIndex._ReverseIterator(this._events, startDate, endDate, this._unit); }; EventIndex.prototype.getAllIterator = function() { return new EventIndex._AllIterator(this._events); }; EventIndex.prototype.getEarliestDate = function() { var evt = this._events.getFirst(); return (evt == null) ? null : evt.getStart(); }; EventIndex.prototype.getLatestDate = function() { var evt = this._events.getLast(); if (evt == null) { return null; } if (!this._indexed) { this._index(); } var index = evt._earliestOverlapIndex; var date = this._events.elementAt(index).getEnd(); for (var i = index + 1; i < this._events.length(); i++) { date = this._unit.later(date, this._events.elementAt(i).getEnd()); } return date; }; EventIndex.prototype._index = function() { /* * For each event, we want to find the earliest preceding * event that overlaps with it, if any. */ var l = this._events.length(); for (var i = 0; i < l; i++) { var evt = this._events.elementAt(i); evt._earliestOverlapIndex = i; } var toIndex = 1; for (var i = 0; i < l; i++) { var evt = this._events.elementAt(i); var end = evt.getEnd(); toIndex = Math.max(toIndex, i + 1); while (toIndex < l) { var evt2 = this._events.elementAt(toIndex); var start2 = evt2.getStart(); if (this._unit.compare(start2, end) < 0) { evt2._earliestOverlapIndex = i; toIndex++; } else { break; } } } this._indexed = true; }; EventIndex._Iterator = function(events, startDate, endDate, unit) { this._events = events; this._startDate = startDate; this._endDate = endDate; this._unit = unit; this._currentIndex = events.find(function(evt) { return unit.compare(evt.getStart(), startDate); }); if (this._currentIndex - 1 >= 0) { this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex; } this._currentIndex--; this._maxIndex = events.find(function(evt) { return unit.compare(evt.getStart(), endDate); }); this._hasNext = false; this._next = null; this._findNext(); }; EventIndex._Iterator.prototype = { hasNext: function() { return this._hasNext; }, next: function() { if (this._hasNext) { var next = this._next; this._findNext(); return next; } else { return null; } }, _findNext: function() { var unit = this._unit; while ((++this._currentIndex) < this._maxIndex) { var evt = this._events.elementAt(this._currentIndex); if (unit.compare(evt.getStart(), this._endDate) < 0 && unit.compare(evt.getEnd(), this._startDate) > 0) { this._next = evt; this._hasNext = true; return; } } this._next = null; this._hasNext = false; } }; EventIndex._ReverseIterator = function(events, startDate, endDate, unit) { this._events = events; this._startDate = startDate; this._endDate = endDate; this._unit = unit; this._minIndex = events.find(function(evt) { return unit.compare(evt.getStart(), startDate); }); if (this._minIndex - 1 >= 0) { this._minIndex = this._events.elementAt(this._minIndex - 1)._earliestOverlapIndex; } this._maxIndex = events.find(function(evt) { return unit.compare(evt.getStart(), endDate); }); this._currentIndex = this._maxIndex; this._hasNext = false; this._next = null; this._findNext(); }; EventIndex._ReverseIterator.prototype = { hasNext: function() { return this._hasNext; }, next: function() { if (this._hasNext) { var next = this._next; this._findNext(); return next; } else { return null; } }, _findNext: function() { var unit = this._unit; while ((--this._currentIndex) >= this._minIndex) { var evt = this._events.elementAt(this._currentIndex); if (unit.compare(evt.getStart(), this._endDate) < 0 && unit.compare(evt.getEnd(), this._startDate) > 0) { this._next = evt; this._hasNext = true; return; } } this._next = null; this._hasNext = false; } }; EventIndex._AllIterator = function(events) { this._events = events; this._index = 0; }; EventIndex._AllIterator.prototype = { hasNext: function() { return this._index < this._events.length(); }, next: function() { return this._index < this._events.length() ? this._events.elementAt(this._index++) : null; } }; return EventIndex; }); /*================================================== * General, miscellaneous SimileAjax stuff *================================================== */ define('scripts/ajax',["./debug"], function(Debug) { var ListenerQueue = function(wildcardHandlerName) { this._listeners = []; this._wildcardHandlerName = wildcardHandlerName; }; ListenerQueue.prototype.add = function(listener) { this._listeners.push(listener); }; ListenerQueue.prototype.remove = function(listener) { var listeners = this._listeners; for (var i = 0; i < listeners.length; i++) { if (listeners[i] == listener) { listeners.splice(i, 1); break; } } }; ListenerQueue.prototype.fire = function(handlerName, args) { var listeners = [].concat(this._listeners); for (var i = 0; i < listeners.length; i++) { var listener = listeners[i]; if (handlerName in listener) { try { listener[handlerName].apply(listener, args); } catch (e) { Debug.exception("Error firing event of name " + handlerName, e); } } else if (this._wildcardHandlerName != null && this._wildcardHandlerName in listener) { try { listener[this._wildcardHandlerName].apply(listener, [ handlerName ]); } catch (e) { Debug.exception("Error firing event of name " + handlerName + " to wildcard handler", e); } } } }; return ListenerQueue; }); /*====================================================================== * History * * This is a singleton that keeps track of undoable user actions and * performs undos and redos in response to the browser's Back and * Forward buttons. * * Call addAction(action) to register an undoable user action. action * must have 4 fields: * * perform: an argument-less function that carries out the action * undo: an argument-less function that undos the action * label: a short, user-friendly string describing the action * uiLayer: the UI layer on which the action takes place * * By default, the history keeps track of upto 10 actions. You can * configure this behavior by setting * SAHistory.maxHistoryLength * to a different number. * * An iframe is inserted into the document's body element to track * onload events. *====================================================================== */ define('scripts/history',[ "./ajax", "./dom", "./debug", "./window-manager" ], function(ListenerQueue, DOM, Debug, WindowManager) { var SAHistory = { maxHistoryLength: 10, historyFile: "__history__.html", enabled: true, _initialized: false, _listeners: new ListenerQueue(), _actions: [], _baseIndex: 0, _currentIndex: 0, _plainDocumentTitle: document.title }; SAHistory.formatHistoryEntryTitle = function(actionLabel) { return SAHistory._plainDocumentTitle + " {" + actionLabel + "}"; }; SAHistory.initialize = function() { if (SAHistory._initialized) { return; } if (SAHistory.enabled) { var iframe = document.createElement("iframe"); iframe.id = "simile-ajax-history"; iframe.style.position = "absolute"; iframe.style.width = "10px"; iframe.style.height = "10px"; iframe.style.top = "0px"; iframe.style.left = "0px"; iframe.style.visibility = "hidden"; iframe.src = SAHistory.historyFile + "?0"; document.body.appendChild(iframe); DOM.registerEvent(iframe, "load", SAHistory._handleIFrameOnLoad); SAHistory._iframe = iframe; } SAHistory._initialized = true; }; SAHistory.addListener = function(listener) { SAHistory._listeners.add(listener); }; SAHistory.removeListener = function(listener) { SAHistory._listeners.remove(listener); }; SAHistory.addAction = function(action) { SAHistory._listeners.fire("onBeforePerform", [ action ]); window.setTimeout(function() { try { action.perform(); SAHistory._listeners.fire("onAfterPerform", [ action ]); if (SAHistory.enabled) { SAHistory._actions = SAHistory._actions.slice( 0, SAHistory._currentIndex - SAHistory._baseIndex); SAHistory._actions.push(action); SAHistory._currentIndex++; var diff = SAHistory._actions.length - SAHistory.maxHistoryLength; if (diff > 0) { SAHistory._actions = SAHistory._actions.slice(diff); SAHistory._baseIndex += diff; } try { SAHistory._iframe.contentWindow.location.search = "?" + SAHistory._currentIndex; } catch (e) { /* * We can't modify location.search most probably because it's a file:// url. * We'll just going to modify the document's title. */ var title = SAHistory.formatHistoryEntryTitle(action.label); document.title = title; } } } catch (e) { Debug.exception(e, "Error adding action {" + action.label + "} to history"); } }, 0); }; SAHistory.addLengthyAction = function(perform, undo, label) { SAHistory.addAction({ perform: perform, undo: undo, label: label, uiLayer: WindowManager.getBaseLayer(), lengthy: true }); }; SAHistory._handleIFrameOnLoad = function() { /* * This function is invoked when the user herself * navigates backward or forward. We need to adjust * the application's state accordingly. */ try { var q = SAHistory._iframe.contentWindow.location.search; var c = (q.length == 0) ? 0 : Math.max(0, parseInt(q.substr(1))); var finishUp = function() { var diff = c - SAHistory._currentIndex; SAHistory._currentIndex += diff; SAHistory._baseIndex += diff; SAHistory._iframe.contentWindow.location.search = "?" + c; }; if (c < SAHistory._currentIndex) { // need to undo SAHistory._listeners.fire("onBeforeUndoSeveral", []); window.setTimeout(function() { while (SAHistory._currentIndex > c && SAHistory._currentIndex > SAHistory._baseIndex) { SAHistory._currentIndex--; var action = SAHistory._actions[SAHistory._currentIndex - SAHistory._baseIndex]; try { action.undo(); } catch (e) { Debug.exception(e, "History: Failed to undo action {" + action.label + "}"); } } SAHistory._listeners.fire("onAfterUndoSeveral", []); finishUp(); }, 0); } else if (c > SAHistory._currentIndex) { // need to redo SAHistory._listeners.fire("onBeforeRedoSeveral", []); window.setTimeout(function() { while (SAHistory._currentIndex < c && SAHistory._currentIndex - SAHistory._baseIndex < SAHistory._actions.length) { var action = SAHistory._actions[SAHistory._currentIndex - SAHistory._baseIndex]; try { action.perform(); } catch (e) { Debug.exception(e, "History: Failed to redo action {" + action.label + "}"); } SAHistory._currentIndex++; } SAHistory._listeners.fire("onAfterRedoSeveral", []); finishUp(); }, 0); } else { var index = SAHistory._currentIndex - SAHistory._baseIndex - 1; var title = (index >= 0 && index < SAHistory._actions.length) ? SAHistory.formatHistoryEntryTitle(SAHistory._actions[index].label) : SAHistory._plainDocumentTitle; SAHistory._iframe.contentWindow.document.title = title; document.title = title; } } catch (e) { // silent } }; SAHistory.getNextUndoAction = function() { try { var index = SAHistory._currentIndex - SAHistory._baseIndex - 1; return SAHistory._actions[index]; } catch (e) { return null; } }; SAHistory.getNextRedoAction = function() { try { var index = SAHistory._currentIndex - SAHistory._baseIndex; return SAHistory._actions[index]; } catch (e) { return null; } }; return SAHistory; }); /*================================================== * Simile Ajax API *================================================== */ /*================================================== * REMEMBER to update the Version! Now found in scripts/base.js *================================================== */ define('simile-ajax',[ "module", "./scripts/simile-ajax-base", "./scripts/platform", "./scripts/debug", "./scripts/xmlhttp", "./scripts/dom", "./scripts/bubble", "./scripts/date-time", "./scripts/string", "./scripts/html", "./scripts/set", "./scripts/sorted-array", "./scripts/event-index", "./scripts/units", "./scripts/ajax", "./scripts/history", "./scripts/window-manager" ], function(module, SimileAjax, Platform, Debug, XmlHttp, DOM, Graphics, DateTime, StringUtils, HTML, Set, SortedArray, EventIndex, NativeDateUnit, ListenerQueue, SAHistory, WindowManager) { SimileAjax.Platform = Platform; SimileAjax.Debug = Debug; SimileAjax.XmlHttp = XmlHttp; SimileAjax.DOM = DOM; SimileAjax.Graphics = Graphics; SimileAjax.DateTime = DateTime; SimileAjax.StringUtils = StringUtils; SimileAjax.HTML = HTML; SimileAjax.Set = Set; SimileAjax.SortedArray = SortedArray; SimileAjax.EventIndex = EventIndex; SimileAjax.NativeDateUnit = NativeDateUnit; SimileAjax.ListenerQueue = ListenerQueue; SimileAjax.History = SAHistory; SimileAjax.WindowManager = WindowManager; var getHead = function(doc) { return doc.getElementsByTagName("head")[0]; }; SimileAjax.findScript = function(doc, substring) { var scripts, s, url, i; scripts = doc.documentElement.getElementsByTagName("script"); for (s = 0; s < scripts.length; s++) { url = scripts[s].src; i = url.indexOf(substring); if (i >= 0) { return url; } } return null; }; /** * Parse out the query parameters from a URL * @param {String} url the url to parse, or location.href if undefined * @param {Object} to optional object to extend with the parameters * @param {Object} types optional object mapping keys to value types * (String, Number, Boolean or Array, String by default) * @return a key/value Object whose keys are the query parameter names * @type Object */ SimileAjax.parseURLParameters = function(url, to, types) { to = to || {}; types = types || {}; if (typeof url == "undefined") { url = location.href; } var q = url.indexOf("?"); if (q < 0) { return to; } url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment var params = url.split("&"), param, parsed = {}; var decode = window.decodeURIComponent || unescape; for (var i = 0; param = params[i]; i++) { var eq = param.indexOf("="); var name = decode(param.slice(0,eq)); var old = parsed[name]; var replacement = decode(param.slice(eq+1)); if (typeof old == "undefined") { old = []; } else if (!(old instanceof Array)) { old = [old]; } parsed[name] = old.concat(replacement); } for (var i in parsed) { if (!parsed.hasOwnProperty(i)) continue; var type = types[i] || String; var data = parsed[i]; if (!(data instanceof Array)) { data = [data]; } if (type === Boolean && data[0] == "false") { to[i] = false; // because Boolean("false") === true } else { to[i] = type.apply(this, data); } } return to; }; /** * @deprecated Use RequireJS loading mechanisms instead. */ SimileAjax.includeJavascriptFile = function(doc, url, onerror, charset, callback) { SimileAjax.Debug.warn("Loading scripts is no longer a feature of SimileAjax. Use RequireJS instead."); return; }; /** * @deprecated Use RequireJS loading mechanisms instead. */ SimileAjax.includeJavascriptFiles = function(doc, urlPrefix, filenames) { SimileAjax.Debug.warn("Loading scripts is no longer a feature of SimileAjax. Use RequireJS instead."); return; }; SimileAjax.includeCssFile = function(doc, url) { if (doc.body == null) { try { doc.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>"); return; } catch (e) { // fall through } } var link = doc.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); link.setAttribute("href", url); getHead(doc).appendChild(link); }; SimileAjax.includeCssFiles = function(doc, urlPrefix, filenames) { for (var i = 0; i < filenames.length; i++) { SimileAjax.includeCssFile(doc, urlPrefix + filenames[i]); } }; /** * Append into urls each string in suffixes after prefixing it with urlPrefix. * @param {Array} urls * @param {String} urlPrefix * @param {Array} suffixes */ SimileAjax.prefixURLs = function(urls, urlPrefix, suffixes) { for (var i = 0; i < suffixes.length; i++) { urls.push(urlPrefix + suffixes[i]); } }; /** * A call to set the prefix and load CSS. * @param {String} prefix * @returns {Boolean} */ SimileAjax.setPrefix = function(prefix) { if (SimileAjax.urlPrefix === null && prefix !== null) { if (prefix.substr(-1) !== "/") { prefix += "/"; } SimileAjax.urlPrefix = prefix; SimileAjax.params.prefix = prefix; SimileAjax.loadCSS(SimileAjax.params.bundle); return true; }; return false; }; /** * Private call to load CSS. * @prefix {Boolean} bundle Whether to load bundled CSS or individual. */ SimileAjax.loadCSS = function(bundle) { var cssFiles = ["main.css"], bundledCssFile = "simile-ajax-bundle.css"; bundle = bundle || true; if (bundle) { SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/" + bundledCssFile); } else { SimileAjax.includeCssFiles(document, SimileAjax.urlPrefix + "styles/", cssFiles); } }; /** * Deal with legacy methods of passing configuration to SimileAjax. */ SimileAjax.loadLegacy = function() { var prefix, url, targets, target, i; prefix = null; if (typeof SimileAjax_urlPrefix == "string") { prefix = SimileAjax_urlPrefix; SimileAjax.setPrefix(prefix); } else { url = null; targets = ["simile-ajax-api.js", "simile-ajax-bundle.js"]; for (i = 0; i < targets.length; i++) { target = targets[i]; url = SimileAjax.findScript(document, target); if (url != null) { prefix = url.substr(0, url.indexOf(target)); break; } } if (url === null) { SimileAjax.error = new Error("Failed to derive URL prefix for SimileAjax"); } else { SimileAjax.setPrefix(prefix); SimileAjax.params = SimileAjax.parseURLParameters(url, SimileAjax.params, SimileAjax.paramTypes); } } SimileAjax.Graphics = Graphics.initialize(Graphics); SimileAjax.History.initialize(); SimileAjax.WindowManager.initialize(); }; /** * Load based on RequireJS configuration. */ SimileAjax.loadRequire = function() { var conf; conf = module.config(); SimileAjax.params = conf; SimileAjax.setPrefix(SimileAjax.params.prefix); SimileAjax.Graphics = Graphics.initialize(Graphics); SimileAjax.History.initialize(); SimileAjax.WindowManager.initialize(); }; SimileAjax.load = function() { if (SimileAjax.loaded) { return; } else { SimileAjax.loaded = true; if (module.config().hasOwnProperty("prefix")) { SimileAjax.loadRequire(); } else { SimileAjax.loadLegacy(); } } }; return SimileAjax; }); return require("simile-ajax"); }));