Added: openoffice/ooo-site/trunk/content/scripts/simile-widget/ajax/2.2.4/simile-ajax-api-debug.js URL: http://svn.apache.org/viewvc/openoffice/ooo-site/trunk/content/scripts/simile-widget/ajax/2.2.4/simile-ajax-api-debug.js?rev=1791126&view=auto ============================================================================== --- openoffice/ooo-site/trunk/content/scripts/simile-widget/ajax/2.2.4/simile-ajax-api-debug.js (added) +++ openoffice/ooo-site/trunk/content/scripts/simile-widget/ajax/2.2.4/simile-ajax-api-debug.js Wed Apr 12 14:36:37 2017 @@ -0,0 +1,4092 @@ +(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
[... 1506 lines stripped ...]
