Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/index.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/index.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/index.html 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,188 @@ + + + + Testground + + + + + + + + + + + + + + + + + + + + + + + + +
+

FileManager Demo

+
+ +
+
+ +
+
+ Open File-Manager from a link (German) +
+ +
+ + +
+
+
+ + \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/manager.php =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/manager.php,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/manager.php 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,19 @@ + 'Files/', + 'assetBasePath' => '../Assets', + 'upload' => false, + 'destroy' => false, +)); + +$browser->fireEvent(!empty($_GET['event']) ? $_GET['event'] : null); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-core.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-core.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-core.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,4225 @@ +/* +--- + +script: Core.js + +description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts. + +license: MIT-style license. + +copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). + +authors: The MooTools production team (http://mootools.net/developers/) + +inspiration: +- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) +- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) + +provides: [Mootools, Native, Hash.base, Array.each, $util] + +... +*/ + +var MooTools = { + 'version': '1.2.4', + 'build': '0d9113241a90b9cd5643b926795852a2026710d4' +}; + +var Native = function(options){ + options = options || {}; + var name = options.name; + var legacy = options.legacy; + var protect = options.protect; + var methods = options.implement; + var generics = options.generics; + var initialize = options.initialize; + var afterImplement = options.afterImplement || function(){}; + var object = initialize || legacy; + generics = generics !== false; + + object.constructor = Native; + object.$family = {name: 'native'}; + if (legacy && initialize) object.prototype = legacy.prototype; + object.prototype.constructor = object; + + if (name){ + var family = name.toLowerCase(); + object.prototype.$family = {name: family}; + Native.typize(object, family); + } + + var add = function(obj, name, method, force){ + if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; + if (generics) Native.genericize(obj, name, protect); + afterImplement.call(obj, name, method); + return obj; + }; + + object.alias = function(a1, a2, a3){ + if (typeof a1 == 'string'){ + var pa1 = this.prototype[a1]; + if ((a1 = pa1)) return add(this, a2, a1, a3); + } + for (var a in a1) this.alias(a, a1[a], a2); + return this; + }; + + object.implement = function(a1, a2, a3){ + if (typeof a1 == 'string') return add(this, a1, a2, a3); + for (var p in a1) add(this, p, a1[p], a2); + return this; + }; + + if (methods) object.implement(methods); + + return object; +}; + +Native.genericize = function(object, property, check){ + if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ + var args = Array.prototype.slice.call(arguments); + return object.prototype[property].apply(args.shift(), args); + }; +}; + +Native.implement = function(objects, properties){ + for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); +}; + +Native.typize = function(object, family){ + if (!object.type) object.type = function(item){ + return ($type(item) === family); + }; +}; + +(function(){ + var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; + for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); + + var types = {'boolean': Boolean, 'native': Native, 'object': Object}; + for (var t in types) Native.typize(types[t], t); + + var generics = { + 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], + 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] + }; + for (var g in generics){ + for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); + } +})(); + +var Hash = new Native({ + + name: 'Hash', + + initialize: function(object){ + if ($type(object) == 'hash') object = $unlink(object.getClean()); + for (var key in object) this[key] = object[key]; + return this; + } + +}); + +Hash.implement({ + + forEach: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); + } + }, + + getClean: function(){ + var clean = {}; + for (var key in this){ + if (this.hasOwnProperty(key)) clean[key] = this[key]; + } + return clean; + }, + + getLength: function(){ + var length = 0; + for (var key in this){ + if (this.hasOwnProperty(key)) length++; + } + return length; + } + +}); + +Hash.alias('forEach', 'each'); + +Array.implement({ + + forEach: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); + } + +}); + +Array.alias('forEach', 'each'); + +function $A(iterable){ + if (iterable.item){ + var l = iterable.length, array = new Array(l); + while (l--) array[l] = iterable[l]; + return array; + } + return Array.prototype.slice.call(iterable); +}; + +function $arguments(i){ + return function(){ + return arguments[i]; + }; +}; + +function $chk(obj){ + return !!(obj || obj === 0); +}; + +function $clear(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +function $defined(obj){ + return (obj != undefined); +}; + +function $each(iterable, fn, bind){ + var type = $type(iterable); + ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); +}; + +function $empty(){}; + +function $extend(original, extended){ + for (var key in (extended || {})) original[key] = extended[key]; + return original; +}; + +function $H(object){ + return new Hash(object); +}; + +function $lambda(value){ + return ($type(value) == 'function') ? value : function(){ + return value; + }; +}; + +function $merge(){ + var args = Array.slice(arguments); + args.unshift({}); + return $mixin.apply(null, args); +}; + +function $mixin(mix){ + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + if ($type(object) != 'object') continue; + for (var key in object){ + var op = object[key], mp = mix[key]; + mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); + } + } + return mix; +}; + +function $pick(){ + for (var i = 0, l = arguments.length; i < l; i++){ + if (arguments[i] != undefined) return arguments[i]; + } + return null; +}; + +function $random(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +function $splat(obj){ + var type = $type(obj); + return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; +}; + +var $time = Date.now || function(){ + return +new Date; +}; + +function $try(){ + for (var i = 0, l = arguments.length; i < l; i++){ + try { + return arguments[i](); + } catch(e){} + } + return null; +}; + +function $type(obj){ + if (obj == undefined) return false; + if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; + if (obj.nodeName){ + switch (obj.nodeType){ + case 1: return 'element'; + case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; + } + } else if (typeof obj.length == 'number'){ + if (obj.callee) return 'arguments'; + else if (obj.item) return 'collection'; + } + return typeof obj; +}; + +function $unlink(object){ + var unlinked; + switch ($type(object)){ + case 'object': + unlinked = {}; + for (var p in object) unlinked[p] = $unlink(object[p]); + break; + case 'hash': + unlinked = new Hash(object); + break; + case 'array': + unlinked = []; + for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); + break; + default: return object; + } + return unlinked; +}; + + +/* +--- + +script: Browser.js + +description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Browser, Window, Document, $exec] + +... +*/ + +var Browser = $merge({ + + Engine: {name: 'unknown', version: 0}, + + Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, + + Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, + + Plugins: {}, + + Engines: { + + presto: function(){ + return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); + }, + + trident: function(){ + return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); + }, + + webkit: function(){ + return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); + }, + + gecko: function(){ + return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); + } + + } + +}, Browser || {}); + +Browser.Platform[Browser.Platform.name] = true; + +Browser.detect = function(){ + + for (var engine in this.Engines){ + var version = this.Engines[engine](); + if (version){ + this.Engine = {name: engine, version: version}; + this.Engine[engine] = this.Engine[engine + version] = true; + break; + } + } + + return {name: engine, version: version}; + +}; + +Browser.detect(); + +Browser.Request = function(){ + return $try(function(){ + return new XMLHttpRequest(); + }, function(){ + return new ActiveXObject('MSXML2.XMLHTTP'); + }, function(){ + return new ActiveXObject('Microsoft.XMLHTTP'); + }); +}; + +Browser.Features.xhr = !!(Browser.Request()); + +Browser.Plugins.Flash = (function(){ + var version = ($try(function(){ + return navigator.plugins['Shockwave Flash'].description; + }, function(){ + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + }) || '0 r0').match(/\d+/g); + return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; +})(); + +function $exec(text){ + if (!text) return text; + if (window.execScript){ + window.execScript(text); + } else { + var script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; + document.head.appendChild(script); + document.head.removeChild(script); + } + return text; +}; + +Native.UID = 1; + +var $uid = (Browser.Engine.trident) ? function(item){ + return (item.uid || (item.uid = [Native.UID++]))[0]; +} : function(item){ + return item.uid || (item.uid = Native.UID++); +}; + +var Window = new Native({ + + name: 'Window', + + legacy: (Browser.Engine.trident) ? null: window.Window, + + initialize: function(win){ + $uid(win); + if (!win.Element){ + win.Element = $empty; + if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 + win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; + } + win.document.window = win; + return $extend(win, Window.Prototype); + }, + + afterImplement: function(property, value){ + window[property] = Window.Prototype[property] = value; + } + +}); + +Window.Prototype = {$family: {name: 'window'}}; + +new Window(window); + +var Document = new Native({ + + name: 'Document', + + legacy: (Browser.Engine.trident) ? null: window.Document, + + initialize: function(doc){ + $uid(doc); + doc.head = doc.getElementsByTagName('head')[0]; + doc.html = doc.getElementsByTagName('html')[0]; + if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ + doc.execCommand("BackgroundImageCache", false, true); + }); + if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){ + doc.window.detachEvent('onunload', arguments.callee); + doc.head = doc.html = doc.window = null; + }); + return $extend(doc, Document.Prototype); + }, + + afterImplement: function(property, value){ + document[property] = Document.Prototype[property] = value; + } + +}); + +Document.Prototype = {$family: {name: 'document'}}; + +new Document(document); + + +/* +--- + +script: Array.js + +description: Contains Array Prototypes like each, contains, and erase. + +license: MIT-style license. + +requires: +- /$util +- /Array.each + +provides: [Array] + +... +*/ + +Array.implement({ + + every: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (!fn.call(bind, this[i], i, this)) return false; + } + return true; + }, + + filter: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) results.push(this[i]); + } + return results; + }, + + clean: function(){ + return this.filter($defined); + }, + + indexOf: function(item, from){ + var len = this.length; + for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + if (this[i] === item) return i; + } + return -1; + }, + + map: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); + return results; + }, + + some: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) return true; + } + return false; + }, + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + }, + + link: function(object){ + var result = {}; + for (var i = 0, l = this.length; i < l; i++){ + for (var key in object){ + if (object[key](this[i])){ + result[key] = this[i]; + delete object[key]; + break; + } + } + } + return result; + }, + + contains: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + extend: function(array){ + for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); + return this; + }, + + getLast: function(){ + return (this.length) ? this[this.length - 1] : null; + }, + + getRandom: function(){ + return (this.length) ? this[$random(0, this.length - 1)] : null; + }, + + include: function(item){ + if (!this.contains(item)) this.push(item); + return this; + }, + + combine: function(array){ + for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); + return this; + }, + + erase: function(item){ + for (var i = this.length; i--; i){ + if (this[i] === item) this.splice(i, 1); + } + return this; + }, + + empty: function(){ + this.length = 0; + return this; + }, + + flatten: function(){ + var array = []; + for (var i = 0, l = this.length; i < l; i++){ + var type = $type(this[i]); + if (!type) continue; + array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); + } + return array; + }, + + hexToRgb: function(array){ + if (this.length != 3) return null; + var rgb = this.map(function(value){ + if (value.length == 1) value += value; + return value.toInt(16); + }); + return (array) ? rgb : 'rgb(' + rgb + ')'; + }, + + rgbToHex: function(array){ + if (this.length < 3) return null; + if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i] - 0).toString(16); + hex.push((bit.length == 1) ? '0' + bit : bit); + } + return (array) ? hex : '#' + hex.join(''); + } + +}); + + +/* +--- + +script: Function.js + +description: Contains Function Prototypes like create, bind, pass, and delay. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Function] + +... +*/ + +Function.implement({ + + extend: function(properties){ + for (var property in properties) this[property] = properties[property]; + return this; + }, + + create: function(options){ + var self = this; + options = options || {}; + return function(event){ + var args = options.arguments; + args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); + if (options.event) args = [event || window.event].extend(args); + var returns = function(){ + return self.apply(options.bind || null, args); + }; + if (options.delay) return setTimeout(returns, options.delay); + if (options.periodical) return setInterval(returns, options.periodical); + if (options.attempt) return $try(returns); + return returns(); + }; + }, + + run: function(args, bind){ + return this.apply(bind, $splat(args)); + }, + + pass: function(args, bind){ + return this.create({bind: bind, arguments: args}); + }, + + bind: function(bind, args){ + return this.create({bind: bind, arguments: args}); + }, + + bindWithEvent: function(bind, args){ + return this.create({bind: bind, arguments: args, event: true}); + }, + + attempt: function(args, bind){ + return this.create({bind: bind, arguments: args, attempt: true})(); + }, + + delay: function(delay, bind, args){ + return this.create({bind: bind, arguments: args, delay: delay})(); + }, + + periodical: function(periodical, bind, args){ + return this.create({bind: bind, arguments: args, periodical: periodical})(); + } + +}); + + +/* +--- + +script: Number.js + +description: Contains Number Prototypes like limit, round, times, and ceil. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Number] + +... +*/ + +Number.implement({ + + limit: function(min, max){ + return Math.min(max, Math.max(min, this)); + }, + + round: function(precision){ + precision = Math.pow(10, precision || 0); + return Math.round(this * precision) / precision; + }, + + times: function(fn, bind){ + for (var i = 0; i < this; i++) fn.call(bind, i, this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + } + +}); + +Number.alias('times', 'each'); + +(function(math){ + var methods = {}; + math.each(function(name){ + if (!Number[name]) methods[name] = function(){ + return Math[name].apply(null, [this].concat($A(arguments))); + }; + }); + Number.implement(methods); +})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); + + +/* +--- + +script: String.js + +description: Contains String Prototypes like camelCase, capitalize, test, and toInt. + +license: MIT-style license. + +requires: +- /Native + +provides: [String] + +... +*/ + +String.implement({ + + test: function(regex, params){ + return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); + }, + + contains: function(string, separator){ + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + }, + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return this.replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return this.replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return this.replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + stripScripts: function(option){ + var scripts = ''; + var text = this.replace(/]*>([\s\S]*?)<\/script>/gi, function(){ + scripts += arguments[1] + '\n'; + return ''; + }); + if (option === true) $exec(scripts); + else if ($type(option) == 'function') option(scripts, text); + return text; + }, + + substitute: function(object, regexp){ + return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != undefined) ? object[name] : ''; + }); + } + +}); + + +/* +--- + +script: Hash.js + +description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. + +license: MIT-style license. + +requires: +- /Hash.base + +provides: [Hash] + +... +*/ + +Hash.implement({ + + has: Object.prototype.hasOwnProperty, + + keyOf: function(value){ + for (var key in this){ + if (this.hasOwnProperty(key) && this[key] === value) return key; + } + return null; + }, + + hasValue: function(value){ + return (Hash.keyOf(this, value) !== null); + }, + + extend: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.set(this, key, value); + }, this); + return this; + }, + + combine: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.include(this, key, value); + }, this); + return this; + }, + + erase: function(key){ + if (this.hasOwnProperty(key)) delete this[key]; + return this; + }, + + get: function(key){ + return (this.hasOwnProperty(key)) ? this[key] : null; + }, + + set: function(key, value){ + if (!this[key] || this.hasOwnProperty(key)) this[key] = value; + return this; + }, + + empty: function(){ + Hash.each(this, function(value, key){ + delete this[key]; + }, this); + return this; + }, + + include: function(key, value){ + if (this[key] == undefined) this[key] = value; + return this; + }, + + map: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + results.set(key, fn.call(bind, value, key, this)); + }, this); + return results; + }, + + filter: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + if (fn.call(bind, value, key, this)) results.set(key, value); + }, this); + return results; + }, + + every: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; + } + return true; + }, + + some: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; + } + return false; + }, + + getKeys: function(){ + var keys = []; + Hash.each(this, function(value, key){ + keys.push(key); + }); + return keys; + }, + + getValues: function(){ + var values = []; + Hash.each(this, function(value){ + values.push(value); + }); + return values; + }, + + toQueryString: function(base){ + var queryString = []; + Hash.each(this, function(value, key){ + if (base) key = base + '[' + key + ']'; + var result; + switch ($type(value)){ + case 'object': result = Hash.toQueryString(value, key); break; + case 'array': + var qs = {}; + value.each(function(val, i){ + qs[i] = val; + }); + result = Hash.toQueryString(qs, key); + break; + default: result = key + '=' + encodeURIComponent(value); + } + if (value != undefined) queryString.push(result); + }); + + return queryString.join('&'); + } + +}); + +Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); + + +/* +--- + +script: Event.js + +description: Contains the Event Class, to make the event object cross-browser. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Hash +- /Array +- /Function +- /String + +provides: [Event] + +... +*/ + +var Event = new Native({ + + name: 'Event', + + initialize: function(event, win){ + win = win || window; + var doc = win.document; + event = event || win.event; + if (event.$extended) return event; + this.$extended = true; + var type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + + if (type.test(/key/)){ + var code = event.which || event.keyCode; + var key = Event.Keys.keyOf(code); + if (type == 'keydown'){ + var fKey = code - 111; + if (fKey > 0 && fKey < 13) key = 'f' + fKey; + } + key = key || String.fromCharCode(code).toLowerCase(); + } else if (type.match(/(click|mouse|menu)/i)){ + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + var page = { + x: event.pageX || event.clientX + doc.scrollLeft, + y: event.pageY || event.clientY + doc.scrollTop + }; + var client = { + x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type.match(/DOMMouseScroll|mousewheel/)){ + var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + } + var rightClick = (event.which == 3) || (event.button == 2); + var related = null; + if (type.match(/over|out/)){ + switch (type){ + case 'mouseover': related = event.relatedTarget || event.fromElement; break; + case 'mouseout': related = event.relatedTarget || event.toElement; + } + if (!(function(){ + while (related && related.nodeType == 3) related = related.parentNode; + return true; + }).create({attempt: Browser.Engine.gecko})()) related = false; + } + } + + return $extend(this, { + event: event, + type: type, + + page: page, + client: client, + rightClick: rightClick, + + wheel: wheel, + + relatedTarget: related, + target: target, + + code: code, + key: key, + + shift: event.shiftKey, + control: event.ctrlKey, + alt: event.altKey, + meta: event.metaKey + }); + } + +}); + +Event.Keys = new Hash({ + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'tab': 9, + 'delete': 46 +}); + +Event.implement({ + + stop: function(){ + return this.stopPropagation().preventDefault(); + }, + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + + +/* +--- + +script: Class.js + +description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. + +license: MIT-style license. + +requires: +- /$util +- /Native +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Class] + +... +*/ + +function Class(params){ + + if (params instanceof Function) params = {initialize: params}; + + var newClass = function(){ + Object.reset(this); + if (newClass._prototyping) return this; + this._current = $empty; + var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; + delete this._current; delete this.caller; + return value; + }.extend(this); + + newClass.implement(params); + + newClass.constructor = Class; + newClass.prototype.constructor = newClass; + + return newClass; + +}; + +Function.prototype.protect = function(){ + this._protected = true; + return this; +}; + +Object.reset = function(object, key){ + + if (key == null){ + for (var p in object) Object.reset(object, p); + return object; + } + + delete object[key]; + + switch ($type(object[key])){ + case 'object': + var F = function(){}; + F.prototype = object[key]; + var i = new F; + object[key] = Object.reset(i); + break; + case 'array': object[key] = $unlink(object[key]); break; + } + + return object; + +}; + +new Native({name: 'Class', initialize: Class}).extend({ + + instantiate: function(F){ + F._prototyping = true; + var proto = new F; + delete F._prototyping; + return proto; + }, + + wrap: function(self, key, method){ + if (method._origin) method = method._origin; + + return function(){ + if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); + var caller = this.caller, current = this._current; + this.caller = current; this._current = arguments.callee; + var result = method.apply(this, arguments); + this._current = current; this.caller = caller; + return result; + }.extend({_owner: self, _origin: method, _name: key}); + + } + +}); + +Class.implement({ + + implement: function(key, value){ + + if ($type(key) == 'object'){ + for (var p in key) this.implement(p, key[p]); + return this; + } + + var mutator = Class.Mutators[key]; + + if (mutator){ + value = mutator.call(this, value); + if (value == null) return this; + } + + var proto = this.prototype; + + switch ($type(value)){ + + case 'function': + if (value._hidden) return this; + proto[key] = Class.wrap(this, key, value); + break; + + case 'object': + var previous = proto[key]; + if ($type(previous) == 'object') $mixin(previous, value); + else proto[key] = $unlink(value); + break; + + case 'array': + proto[key] = $unlink(value); + break; + + default: proto[key] = value; + + } + + return this; + + } + +}); + +Class.Mutators = { + + Extends: function(parent){ + + this.parent = parent; + this.prototype = Class.instantiate(parent); + + this.implement('parent', function(){ + var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; + if (!previous) throw new Error('The method "' + name + '" has no parent.'); + return previous.apply(this, arguments); + }.protect()); + + }, + + Implements: function(items){ + $splat(items).each(function(item){ + if (item instanceof Function) item = Class.instantiate(item); + this.implement(item); + }, this); + + } + +}; + + +/* +--- + +script: Class.Extras.js + +description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. + +license: MIT-style license. + +requires: +- /Class + +provides: [Chain, Events, Options] + +... +*/ + +var Chain = new Class({ + + $chain: [], + + chain: function(){ + this.$chain.extend(Array.flatten(arguments)); + return this; + }, + + callChain: function(){ + return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; + }, + + clearChain: function(){ + this.$chain.empty(); + return this; + } + +}); + +var Events = new Class({ + + $events: {}, + + addEvent: function(type, fn, internal){ + type = Events.removeOn(type); + if (fn != $empty){ + this.$events[type] = this.$events[type] || []; + this.$events[type].include(fn); + if (internal) fn.internal = true; + } + return this; + }, + + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; + }, + + fireEvent: function(type, args, delay){ + type = Events.removeOn(type); + if (!this.$events || !this.$events[type]) return this; + this.$events[type].each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + removeEvent: function(type, fn){ + type = Events.removeOn(type); + if (!this.$events[type]) return this; + if (!fn.internal) this.$events[type].erase(fn); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + if (events) events = Events.removeOn(events); + for (type in this.$events){ + if (events && events != type) continue; + var fns = this.$events[type]; + for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); + } + return this; + } + +}); + +Events.removeOn = function(string){ + return string.replace(/^on([A-Z])/, function(full, first){ + return first.toLowerCase(); + }); +}; + +var Options = new Class({ + + setOptions: function(){ + this.options = $merge.run([this.options].extend(arguments)); + if (!this.addEvent) return this; + for (var option in this.options){ + if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; + this.addEvent(option, this.options[option]); + delete this.options[option]; + } + return this; + } + +}); + + +/* +--- + +script: Element.js + +description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Element, Elements, $, $$, Iframe] + +... +*/ + +var Element = new Native({ + + name: 'Element', + + legacy: window.Element, + + initialize: function(tag, props){ + var konstructor = Element.Constructors.get(tag); + if (konstructor) return konstructor(props); + if (typeof tag == 'string') return document.newElement(tag, props); + return document.id(tag).set(props); + }, + + afterImplement: function(key, value){ + Element.Prototype[key] = value; + if (Array[key]) return; + Elements.implement(key, function(){ + var items = [], elements = true; + for (var i = 0, j = this.length; i < j; i++){ + var returns = this[i][key].apply(this[i], arguments); + items.push(returns); + if (elements) elements = ($type(returns) == 'element'); + } + return (elements) ? new Elements(items) : items; + }); + } + +}); + +Element.Prototype = {$family: {name: 'element'}}; + +Element.Constructors = new Hash; + +var IFrame = new Native({ + + name: 'IFrame', + + generics: false, + + initialize: function(){ + var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); + var props = params.properties || {}; + var iframe = document.id(params.iframe); + var onload = props.onload || $empty; + delete props.onload; + props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time()); + iframe = new Element(iframe || 'iframe', props); + var onFrameLoad = function(){ + var host = $try(function(){ + return iframe.contentWindow.location.host; + }); + if (!host || host == window.location.host){ + var win = new Window(iframe.contentWindow); + new Document(iframe.contentWindow.document); + $extend(win.Element.prototype, Element.Prototype); + } + onload.call(iframe.contentWindow, iframe.contentWindow.document); + }; + var contentWindow = $try(function(){ + return iframe.contentWindow; + }); + ((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); + return iframe; + } + +}); + +var Elements = new Native({ + + initialize: function(elements, options){ + options = $extend({ddup: true, cash: true}, options); + elements = elements || []; + if (options.ddup || options.cash){ + var uniques = {}, returned = []; + for (var i = 0, l = elements.length; i < l; i++){ + var el = document.id(elements[i], !options.cash); + if (options.ddup){ + if (uniques[el.uid]) continue; + uniques[el.uid] = true; + } + if (el) returned.push(el); + } + elements = returned; + } + return (options.cash) ? $extend(elements, this) : elements; + } + +}); + +Elements.implement({ + + filter: function(filter, bind){ + if (!filter) return this; + return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ + return item.match(filter); + } : filter, bind)); + } + +}); + +Document.implement({ + + newElement: function(tag, props){ + if (Browser.Engine.trident && props){ + ['name', 'type', 'checked'].each(function(attribute){ + if (!props[attribute]) return; + tag += ' ' + attribute + '="' + props[attribute] + '"'; + if (attribute != 'checked') delete props[attribute]; + }); + tag = '<' + tag + '>'; + } + return document.id(this.createElement(tag)).set(props); + }, + + newTextNode: function(text){ + return this.createTextNode(text); + }, + + getDocument: function(){ + return this; + }, + + getWindow: function(){ + return this.window; + }, + + id: (function(){ + + var types = { + + string: function(id, nocash, doc){ + id = doc.getElementById(id); + return (id) ? types.element(id, nocash) : null; + }, + + element: function(el, nocash){ + $uid(el); + if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ + var proto = Element.Prototype; + for (var p in proto) el[p] = proto[p]; + }; + return el; + }, + + object: function(obj, nocash, doc){ + if (obj.toElement) return types.element(obj.toElement(doc), nocash); + return null; + } + + }; + + types.textnode = types.whitespace = types.window = types.document = $arguments(0); + + return function(el, nocash, doc){ + if (el && el.$family && el.uid) return el; + var type = $type(el); + return (types[type]) ? types[type](el, nocash, doc || document) : null; + }; + + })() + +}); + +if (window.$ == null) Window.implement({ + $: function(el, nc){ + return document.id(el, nc, this.document); + } +}); + +Window.implement({ + + $$: function(selector){ + if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); + var elements = []; + var args = Array.flatten(arguments); + for (var i = 0, l = args.length; i < l; i++){ + var item = args[i]; + switch ($type(item)){ + case 'element': elements.push(item); break; + case 'string': elements.extend(this.document.getElements(item, true)); + } + } + return new Elements(elements); + }, + + getDocument: function(){ + return this.document; + }, + + getWindow: function(){ + return this; + } + +}); + +Native.implement([Element, Document], { + + getElement: function(selector, nocash){ + return document.id(this.getElements(selector, true)[0] || null, nocash); + }, + + getElements: function(tags, nocash){ + tags = tags.split(','); + var elements = []; + var ddup = (tags.length > 1); + tags.each(function(tag){ + var partial = this.getElementsByTagName(tag.trim()); + (ddup) ? elements.extend(partial) : elements = partial; + }, this); + return new Elements(elements, {ddup: ddup, cash: !nocash}); + } + +}); + +(function(){ + +var collected = {}, storage = {}; +var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item, retain){ + if (!item) return; + var uid = item.uid; + if (Browser.Engine.trident){ + if (item.clearAttributes){ + var clone = retain && item.cloneNode(false); + item.clearAttributes(); + if (clone) item.mergeAttributes(clone); + } else if (item.removeEvents){ + item.removeEvents(); + } + if ((/object/i).test(item.tagName)){ + for (var p in item){ + if (typeof item[p] == 'function') item[p] = $empty; + } + Element.dispose(item); + } + } + if (!uid) return; + collected[uid] = storage[uid] = null; +}; + +var purge = function(){ + Hash.each(collected, clean); + if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); + if (window.CollectGarbage) CollectGarbage(); + collected = storage = null; +}; + +var walk = function(element, walk, start, match, all, nocash){ + var el = element[start || walk]; + var elements = []; + while (el){ + if (el.nodeType == 1 && (!match || Element.match(el, match))){ + if (!all) return document.id(el, nocash); + elements.push(el); + } + el = el[walk]; + } + return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; +}; + +var attributes = { + 'html': 'innerHTML', + 'class': 'className', + 'for': 'htmlFor', + 'defaultValue': 'defaultValue', + 'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' +}; +var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; +var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; + +bools = bools.associate(bools); + +Hash.extend(attributes, bools); +Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); + +var inserters = { + + before: function(context, element){ + if (element.parentNode) element.parentNode.insertBefore(context, element); + }, + + after: function(context, element){ + if (!element.parentNode) return; + var next = element.nextSibling; + (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); + }, + + bottom: function(context, element){ + element.appendChild(context); + }, + + top: function(context, element){ + var first = element.firstChild; + (first) ? element.insertBefore(context, first) : element.appendChild(context); + } + +}; + +inserters.inside = inserters.bottom; + +Hash.each(inserters, function(inserter, where){ + + where = where.capitalize(); + + Element.implement('inject' + where, function(el){ + inserter(this, document.id(el, true)); + return this; + }); + + Element.implement('grab' + where, function(el){ + inserter(document.id(el, true), this); + return this; + }); + +}); + +Element.implement({ + + set: function(prop, value){ + switch ($type(prop)){ + case 'object': + for (var p in prop) this.set(p, prop[p]); + break; + case 'string': + var property = Element.Properties.get(prop); + (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); + } + return this; + }, + + get: function(prop){ + var property = Element.Properties.get(prop); + return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); + }, + + erase: function(prop){ + var property = Element.Properties.get(prop); + (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); + return this; + }, + + setProperty: function(attribute, value){ + var key = attributes[attribute]; + if (value == undefined) return this.removeProperty(attribute); + if (key && bools[attribute]) value = !!value; + (key) ? this[key] = value : this.setAttribute(attribute, '' + value); + return this; + }, + + setProperties: function(attributes){ + for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + return this; + }, + + getProperty: function(attribute){ + var key = attributes[attribute]; + var value = (key) ? this[key] : this.getAttribute(attribute, 2); + return (bools[attribute]) ? !!value : (key) ? value : value || null; + }, + + getProperties: function(){ + var args = $A(arguments); + return args.map(this.getProperty, this).associate(args); + }, + + removeProperty: function(attribute){ + var key = attributes[attribute]; + (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); + return this; + }, + + removeProperties: function(){ + Array.each(arguments, this.removeProperty, this); + return this; + }, + + hasClass: function(className){ + return this.className.contains(className, ' '); + }, + + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); + return this; + }, + + removeClass: function(className){ + this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); + return this; + }, + + toggleClass: function(className){ + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); + }, + + adopt: function(){ + Array.flatten(arguments).each(function(element){ + element = document.id(element, true); + if (element) this.appendChild(element); + }, this); + return this; + }, + + appendText: function(text, where){ + return this.grab(this.getDocument().newTextNode(text), where); + }, + + grab: function(el, where){ + inserters[where || 'bottom'](document.id(el, true), this); + return this; + }, + + inject: function(el, where){ + inserters[where || 'bottom'](this, document.id(el, true)); + return this; + }, + + replaces: function(el){ + el = document.id(el, true); + el.parentNode.replaceChild(this, el); + return this; + }, + + wraps: function(el, where){ + el = document.id(el, true); + return this.replaces(el).grab(el, where); + }, + + getPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, false, nocash); + }, + + getAllPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, true, nocash); + }, + + getNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, false, nocash); + }, + + getAllNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, true, nocash); + }, + + getFirst: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, false, nocash); + }, + + getLast: function(match, nocash){ + return walk(this, 'previousSibling', 'lastChild', match, false, nocash); + }, + + getParent: function(match, nocash){ + return walk(this, 'parentNode', null, match, false, nocash); + }, + + getParents: function(match, nocash){ + return walk(this, 'parentNode', null, match, true, nocash); + }, + + getSiblings: function(match, nocash){ + return this.getParent().getChildren(match, nocash).erase(this); + }, + + getChildren: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, true, nocash); + }, + + getWindow: function(){ + return this.ownerDocument.window; + }, + + getDocument: function(){ + return this.ownerDocument; + }, + + getElementById: function(id, nocash){ + var el = this.ownerDocument.getElementById(id); + if (!el) return null; + for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ + if (!parent) return null; + } + return document.id(el, nocash); + }, + + getSelected: function(){ + return new Elements($A(this.options).filter(function(option){ + return option.selected; + })); + }, + + getComputedStyle: function(property){ + if (this.currentStyle) return this.currentStyle[property.camelCase()]; + var computed = this.getDocument().defaultView.getComputedStyle(this, null); + return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; + }, + + toQueryString: function(){ + var queryString = []; + this.getElements('input, select, textarea', true).each(function(el){ + if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; + var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ + return opt.value; + }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; + $splat(value).each(function(val){ + if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); + }); + }); + return queryString.join('&'); + }, + + clone: function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents); + var clean = function(node, element){ + if (!keepid) node.removeAttribute('id'); + if (Browser.Engine.trident){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uid'); + if (node.options){ + var no = node.options, eo = element.options; + for (var j = no.length; j--;) no[j].selected = eo[j].selected; + } + } + var prop = props[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; + }; + + if (contents){ + var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); + for (var i = ce.length; i--;) clean(ce[i], te[i]); + } + + clean(clone, this); + return document.id(clone); + }, + + destroy: function(){ + Element.empty(this); + Element.dispose(this); + clean(this, true); + return null; + }, + + empty: function(){ + $A(this.childNodes).each(function(node){ + Element.destroy(node); + }); + return this; + }, + + dispose: function(){ + return (this.parentNode) ? this.parentNode.removeChild(this) : this; + }, + + hasChild: function(el){ + el = document.id(el, true); + if (!el) return false; + if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); + return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); + }, + + match: function(tag){ + return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); + } + +}); + +Native.implement([Element, Window, Document], { + + addListener: function(type, fn){ + if (type == 'unload'){ + var old = fn, self = this; + fn = function(){ + self.removeListener('unload', fn); + old(); + }; + } else { + collected[this.uid] = this; + } + if (this.addEventListener) this.addEventListener(type, fn, false); + else this.attachEvent('on' + type, fn); + return this; + }, + + removeListener: function(type, fn){ + if (this.removeEventListener) this.removeEventListener(type, fn, false); + else this.detachEvent('on' + type, fn); + return this; + }, + + retrieve: function(property, dflt){ + var storage = get(this.uid), prop = storage[property]; + if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; + return $pick(prop); + }, + + store: function(property, value){ + var storage = get(this.uid); + storage[property] = value; + return this; + }, + + eliminate: function(property){ + var storage = get(this.uid); + delete storage[property]; + return this; + } + +}); + +window.addListener('unload', purge); + +})(); + +Element.Properties = new Hash; + +Element.Properties.style = { + + set: function(style){ + this.style.cssText = style; + }, + + get: function(){ + return this.style.cssText; + }, + + erase: function(){ + this.style.cssText = ''; + } + +}; + +Element.Properties.tag = { + + get: function(){ + return this.tagName.toLowerCase(); + } + +}; + +Element.Properties.html = (function(){ + var wrapper = document.createElement('div'); + + var translations = { + table: [1, '', '
'], + select: [1, ''], + tbody: [2, '', '
'], + tr: [3, '', '
'] + }; + translations.thead = translations.tfoot = translations.tbody; + + var html = { + set: function(){ + var html = Array.flatten(arguments).join(''); + var wrap = Browser.Engine.trident && translations[this.get('tag')]; + if (wrap){ + var first = wrapper; + first.innerHTML = wrap[1] + html + wrap[2]; + for (var i = wrap[0]; i--;) first = first.firstChild; + this.empty().adopt(first.childNodes); + } else { + this.innerHTML = html; + } + } + }; + + html.erase = html.set; + + return html; +})(); + +if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { + get: function(){ + if (this.innerText) return this.innerText; + var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); + var text = temp.innerText; + temp.destroy(); + return text; + } +}; + + +/* +--- + +script: Element.Event.js + +description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. + +license: MIT-style license. + +requires: +- /Element +- /Event + +provides: [Element.Event] + +... +*/ + +Element.Properties.events = {set: function(events){ + this.addEvents(events); +}}; + +Native.implement([Element, Window, Document], { + + addEvent: function(type, fn){ + var events = this.retrieve('events', {}); + events[type] = events[type] || {'keys': [], 'values': []}; + if (events[type].keys.contains(fn)) return this; + events[type].keys.push(fn); + var realType = type, custom = Element.Events.get(type), condition = fn, self = this; + if (custom){ + if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.condition){ + condition = function(event){ + if (custom.condition.call(this, event)) return fn.call(this, event); + return true; + }; + } + realType = custom.base || realType; + } + var defn = function(){ + return fn.call(self); + }; + var nativeEvent = Element.NativeEvents[realType]; + if (nativeEvent){ + if (nativeEvent == 2){ + defn = function(event){ + event = new Event(event, self.getWindow()); + if (condition.call(self, event) === false) event.stop(); + }; + } + this.addListener(realType, defn); + } + events[type].values.push(defn); + return this; + }, + + removeEvent: function(type, fn){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + var pos = events[type].keys.indexOf(fn); + if (pos == -1) return this; + events[type].keys.splice(pos, 1); + var value = events[type].values.splice(pos, 1)[0]; + var custom = Element.Events.get(type); + if (custom){ + if (custom.onRemove) custom.onRemove.call(this, fn); + type = custom.base || type; + } + return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; + }, + + addEvents: function(events){ + for (var event in events) this.addEvent(event, events[event]); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + var attached = this.retrieve('events'); + if (!attached) return this; + if (!events){ + for (type in attached) this.removeEvents(type); + this.eliminate('events'); + } else if (attached[events]){ + while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); + attached[events] = null; + } + return this; + }, + + fireEvent: function(type, args, delay){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + events[type].keys.each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + cloneEvents: function(from, type){ + from = document.id(from); + var fevents = from.retrieve('events'); + if (!fevents) return this; + if (!type){ + for (var evType in fevents) this.cloneEvents(from, evType); + } else if (fevents[type]){ + fevents[type].keys.each(function(fn){ + this.addEvent(type, fn); + }, this); + } + return this; + } + +}); + +Element.NativeEvents = { + click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons + mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement + keydown: 2, keypress: 2, keyup: 2, //keyboard + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements + load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window + error: 1, abort: 1, scroll: 1 //misc +}; + +(function(){ + +var $check = function(event){ + var related = event.relatedTarget; + if (related == undefined) return true; + if (related === false) return false; + return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); +}; + +Element.Events = new Hash({ + + mouseenter: { + base: 'mouseover', + condition: $check + }, + + mouseleave: { + base: 'mouseout', + condition: $check + }, + + mousewheel: { + base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' + } + +}); + +})(); + + +/* +--- + +script: Element.Style.js + +description: Contains methods for interacting with the styles of Elements in a fashionable way. + +license: MIT-style license. + +requires: +- /Element + +provides: [Element.Style] + +... +*/ + +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; + +Element.Properties.opacity = { + + set: function(opacity, novisibility){ + if (!novisibility){ + if (opacity == 0){ + if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; + } else { + if (this.style.visibility != 'visible') this.style.visibility = 'visible'; + } + } + if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; + if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; + this.style.opacity = opacity; + this.store('opacity', opacity); + }, + + get: function(){ + return this.retrieve('opacity', 1); + } + +}; + +Element.implement({ + + setOpacity: function(value){ + return this.set('opacity', value, true); + }, + + getOpacity: function(){ + return this.get('opacity'); + }, + + setStyle: function(property, value){ + switch (property){ + case 'opacity': return this.set('opacity', parseFloat(value)); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + if ($type(value) != 'string'){ + var map = (Element.Styles.get(property) || '@').split(' '); + value = $splat(value).map(function(val, i){ + if (!map[i]) return ''; + return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; + }).join(' '); + } else if (value == String(Number(value))){ + value = Math.round(value); + } + this.style[property] = value; + return this; + }, + + getStyle: function(property){ + switch (property){ + case 'opacity': return this.get('opacity'); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + var result = this.style[property]; + if (!$chk(result)){ + result = []; + for (var style in Element.ShortStyles){ + if (property != style) continue; + for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); + return result.join(' '); + } + result = this.getComputedStyle(property); + } + if (result){ + result = String(result); + var color = result.match(/rgba?\([\d\s,]+\)/); + if (color) result = result.replace(color[0], color[0].rgbToHex()); + } + if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ + if (property.test(/^(height|width)$/)){ + var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; + values.each(function(value){ + size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); + }, this); + return this['offset' + property.capitalize()] - size + 'px'; + } + if ((Browser.Engine.presto) && String(result).test('px')) return result; + if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; + } + return result; + }, + + setStyles: function(styles){ + for (var style in styles) this.setStyle(style, styles[style]); + return this; + }, + + getStyles: function(){ + var result = {}; + Array.flatten(arguments).each(function(key){ + result[key] = this.getStyle(key); + }, this); + return result; + } + +}); + +Element.Styles = new Hash({ + left: '@px', top: '@px', bottom: '@px', right: '@px', + width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', + backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', + fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', + margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', + borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', + zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' +}); + +Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; + +['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ + var Short = Element.ShortStyles; + var All = Element.Styles; + ['margin', 'padding'].each(function(style){ + var sd = style + direction; + Short[style][sd] = All[sd] = '@px'; + }); + var bd = 'border' + direction; + Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; + var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; + Short[bd] = {}; + Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; + Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; + Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; +}); + + +/* +--- + +script: Element.Dimensions.js + +description: Contains methods to work with size, scroll, or positioning of Elements and the window object. + +license: MIT-style license. + +credits: +- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). +- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). + +requires: +- /Element + +provides: [Element.Dimensions] + +... +*/ + +(function(){ + +Element.implement({ + + scrollTo: function(x, y){ + if (isBody(this)){ + this.getWindow().scrollTo(x, y); + } else { + this.scrollLeft = x; + this.scrollTop = y; + } + return this; + }, + + getSize: function(){ + if (isBody(this)) return this.getWindow().getSize(); + return {x: this.offsetWidth, y: this.offsetHeight}; + }, + + getScrollSize: function(){ + if (isBody(this)) return this.getWindow().getScrollSize(); + return {x: this.scrollWidth, y: this.scrollHeight}; + }, + + getScroll: function(){ + if (isBody(this)) return this.getWindow().getScroll(); + return {x: this.scrollLeft, y: this.scrollTop}; + }, + + getScrolls: function(){ + var element = this, position = {x: 0, y: 0}; + while (element && !isBody(element)){ + position.x += element.scrollLeft; + position.y += element.scrollTop; + element = element.parentNode; + } + return position; + }, + + getOffsetParent: function(){ + var element = this; + if (isBody(element)) return null; + if (!Browser.Engine.trident) return element.offsetParent; + while ((element = element.parentNode) && !isBody(element)){ + if (styleString(element, 'position') != 'static') return element; + } + return null; + }, + + getOffsets: function(){ + if (this.getBoundingClientRect){ + var bound = this.getBoundingClientRect(), + html = document.id(this.getDocument().documentElement), + htmlScroll = html.getScroll(), + elemScrolls = this.getScrolls(), + elemScroll = this.getScroll(), + isFixed = (styleString(this, 'position') == 'fixed'); + + return { + x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, + y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop + }; + } + + var element = this, position = {x: 0, y: 0}; + if (isBody(this)) return position; + + while (element && !isBody(element)){ + position.x += element.offsetLeft; + position.y += element.offsetTop; + + if (Browser.Engine.gecko){ + if (!borderBox(element)){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + var parent = element.parentNode; + if (parent && styleString(parent, 'overflow') != 'visible'){ + position.x += leftBorder(parent); + position.y += topBorder(parent); + } + } else if (element != this && Browser.Engine.webkit){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + + element = element.offsetParent; + } + if (Browser.Engine.gecko && !borderBox(this)){ + position.x -= leftBorder(this); + position.y -= topBorder(this); + } + return position; + }, + + getPosition: function(relative){ + if (isBody(this)) return {x: 0, y: 0}; + var offset = this.getOffsets(), + scroll = this.getScrolls(); + var position = { + x: offset.x - scroll.x, + y: offset.y - scroll.y + }; + var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0}; + return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; + }, + + getCoordinates: function(element){ + if (isBody(this)) return this.getWindow().getCoordinates(); + var position = this.getPosition(element), + size = this.getSize(); + var obj = { + left: position.x, + top: position.y, + width: size.x, + height: size.y + }; + obj.right = obj.left + obj.width; + obj.bottom = obj.top + obj.height; + return obj; + }, + + computePosition: function(obj){ + return { + left: obj.x - styleNumber(this, 'margin-left'), + top: obj.y - styleNumber(this, 'margin-top') + }; + }, + + setPosition: function(obj){ + return this.setStyles(this.computePosition(obj)); + } + +}); + + +Native.implement([Document, Window], { + + getSize: function(){ + if (Browser.Engine.presto || Browser.Engine.webkit){ + var win = this.getWindow(); + return {x: win.innerWidth, y: win.innerHeight}; + } + var doc = getCompatElement(this); + return {x: doc.clientWidth, y: doc.clientHeight}; + }, + + getScroll: function(){ + var win = this.getWindow(), doc = getCompatElement(this); + return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; + }, + + getScrollSize: function(){ + var doc = getCompatElement(this), min = this.getSize(); + return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; + }, + + getPosition: function(){ + return {x: 0, y: 0}; + }, + + getCoordinates: function(){ + var size = this.getSize(); + return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; + } + +}); + +// private methods + +var styleString = Element.getComputedStyle; + +function styleNumber(element, style){ + return styleString(element, style).toInt() || 0; +}; + +function borderBox(element){ + return styleString(element, '-moz-box-sizing') == 'border-box'; +}; + +function topBorder(element){ + return styleNumber(element, 'border-top-width'); +}; + +function leftBorder(element){ + return styleNumber(element, 'border-left-width'); +}; + +function isBody(element){ + return (/^(?:body|html)$/i).test(element.tagName); +}; + +function getCompatElement(element){ + var doc = element.getDocument(); + return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; +}; + +})(); + +//aliases +Element.alias('setPosition', 'position'); //compatability + +Native.implement([Window, Document, Element], { + + getHeight: function(){ + return this.getSize().y; + }, + + getWidth: function(){ + return this.getSize().x; + }, + + getScrollTop: function(){ + return this.getScroll().y; + }, + + getScrollLeft: function(){ + return this.getScroll().x; + }, + + getScrollHeight: function(){ + return this.getScrollSize().y; + }, + + getScrollWidth: function(){ + return this.getScrollSize().x; + }, + + getTop: function(){ + return this.getPosition().y; + }, + + getLeft: function(){ + return this.getPosition().x; + } + +}); + + +/* +--- + +script: Selectors.js + +description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors. + +license: MIT-style license. + +requires: +- /Element + +provides: [Selectors] + +... +*/ + +Native.implement([Document, Element], { + + getElements: function(expression, nocash){ + expression = expression.split(','); + var items, local = {}; + for (var i = 0, l = expression.length; i < l; i++){ + var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); + if (i != 0 && elements.item) elements = $A(elements); + items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); + } + return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); + } + +}); + +Element.implement({ + + match: function(selector){ + if (!selector || (selector == this)) return true; + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false; + var parsed = Selectors.Utils.parseSelector(selector); + return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; + } + +}); + +var Selectors = {Cache: {nth: {}, parsed: {}}}; + +Selectors.RegExps = { + id: (/#([\w-]+)/), + tag: (/^(\w+|\*)/), + quick: (/^(\w+|\*)$/), + splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), + combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) +}; + +Selectors.Utils = { + + chk: function(item, uniques){ + if (!uniques) return true; + var uid = $uid(item); + if (!uniques[uid]) return uniques[uid] = true; + return false; + }, + + parseNthArgument: function(argument){ + if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; + var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); + if (!parsed) return false; + var inta = parseInt(parsed[1], 10); + var a = (inta || inta === 0) ? inta : 1; + var special = parsed[2] || false; + var b = parseInt(parsed[3], 10) || 0; + if (a != 0){ + b--; + while (b < 1) b += a; + while (b >= a) b -= a; + } else { + a = b; + special = 'index'; + } + switch (special){ + case 'n': parsed = {a: a, b: b, special: 'n'}; break; + case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; + case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; + case 'first': parsed = {a: 0, special: 'index'}; break; + case 'last': parsed = {special: 'last-child'}; break; + case 'only': parsed = {special: 'only-child'}; break; + default: parsed = {a: (a - 1), special: 'index'}; + } + + return Selectors.Cache.nth[argument] = parsed; + }, + + parseSelector: function(selector){ + if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; + var m, parsed = {classes: [], pseudos: [], attributes: []}; + while ((m = Selectors.RegExps.combined.exec(selector))){ + var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; + if (cn){ + parsed.classes.push(cn); + } else if (pn){ + var parser = Selectors.Pseudo.get(pn); + if (parser) parsed.pseudos.push({parser: parser, argument: pa}); + else parsed.attributes.push({name: pn, operator: '=', value: pa}); + } else if (an){ + parsed.attributes.push({name: an, operator: ao, value: av}); + } + } + if (!parsed.classes.length) delete parsed.classes; + if (!parsed.attributes.length) delete parsed.attributes; + if (!parsed.pseudos.length) delete parsed.pseudos; + if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; + return Selectors.Cache.parsed[selector] = parsed; + }, + + parseTagAndID: function(selector){ + var tag = selector.match(Selectors.RegExps.tag); + var id = selector.match(Selectors.RegExps.id); + return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; + }, + + filter: function(item, parsed, local){ + var i; + if (parsed.classes){ + for (i = parsed.classes.length; i--; i){ + var cn = parsed.classes[i]; + if (!Selectors.Filters.byClass(item, cn)) return false; + } + } + if (parsed.attributes){ + for (i = parsed.attributes.length; i--; i){ + var att = parsed.attributes[i]; + if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; + } + } + if (parsed.pseudos){ + for (i = parsed.pseudos.length; i--; i){ + var psd = parsed.pseudos[i]; + if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; + } + } + return true; + }, + + getByTagAndID: function(ctx, tag, id){ + if (id){ + var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); + return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; + } else { + return ctx.getElementsByTagName(tag); + } + }, + + search: function(self, expression, local){ + var splitters = []; + + var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ + splitters.push(m1); + return ':)' + m2; + }).split(':)'); + + var items, filtered, item; + + for (var i = 0, l = selectors.length; i < l; i++){ + + var selector = selectors[i]; + + if (i == 0 && Selectors.RegExps.quick.test(selector)){ + items = self.getElementsByTagName(selector); + continue; + } + + var splitter = splitters[i - 1]; + + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + + if (i == 0){ + items = Selectors.Utils.getByTagAndID(self, tag, id); + } else { + var uniques = {}, found = []; + for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); + items = found; + } + + var parsed = Selectors.Utils.parseSelector(selector); + + if (parsed){ + filtered = []; + for (var m = 0, n = items.length; m < n; m++){ + item = items[m]; + if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); + } + items = filtered; + } + + } + + return items; + + } + +}; + +Selectors.Getters = { + + ' ': function(found, self, tag, id, uniques){ + var items = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = items.length; i < l; i++){ + var item = items[i]; + if (Selectors.Utils.chk(item, uniques)) found.push(item); + } + return found; + }, + + '>': function(found, self, tag, id, uniques){ + var children = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = children.length; i < l; i++){ + var child = children[i]; + if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); + } + return found; + }, + + '+': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + break; + } + } + return found; + }, + + '~': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (!Selectors.Utils.chk(self, uniques)) break; + if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + } + } + return found; + } + +}; + +Selectors.Filters = { + + byTag: function(self, tag){ + return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); + }, + + byID: function(self, id){ + return (!id || (self.id && self.id == id)); + }, + + byClass: function(self, klass){ + return (self.className && self.className.contains && self.className.contains(klass, ' ')); + }, + + byPseudo: function(self, parser, argument, local){ + return parser.call(self, argument, local); + }, + + byAttribute: function(self, name, operator, value){ + var result = Element.prototype.getProperty.call(self, name); + if (!result) return (operator == '!='); + if (!operator || value == undefined) return true; + switch (operator){ + case '=': return (result == value); + case '*=': return (result.contains(value)); + case '^=': return (result.substr(0, value.length) == value); + case '$=': return (result.substr(result.length - value.length) == value); + case '!=': return (result != value); + case '~=': return result.contains(value, ' '); + case '|=': return result.contains(value, '-'); + } + return false; + } + +}; + +Selectors.Pseudo = new Hash({ + + // w3c pseudo selectors + + checked: function(){ + return this.checked; + }, + + empty: function(){ + return !(this.innerText || this.textContent || '').length; + }, + + not: function(selector){ + return !Element.match(this, selector); + }, + + contains: function(text){ + return (this.innerText || this.textContent || '').contains(text); + }, + + 'first-child': function(){ + return Selectors.Pseudo.index.call(this, 0); + }, + + 'last-child': function(){ + var element = this; + while ((element = element.nextSibling)){ + if (element.nodeType == 1) return false; + } + return true; + }, + + 'only-child': function(){ + var prev = this; + while ((prev = prev.previousSibling)){ + if (prev.nodeType == 1) return false; + } + var next = this; + while ((next = next.nextSibling)){ + if (next.nodeType == 1) return false; + } + return true; + }, + + 'nth-child': function(argument, local){ + argument = (argument == undefined) ? 'n' : argument; + var parsed = Selectors.Utils.parseNthArgument(argument); + if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); + var count = 0; + local.positions = local.positions || {}; + var uid = $uid(this); + if (!local.positions[uid]){ + var self = this; + while ((self = self.previousSibling)){ + if (self.nodeType != 1) continue; + count ++; + var position = local.positions[$uid(self)]; + if (position != undefined){ + count = position + count; + break; + } + } + local.positions[uid] = count; + } + return (local.positions[uid] % parsed.a == parsed.b); + }, + + // custom pseudo selectors + + index: function(index){ + var element = this, count = 0; + while ((element = element.previousSibling)){ + if (element.nodeType == 1 && ++count > index) return false; + } + return (count == index); + }, + + even: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); + }, + + odd: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n', local); + }, + + selected: function(){ + return this.selected; + }, + + enabled: function(){ + return (this.disabled === false); + } + +}); + + +/* +--- + +script: DomReady.js + +description: Contains the custom event domready. + +license: MIT-style license. + +requires: +- /Element.Event + +provides: [DomReady] + +... +*/ + +Element.Events.domready = { + + onAdd: function(fn){ + if (Browser.loaded) fn.call(this); + } + +}; + +(function(){ + + var domready = function(){ + if (Browser.loaded) return; + Browser.loaded = true; + window.fireEvent('domready'); + document.fireEvent('domready'); + }; + + window.addEvent('load', domready); + + if (Browser.Engine.trident){ + var temp = document.createElement('div'); + (function(){ + ($try(function(){ + temp.doScroll(); // Technique by Diego Perini + return document.id(temp).inject(document.body).set('html', 'temp').dispose(); + })) ? domready() : arguments.callee.delay(50); + })(); + } else if (Browser.Engine.webkit && Browser.Engine.version < 525){ + (function(){ + (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); + })(); + } else { + document.addEvent('DOMContentLoaded', domready); + } + +})(); + + +/* +--- + +script: JSON.js + +description: JSON encoder and decoder. + +license: MIT-style license. + +See Also: + +requires: +- /Array +- /String +- /Number +- /Function +- /Hash + +provides: [JSON] + +... +*/ + +var JSON = new Hash(this.JSON && { + stringify: JSON.stringify, + parse: JSON.parse +}).extend({ + + $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, + + $replaceChars: function(chr){ + return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); + }, + + encode: function(obj){ + switch ($type(obj)){ + case 'string': + return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; + case 'array': + return '[' + String(obj.map(JSON.encode).clean()) + ']'; + case 'object': case 'hash': + var string = []; + Hash.each(obj, function(value, key){ + var json = JSON.encode(value); + if (json) string.push(JSON.encode(key) + ':' + json); + }); + return '{' + string + '}'; + case 'number': case 'boolean': return String(obj); + case false: return 'null'; + } + return null; + }, + + decode: function(string, secure){ + if ($type(string) != 'string' || !string.length) return null; + if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; + return eval('(' + string + ')'); + } + +}); + +Native.implement([Hash, Array, String, Number], { + + toJSON: function(){ + return JSON.encode(this); + } + +}); + + +/* +--- + +script: Cookie.js + +description: Class for creating, reading, and deleting browser Cookies. + +license: MIT-style license. + +credits: +- Based on the functions by Peter-Paul Koch (http://quirksmode.org). + +requires: +- /Options + +provides: [Cookie] + +... +*/ + +var Cookie = new Class({ + + Implements: Options, + + options: { + path: false, + domain: false, + duration: false, + secure: false, + document: document + }, + + initialize: function(key, options){ + this.key = key; + this.setOptions(options); + }, + + write: function(value){ + value = encodeURIComponent(value); + if (this.options.domain) value += '; domain=' + this.options.domain; + if (this.options.path) value += '; path=' + this.options.path; + if (this.options.duration){ + var date = new Date(); + date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); + value += '; expires=' + date.toGMTString(); + } + if (this.options.secure) value += '; secure'; + this.options.document.cookie = this.key + '=' + value; + return this; + }, + + read: function(){ + var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); + return (value) ? decodeURIComponent(value[1]) : null; + }, + + dispose: function(){ + new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); + return this; + } + +}); + +Cookie.write = function(key, value, options){ + return new Cookie(key, options).write(value); +}; + +Cookie.read = function(key){ + return new Cookie(key).read(); +}; + +Cookie.dispose = function(key, options){ + return new Cookie(key, options).dispose(); +}; + + +/* +--- + +script: Swiff.js + +description: Wrapper for embedding SWF movies. Supports External Interface Communication. + +license: MIT-style license. + +credits: +- Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. + +requires: +- /Options +- /$util + +provides: [Swiff] + +... +*/ + +var Swiff = new Class({ + + Implements: [Options], + + options: { + id: null, + height: 1, + width: 1, + container: null, + properties: {}, + params: { + quality: 'high', + allowScriptAccess: 'always', + wMode: 'transparent', + swLiveConnect: true + }, + callBacks: {}, + vars: {} + }, + + toElement: function(){ + return this.object; + }, + + initialize: function(path, options){ + this.instance = 'Swiff_' + $time(); + + this.setOptions(options); + options = this.options; + var id = this.id = options.id || this.instance; + var container = document.id(options.container); + + Swiff.CallBacks[this.instance] = {}; + + var params = options.params, vars = options.vars, callBacks = options.callBacks; + var properties = $extend({height: options.height, width: options.width}, options.properties); + + var self = this; + + for (var callBack in callBacks){ + Swiff.CallBacks[this.instance][callBack] = (function(option){ + return function(){ + return option.apply(self.object, arguments); + }; + })(callBacks[callBack]); + vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; + } + + params.flashVars = Hash.toQueryString(vars); + if (Browser.Engine.trident){ + properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; + params.movie = path; + } else { + properties.type = 'application/x-shockwave-flash'; + properties.data = path; + } + var build = ''; + } + build += ''; + this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; + }, + + replaces: function(element){ + element = document.id(element, true); + element.parentNode.replaceChild(this.toElement(), element); + return this; + }, + + inject: function(element){ + document.id(element, true).appendChild(this.toElement()); + return this; + }, + + remote: function(){ + return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); + } + +}); + +Swiff.CallBacks = {}; + +Swiff.remote = function(obj, fn){ + var rs = obj.CallFunction('' + __flash__argumentsToXML(arguments, 2) + ''); + return eval(rs); +}; + + +/* +--- + +script: Fx.js + +description: Contains the basic animation logic to be extended by all other Fx Classes. + +license: MIT-style license. + +requires: +- /Chain +- /Events +- /Options + +provides: [Fx] + +... +*/ + +var Fx = new Class({ + + Implements: [Chain, Events, Options], + + options: { + /* + onStart: $empty, + onCancel: $empty, + onComplete: $empty, + */ + fps: 50, + unit: false, + duration: 500, + link: 'ignore' + }, + + initialize: function(options){ + this.subject = this.subject || this; + this.setOptions(options); + this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); + var wait = this.options.wait; + if (wait === false) this.options.link = 'cancel'; + }, + + getTransition: function(){ + return function(p){ + return -(Math.cos(Math.PI * p) - 1) / 2; + }; + }, + + step: function(){ + var time = $time(); + if (time < this.time + this.options.duration){ + var delta = this.transition((time - this.time) / this.options.duration); + this.set(this.compute(this.from, this.to, delta)); + } else { + this.set(this.compute(this.from, this.to, 1)); + this.complete(); + } + }, + + set: function(now){ + return now; + }, + + compute: function(from, to, delta){ + return Fx.compute(from, to, delta); + }, + + check: function(){ + if (!this.timer) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + start: function(from, to){ + if (!this.check(from, to)) return this; + this.from = from; + this.to = to; + this.time = 0; + this.transition = this.getTransition(); + this.startTimer(); + this.onStart(); + return this; + }, + + complete: function(){ + if (this.stopTimer()) this.onComplete(); + return this; + }, + + cancel: function(){ + if (this.stopTimer()) this.onCancel(); + return this; + }, + + onStart: function(){ + this.fireEvent('start', this.subject); + }, + + onComplete: function(){ + this.fireEvent('complete', this.subject); + if (!this.callChain()) this.fireEvent('chainComplete', this.subject); + }, + + onCancel: function(){ + this.fireEvent('cancel', this.subject).clearChain(); + }, + + pause: function(){ + this.stopTimer(); + return this; + }, + + resume: function(){ + this.startTimer(); + return this; + }, + + stopTimer: function(){ + if (!this.timer) return false; + this.time = $time() - this.time; + this.timer = $clear(this.timer); + return true; + }, + + startTimer: function(){ + if (this.timer) return false; + this.time = $time() - this.time; + this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); + return true; + } + +}); + +Fx.compute = function(from, to, delta){ + return (to - from) * delta + from; +}; + +Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; + + +/* +--- + +script: Fx.CSS.js + +description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. + +license: MIT-style license. + +requires: +- /Fx +- /Element.Style + +provides: [Fx.CSS] + +... +*/ + +Fx.CSS = new Class({ + + Extends: Fx, + + //prepares the base from/to object + + prepare: function(element, property, values){ + values = $splat(values); + var values1 = values[1]; + if (!$chk(values1)){ + values[1] = values[0]; + values[0] = element.getStyle(property); + } + var parsed = values.map(this.parse); + return {from: parsed[0], to: parsed[1]}; + }, + + //parses a value into an array + + parse: function(value){ + value = $lambda(value)(); + value = (typeof value == 'string') ? value.split(' ') : $splat(value); + return value.map(function(val){ + val = String(val); + var found = false; + Fx.CSS.Parsers.each(function(parser, key){ + if (found) return; + var parsed = parser.parse(val); + if ($chk(parsed)) found = {value: parsed, parser: parser}; + }); + found = found || {value: val, parser: Fx.CSS.Parsers.String}; + return found; + }); + }, + + //computes by a from and to prepared objects, using their parsers. + + compute: function(from, to, delta){ + var computed = []; + (Math.min(from.length, to.length)).times(function(i){ + computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); + }); + computed.$family = {name: 'fx:css:value'}; + return computed; + }, + + //serves the value as settable + + serve: function(value, unit){ + if ($type(value) != 'fx:css:value') value = this.parse(value); + var returned = []; + value.each(function(bit){ + returned = returned.concat(bit.parser.serve(bit.value, unit)); + }); + return returned; + }, + + //renders the change to an element + + render: function(element, property, value, unit){ + element.setStyle(property, this.serve(value, unit)); + }, + + //searches inside the page css to find the values for a selector + + search: function(selector){ + if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; + var to = {}; + Array.each(document.styleSheets, function(sheet, j){ + var href = sheet.href; + if (href && href.contains('://') && !href.contains(document.domain)) return; + var rules = sheet.rules || sheet.cssRules; + Array.each(rules, function(rule, i){ + if (!rule.style) return; + var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ + return m.toLowerCase(); + }) : null; + if (!selectorText || !selectorText.test('^' + selector + '$')) return; + Element.Styles.each(function(value, style){ + if (!rule.style[style] || Element.ShortStyles[style]) return; + value = String(rule.style[style]); + to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; + }); + }); + }); + return Fx.CSS.Cache[selector] = to; + } + +}); + +Fx.CSS.Cache = {}; + +Fx.CSS.Parsers = new Hash({ + + Color: { + parse: function(value){ + if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); + return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; + }, + compute: function(from, to, delta){ + return from.map(function(value, i){ + return Math.round(Fx.compute(from[i], to[i], delta)); + }); + }, + serve: function(value){ + return value.map(Number); + } + }, + + Number: { + parse: parseFloat, + compute: Fx.compute, + serve: function(value, unit){ + return (unit) ? value + unit : value; + } + }, + + String: { + parse: $lambda(false), + compute: $arguments(1), + serve: $arguments(0) + } + +}); + + +/* +--- + +script: Fx.Tween.js + +description: Formerly Fx.Style, effect to transition any CSS property for an element. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Tween, Element.fade, Element.highlight] + +... +*/ + +Fx.Tween = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(property, now){ + if (arguments.length == 1){ + now = property; + property = this.property || this.options.property; + } + this.render(this.element, property, now, this.options.unit); + return this; + }, + + start: function(property, from, to){ + if (!this.check(property, from, to)) return this; + var args = Array.flatten(arguments); + this.property = this.options.property || args.shift(); + var parsed = this.prepare(this.element, this.property, args); + return this.parent(parsed.from, parsed.to); + } + +}); + +Element.Properties.tween = { + + set: function(options){ + var tween = this.retrieve('tween'); + if (tween) tween.cancel(); + return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('tween')){ + if (options || !this.retrieve('tween:options')) this.set('tween', options); + this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); + } + return this.retrieve('tween'); + } + +}; + +Element.implement({ + + tween: function(property, from, to){ + this.get('tween').start(arguments); + return this; + }, + + fade: function(how){ + var fade = this.get('tween'), o = 'opacity', toggle; + how = $pick(how, 'toggle'); + switch (how){ + case 'in': fade.start(o, 1); break; + case 'out': fade.start(o, 0); break; + case 'show': fade.set(o, 1); break; + case 'hide': fade.set(o, 0); break; + case 'toggle': + var flag = this.retrieve('fade:flag', this.get('opacity') == 1); + fade.start(o, (flag) ? 0 : 1); + this.store('fade:flag', !flag); + toggle = true; + break; + default: fade.start(o, arguments); + } + if (!toggle) this.eliminate('fade:flag'); + return this; + }, + + highlight: function(start, end){ + if (!end){ + end = this.retrieve('highlight:original', this.getStyle('background-color')); + end = (end == 'transparent') ? '#fff' : end; + } + var tween = this.get('tween'); + tween.start('background-color', start || '#ffff88', end).chain(function(){ + this.setStyle('background-color', this.retrieve('highlight:original')); + tween.callChain(); + }.bind(this)); + return this; + } + +}); + + +/* +--- + +script: Fx.Morph.js + +description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Morph] + +... +*/ + +Fx.Morph = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(now){ + if (typeof now == 'string') now = this.search(now); + for (var p in now) this.render(this.element, p, now[p], this.options.unit); + return this; + }, + + compute: function(from, to, delta){ + var now = {}; + for (var p in from) now[p] = this.parent(from[p], to[p], delta); + return now; + }, + + start: function(properties){ + if (!this.check(properties)) return this; + if (typeof properties == 'string') properties = this.search(properties); + var from = {}, to = {}; + for (var p in properties){ + var parsed = this.prepare(this.element, p, properties[p]); + from[p] = parsed.from; + to[p] = parsed.to; + } + return this.parent(from, to); + } + +}); + +Element.Properties.morph = { + + set: function(options){ + var morph = this.retrieve('morph'); + if (morph) morph.cancel(); + return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('morph')){ + if (options || !this.retrieve('morph:options')) this.set('morph', options); + this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); + } + return this.retrieve('morph'); + } + +}; + +Element.implement({ + + morph: function(props){ + this.get('morph').start(props); + return this; + } + +}); + + +/* +--- + +script: Fx.Transitions.js + +description: Contains a set of advanced transitions to be used with any of the Fx Classes. + +license: MIT-style license. + +credits: +- Easing Equations by Robert Penner, , modified and optimized to be used with MooTools. + +requires: +- /Fx + +provides: [Fx.Transitions] + +... +*/ + +Fx.implement({ + + getTransition: function(){ + var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; + if (typeof trans == 'string'){ + var data = trans.split(':'); + trans = Fx.Transitions; + trans = trans[data[0]] || trans[data[0].capitalize()]; + if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; + } + return trans; + } + +}); + +Fx.Transition = function(transition, params){ + params = $splat(params); + return $extend(transition, { + easeIn: function(pos){ + return transition(pos, params); + }, + easeOut: function(pos){ + return 1 - transition(1 - pos, params); + }, + easeInOut: function(pos){ + return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; + } + }); +}; + +Fx.Transitions = new Hash({ + + linear: $arguments(0) + +}); + +Fx.Transitions.extend = function(transitions){ + for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); +}; + +Fx.Transitions.extend({ + + Pow: function(p, x){ + return Math.pow(p, x[0] || 6); + }, + + Expo: function(p){ + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p){ + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p){ + return 1 - Math.sin((1 - p) * Math.PI / 2); + }, + + Back: function(p, x){ + x = x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p){ + var value; + for (var a = 0, b = 1; 1; a += b, b /= 2){ + if (p >= (7 - 4 * a) / 11){ + value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); + break; + } + } + return value; + }, + + Elastic: function(p, x){ + return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); + } + +}); + +['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ + Fx.Transitions[transition] = new Fx.Transition(function(p){ + return Math.pow(p, [i + 2]); + }); +}); + + +/* +--- + +script: Request.js + +description: Powerful all purpose Request Class. Uses XMLHTTPRequest. + +license: MIT-style license. + +requires: +- /Element +- /Chain +- /Events +- /Options +- /Browser + +provides: [Request] + +... +*/ + +var Request = new Class({ + + Implements: [Chain, Events, Options], + + options: {/* + onRequest: $empty, + onComplete: $empty, + onCancel: $empty, + onSuccess: $empty, + onFailure: $empty, + onException: $empty,*/ + url: '', + data: '', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }, + async: true, + format: false, + method: 'post', + link: 'ignore', + isSuccess: null, + emulation: true, + urlEncoded: true, + encoding: 'utf-8', + evalScripts: false, + evalResponse: false, + noCache: false + }, + + initialize: function(options){ + this.xhr = new Browser.Request(); + this.setOptions(options); + this.options.isSuccess = this.options.isSuccess || this.isSuccess; + this.headers = new Hash(this.options.headers); + }, + + onStateChange: function(){ + if (this.xhr.readyState != 4 || !this.running) return; + this.running = false; + this.status = 0; + $try(function(){ + this.status = this.xhr.status; + }.bind(this)); + this.xhr.onreadystatechange = $empty; + if (this.options.isSuccess.call(this, this.status)){ + this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; + this.success(this.response.text, this.response.xml); + } else { + this.response = {text: null, xml: null}; + this.failure(); + } + }, + + isSuccess: function(){ + return ((this.status >= 200) && (this.status < 300)); + }, + + processScripts: function(text){ + if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); + return text.stripScripts(this.options.evalScripts); + }, + + success: function(text, xml){ + this.onSuccess(this.processScripts(text), xml); + }, + + onSuccess: function(){ + this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); + }, + + failure: function(){ + this.onFailure(); + }, + + onFailure: function(){ + this.fireEvent('complete').fireEvent('failure', this.xhr); + }, + + setHeader: function(name, value){ + this.headers.set(name, value); + return this; + }, + + getHeader: function(name){ + return $try(function(){ + return this.xhr.getResponseHeader(name); + }.bind(this)); + }, + + check: function(){ + if (!this.running) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + send: function(options){ + if (!this.check(options)) return this; + this.running = true; + + var type = $type(options); + if (type == 'string' || type == 'element') options = {data: options}; + + var old = this.options; + options = $extend({data: old.data, url: old.url, method: old.method}, options); + var data = options.data, url = String(options.url), method = options.method.toLowerCase(); + + switch ($type(data)){ + case 'element': data = document.id(data).toQueryString(); break; + case 'object': case 'hash': data = Hash.toQueryString(data); + } + + if (this.options.format){ + var format = 'format=' + this.options.format; + data = (data) ? format + '&' + data : format; + } + + if (this.options.emulation && !['get', 'post'].contains(method)){ + var _method = '_method=' + method; + data = (data) ? _method + '&' + data : _method; + method = 'post'; + } + + if (this.options.urlEncoded && method == 'post'){ + var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; + this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); + } + + if (this.options.noCache){ + var noCache = 'noCache=' + new Date().getTime(); + data = (data) ? noCache + '&' + data : noCache; + } + + var trimPosition = url.lastIndexOf('/'); + if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); + + if (data && method == 'get'){ + url = url + (url.contains('?') ? '&' : '?') + data; + data = null; + } + + this.xhr.open(method.toUpperCase(), url, this.options.async); + + this.xhr.onreadystatechange = this.onStateChange.bind(this); + + this.headers.each(function(value, key){ + try { + this.xhr.setRequestHeader(key, value); + } catch (e){ + this.fireEvent('exception', [key, value]); + } + }, this); + + this.fireEvent('request'); + this.xhr.send(data); + if (!this.options.async) this.onStateChange(); + return this; + }, + + cancel: function(){ + if (!this.running) return this; + this.running = false; + this.xhr.abort(); + this.xhr.onreadystatechange = $empty; + this.xhr = new Browser.Request(); + this.fireEvent('cancel'); + return this; + } + +}); + +(function(){ + +var methods = {}; +['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ + methods[method] = function(){ + var params = Array.link(arguments, {url: String.type, data: $defined}); + return this.send($extend(params, {method: method})); + }; +}); + +Request.implement(methods); + +})(); + +Element.Properties.send = { + + set: function(options){ + var send = this.retrieve('send'); + if (send) send.cancel(); + return this.eliminate('send').store('send:options', $extend({ + data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') + }, options)); + }, + + get: function(options){ + if (options || !this.retrieve('send')){ + if (options || !this.retrieve('send:options')) this.set('send', options); + this.store('send', new Request(this.retrieve('send:options'))); + } + return this.retrieve('send'); + } + +}; + +Element.implement({ + + send: function(url){ + var sender = this.get('send'); + sender.send({data: this, url: url || sender.options.url}); + return this; + } + +}); + + +/* +--- + +script: Request.JSON.js + +description: Extends the basic Request Class with additional methods for sending and receiving JSON data. + +license: MIT-style license. + +requires: +- /Request JSON + +provides: [Request.HTML] + +... +*/ + +Request.JSON = new Class({ + + Extends: Request, + + options: { + secure: true + }, + + initialize: function(options){ + this.parent(options); + this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); + }, + + success: function(text){ + this.response.json = JSON.decode(text, this.options.secure); + this.onSuccess(this.response.json, text); + } + +}); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-more.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-more.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/mootools-more.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,789 @@ +//MooTools More, . Copyright (c) 2006-2009 Aaron Newton , Valerio Proietti & the MooTools team , MIT Style License. + +/* +--- + +script: More.js + +description: MooTools More + +license: MIT-style license + +authors: +- Guillermo Rauch +- Thomas Aylott +- Scott Kyle + +requires: +- core:1.2.4/MooTools + +provides: [MooTools.More] + +... +*/ + +MooTools.More = { + 'version': '1.2.4.2dev', + 'build': '%build%' +}; + +/* +--- + +script: Element.Delegation.js + +description: Extends the Element native object to include the delegate method for more efficient event management. + +credits: +- "Event checking based on the work of Daniel Steigerwald. License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" + +license: MIT-style license + +authors: +- Aaron Newton +- Daniel Steigerwald + +requires: +- core:1.2.4/Element.Event +- core:1.2.4/Selectors +- /MooTools.More + +provides: [Element.Delegation] + +... +*/ +(function(addEvent, removeEvent){ + + var match = /(.*?):relay\(([^)]+)\)$/, + combinators = /[+>~\s]/, + splitType = function(type){ + var bits = type.match(match); + return !bits ? {event: type} : { + event: bits[1], + selector: bits[2] + }; + }, + check = function(e, selector){ + var t = e.target; + if (combinators.test(selector = selector.trim())){ + var els = this.getElements(selector); + for (var i = els.length; i--; ){ + var el = els[i]; + if (t == el || el.hasChild(t)) return el; + } + } else { + for ( ; t && t != this; t = t.parentNode){ + if (Element.match(t, selector)) return document.id(t); + } + } + return null; + }; + + Element.implement({ + + addEvent: function(type, fn){ + var splitted = splitType(type); + if (splitted.selector){ + var monitors = this.retrieve('$moo:delegateMonitors', {}); + if (!monitors[type]){ + var monitor = function(e){ + var el = check.call(this, e, splitted.selector); + if (el) this.fireEvent(type, [e, el], 0, el); + }.bind(this); + monitors[type] = monitor; + addEvent.call(this, splitted.event, monitor); + } + } + return addEvent.apply(this, arguments); + }, + + removeEvent: function(type, fn){ + var splitted = splitType(type); + if (splitted.selector){ + var events = this.retrieve('events'); + if (!events || !events[type] || (fn && !events[type].keys.contains(fn))) return this; + + if (fn) removeEvent.apply(this, [type, fn]); + else removeEvent.apply(this, type); + + events = this.retrieve('events'); + if (events && events[type] && events[type].keys.length == 0){ + var monitors = this.retrieve('$moo:delegateMonitors', {}); + removeEvent.apply(this, [splitted.event, monitors[type]]); + delete monitors[type]; + } + return this; + } + + return removeEvent.apply(this, arguments); + }, + + fireEvent: function(type, args, delay, bind){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + events[type].keys.each(function(fn){ + fn.create({bind: bind || this, delay: delay, arguments: args})(); + }, this); + return this; + } + + }); + +})(Element.prototype.addEvent, Element.prototype.removeEvent); + +/* +--- + +script: Drag.js + +description: The base Drag Class. Can be used to drag and resize Elements using mouse events. + +license: MIT-style license + +authors: +- Valerio Proietti +- Tom Occhinno +- Jan Kassens + +requires: +- core:1.2.4/Events +- core:1.2.4/Options +- core:1.2.4/Element.Event +- core:1.2.4/Element.Style +- /MooTools.More + +provides: [Drag] + +*/ + +var Drag = new Class({ + + Implements: [Events, Options], + + options: {/* + onBeforeStart: $empty(thisElement), + onStart: $empty(thisElement, event), + onSnap: $empty(thisElement) + onDrag: $empty(thisElement, event), + onCancel: $empty(thisElement), + onComplete: $empty(thisElement, event),*/ + snap: 6, + unit: 'px', + grid: false, + style: true, + limit: false, + handle: false, + invert: false, + preventDefault: false, + modifiers: {x: 'left', y: 'top'} + }, + + initialize: function(){ + var params = Array.link(arguments, {'options': Object.type, 'element': $defined}); + this.element = document.id(params.element); + this.document = this.element.getDocument(); + this.setOptions(params.options || {}); + var htype = $type(this.options.handle); + this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element; + this.mouse = {'now': {}, 'pos': {}}; + this.value = {'start': {}, 'now': {}}; + + this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown'; + + this.bound = { + start: this.start.bind(this), + check: this.check.bind(this), + drag: this.drag.bind(this), + stop: this.stop.bind(this), + cancel: this.cancel.bind(this), + eventStop: $lambda(false) + }; + this.attach(); + }, + + attach: function(){ + this.handles.addEvent('mousedown', this.bound.start); + return this; + }, + + detach: function(){ + this.handles.removeEvent('mousedown', this.bound.start); + return this; + }, + + start: function(event){ + if (event.rightClick) return; + if (this.options.preventDefault) event.preventDefault(); + this.mouse.start = event.page; + this.fireEvent('beforeStart', this.element); + var limit = this.options.limit; + this.limit = {x: [], y: []}; + for (var z in this.options.modifiers){ + if (!this.options.modifiers[z]) continue; + if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt(); + else this.value.now[z] = this.element[this.options.modifiers[z]]; + if (this.options.invert) this.value.now[z] *= -1; + this.mouse.pos[z] = event.page[z] - this.value.now[z]; + if (limit && limit[z]){ + for (var i = 2; i--; i){ + if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])(); + } + } + } + if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid}; + this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel}); + this.document.addEvent(this.selection, this.bound.eventStop); + }, + + check: function(event){ + if (this.options.preventDefault) event.preventDefault(); + var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); + if (distance > this.options.snap){ + this.cancel(); + this.document.addEvents({ + mousemove: this.bound.drag, + mouseup: this.bound.stop + }); + this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element); + } + }, + + drag: function(event){ + if (this.options.preventDefault) event.preventDefault(); + this.mouse.now = event.page; + for (var z in this.options.modifiers){ + if (!this.options.modifiers[z]) continue; + this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; + if (this.options.invert) this.value.now[z] *= -1; + if (this.options.limit && this.limit[z]){ + if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ + this.value.now[z] = this.limit[z][1]; + } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ + this.value.now[z] = this.limit[z][0]; + } + } + if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]); + if (this.options.style) { + this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); + } else { + this.element[this.options.modifiers[z]] = this.value.now[z]; + } + } + this.fireEvent('drag', [this.element, event]); + }, + + cancel: function(event){ + this.document.removeEvent('mousemove', this.bound.check); + this.document.removeEvent('mouseup', this.bound.cancel); + if (event){ + this.document.removeEvent(this.selection, this.bound.eventStop); + this.fireEvent('cancel', this.element); + } + }, + + stop: function(event){ + this.document.removeEvent(this.selection, this.bound.eventStop); + this.document.removeEvent('mousemove', this.bound.drag); + this.document.removeEvent('mouseup', this.bound.stop); + if (event) this.fireEvent('complete', [this.element, event]); + } + +}); + +Element.implement({ + + makeResizable: function(options){ + var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options)); + this.store('resizer', drag); + return drag.addEvent('drag', function(){ + this.fireEvent('resize', drag); + }.bind(this)); + } + +}); + + +/* +--- + +script: Drag.Move.js + +description: A Drag extension that provides support for the constraining of draggables to containers and droppables. + +license: MIT-style license + +authors: +- Valerio Proietti +- Tom Occhinno +- Jan Kassens +- Aaron Newton +- Scott Kyle + +requires: +- core:1.2.4/Element.Dimensions +- /Drag + +provides: [Drag.Move] + +... +*/ + +Drag.Move = new Class({ + + Extends: Drag, + + options: {/* + onEnter: $empty(thisElement, overed), + onLeave: $empty(thisElement, overed), + onDrop: $empty(thisElement, overed, event),*/ + droppables: [], + container: false, + precalculate: false, + includeMargins: true, + checkDroppables: true + }, + + initialize: function(element, options){ + this.parent(element, options); + element = this.element; + + this.droppables = $$(this.options.droppables); + this.container = document.id(this.options.container); + + if (this.container && $type(this.container) != 'element') + this.container = document.id(this.container.getDocument().body); + + var styles = element.getStyles('left', 'top', 'position'); + if (styles.left == 'auto' || styles.top == 'auto') + element.setPosition(element.getPosition(element.getOffsetParent())); + + if (styles.position == 'static') + element.setStyle('position', 'absolute'); + + this.addEvent('start', this.checkDroppables, true); + + this.overed = null; + }, + + start: function(event){ + if (this.container) this.options.limit = this.calculateLimit(); + + if (this.options.precalculate){ + this.positions = this.droppables.map(function(el){ + return el.getCoordinates(); + }); + } + + this.parent(event); + }, + + calculateLimit: function(){ + var offsetParent = this.element.getOffsetParent(), + containerCoordinates = this.container.getCoordinates(offsetParent), + containerBorder = {}, + elementMargin = {}, + elementBorder = {}, + containerMargin = {}, + offsetParentPadding = {}; + + ['top', 'right', 'bottom', 'left'].each(function(pad){ + containerBorder[pad] = this.container.getStyle('border-' + pad).toInt(); + elementBorder[pad] = this.element.getStyle('border-' + pad).toInt(); + elementMargin[pad] = this.element.getStyle('margin-' + pad).toInt(); + containerMargin[pad] = this.container.getStyle('margin-' + pad).toInt(); + offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt(); + }, this); + + var width = this.element.offsetWidth + elementMargin.left + elementMargin.right, + height = this.element.offsetHeight + elementMargin.top + elementMargin.bottom, + left = 0, + top = 0, + right = containerCoordinates.right - containerBorder.right - width, + bottom = containerCoordinates.bottom - containerBorder.bottom - height; + + if (this.options.includeMargins){ + left += elementMargin.left; + top += elementMargin.top; + } else { + right += elementMargin.right; + bottom += elementMargin.bottom; + } + + if (this.element.getStyle('position') == 'relative'){ + var coords = this.element.getCoordinates(offsetParent); + coords.left -= this.element.getStyle('left').toInt(); + coords.top -= this.element.getStyle('top').toInt(); + + left += containerBorder.left - coords.left; + top += containerBorder.top - coords.top; + right += elementMargin.left - coords.left; + bottom += elementMargin.top - coords.top; + + if (this.container != offsetParent){ + left += containerMargin.left + offsetParentPadding.left; + top += (Browser.Engine.trident4 ? 0 : containerMargin.top) + offsetParentPadding.top; + } + } else { + left -= elementMargin.left; + top -= elementMargin.top; + + if (this.container == offsetParent){ + right -= containerBorder.left; + bottom -= containerBorder.top; + } else { + left += containerCoordinates.left + containerBorder.left; + top += containerCoordinates.top + containerBorder.top; + } + } + + return { + x: [left, right], + y: [top, bottom] + }; + }, + + checkAgainst: function(el, i){ + el = (this.positions) ? this.positions[i] : el.getCoordinates(); + var now = this.mouse.now; + return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top); + }, + + checkDroppables: function(){ + var overed = this.droppables.filter(this.checkAgainst, this).getLast(); + if (this.overed != overed){ + if (this.overed) this.fireEvent('leave', [this.element, this.overed]); + if (overed) this.fireEvent('enter', [this.element, overed]); + this.overed = overed; + } + }, + + drag: function(event){ + this.parent(event); + if (this.options.checkDroppables && this.droppables.length) this.checkDroppables(); + }, + + stop: function(event){ + this.checkDroppables(); + this.fireEvent('drop', [this.element, this.overed, event]); + this.overed = null; + return this.parent(event); + } + +}); + +Element.implement({ + + makeDraggable: function(options){ + var drag = new Drag.Move(this, options); + this.store('dragger', drag); + return drag; + } + +}); + + +/* +--- + +script: Assets.js + +description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document. + +license: MIT-style license + +authors: +- Valerio Proietti + +requires: +- core:1.2.4/Element.Event +- /MooTools.More + +provides: [Assets] + +... +*/ + +var Asset = { + + javascript: function(source, properties){ + properties = $extend({ + onload: $empty, + document: document, + check: $lambda(true) + }, properties); + + var script = new Element('script', {src: source, type: 'text/javascript'}); + + var load = properties.onload.bind(script), + check = properties.check, + doc = properties.document; + delete properties.onload; + delete properties.check; + delete properties.document; + + script.addEvents({ + load: load, + readystatechange: function(){ + if (['loaded', 'complete'].contains(this.readyState)) load(); + } + }).set(properties); + + if (Browser.Engine.webkit419) var checker = (function(){ + if (!$try(check)) return; + $clear(checker); + load(); + }).periodical(50); + + return script.inject(doc.head); + }, + + css: function(source, properties){ + return new Element('link', $merge({ + rel: 'stylesheet', + media: 'screen', + type: 'text/css', + href: source + }, properties)).inject(document.head); + }, + + image: function(source, properties){ + properties = $merge({ + onload: $empty, + onabort: $empty, + onerror: $empty + }, properties); + var image = new Image(); + var element = document.id(image) || new Element('img'); + ['load', 'abort', 'error'].each(function(name){ + var type = 'on' + name; + var event = properties[type]; + delete properties[type]; + image[type] = function(){ + if (!image) return; + if (!element.parentNode){ + element.width = image.width; + element.height = image.height; + } + image = image.onload = image.onabort = image.onerror = null; + event.delay(1, element, element); + element.fireEvent(name, element, 1); + }; + }); + image.src = element.src = source; + if (image && image.complete) image.onload.delay(1); + return element.set(properties); + }, + + images: function(sources, options){ + options = $merge({ + onComplete: $empty, + onProgress: $empty, + onError: $empty, + properties: {} + }, options); + sources = $splat(sources); + var images = []; + var counter = 0; + return new Elements(sources.map(function(source){ + return Asset.image(source, $extend(options.properties, { + onload: function(){ + options.onProgress.call(this, counter, sources.indexOf(source)); + counter++; + if (counter == sources.length) options.onComplete(); + }, + onerror: function(){ + options.onError.call(this, counter, sources.indexOf(source)); + counter++; + if (counter == sources.length) options.onComplete(); + } + })); + })); + } + +}; + +/* +--- + +script: Tips.js + +description: Class for creating nice tips that follow the mouse cursor when hovering an element. + +license: MIT-style license + +authors: +- Valerio Proietti +- Christoph Pojer + +requires: +- core:1.2.4/Options +- core:1.2.4/Events +- core:1.2.4/Element.Event +- core:1.2.4/Element.Style +- core:1.2.4/Element.Dimensions +- /MooTools.More + +provides: [Tips] + +... +*/ + +(function(){ + +var read = function(option, element){ + return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : ''; +}; + +this.Tips = new Class({ + + Implements: [Events, Options], + + options: { + /* + onAttach: $empty(element), + onDetach: $empty(element), + */ + onShow: function(){ + this.tip.setStyle('display', 'block'); + }, + onHide: function(){ + this.tip.setStyle('display', 'none'); + }, + title: 'title', + text: function(element){ + return element.get('rel') || element.get('href'); + }, + showDelay: 100, + hideDelay: 100, + className: 'tip-wrap', + offset: {x: 16, y: 16}, + fixed: false + }, + + initialize: function(){ + var params = Array.link(arguments, {options: Object.type, elements: $defined}); + this.setOptions(params.options); + document.id(this); + + if (params.elements) this.attach(params.elements); + }, + + toElement: function(){ + if (this.tip) return this.tip; + + this.container = new Element('div', {'class': 'tip'}); + return this.tip = new Element('div', { + 'class': this.options.className, + styles: { + display: 'none', + position: 'absolute', + top: 0, + left: 0 + } + }).adopt( + new Element('div', {'class': 'tip-top'}), + this.container, + new Element('div', {'class': 'tip-bottom'}) + ).inject(document.body); + }, + + attach: function(elements){ + $$(elements).each(function(element){ + var title = read(this.options.title, element), + text = read(this.options.text, element); + + element.erase('title').store('tip:native', title).retrieve('tip:title', title); + element.retrieve('tip:text', text); + this.fireEvent('attach', [element]); + + var events = ['enter', 'leave']; + if (!this.options.fixed) events.push('move'); + + events.each(function(value){ + var event = element.retrieve('tip:' + value); + if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element); + + element.store('tip:' + value, event).addEvent('mouse' + value, event); + }, this); + }, this); + + return this; + }, + + detach: function(elements){ + $$(elements).each(function(element){ + ['enter', 'leave', 'move'].each(function(value){ + element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); + }); + + this.fireEvent('detach', [element]); + + if (this.options.title == 'title'){ // This is necessary to check if we can revert the title + var original = element.retrieve('tip:native'); + if (original) element.set('title', original); + } + }, this); + + return this; + }, + + elementEnter: function(event, element){ + this.container.empty(); + + ['title', 'text'].each(function(value){ + var content = element.retrieve('tip:' + value); + if (content) this.fill(new Element('div', {'class': 'tip-' + value}).inject(this.container), content); + }, this); + + $clear(this.timer); + this.timer = this.show.delay(this.options.showDelay, this, element); + this.position((this.options.fixed) ? {page: element.getPosition()} : event); + }, + + elementLeave: function(event, element){ + $clear(this.timer); + this.timer = this.hide.delay(this.options.hideDelay, this, element); + this.fireForParent(event, element); + }, + + fireForParent: function(event, element) { + parentNode = element.getParent(); + if (parentNode == document.body) return; + if (parentNode.retrieve('tip:enter')) parentNode.fireEvent('mouseenter', event); + else return this.fireForParent(event, parentNode); // Why was this reversed in the original? + }, + + elementMove: function(event, element){ + this.position(event); + }, + + position: function(event){ + var size = window.getSize(), scroll = window.getScroll(), + tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, + props = {x: 'left', y: 'top'}, + obj = {}; + + for (var z in props){ + obj[props[z]] = event.page[z] + this.options.offset[z]; + if ((obj[props[z]] + tip[z] - scroll[z]) > size[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + } + + this.tip.setStyles(obj); + }, + + fill: function(element, contents){ + if(typeof contents == 'string') element.set('html', contents); + else element.adopt(contents); + }, + + show: function(element){ + this.fireEvent('show', [element]); + }, + + hide: function(element){ + this.fireEvent('hide', [element]); + } + +}); + +})(); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/selectImage.php =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/selectImage.php,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/selectImage.php 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,13 @@ + 'Files/', + 'assetBasePath' => '../Assets', + 'upload' => false, + 'destroy' => false, + 'filter' => 'image/', +)); + +$browser->fireEvent(!empty($_GET['event']) ? $_GET['event'] : null); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/tinymce.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/tinymce.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Demos/tinymce.html 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,116 @@ + + + + Testground + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

FileManager Demo

+
+ + +
+
+
+ + \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.br.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.br.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.br.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,72 @@ +/* +Script: Language.br.js + MooTools FileManager - Language Strings in Brazilian Portuguese + +Translation: + [Fabiana Pires](http://twitter.com/nervosinha) +*/ + +FileManager.Language.br = { + more: 'Detalhes', + width: 'Largura:', + height: 'Altura:', + + ok: 'Ok', + open: 'Selecione o arquivo', + upload: 'Upload', + create: 'Criar pasta', + createdir: 'Por favor especifique o nome da pasta:', + cancel: 'Cancelar', + + information: 'Informa��o', + type: 'Tipo:', + size: 'Tamanho:', + dir: 'Caminho:', + modified: '�ltima modifica��o:', + preview: 'Pr�-visualiza��o', + close: 'Fechar', + destroy: 'Apagar', + destroyfile: 'Tem certeza que deseja apagar este arquivo?', + + rename: 'Renomear', + renamefile: 'Por favor especifique o novo nome do arquivo:', + + download: 'Download', + nopreview: 'Pr�-visualiza��o indispon�vel', + + title: 'T�tulo:', + artist: 'Artista:', + album: 'Album:', + length: 'Tamanho:', + bitrate: 'Bitrate:', + + deselect: 'Desfazer', + + nodestroy: 'Apagar arquivos est� desabilitado neste servidor.', + + 'upload.disabled': 'N�o � permitido enviar arquivos neste servidor.', + 'upload.authenticated': 'Voc� n�o est� autenticado para enviar arquivos neste servidor.', + 'upload.path': 'A pasta especificada n�o existe. Por favor contate o administrador do site.', + 'upload.exists': 'A pasta especificada j� existe. Por favor contate o administrador do site.', + 'upload.mime': 'O tipo de arquivo especificado n�o � permitido.', + 'upload.extension': 'O arquivo enviado � de tipo desconhecido ou proibido.', + 'upload.size': 'O tamanho do arquivo enviado � muito grande para ser processado neste servidor. Por favor, envie um arquivo menor.', + 'upload.partial': 'O arquivo enviado foi corrompido, por favor envie o arquivo novamente.', + 'upload.nofile': 'N�o existe arquivo especificado para ser enviado.', + 'upload.default': 'Erro no envio do arquivo.', + + /* FU */ + uploader: { + unknown: 'Erro desconhecido', + sizeLimitMin: 'N�o � permitido anexar "${name}" (${size}), o tamanho m�nimo para o arquivo � de ${size_min}!', + sizeLimitMax: 'N�o � permitido anexar "${name}" (${size}), o tamanho m�ximo para o arquivo � de ${size_max}!' + }, + + flash: { + hidden: 'Para habilitar o uploader, desbloqueie a fun��o em seu browser e recarregue a p�gina (veja Adblock).', + disabled: 'Para habilitar o uploader, habilite o arquivo Flash e recarregue a p�gina (veja Flashblock).', + flash: 'Para enviar arquivos � necess�rio instalar o Adobe Flash Player.' + }, + + resizeImages: 'Redimensionar imagens grandes ao enviar' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.cs.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.cs.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.cs.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.cs.js + MooTools FileManager - Language Strings in Czech + +Translation: + [Matěj Grabovský](http://mgrabovsky.is-game.com) +*/ + +FileManager.Language.cs = { + more: 'Podrobnosti', + width: 'Šířka:', + height: 'Výška:', + + ok: 'Ok', + open: 'Vybrat soubor', + upload: 'Nahrát', + create: 'Vytvořit složku', + createdir: 'Prosím zadejte název složky:', + cancel: 'Storno', + + information: 'Informace', + type: 'Typ:', + size: 'Velikost:', + dir: 'Cesta:', + modified: 'Naposledy změněno:', + preview: 'Náhled', + close: 'Zavřít', + destroy: 'Smazat', + destroyfile: 'Určitě chcete smazat tento soubor?', + + rename: 'Přejmenovat', + renamefile: 'Prosím zadejte název nového souboru:', + + download: 'Stáhnout', + nopreview: 'Náhled není dostupný', + + title: 'Název:', + artist: 'Umělec:', + album: 'Album:', + length: 'Délka:', + bitrate: 'Přenosová rychlost:', + + deselect: 'Odstranit z výběru', + + nodestroy: 'Mazání souborů je na tomto serveru zakázáno.', + + 'upload.disabled': 'Nahrávání souborů je na tomto serveru zakázáno.', + 'upload.authenticated': 'Nemáte právo nahrávat soubory.', + 'upload.path': 'Specifikovaná složka pro nahrávání neexistuje. Prosím kontaktujte správce těchto stránek.', + 'upload.exists': 'Specifikovaný soubor již existuje. Prosím kontaktujte správce těchto stránek.', + 'upload.mime': 'Specifikovaný typ souboru není povolen.', + 'upload.extension': 'Nahrávaný soubor má neznámou nebo zakázanou příponu.', + 'upload.size': 'Velikost nahrávaného souboru je přílíš velká. Prosím nahrajte menší soubor.', + 'upload.partial': 'Nahrávaný soubor byl nahrán jen zčásti. Prosím nahrajte ho znovu.', + 'upload.nofile': 'Nebyl vybrán žádný soubor pro nahrání.', + 'upload.default': 'Něco se nepovedlo při nahrávání souboru.', + + /* FU */ + uploader: { + unknown: 'Neznámá chyba', + duplicate: 'Nelze přidat soubor „${name}“ (${size}), byl již přidán!', + sizeLimitMin: 'Nelze přidat soubor „${name}“ (${size}), minimální povolená velikost souboru je ${size_min}!', + sizeLimitMax: 'Nelze přidat soubor „${name}“ (${size}), maximální povolená velikost souboru je ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'Pokud chcete nahrávat soubory, musíte mít nainstalovaný Adobe Flash' + }, + + resizeImages: 'Změnšit velké obrázky při nahrávání' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.da.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.da.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.da.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.da.js + MooTools FileManager - Language Strings in Danish + +Translation: + Jan Ebsen +*/ + +FileManager.Language.da = { + more: 'Detaljer', + width: 'Bredde:', + height: 'Højde:', + + ok: 'Ok', + open: 'Vælg fil', + upload: 'Upload', + create: 'Opret mappe', + createdir: 'Angiv venligst mappe navn:', + cancel: 'Anuller', + + information: 'Information', + type: 'Type:', + size: 'Størrelse:', + dir: 'Sti:', + modified: 'Sidst ændret:', + preview: 'Miniature', + close: 'Luk', + destroy: 'Slet', + destroyfile: 'Er du sikker på du vil slette denne fil?', + + rename: 'Omdøb', + renamefile: 'Skriv nyt filnavn:', + + download: 'Download', + nopreview: 'Ingen miniature tilgængelig', + + title: 'Titel:', + artist: 'Kunstner:', + album: 'Album:', + length: 'Længde:', + bitrate: 'Bitrate:', + + deselect: 'Fravælg', + + nodestroy: 'Det er ikke muligt at slette filer på serveren.', + + 'upload.disabled': 'Det er ikke muligt at uploade filer på serveren.', + 'upload.authenticated': 'Du har ikke rettigheder til at uploade filer.', + 'upload.path': 'Upload mappen findes ikke. Kontakt venligst sidens administrator.', + 'upload.exists': 'Upload mappen findes allerede. Kontakt venligst sidens administrator.', + 'upload.mime': 'Fil-typen er ikke tilladt.', + 'upload.extension': 'Filen er af en ukendt, eller ulovlig type.', + 'upload.size': 'Filen er for stor, upload venligst en mindre fil.', + 'upload.partial': 'Filen blev kun delvist uploaded, prøv venligst igen.', + 'upload.nofile': 'Der er ikke angivet nogen fil til upload.', + 'upload.default': 'Noget gik galt med fil-uploaderen.', + + /* FU */ + uploader: { + unknown: 'Ukendt fejl', + duplicate: 'Du kan ikke tilføje "${name}" (${size}), den er allerede tilføjet!', + sizeLimitMin: 'Du kan ikke tilføje "${name}" (${size}), mindst tilladte filstørrelse er ${size_min}!', + sizeLimitMax: 'Du kan ikke tilføje "${name}" (${size}), højst tilladte filstørrelse er ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'For at uploade filer skal du installere Adobe Flash.' + }, + + resizeImages: 'Scaler store billeder ved upload' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.de.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.de.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.de.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,80 @@ +/* +Script: Language.de.js + MooTools FileManager - Language Strings in German + +Translation: + [Christoph Pojer](http://cpojer.net) +*/ + +FileManager.Language.de = { + more: 'Details', + width: 'Breite:', + height: 'Höhe:', + + ok: 'Ok', + open: 'Datei wählen', + upload: 'Datei hochladen', + create: 'Ordner erstellen', + createdir: 'Bitte gib einen Ordnernamen ein:', + cancel: 'Abbrechen', + + information: 'Information', + type: 'Typ:', + size: 'Größe:', + dir: 'Verzeichnis:', + modified: 'Zuletzt bearbeitet:', + preview: 'Vorschau', + close: 'Schließen', + destroy: 'Löschen', + destroyfile: 'Bist du sicher, dass du diese Datei löschen möchtest?', + + rename: 'Umbenennen', + renamefile: 'Gib einen neuen Dateinamen ein:', + + download: 'Download', + nopreview: 'Keine Vorschau verfügbar', + + title: 'Titel:', + artist: 'Artist:', + album: 'Album:', + length: 'Länge:', + bitrate: 'Bitrate:', + + deselect: 'Entfernen', + + nodestroy: 'Dateien löschen wurde auf diesem Server deaktiviert.', + + 'upload.disabled': 'Der Datei-Upload wurde auf diesem Server deaktiviert.', + 'upload.authenticated': 'Upload fehlgeschlagen: Du bist nicht authentifiziert.', + 'upload.path': 'Der angegebene Upload-Ordner existiert nicht. Bitte kontaktiere den Administrator dieser Website.', + 'upload.exists': 'Der angegebene Upload-Speicherort existiert bereits. Bitte kontaktiere den Administrator dieser Website.', + 'upload.mime': 'Der angegebene Dateityp ist nicht erlaubt.', + 'upload.extension': 'Die Datei hat eine unbekannte oder unerlaubte Datei-Erweiterung.', + 'upload.size': 'Die Datei, die du hochgeladen hast, ist zu groß um sie auf diesem Server zu verarbeiten. Bitte lade eine kleinere Datei hoch.', + 'upload.partial': 'Die Datei wurde nur teilweise hochgeladen. Bitte lade sie erneut hoch.', + 'upload.nofile': 'Es wurde keine Datei hochgeladen.', + 'upload.default': 'Der Datei-Upload ist fehlgeschlagen.', + + /* FU */ + uploader: { + unknown: 'Unbekannter Fehler', + sizeLimitMin: 'Die Datei "${name}" (${size}), ist zu klein. Minimaldateigröße: ${size_min}!', + sizeLimitMax: 'Die Datei "${name}" (${size}), ist zu groß. Dateigrößen-Limit: ${size_max}!' + }, + + flash: { + hidden: 'Um den Uploader benutzen zu können, muss er im Browser freigegeben werden und die Seite muss neu geladen werden (Adblock).', + disabled: 'Um den Uploader benutzen zu können, muss die geblockte Flash Datei freigegeben werden und die Seite muss neu geladen werden (Flashblock).', + flash: 'Um Dateien hochzuladen muss Adobe Flash installiert werden.' + }, + + resizeImages: 'Große Bilder bei Upload verkleinern', + + serialize: 'Galerie speichern', + gallery: { + text: 'Bildtext', + save: 'Speichern', + remove: 'Entfernen', + drag: 'Verschiebe Bilder in diesen Bereich um eine Galerie zu erstellen...' + } +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.en.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.en.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.en.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,80 @@ +/* +Script: Language.en.js + MooTools FileManager - Language Strings in English + +Translation: + [Christoph Pojer](http://cpojer.net) +*/ + +FileManager.Language.en = { + more: 'Details', + width: 'Width:', + height: 'Height:', + + ok: 'Ok', + open: 'Select file', + upload: 'Upload', + create: 'Create folder', + createdir: 'Please specify a folder name:', + cancel: 'Cancel', + + information: 'Information', + type: 'Type:', + size: 'Size:', + dir: 'Path:', + modified: 'Created:', + preview: 'Preview', + close: 'Close', + destroy: 'Delete', + destroyfile: 'Are you sure to delete this file?', + + rename: 'Rename', + renamefile: 'Please enter a new file name:', + + download: 'Download', + nopreview: 'No preview available', + + title: 'Title:', + artist: 'Artist:', + album: 'Album:', + length: 'Length:', + bitrate: 'Bitrate:', + + deselect: 'Deselect', + + nodestroy: 'Deleting files has been disabled on this Server.', + + 'upload.disabled': 'Uploading has been disabled on this Server.', + 'upload.authenticated': 'You are not authenticated to upload files.', + 'upload.path': 'The specified Upload-Folder does not exist. Please contact the administrator of this Website.', + 'upload.exists': 'The specified Upload-Location does already exist. Please contact the administrator of this Website.', + 'upload.mime': 'The specified file-type is not allowed.', + 'upload.extension': 'The uploaded file has an unknown or forbidden file extension.', + 'upload.size': 'The size of the file you uploaded is too big to be processed on this server. Please upload a smaller file.', + 'upload.partial': 'The file you uploaded was only partially uploaded, please upload the file again.', + 'upload.nofile': 'There was no file specified to be uploaded.', + 'upload.default': 'Something went wrong with the File-Upload.', + + /* FU */ + uploader: { + unknown: 'Unknown Error', + sizeLimitMin: 'You can not attach "${name}" (${size}), the file size minimum is ${size_min}!', + sizeLimitMax: 'You can not attach "${name}" (${size}), the file size limit is ${size_max}!' + }, + + flash: { + hidden: 'To enable the embedded uploader, unblock it in your browser and refresh (see Adblock).', + disabled: 'To enable the embedded uploader, enable the blocked Flash movie and refresh (see Flashblock).', + flash: 'In order to upload files you need to install Adobe Flash.' + }, + + resizeImages: 'Resize big images on upload', + + serialize: 'Save gallery', + gallery: { + text: 'Image caption', + save: 'Save', + remove: 'Remove from gallery', + drag: 'Drag items here to create a gallery...' + } +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.es.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.es.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.es.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.es.js + MooTools FileManager - Language Strings in Spanish + +Translation: + [Sergio Rubio](http://rubiojr.netcorex.org) +*/ + +FileManager.Language.es = { + more: 'Detalles', + width: 'Anchura:', + height: 'Altura:', + + ok: 'Ok', + open: 'Seleccionar Fichero', + upload: 'Subir ficheros', + create: 'Crear carpeta', + createdir: 'Especifica el nombre de la carpeta:', + cancel: 'Cancelar', + + information: 'Información', + type: 'Tipo:', + size: 'Tamaño:', + dir: 'Ruta:', + modified: 'Última modificación:', + preview: 'Previsualización', + close: 'Cerrar', + destroy: 'Borrar', + destroyfile: '¿Seguro que deseas borrar el fichero?', + + rename: 'Renombrar', + renamefile: 'Especifica un nuevo nombre para el fichero:', + + download: 'Descargar', + nopreview: 'No hay previsualizacion disponible', + + title: 'Título:', + artist: 'Artista:', + album: 'Album:', + length: 'Duración:', + bitrate: 'Bitrate:', + + deselect: 'Desmarcar', + + nodestroy: 'El borrado de ficheros ha sido deshabilitado.', + + 'upload.disabled': 'La carga de archivos ha sido deshabilitada.', + 'upload.authenticated': 'Necesitas autorización para subir ficheros.', + 'upload.path': 'La carpeta destino especificada no existe. Contacta con el administrador del sitio web.', + 'upload.exists': 'El la ruta destino ya existe. Por favor, contacta con el administrador del sitio web.', + 'upload.mime': 'No se permite subir el tipo de fichero especificado.', + 'upload.extension': 'El fichero subido tienen una extensión no permitida o desconocida.', + 'upload.size': 'El tamaño del fichero que intentas subir es demasiado grande para ser procesado por el servidor. Por favor, sube un fichero mas pequeño.', + 'upload.partial': 'El fichero se ha subido parcialmente, por favor, sube el fichero de nuevo.', + 'upload.nofile': 'No se especificó el fichero a subir.', + 'upload.default': 'Algo falló durante la carga del fichero.', + + /* FU */ + uploader: { + unknown: 'Error desconocido', + duplicate: 'No se puede subir "${name}" (${size}), ya ha sido añadido!', + sizeLimitMin: 'No se puede subir "${name}" (${size}), el tamaño mínimo de fichero es ${size_min}!', + sizeLimitMax: 'No se puede subir "${name}" (${size}), el tamaño máximo de fichero es ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'Para poder subir ficheros necesitas instalar Adobe Flash.' + }, + + resizeImages: 'Redimensionar las imágenes grandes al subirlas' +}; Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fi.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fi.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fi.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.fi.js + MooTools FileManager - Language Strings in Finnish + +Translation: + [Jabis Sevón](http://pumppumedia.com) +*/ + +FileManager.Language.fi = { + more: 'Lisätiedot', + width: 'Leveys:', + height: 'Korkeus:', + + ok: 'Ok', + open: 'Valitse tiedosto', + upload: 'Lähetä', + create: 'Luo kansio', + createdir: 'Kansion nimi:', + cancel: 'Peruuta', + + information: 'Tiedot', + type: 'Tyyppi:', + size: 'Koko:', + dir: 'Polku:', + modified: 'Viimeksi muokattu:', + preview: 'Esikatselu', + close: 'Sulje', + destroy: 'Poista', + destroyfile: 'Haluatko varmasti poistaa tiedoston?', + + rename: 'Nimeä uudelleen', + renamefile: 'Syötä tiedoston uusi nimi:', + + download: 'Lataa', + nopreview: 'Esikatselua ei voida näyttää', + + title: 'Kappaleen nimi:', + artist: 'Artisti:', + album: 'Albumi:', + length: 'Pituus:', + bitrate: 'Bitrate:', + + deselect: 'Poista valinta', + + nodestroy: 'Tiedostojen poisto otettu käytöstä.', + + 'upload.disabled': 'Tiedostojen lähetys otettu käytöstä.', + 'upload.authenticated': 'Sinulla ei ole oikeuksia tiedostojen lähettämiseen.', + 'upload.path': 'Määritettyä kansiota ei löydy. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään.', + 'upload.exists': 'Tiedosto on jo olemassa - siirto peruttu. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään.', + 'upload.mime': 'Tiedostotyyppi ei ole sallittujen listalla - siirto peruttu.', + 'upload.extension': 'Tiedostopääte tuntematon, tai ei sallittujen listalla - siirto peruttu.', + 'upload.size': 'Tiedostokoko liian suuri palvelimelle. Ole hyvä ja siirrä pienempiä tiedostoja.', + 'upload.partial': 'Tiedonsiirto onnistui vain osittain - siirto epäonnistui. Ole hyvä ja siirrä tiedosto uudestaan', + 'upload.nofile': 'Tiedostoa ei määritetty.', + 'upload.default': 'Tiedonsiirto epäonnistui tunnistamattomasta syystä.', + + /* FU */ + uploader: { + unknown: 'Tunnistamaton virhe', + duplicate: 'Et voi lisätä seuraavaa tiedostoa: "${name}" (${size}), koska se on jo siirtolistalla!', + sizeLimitMin: 'Et voi lisätä seuraavaa tiedostoa: "${name}" (${size}). Tiedostojen minimikoko on ${size_min}!', + sizeLimitMax: 'Et voi lisätä seuraavaa tiedostoa: "${name}" (${size}). Tiedostojen maksimikoko on ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'Käyttääksesi FileManageria, tarvitset Adobe Flash Playerin. Lataa tästä.' + }, + + resizeImages: 'Pienennä liian suuret kuvat automaattisesti siirron yhteydessä' +}; Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fr.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fr.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.fr.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.fr.js + MooTools FileManager - Language Strings in French + +Translation: + [Samuel Sanchez](http://www.kromack.com) +*/ + +FileManager.Language.fr = { + more: 'Détails', + width: 'Largeur :', + height: 'Hauteur :', + + ok: 'Ok', + open: 'Sélectionner un fichier', + upload: 'Téléverser', + create: 'Créer un dossier', + createdir: 'Merci de spécifier un nom de dossier :', + cancel: 'Annuler', + + information: 'Informations', + type: 'Type :', + size: 'Taille :', + dir: 'Chemin :', + modified: 'Modifié le :', + preview: 'Aperçu', + close: 'Fermer', + destroy: 'Supprimer', + destroyfile: 'Voulez-vous vraiment supprimer ce fichier ?', + + rename: 'Renommer', + renamefile: 'Merci de spécifier un nouveau nom de fichier :', + + download: 'Télécharger', + nopreview: 'Aucun aperçu disponible', + + title: 'Titre :', + artist: 'Artiste :', + album: 'Album :', + length: 'Durée :', + bitrate: 'Débit :', + + deselect: 'Désélectionner', + + nodestroy: 'La suppression de fichier a été désactivée sur ce serveur.', + + 'upload.disabled': 'Le téléversement de fichier a été désactivé sur ce serveur.', + 'upload.authenticated': 'Vous n\'êtes pas authentifié et ne pouvez pas téléverser de fichier.', + 'upload.path': 'Le répertoire de téléversement spécifié n\'existe pas. Merci de contacter l\'administrateur de ce site Internet.', + 'upload.exists': 'Le chemin de téléversement spécifié existe déjà. Merci de contacter l\'administrateur de ce site Internet.', + 'upload.mime': 'Le type de fichier spécifié n\'est pas autorisé.', + 'upload.extension': 'Le fichier téléversé a une extension inconnue ou interdite.', + 'upload.size': 'La taille de votre fichier est trop grande pour être téléversée sur ce serveur. Merci de sélectionner un fichier moins lourd.', + 'upload.partial': 'Le fichier a été partiellement téléversé, merci de recommencer l\'opération.', + 'upload.nofile': 'Aucun fichier n\'a été spécifié.', + 'upload.default': 'Une erreur s\'est produite.', + + /* FU */ + uploader: { + unknown: 'Erreur inconnue', + duplicate: 'Vous ne pouvez pas ajouter "${name}" (${size}), car l\'élément est déjà ajoutée !', + sizeLimitMin: 'Vous ne pouvez pas ajouter "${name}" (${size}), la taille minimale des fichiers est de ${size_min}!', + sizeLimitMax: 'Vous ne pouvez pas ajouter "${name}" (${size}), la taille maximale des fichiers est de ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'Dans le but de téléverser des fichiers, vous devez installer Adobe Flash.' + }, + + resizeImages: 'Redimensionner les images pendant le téléversement' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.it.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.it.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.it.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,80 @@ +/* +Script: Language.it.js + MooTools FileManager - Language Strings in English + +Translation: + Moreno Monga +*/ + +FileManager.Language.it = { + more: 'Dettagli', + width: 'Larghezza:', + height: 'Altezza:', + + ok: 'Ok', + open: 'Seleziona file', + upload: 'Upload', + create: 'Crea cartella', + createdir: 'Specifica il nome della cartella:', + cancel: 'Annulla', + + information: 'Informazioni', + type: 'Tipo:', + size: 'Dimensione:', + dir: 'Percorso:', + modified: 'Ultima modifica:', + preview: 'Anteprima', + close: 'Chiudi', + destroy: 'Cancella', + destroyfile: 'Sei sicuro di voler cancellare questo file?', + + rename: 'Rinomina', + renamefile: 'Scrivi un nuovo nome per il file:', + + download: 'Download', + nopreview: 'Non sono disponibili anteprime', + + title: 'Titolo:', + artist: 'Artista:', + album: 'Album:', + length: 'Lunghezza:', + bitrate: 'Bitrate:', + + deselect: 'Deseleziona', + + nodestroy: 'La cancellazioni dei file è disabilitata.', + + 'upload.disabled': 'L Upload dei file è disabilitato.', + 'upload.authenticated': 'Non sei autorizzato a fare l upload dei file.', + 'upload.path': 'La cartella degli upload non esiste. Contattare il webmaster.', + 'upload.exists': 'La cartella specificata per gli upload esiste già. Contattare il webmaster.', + 'upload.mime': 'Il tipo del file specificato non è consentito.', + 'upload.extension': 'Il tipo di file che si vuole caricare non è consentito o è sconosciuto.', + 'upload.size': 'La dimensione del file è troppo grande per essere processato. Ricarica un file con dimensioni ridotte.', + 'upload.partial': 'Il file è stato parzialmente caricato. Per favore, prova a ricaricarlo.', + 'upload.nofile': 'Non è stato specificato alcun file da caricare.', + 'upload.default': 'Mi spiace, l operazione non è andata a buon fine.', + + /* FU */ + uploader: { + unknown: 'Errore sconosciuto', + sizeLimitMin: 'Non puoi caricare "${name}" (${size}), la dimensione minima del file è ${size_min}!', + sizeLimitMax: 'Non puoi caricare "${name}" (${size}), la dimensione massima del file è ${size_max}!' + }, + + flash: { + hidden: 'To enable the embedded uploader, unblock it in your browser and refresh (see Adblock).', + disabled: 'To enable the embedded uploader, enable the blocked Flash movie and refresh (see Flashblock).', + flash: 'In order to upload files you need to install Adobe Flash.' + }, + + resizeImages: 'Ridimensiona immagini grandi', + + serialize: 'Salva galleria', + gallery: { + text: 'Titolo immagine', + save: 'Salva', + remove: 'Rimuovi dalla galleria', + drag: 'Sposta gli oggetti qui per creare una galleria...' + } +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.nl.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.nl.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.nl.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,72 @@ +/* +Script: Language.nl.js + MooTools FileManager - Language Strings in Dutch + +Translation: + [Dave De Vos](http://wnz.be) +*/ + +FileManager.Language.nl = { + more: 'Details', + width: 'Breedte:', + height: 'Hoogte:', + + ok: 'Ok', + open: 'Kies bestand', + upload: 'Uploaden', + create: 'Maak map', + createdir: 'Geef een map-naam op:', + cancel: 'Annuleren', + + information: 'Informatie', + type: 'Type:', + size: 'Grootte:', + dir: 'Locatie:', + modified: 'Laatste wijziging:', + preview: 'Voorbeeld', + close: 'Sluiten', + destroy: 'Verwijderen', + destroyfile: 'Ben je zeker dat je dit bestand wil verwijderen?', + + rename: 'Naam wijzigen', + renamefile: 'Geef een nieuwe bestandsnaam op:', + + download: 'Downloaden', + nopreview: 'G��n voorbeeld beschikbaar', + + title: 'Titel:', + artist: 'Artiest:', + album: 'Album:', + length: 'Lengte:', + bitrate: 'Bitrate:', + + deselect: 'Deselecteren', + + nodestroy: 'Het is niet mogelijk bestanden te verwijderen op deze server.', + + 'upload.disabled': 'Uploaden is uitgeschakeld op deze server.', + 'upload.authenticated': 'Je hebt geen toelating om bestanden te uploaden.', + 'upload.path': 'Deze upload-map bestaat niet. Contacteer de beheerder van deze website voor hulp.', + 'upload.exists': 'Deze upload-locatie bestaat reeds. Contacteer de beheerder van deze website voor hulp.', + 'upload.mime': 'Dit bestandstype is niet toegelaten.', + 'upload.extension': 'Het verstuurde bestand heeft een onbekende of niet-toegelaten extensie.', + 'upload.size': 'Het verstuurde bestand is te groot voor verwerking. Probeer opnieuw met een kleiner bestand.', + 'upload.partial': 'Het bestand dat je verstuurde werd slechts gedeeltelijk ontvangen, probeer het bestand opnieuw te versturen.', + 'upload.nofile': 'Er werd g��n bestand verstuurd.', + 'upload.default': 'Er ging iets fout bij het uploaden van het bestand.', + + /* FU */ + uploader: { + unknown: 'Onbekende fout', + sizeLimitMin: 'Je kan het bestand "${name}" (${size}) niet toevoegen, de minimum bestandsgrootte voor upload is ${size_min}!', + sizeLimitMax: 'Je kan het bestand "${name}" (${size}) niet toevoegen, de minimum bestandsgrootte voor upload is ${size_max}!' + }, + + flash: { + hidden: 'Om de ingebouwde uploader in te schakelen, deblokkeer deze in je browser en vernieuw de pagina (zie Adblock).', + disabled: 'Om de ingebouwde uploader in te schakelen, schakel het geblokkeerde Flash-component in en vernieuw de pagina (zie Flashblock).', + flash: 'Om bestanden te kunnen uploaden dien je Adobe Flash te installeren.' + }, + + resizeImages: 'Pas de dimensies van grote afbeeldingen aan' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.pl.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.pl.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.pl.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,72 @@ +/* +Script: Language.pl.js + MooTools FileManager - Language Strings in Polish + +Translation: + [Marek Kalucki](http://www.webdeco.pl) +*/ + +FileManager.Language.pl = { + more: 'Szczegóły', + width: 'Szerokość:', + height: 'Wysokość:', + + ok: 'Ok', + open: 'Wybierz plik', + upload: 'Wyślij', + create: 'Stwórz folder', + createdir: 'Podaj nazwe folderu:', + cancel: 'Anuluj', + + information: 'Informacje', + type: 'Typ:', + size: 'Rozmiar:', + dir: 'Ścieżka:', + modified: 'Ost. modyfikacja:', + preview: 'Podgląd', + close: 'Zamknij', + destroy: 'Usuń', + destroyfile: 'Na pewno chcesz usunąć ten plik?', + + rename: 'Zmień nazwe', + renamefile: 'Podaj nową nazwę pliku:', + + download: 'Ściągnij', + nopreview: 'Podgląd niedostępny', + + title: 'Tytuł:', + artist: 'Wykonawca:', + album: 'Płyta:', + length: 'Długość:', + bitrate: 'Bitrate:', + + deselect: 'Odznacz', + + nodestroy: 'Usuwanie plików z serwera zostało wyłączone.', + + 'upload.disabled': 'Wysyłanie plików na serwer zostało wyłączone.', + 'upload.authenticated': 'Nie jesteś upoważniony do wysyłania plików na serwer.', + 'upload.path': 'Folder do wysyłania plików nie istnieje. Skontaktuj się z administratorem.', + 'upload.exists': 'Folder do wysyłania plików istnieje. Skontaktuj się z administratorem.', + 'upload.mime': 'Typ wybranego pliku jest niedozwolony.', + 'upload.extension': 'Wysyłany plik ma nieznane lub niedozwolone rozszerzenie.', + 'upload.size': 'Rozmiar wysyłanego pliku jest zbyt duży. Wyślij mniejszy plik (jeśli wysyłasz obrazy-zmniejsz obraz na swoim komputerze i ponów wysyłanie).', + 'upload.partial': 'Plik nie został wysłany w całości. Ponów próbę wysyłki pliku.', + 'upload.nofile': 'Nie wybrano pliku do wysyłki.', + 'upload.default': 'Wystąpił błąd w trakcie wysyłki.', + + /* FU */ + uploader: { + unknown: 'Wystąpił nieznany błąd.', + sizeLimitMin: 'Nie można wybrać "${name}" (${size}), minimalny rozmiar pliku to ${size_min}!', + sizeLimitMax: 'Nie można wybrać "${name}" (${size}), maksymalny rozmiar pliku to ${size_max}!' + }, + + flash: { + hidden: 'Aby włączyć wysyłanie plików, odblokuj go w swojej przeglądarce i odśwież stronę (prawdopodobnie wysyłanie plików jest blokowane przez wtyczkę Adblock).', + disabled: 'Aby włączyć wysyłanie plików, odblokuj obiekt flash i odśwież stronę (prawdopodobnie wysyłanie plików blokowane jest przez wtyczkę Flashblock).', + flash: 'Aby wysyłać pliki na serwer, należy zainstalować w przeglądarce wtyczkę Adobe Flash.' + }, + + resizeImages: 'Zmniejsz duże obrazy w trakcie wysyłania' +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.ru.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.ru.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.ru.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,72 @@ +/* +Script: Language.ru.js + MooTools FileManager - Language Strings in Russian + +Translation: + [Ilya V. Goryachev](http://cok-studio.ru/) +*/ + +FileManager.Language.ru = { + more: 'Подробнее', + width: 'Ширина:', + height: 'Высота:', + + ok: 'Ok', + open: 'Выбрать файл', + upload: 'Загрузка', + create: 'Создать папку', + createdir: 'Пожалуйста укажите имя папки:', + cancel: 'Отмена', + + information: 'Информация', + type: 'Тип:', + size: 'Размер:', + dir: 'Путь:', + modified: 'Последнее изменение:', + preview: 'Предпросмотр', + close: 'Закрыть', + destroy: 'Удалить', + destroyfile: 'Уверены, что хотите удалить этот файл?', + + rename: 'Переименовать', + renamefile: 'Пожалуйста укажите имя файла:', + + download: 'Скачать', + nopreview: 'Предпросмотр недоступен', + + title: 'Название:', + artist: 'Исполнитель:', + album: 'Альбом:', + length: 'Продолжительность:', + bitrate: 'Битрэйт:', + + deselect: 'Снять выделение', + + nodestroy: 'Удаление файлов отключено на сервере.', + + 'upload.disabled': 'Загрузка файлов отключена на сервере.', + 'upload.authenticated': 'Вам не разрешено загружать файлы.', + 'upload.path': 'Указанная директория для загрузки файлов не существует. Пожалуйста обратитесь к администратору сайта.', + 'upload.exists': 'Указанная директория для загрузки файлов уже существует. Пожалуйста обратитесь к администратору сайта', + 'upload.mime': 'Такой тип файла не поддерживается.', + 'upload.extension': 'Загруженный файл не опознан или такое расширение не разрешено.', + 'upload.size': 'Размер загружаемого файла слишком велик. Пожалуйста загрузите файл поменьше.', + 'upload.partial': 'Файл был загружен частично, пожалуйста загрузите этот файл еще раз.', + 'upload.nofile': 'Не указаны файлы для загрузки.', + 'upload.default': 'При загрузке файлов что-то пошло не так.', + + /* FU */ + uploader: { + unknown: 'Неизвестная ошибка', + sizeLimitMin: 'Невозможно прикрепить файл "${name}" (${size}), минимальный размер фала ${size_min}!', + sizeLimitMax: 'Невозможно прикрепить файл "${name}" (${size}), максимальный размер файла ${size_max}!' + }, + + flash: { + hidden: 'Чтобы включить embedded загрузчик, разблокируйте подключаемые элементы в вашем браузере (см. Блокировку рекламы).', + disabled: 'Чтобы включить embedded загрузчик, снимите блокировку флеш и обновите страницу (см. Блокировка флеш).', + flash: 'Чтобы загружать файлы, Вам необходимо установить Adobe Flash.' + }, + + resizeImages: 'Менять размер больших изображений при загрузке' +}; Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.se.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.se.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Language/Language.se.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,73 @@ +/* +Script: Language.se.js + MooTools FileManager - Language Strings in Swedish + +Translation: + [Marcus *xintron* Carlsson](http://xintron.se) +*/ + +FileManager.Language.se = { + more: 'Detaljer', + width: 'Bredd:', + height: 'Höjd:', + + ok: 'Ok', + open: 'Välj fil', + upload: 'Ladda upp', + create: 'Skapa mapp', + createdir: 'Vänligen ange ett mapp-namn:', + cancel: 'Avbryt', + + information: 'Information', + type: 'Typ:', + size: 'Storlek:', + dir: 'Sökväg:', + modified: 'Senast ändad:', + preview: 'Förhandsgranska', + close: 'Stäng', + destroy: 'Ta bort', + destroyfile: 'Är du säker på att du vill ta bort filen?', + + rename: 'Döp om', + renamefile: 'Vänligen ange ett nytt filnamn:', + + download: 'Ladda ner', + nopreview: 'Ingen förhandsgranskning tillgänglig', + + title: 'Titel:', + artist: 'Artist:', + album: 'Album:', + length: 'Längd:', + bitrate: 'Bitrate:', + + deselect: 'Avmarkera', + + nodestroy: 'Funktionen ta bort filer är avstängd på denna server.', + + 'upload.disabled': 'Uppladdning är avstängt på denna server.', + 'upload.authenticated': 'Du har inte behörighet att ladda upp filer.', + 'upload.path': 'Den angivna uppladdnings-mappen existerar inte. Vänligen kontakta serveradministratören.', + 'upload.exists': 'Den angivna uppladdnings-mappen existerar redan. Vänligen kontakta serveradministratören.', + 'upload.mime': 'Denna filtyp accepteras inte på denna server.', + 'upload.extension': 'Den uppladdade filen har en okänd eller förbjuden filändelse.', + 'upload.size': 'Filen är för stor för denna server. Vänligen ladda upp en mindre fil.', + 'upload.partial': 'Ett fel uppstod och hela filen kunde inte laddas upp. Vänligen försök igen.', + 'upload.nofile': 'Du måste välja en fil att ladda upp.', + 'upload.default': 'Ett fel inträffade under uppladdningen.', + + /* FU */ + uploader: { + unknown: 'Okänt fel', + duplicate: 'Du kan inte ladda upp "${name}" (${size}), filen existerar redan!', + sizeLimitMin: 'Du kan inte ladda upp "${name}" (${size}), minsta storlek som accepteras är ${size_min}!', + sizeLimitMax: 'Du kan inte ladda upp "${name}" (${size}), filens storlek får inte överstiga ${size_max}!' + }, + + flash: { + hidden: null, + disabled: null, + flash: 'För att kunna ladda upp filer behöver du ha Adobe Flash installerat.' + }, + + resizeImages: 'Ändra storleken på bilden under uppladdningen' +}; Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Additions.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Additions.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Additions.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,204 @@ +/* +--- +description: FileManager Additions + +authors: + - Christoph Pojer + +requires: + core/1.2.4: '*' + +provides: + - filemanager.additions + +license: + MIT-style license + +contains: + - Element.appearOn: Can be used to show an element when another one is hovered: $(myElement).appearOn(myWrapper) + - Element.center: Centers an element + - Dialog, Overlay: Classes used by the FileManager +... +*/ + +(function(){ + +Element.implement({ + + appearOn: function(el, opacity, options){ + opacity = $type(opacity) == 'array' ? [opacity[0] || 1, opacity[1] || 0] : [opacity || 1, 0]; + + this.set({ + opacity: opacity[1], + tween: options || {duration: 200} + }); + + $(el).addEvents({ + mouseenter: this.fade.bind(this, opacity[0]), + mouseleave: this.fade.bind(this, opacity[1]) + }); + + return this; + }, + + center: function(offsets){ + var scroll = document.getScroll(), + offset = document.getSize(), + size = this.getSize(), + values = {x: 'left', y: 'top'}; + + if (!offsets) offsets = {}; + + for (var z in values){ + var style = scroll[z] + (offset[z] - size[z]) / 2 + (offsets[z] || 0); + this.setStyle(values[z], style < 10 ? 10 : style); + } + + return this; + } + +}); + +this.Dialog = new Class({ + + Implements: [Options, Events], + + options: { + /*onShow: $empty, + onOpen: $empty, + onConfirm: $empty, + onDecline: $empty, + onClose: $empty,*/ + request: null, + buttons: ['confirm', 'decline'], + language: {} + }, + + initialize: function(text, options){ + this.setOptions(options); + + this.el = new Element('div', { + 'class': 'fm-dialog fm-dialog-engine-' + Browser.Engine.name + ' fm-dialog-engine-' + Browser.Engine.name + (Browser.Engine.trident ? Browser.Engine.version : ''), + opacity: 0, + tween: {duration: 250} + }).adopt([ + $type(text) == 'string' ? new Element('div', {text: text}) : text + ]); + + if (this.options.content) this.el.getElement('div').adopt(this.options.content); + + Array.each(this.options.buttons, function(v){ + new Element('button', {'class': 'fm-dialog-' + v, text: this.options.language[v]}).addEvent('click', (function(e){ + if (e) e.stop(); + this.fireEvent(v).fireEvent('close'); + this.overlay.hide(); + this.destroy(); + }).bind(this)).inject(this.el); + }, this); + + this.overlay = new Overlay({ + 'class': 'fm-overlay fm-overlay-dialog', + events: {click: this.fireEvent.bind(this, ['close'])}, + tween: {duration: 250} + }); + + this.bound = { + scroll: (function(){ + if (!this.el) this.destroy(); + else this.el.center(); + }).bind(this), + keyesc: (function(e){ + if (e.key == 'esc') this.fireEvent('close').destroy(); + }).bind(this) + }; + + this.show(); + }, + + show: function(){ + this.overlay.show(); + var self = this.fireEvent('open'); + this.el.setStyle('display', 'block').inject(document.body).center().fade(1).get('tween').chain(function(){ + var button = this.element.getElement('button.fm-dialog-confirm') || this.element.getElement('button'); + if (button) button.focus(); + self.fireEvent('show'); + }); + + window.addEvents({ + scroll: this.bound.scroll, + resize: this.bound.scroll, + keyup: this.bound.keyesc + }); + }, + + destroy: function(){ + if (this.el) this.el.fade(0).get('tween').chain((function(){ + this.overlay.destroy(); + this.el.destroy(); + }).bind(this)); + + window.removeEvent('scroll', this.bound.scroll).removeEvent('resize', this.bound.scroll).removeEvent('keyup', this.bound.keyesc); + } + +}); + +this.Overlay = new Class({ + + initialize: function(options){ + this.el = new Element('div', $extend({ + 'class': 'fm-overlay' + }, options)).inject(document.body); + }, + + show: function(){ + this.objects = $$('object, select, embed').filter(function(el){ + return el.id == 'SwiffFileManagerUpload' || el.style.visibility == 'hidden' ? false : !!(el.style.visibility = 'hidden'); + }); + + this.resize = (function(){ + if (!this.el) this.destroy(); + else this.el.setStyles({ + width: document.getScrollWidth(), + height: document.getScrollHeight() + }); + }).bind(this); + + this.resize(); + + this.el.setStyles({ + opacity: 0, + display: 'block' + }).get('tween').pause().start('opacity', 0.5); + + window.addEvent('resize', this.resize); + + return this; + }, + + hide: function(){ + this.el.fade(0).get('tween').chain((function(){ + this.revertObjects(); + this.el.setStyle('display', 'none'); + }).bind(this)); + + window.removeEvent('resize', this.resize); + + return this; + }, + + destroy: function(){ + this.revertObjects().el.destroy(); + }, + + revertObjects: function(){ + if (this.objects && this.objects.length) + this.objects.each(function(el){ + el.style.visibility = 'visible'; + }); + + return this; + } + +}); + +})(); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.TinyMCE.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.TinyMCE.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.TinyMCE.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,56 @@ +/* +--- +description: FileManager.TinyMCE +longdescription: MooTools FileManager for integration with [TinyMCE](http://tinymce.moxiecode.com/) + +authors: + - Christoph Pojer + +requires: + core/1.2.4: '*' + +provides: + - filemanager.tinymce + +license: + MIT-style license + +Usage: + - Pass this to the "file_browser_callback"-option of TinyMCE: FileManager.TinyMCE(function(){ return {FileManagerOptions}; }); + - See the Demo for an example. +... +*/ + +FileManager.TinyMCE = function(options){ + return function(field, url, type, win){ + var manager = new FileManager($extend({ + onComplete: function(path){ + if (!win.document) return; + win.document.getElementById(field).value = path; + if (win.ImageDialog) win.ImageDialog.showPreviewImage(path, 1); + this.container.destroy(); + } + }, options(type))); + manager.dragZIndex = 400002; + manager.SwiffZIndex = 400003; + manager.el.setStyle('zIndex', 400001); + manager.overlay.el.setStyle('zIndex', 400000); + document.id(manager.tips).setStyle('zIndex', 400010); + manager.show(); + return manager; + }; +}; + +FileManager.implement('SwiffZIndex', 400003); + +var Dialog = new Class({ + + Extends: Dialog, + + initialize: function(text, options){ + this.parent(text, options); + this.el.setStyle('zIndex', 400010); + this.overlay.el.setStyle('zIndex', 400009); + } + +}); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,701 @@ +/* +--- +description: FileManager + +authors: + - Christoph Pojer + +requires: + core/1.2.4: '*' + more/1.2.4.2: [Drag, Drag.Move, Tips, Assets, Element.Delegation] + +provides: + - filemanager + +license: + MIT-style license + +version: + 1.0 + +todo: + - Add Scroller.js (optional) for Drag&Drop in the Filelist + +inspiration: + - Loosely based on a Script by [Yannick Croissant](http://dev.k1der.net/dev/brooser-un-browser-de-fichier-pour-mootools/) + +options: + - url: (string) The base url to the Backend FileManager, without QueryString + - baseURL: (string) Absolute URL to the FileManager files + - assetBasePath: (string) The path to all images and swf files + - selectable: (boolean, defaults to *false*) If true, provides a button to select a file + - language: (string, defaults to *en*) The language used for the FileManager + - hideOnClick: (boolean, defaults to *false*) When true, hides the FileManager when the area outside of it is clicked + - directory: (string) Can be used to load a subfolder instead of the base folder + +events: + - onComplete(path, file): fired when a file gets selected via the "Select file" button + - onModify(file): fired when a file gets renamed/deleted or modified in another way + - onShow: fired when the FileManager opens + - onHide: event fired when FileManager closes + - onPreview: event fired when the user clicks an image in the preview + - onDetails: event fired when the details are updated after user picking a file + - onHidePreview: event fired when the "preview" is hidden (usually, user uploading file, or changing directory) +... +*/ + +var FileManager = new Class({ + + Implements: [Options, Events], + + Request: null, + Directory: null, + Current: null, + + options: { + /*onComplete: $empty, + onModify: $empty, + onShow: $empty, + onHide: $empty, + onPreview: $empty, + onDetails: $empty, // Xinha: Fired when an item is picked form the files list, supplied object (eg {width: 123, height:456} ) + onHidePreview: $empty, // Xinha: Fired when the preview is hidden (eg when uploading) */ + directory: '', + url: null, + baseURL: '', + assetBasePath: null, + selectable: false, + hideOnClick: false, + language: 'en' + }, + + hooks: { + show: {}, + cleanup: {} + }, + + initialize: function(options){ + this.setOptions(options); + this.options.assetBasePath = this.options.assetBasePath.replace(/(\/|\\)*$/, '/'); + this.dragZIndex = 1300; + this.droppables = []; + this.Directory = this.options.directory; + + this.language = $unlink(FileManager.Language.en); + if (this.options.language != 'en') this.language = $merge(this.language, FileManager.Language[this.options.language]); + + this.container = new Element('div', {'class': 'filemanager-container filemanager-engine-' + Browser.Engine.name + (Browser.Engine.trident ? Browser.Engine.version : '')}); + this.el = new Element('div', {'class': 'filemanager'}).inject(this.container); + this.menu = new Element('div', {'class': 'filemanager-menu'}).inject(this.el); + this.loader = new Element('div', {'class': 'loader', opacity: 0, tween: {duration: 200}}).inject(this.menu); + + var self = this; + this.relayClick = function(e){ + if(e) e.stop(); + var file = this.retrieve('file'); + if (this.retrieve('block') && !Browser.Engine.trident){ + this.eliminate('block'); + return; + } + + if (file.mime == 'text/directory'){ + this.addClass('selected'); + self.load(self.Directory + '/' + file.name); + return; + } + + + if (self.Current) self.Current.removeClass('selected'); + self.Current = this.addClass('selected'); // NB: Also sets self.Current + + // Xinha: We need to have Current assigned before fillInfo because fillInfo adds to it + self.fillInfo(file); + self.switchButton(); + }; + this.browser = new Element('ul', {'class': 'filemanager-browser'}).addEvents({ + click: (function(){ + // return self.deselect(); + }), + 'click:relay(li span.fi)': this.relayClick + }).inject(this.el); + + if (this.options.upload) this.addMenuButton('create'); // Xinha: Create directory permission = upload + if (this.options.selectable) this.addMenuButton('open'); + + this.info = new Element('div', {'class': 'filemanager-infos', opacity: 0}).inject(this.el); + + var head = new Element('div', {'class': 'filemanager-head'}).adopt([ + new Element('img', {'class': 'filemanager-icon'}), + new Element('h1') + ]); + + // Xinha: We need to groupt he headers and lists togethor because we will + // use some CSS to reorganise a bit. So we create "infoarea" which + // will contain the h2 and list for the "Information", that is + // modification date, size, directory etc... + var infoarea = new Element('div', {'class': 'filemanager-info-area'}); + + this.info.adopt([head, infoarea.adopt(new Element('h2', {text: this.language.information}))]); + + new Element('dl').adopt([ + new Element('dt', {text: this.language.modified}), + new Element('dd', {'class': 'filemanager-modified'}), + new Element('dt', {text: this.language.type}), + new Element('dd', {'class': 'filemanager-type'}), + new Element('dt', {text: this.language.size}), + new Element('dd', {'class': 'filemanager-size'}), + new Element('dt', {text: this.language.dir}), + new Element('dd', {'class': 'filemanager-dir'}) + ]).inject(infoarea); + + this.preview = new Element('div', {'class': 'filemanager-preview'}).addEvent('click:relay(img.preview)', function(){ + self.fireEvent('preview', [this.get('src')]); + }); + + // Xinha: We need to group the headers and lists togethor because we will + // use some CSS to reorganise a bit. So we create "filemanager-preview-area" which + // will contain the h2 for the preview and also the preview content returned from + // Backend/FileManager.php + this.info.adopt((new Element('div', {'class': 'filemanager-preview-area'})).adopt([ + new Element('h2', {'class': 'filemanager-headline', text: this.language.preview}), + this.preview + ])); + + this.closeIcon = new Element('div', { + 'class': 'filemanager-close', + title: this.language.close, + events: {click: this.hide.bind(this)} + }).adopt(new Asset.image(this.options.assetBasePath + 'destroy.png')).inject(this.el); + + this.tips = new Tips({ + className: 'tip-filebrowser', + offsets: {x: 15, y: 0}, + text: null, + showDelay: 50, + hideDelay: 50, + onShow: function(){ + this.tip.set('tween', {duration: 250}).setStyle('display', 'block').fade(1); + }, + onHide: function(){ + this.tip.fade(0).get('tween').chain(function(){ + this.element.setStyle('display', 'none'); + }); + } + }); + this.tips.attach(this.closeIcon.appearOn(this.closeIcon, [1, 0.8]).appearOn(this.el, 0.8)); + + this.imageadd = new Asset.image(this.options.assetBasePath + 'add.png', { + 'class': 'browser-add' + }).set('opacity', 0).inject(this.container); + + this.container.inject(document.body); + this.overlay = new Overlay(this.options.hideOnClick ? { + events: {click: this.hide.bind(this)} + } : null); + + this.bound = { + keydown: (function(e){ + if (e.control || e.meta) this.imageadd.fade(1); + }).bind(this), + keyup: (function(){ + this.imageadd.fade(0); + }).bind(this), + keyesc: (function(e){ + if (e.key=='esc') this.hide(); + }).bind(this), + scroll: (function(){ + this.el.center(this.offsets); + this.fireEvent('scroll'); + }).bind(this) + }; + }, + + show: function(e){ + if (e) e.stop(); + + this.load(this.Directory); + this.overlay.show(); + + this.info.set('opacity', 0); + + (function(){ + this.container.setStyles({ + opacity: 0, + display: 'block' + }); + + this.el.center(this.offsets); + this.fireEvent('show'); + this.container.set('opacity', 1); + this.fireHooks('show'); + + window.addEvents({ + scroll: this.bound.scroll, + resize: this.bound.scroll, + keyup: this.bound.keyesc + }); + }).delay(500, this); + }, + + hide: function(e){ + if (e) e.stop(); + + this.overlay.hide(); + this.tips.hide(); + this.browser.empty(); + this.container.setStyle('display', 'none'); + + this.fireHooks('cleanup').fireEvent('hide'); + window.removeEvent('scroll', this.bound.scroll).removeEvent('resize', this.bound.scroll).removeEvent('keyup', this.bound.keyesc); + }, + + open: function(e){ + e.stop(); + + if (!this.Current) return false; + + this.fireEvent('complete', [ + // Xinha: The URL path returned by normal MootoolsFileManager is odd, it includes the last component + // of the base directory, that is, if your base is /foo/bar/images then we get something like + // images/narf.jpg. + // To work around this we take the URL which was worked out by Backend/FileManager.php + // and return that as the url. + this.normalize(this.Current.file_data ? this.Current.file_data.url : this.Directory + '/' + this.Current.retrieve('file').name), + this.Current.retrieve('file') + ]); + this.hide(); + }, + + create: function(e){ + e.stop(); + + var self = this; + new Dialog(this.language.createdir, { + language: { + confirm: this.language.create, + decline: this.language.cancel + }, + content: [ + new Element('input', {'class': 'createDirectory'}) + ], + onOpen: this.onDialogOpen.bind(this), + onClose: this.onDialogClose.bind(this), + onShow: function(){ + var self = this; + this.el.getElement('input').addEvent('keyup', function(e){ + if (e.key == 'enter') self.el.getElement('button-confirm').fireEvent('click'); + }).focus(); + }, + onConfirm: function(){ + new FileManager.Request({ + url: self.options.url + '?event=create', + onSuccess: self.fill.bind(self), + data: { + file: this.el.getElement('input').get('value'), + directory: self.Directory + } + }, self).post(); + } + }); + }, + + deselect: function(el){ + if (el && this.Current != el) return; + + if (el) this.fillInfo(); + if (this.Current) this.Current.removeClass('selected'); + this.Current = null; + + this.switchButton(); + }, + + load: function(dir, nofade){ + this.deselect(); + if (!nofade) this.info.fade(0); + + if (this.Request) this.Request.cancel(); + + this.Request = new FileManager.Request({ + url: this.options.url, + onSuccess: (function(j){ + this.fill(j, nofade); + }).bind(this), + data: { + directory: dir + } + }, this).post(); + }, + + destroy: function(e, file){ + e.stop(); + this.tips.hide(); + + var self = this; + new Dialog(this.language.destroyfile, { + language: { + confirm: this.language.destroy, + decline: this.language.cancel + }, + onOpen: this.onDialogOpen.bind(this), + onClose: this.onDialogClose.bind(this), + onConfirm: function(){ + new FileManager.Request({ + url: self.options.url + '?event=destroy', + data: { + file: file.name, + directory: self.Directory + }, + onSuccess: function(j){ + if (!j || j.content!='destroyed'){ + new Dialog(self.language.nodestroy, {language: {confirm: self.language.ok}, buttons: ['confirm']}); + return; + } + + self.fireEvent('modify', [$unlink(file)]); + file.element.getParent().fade(0).get('tween').chain(function(){ + self.deselect(file.element); + this.element.destroy(); + }); + } + }, self).post(); + } + }); + + }, + + rename: function(e, file){ + e.stop(); + this.tips.hide(); + + var name = file.name; + if (file.mime != 'text/directory') name = name.replace(/\..*$/, ''); + + var self = this; + new Dialog(this.language.renamefile, { + language: { + confirm: this.language.rename, + decline: this.language.cancel + }, + content: [ + new Element('input', {'class': 'rename', value: name}) + ], + onOpen: this.onDialogOpen.bind(this), + onClose: this.onDialogClose.bind(this), + onShow: function(){ + var self = this; + this.el.getElement('input').addEvent('keyup', function(e){ + if (e.key=='enter') self.el.getElement('button-confirm').fireEvent('click'); + }).focus(); + }, + onConfirm: function(){ + new FileManager.Request({ + url: self.options.url + '?event=move', + onSuccess: (function(j){ + if (!j || !j.name) return; + + self.fireEvent('modify', [$unlink(file)]); + + file.element.getElement('span').set('text', j.name); + file.name = j.name; + self.fillInfo(file); + }).bind(this), + data: { + file: file.name, + name: this.el.getElement('input').get('value'), + directory: self.Directory + } + }, self).post(); + } + }); + }, + + fill: function(j, nofade){ + this.Directory = j.path; + this.CurrentDir = j.dir; + if (!nofade) this.fillInfo(j.dir); + this.browser.empty(); + + if (!j.files) return; + + var els = [[], []]; + $each(j.files, function(file){ + file.dir = j.path; + var el = file.element = new Element('span', {'class': 'fi', href: '#'}).adopt( + new Asset.image(this.options.assetBasePath + 'Icons/' + file.icon + '.png'), + new Element('span', {text: file.name}) + ).store('file', file); + + var icons = []; + if (file.mime!='text/directory') + icons.push(new Asset.image(this.options.assetBasePath + 'disk.png', {title: this.language.download}).addClass('browser-icon').addEvent('click', (function(e){ + this.tips.hide(); + e.stop(); + window.open(this.options.baseURL + this.normalize(this.Directory + '/' + file.name)); + }).bind(this)).inject(el, 'top')); + + if (file.name != '..') + ['rename', 'destroy'].each(function(v){ + icons.push(new Asset.image(this.options.assetBasePath + v + '.png', {title: this.language[v]}).addClass('browser-icon').addEvent('click', this[v].bindWithEvent(this, [file])).injectTop(el)); + }, this); + + els[file.mime == 'text/directory' ? 1 : 0].push(el); + if (file.name == '..') el.set('opacity', 0.7); + el.inject(new Element('li').inject(this.browser)).store('parent', el.getParent()); + icons = $$(icons.map(function(icon){ return icon.appearOn(icon, [1, 0.7]); })).appearOn(el.getParent('li'), 0.7); + }, this); + + var self = this, revert = function(el){ + el.set('opacity', 1).store('block', true).removeClass('drag').removeClass('move').setStyles({ + opacity: 1, + zIndex: '', + position: 'relative', + width: 'auto', + left: 0, + top: 0 + }).inject(el.retrieve('parent')); + el.getElements('img.browser-icon').set('opacity', 0); + + document.removeEvents('keydown', self.bound.keydown).removeEvents('keyup', self.bound.keydown); + self.imageadd.fade(0); + + self.relayClick.apply(el); + }; + + if(0) // This (drag to move into subdirectory) is breaking IE, we don't need it that badly + // See: http://github.com/cpojer/mootools-filemanager/issues#issue/11 + $$(els[0]).makeDraggable({ + droppables: $$(this.droppables, els[1]), + + onDrag: function(el, e){ + self.imageadd.setStyles({ + left: e.page.x + 15, + top: e.page.y + 15 + }); + }, + + onBeforeStart: function(el){ + self.deselect(); + self.tips.hide(); + var position = el.getPosition(); + el.addClass('drag').setStyles({ + zIndex: self.dragZIndex, + position: 'absolute', + width: el.getWidth() - el.getStyle('paddingLeft').toInt(), + left: position.x, + top: position.y + }).inject(self.container); + }, + + onCancel: revert, + + onStart: function(el){ + el.set('opacity', 0.7).addClass('move'); + document.addEvents({ + keydown: self.bound.keydown, + keyup: self.bound.keyup + }); + }, + + onEnter: function(el, droppable){ + droppable.addClass('droppable'); + }, + + onLeave: function(el, droppable){ + droppable.removeClass('droppable'); + }, + + onDrop: function(el, droppable, e){ + revert(el); + + if (e.control || e.meta || !droppable) el.setStyles({left: 0, top: 0}); + if (!droppable && !e.control && !e.meta) return; + + var dir; + if (droppable){ + droppable.addClass('selected').removeClass('droppable'); + (function(){ droppable.removeClass('selected'); }).delay(300); + if (self.onDragComplete(el, droppable)) return; + + dir = droppable.retrieve('file'); + } + var file = el.retrieve('file'); + + new FileManager.Request({ + url: self.options.url + '?event=move', + data: { + file: file.name, + directory: self.Directory, + newDirectory: dir ? dir.dir + '/' + dir.name : self.Directory, + copy: e.control || e.meta ? 1 : 0 + }, + onSuccess: function(){ + if (!dir) self.load(self.Directory); + } + }, self).post(); + + self.fireEvent('modify', [$unlink(file)]); + + if (!e.control && !e.meta) + el.fade(0).get('tween').chain(function(){ + self.deselect(el); + el.getParent().destroy(); + }); + } + }); + + $$(els).setStyles({left: 0, top: 0}); + + this.tips.attach(this.browser.getElements('img.browser-icon')); + }, + + fillInfo: function(file, path){ + if (!file) file = this.CurrentDir; + if (!path) path = this.Directory; + + if (!file) return; + var size = this.size(file.size); + + this.info.fade(1).getElement('img').set({ + src: this.options.assetBasePath + 'Icons/' + file.icon + '.png', + alt: file.mime + }); + + this.fireHooks('cleanup'); + this.preview.empty(); + + // Xinha: We need to remove our custom attributes form when the preview is hidden + this.fireEvent('hidePreview'); + + this.info.getElement('h1').set('text', file.name); + this.info.getElement('dd.filemanager-modified').set('text', file.date); + this.info.getElement('dd.filemanager-type').set('text', file.mime); + this.info.getElement('dd.filemanager-size').set('text', !size[0] && size[1] == 'Bytes' ? '-' : (size.join(' ') + (size[1] != 'Bytes' ? ' (' + file.size + ' Bytes)' : ''))); + this.info.getElement('h2.filemanager-headline').setStyle('display', file.mime == 'text/directory' ? 'none' : 'block'); + + var text = [], pre = []; + + path.split('/').each(function(v){ + if (!v) return; + + pre.push(v); + text.push(new Element('a', { + 'class': 'icon', + href: '#', + text: v + }).addEvent('click', (function(e, dir){ + e.stop(); + + this.load(dir); + }).bindWithEvent(this, [pre.join('/')])) + ); + text.push(new Element('span', {text: ' / '})); + }, this); + + text.pop(); + text[text.length-1].addClass('selected').removeEvents('click').addEvent('click', function(e){ e.stop(); }); + + this.info.getElement('dd.filemanager-dir').empty().adopt(new Element('span', {text: '/ '}), text); + + if (file.mime=='text/directory') return; + + if (this.Request) this.Request.cancel(); + + this.Request = new FileManager.Request({ + url: this.options.url + '?event=detail', + onSuccess: (function(j){ + var prev = this.preview.removeClass('filemanager-loading').set('html', j && j.content ? j.content.substitute(this.language, /\\?\$\{([^{}]+)\}/g) : '').getElement('img.prev'); + if (prev) prev.addEvent('load', function(){ + this.setStyle('background', 'none'); + }); + + var els = this.preview.getElements('button'); + if (els) els.addEvent('click', function(e){ + e.stop(); + window.open(this.get('value')); + }); + + // Xinha: We need to add in a form for setting the attributes of images etc, + // so we add this event and pass it the information we have about the item + // as returned by Backend/FileManager.php + this.fireEvent('details', [j]); + + // Xinha: We also want to hold onto the data so we can access it + // when selecting the image. + if(this.Current) this.Current.file_data = j; + }).bind(this), + data: { + directory: this.Directory, + file: file.name + } + }, this).post(); + }, + + size: function(size){ + var tab = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + for(var i = 0; size > 1024; i++) + size = size/1024; + + return [Math.round(size), tab[i]]; + }, + + normalize: function(str){ + return str.replace(/\/+/g, '/'); + }, + + switchButton: function(){ + var chk = !!this.Current; + var el = this.menu.getElement('button.filemanager-open'); + if (el) el.set('disabled', !chk)[(chk ? 'remove' : 'add') + 'Class']('disabled'); + }, + + addMenuButton: function(name){ + var el = new Element('button', { + 'class': 'filemanager-' + name, + text: this.language[name] + }).inject(this.menu, 'top'); + if (this[name]) el.addEvent('click', this[name].bind(this)); + return el; + }, + + fireHooks: function(hook){ + var args = Array.slice(arguments, 1); + for(var key in this.hooks[hook]) this.hooks[hook][key].apply(this, args); + return this; + }, + + onRequest: function(){ this.loader.set('opacity', 1); }, + onComplete: function(){ this.loader.fade(0); }, + onDialogOpen: $empty, + onDialogClose: $empty, + onDragComplete: $lambda(false) + +}); + +FileManager.Request = new Class({ + + Extends: Request.JSON, + + initialize: function(options, filebrowser){ + // Xinha: We need ALL requests from the FileManager to have our authorisation data on it + // normal MootoolsFileManager only has the flash send it :-( + if(filebrowser) + { + options.url += (options.url.match(/\?/) ? '&' : '?') +Hash.toQueryString(filebrowser.options.uploadAuthData); + } + + // Xinha: We also need to clean up the url because our backend already includes a query string + // and MootoolsFileManager adds ?event=..... indiscriminately, our query string always + // ends in an ampersand, so we can just clean up '&?event=' to be '&event=' + options.url = options.url.replace(/&\?event=/, '&event='); + + this.parent(options); + + if (filebrowser) this.addEvents({ + request: filebrowser.onRequest.bind(filebrowser), + complete: filebrowser.onComplete.bind(filebrowser) + }); + } + +}); + +FileManager.Language = {}; Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Gallery.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Gallery.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Gallery.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,305 @@ +/* +--- +description: FileManager.Gallery +longdescription: Adds functionality to create a gallery out of a list of images + +authors: + - Christoph Pojer + +requires: + core/1.2.4: '*' + +provides: + - filemanager.gallery + +license: + MIT-style license +... +*/ + +(function(){ + +FileManager.Gallery = new Class({ + + Extends: FileManager, + + initialize: function(options){ + this.offsets = {y: -72}; + this.parent(options); + + var show = function(){ + this.galleryContainer.setStyles({ + opacity: 0, + display: 'block' + }); + + var size = this.el.getSize(), + pos = this.el.getPosition(); + + this.galleryContainer.setStyles({ + top: pos.y + size.y - 1, + left: pos.x + (size.x - this.galleryContainer.getWidth()) / 2, + opacity: 1 + }); + + this.hideClone(); + this.wrapper.setStyle('display', 'none'); + + if (this.howto){ + var self = this; + (function(){ + if (self.howto && self.howto.fade) self.howto.fade(0).get('tween').chain(function(){ + this.element.destroy(); + self.howto = null; + }); + }).delay(2000); + } + }; + + this.addEvents({ + + scroll: show, + show: (function(){ + show.apply(this); + this.populate(); + }), + + hide: function(){ + this.gallery.empty(); + + this.captions = {}; + this.files = []; + + this.hideClone(); + this.wrapper.setStyle('display', 'none'); + }, + + modify: function(file){ + var name = this.normalize(file.dir + '/' + file.name); + var el = (this.gallery.getElements('li').filter(function(el){ + var f = el.retrieve('file'); + return name == this.normalize(f.dir + '/' + f.name); + }, this) || null)[0]; + + if (el) this.erasePicture(name, el); + } + }); + + this.addMenuButton('serialize'); + this.galleryContainer = new Element('div', {'class': 'filemanager-gallery'}).inject(this.container); + this.gallery = new Element('ul').inject(this.galleryContainer); + + var timer, removeClone = this.removeClone.bind(this); + + this.input = new Element('input', {name: 'imgCaption'}).addEvent('keyup', function(e){ + if (e.key == 'enter') removeClone(e); + }); + this.wrapper = new Element('div', { + 'class': 'filemanager-wrapper', + tween: {duration: 200}, + opacity: 0, + events: { + mouseenter: function(){ + $clear(timer); + }, + mouseleave: function(e){ + timer = (function(){ + removeClone(e); + }).delay(500); + } + } + }).adopt( + new Element('span', {text: this.language.gallery.text}), + this.input, + new Element('div', {'class': 'img'}), + new Element('button', {text: this.language.gallery.save}).addEvent('click', removeClone) + ).inject(document.body); + + this.droppables.push(this.gallery); + + this.captions = {}; + this.files = []; + this.animation = {}; + + this.howto = new Element('div', {'class': 'howto', text: this.language.gallery.drag}).inject(this.galleryContainer); + this.switchButton(); + }, + + onDragComplete: function(el, droppable){ + if (!droppable || droppable != this.gallery) return false; + + var file; + if ($type(el) == 'string'){ + var part = el.split('/'); + file = { + name: part.pop(), + dir: part.join('/') + }; + }else{ + el.setStyles({left: '', top: ''}); + file = el.retrieve('file'); + } + + var self = this, name = this.normalize(file.dir + '/' + file.name); + + if (this.files.contains(name)) return true; + this.files.push(name); + + var img = new Asset.image(this.options.assetBasePath + 'destroy.png').set({ + 'class': 'filemanager-remove', + title: this.language.gallery.remove, + events: {click: this.removePicture} + }).store('gallery', this); + + var li = new Element('li').store('file', file).adopt( + img, + new Asset.image(this.options.baseURL + name, { + onload: function(){ + var el = this; + li.setStyle('background', 'none').addEvent('click', function(e){ + if (e) e.stop(); + + var pos = el.getCoordinates(); + pos.left += el.getStyle('paddingLeft').toInt(); + pos.top += el.getStyle('paddingTop').toInt(); + + self.hideClone(); + self.animation = { + from: { + width: 75, + height: 56, + left: pos.left, + top: pos.top + }, + to: { + width: 200, + height: 150, + left: pos.left - 75, + top: pos.top + pos.height - 150 + } + }; + + self.hideClone(); + self.input.removeEvents('blur').addEvent('blur', function(){ + self.captions[name] = this.get('value') || ''; + }); + + li.set('opacity', 0); + self.clone = el.clone(); + self.clone.store('file', file).store('parent', li).addClass('filemanager-clone').setStyles(self.animation.from).set({ + morph: {link: 'chain'}, + styles: { + position: 'absolute', + zIndex: 1100 + }, + events: { + click: function(e){ + self.fireEvent('preview', [self.options.baseURL + name, self.captions[name], li]); + } + } + }).inject(document.body).morph(self.animation.to).get('morph').chain(function(){ + self.input.set('value', self.captions[name] || ''); + self.wrapper.setStyles({ + opacity: 0, + display: 'block', + left: self.animation.to.left - 12, + top: self.animation.to.top - 53 + }).fade(1).get('tween').chain(function(){ + self.input.focus(); + }); + }); + }); + } + }) + ).inject(this.gallery); + + this.tips.attach(img.appearOn(li)); + this.switchButton(); + + return true; + }, + + removeClone: function(e){ + if (!this.clone || (e.relatedTarget && ([this.clone, this.wrapper].contains(e.relatedTarget) || this.wrapper.hasChild(e.relatedTarget)))) return; + if (this.clone.get('morph').timer) return; + + var file = this.clone.retrieve('file'); + if (!file) return; + + this.captions[this.normalize(file.dir + '/' + file.name)] = this.input.get('value') || ''; + + this.clone.morph(this.animation.from).get('morph').clearChain().chain((function(){ + this.clone.retrieve('parent').set('opacity', 1); + this.clone.destroy(); + }).bind(this)); + + this.wrapper.fade(0).get('tween').chain(function(){ + this.element.setStyle('display', 'none'); + }); + }, + + hideClone: function(){ + if (!this.clone) return; + + this.clone.get('morph').cancel(); + var parent = this.clone.retrieve('parent'); + if (parent) parent.set('opacity', 1); + this.clone.destroy(); + this.wrapper.setStyles({ + opacity: 0, + display: 'none' + }); + }, + + removePicture: function(e){ + if(e) e.stop(); + + var self = this.retrieve('gallery'), + parent = this.getParent('li'), + file = parent.retrieve('file'), + name = self.normalize(file.dir + '/' + file.name); + + self.erasePicture(name, parent); + }, + + erasePicture: function(name, element){ + this.captions[name] = ''; + this.files.erase(name); + this.tips.hide(); + + var self = this; + element.set('tween', {duration: 250}).removeEvents('click').fade(0).get('tween').chain(function(){ + this.element.destroy(); + self.switchButton(); + }); + }, + + switchButton: function(){ + var chk = !!this.gallery.getChildren().length; + + this.menu.getElement('button.filemanager-serialize').set('disabled', !chk)[(chk ? 'remove' : 'add') + 'Class']('disabled'); + }, + + populate: function(data){ + Hash.each(data || {}, function(v, i){ + this.captions[i] = v; + + this.onDragComplete(i, this.gallery); + }, this); + }, + + serialize: function(e){ + if(e) e.stop(); + + var serialized = {}; + this.files.each(function(v){ + serialized[v] = this.captions[v] || ''; + }, this); + + this.hide(); + this.fireEvent('complete', [serialized]); + } + +}); + +})(); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,238 @@ +/* +--- +description: FileManager Uploader +longdescription: Implements Upload functionality into the FileManager based on [FancyUpload](http://digitarald.de) + +authors: + - Christoph Pojer + +requires: + core/1.2.4: '*' + +provides: + - filemanager.uploader + +license: + MIT-style license + +options: + - upload: (boolean, defaults to *true*) + - uploadAuthData: (object) Data to be send with the GET-Request of an Upload as Flash ignores authenticated clients + - resizeImages: (boolean, defaults to *true*) Whether to show the option to resize big images or not +... +*/ + +FileManager.implement({ + + options: { + resizeImages: true, + upload: true, + uploadAuthData: {} + }, + + hooks: { + show: { + upload: function(){ + this.startUpload(); + } + }, + + cleanup: { + upload: function(){ + if (!this.options.upload || !this.upload) return; + + if (this.upload.uploader) this.upload.uploader.set('opacity', 0).dispose(); + } + } + }, + + onDialogOpen: function(){ + if (this.swf && this.swf.box) this.swf.box.setStyle('visibility', 'hidden'); + }, + + onDialogClose: function(){ + if (this.swf && this.swf.box) this.swf.box.setStyle('visibility', 'visible'); + }, + + startUpload: function(){ + if (!this.options.upload || this.swf) return; + + var self = this; + this.upload = { + button: this.addMenuButton('upload').inject(this.menu, 'bottom').addEvents({ + click: function(){ + return false; + }, + mouseenter: function(){ + this.addClass('hover'); + }, + mouseleave: function(){ + this.removeClass('hover'); + this.blur(); + }, + mousedown: function(){ + this.focus(); + } + }), + list: new Element('ul', {'class': 'filemanager-uploader-list'}), + uploader: new Element('div', {opacity: 0, 'class': 'filemanager-uploader-area'}).adopt( + new Element('h2', {text: this.language.upload}), + new Element('div', {'class': 'filemanager-uploader'}) + ) + }; + this.upload.uploader.getElement('div').adopt(this.upload.list); + this.closeIcon.appearOn(this.upload.button, 0.8); + + if (this.options.resizeImages){ + var resizer = new Element('div', {'class': 'checkbox'}), + check = (function(){ this.toggleClass('checkboxChecked'); }).bind(resizer); + check(); + this.upload.label = new Element('label').adopt( + resizer, new Element('span', {text: this.language.resizeImages}) + ).addEvent('click', check).inject(this.menu); + } + + var File = new Class({ + + Extends: Swiff.Uploader.File, + + initialize: function(base, data){ + this.parent(base, data); + this.setOptions({ + url: self.options.url + (self.options.url.indexOf('?') == -1 ? '?' : '&') + Hash.toQueryString($merge({}, self.options.uploadAuthData, { + event: 'upload', + directory: self.normalize(self.Directory), + resize: self.options.resizeImages && resizer.hasClass('checkboxChecked') ? 1 : 0 + })) + }); + }, + + render: function(){ + if (this.invalid){ + var message = self.language.uploader.unknown, sub = { + name: this.name, + size: Swiff.Uploader.formatUnit(this.size, 'b') + }; + + if (self.language.uploader[this.validationError]) + message = self.language.uploader[this.validationError]; + + if (this.validationError == 'sizeLimitMin') + sub.size_min = Swiff.Uploader.formatUnit(this.base.options.fileSizeMin, 'b'); + else if (this.validationError == 'sizeLimitMax') + sub.size_max = Swiff.Uploader.formatUnit(this.base.options.fileSizeMax, 'b'); + + new Dialog(new Element('div', {html: message.substitute(sub, /\\?\$\{([^{}]+)\}/g)}) , {language: {confirm: self.language.ok}, buttons: ['confirm']}); + return this; + } + + this.addEvents({ + open: this.onOpen, + remove: this.onRemove, + requeue: this.onRequeue, + progress: this.onProgress, + stop: this.onStop, + complete: this.onComplete + }); + + this.ui = {}; + this.ui.icon = new Asset.image(self.options.assetBasePath+'Icons/' + this.extension + '.png', { + onerror: function(){ new Asset.image(self.options.assetBasePath + 'Icons/default.png').replaces(this); } + }); + this.ui.element = new Element('li', {'class': 'file', id: 'file-' + this.id}); + this.ui.title = new Element('span', {'class': 'file-title', text: this.name}); + this.ui.size = new Element('span', {'class': 'file-size', text: Swiff.Uploader.formatUnit(this.size, 'b')}); + + var file = this; + this.ui.cancel = new Asset.image(self.options.assetBasePath+'cancel.png', {'class': 'file-cancel', title: self.language.cancel}).addEvent('click', function(){ + file.remove(); + self.tips.hide(); + self.tips.detach(this); + }); + self.tips.attach(this.ui.cancel); + + var progress = new Element('img', {'class': 'file-progress', src: self.options.assetBasePath+'bar.gif'}); + + this.ui.element.adopt( + this.ui.cancel, + progress, + this.ui.icon, + this.ui.title, + this.ui.size + ).inject(self.upload.list).highlight(); + + this.ui.progress = new Fx.ProgressBar(progress).set(0); + + this.base.reposition(); + + return this.parent(); + }, + + onOpen: function(){ + this.ui.element.addClass('file-running'); + }, + + onRemove: function(){ + this.ui = this.ui.element.destroy(); + }, + + onProgress: function(){ + this.ui.progress.start(this.progress.percentLoaded); + }, + + onStop: function(){ + this.remove(); + }, + + onComplete: function(){ + this.ui.progress = this.ui.progress.cancel().element.destroy(); + this.ui.cancel = this.ui.cancel.destroy(); + + var response = JSON.decode(this.response.text); + if (!response.status) + new Dialog(('' + response.error).substitute(self.language, /\\?\$\{([^{}]+)\}/g) , {language: {confirm: self.language.ok}, buttons: ['confirm']}); + + this.ui.element.set('tween', {duration: 2000}).highlight(response.status ? '#e6efc2' : '#f0c2c2'); + (function(){ + this.ui.element.setStyle('overflow', 'hidden').morph({ + opacity: 0, + height: 0 + }).get('morph').chain(function(){ + this.element.destroy(); + if (!self.upload.list.getElements('li').length) + self.upload.uploader.fade(0).get('tween').chain(function(){ + self.fillInfo(); + }); + }); + }).delay(5000, this); + } + + }); + + this.swf = new Swiff.Uploader({ + id: 'SwiffFileManagerUpload', + path: this.options.assetBasePath + 'Swiff.Uploader.swf', + queued: false, + target: this.upload.button, + allowDuplicates: true, + instantStart: true, + fileClass: File, + fileSizeMax: 25 * 1024 * 1024, + zIndex: this.SwiffZIndex || 9999, + onSelectSuccess: function(){ + self.fillInfo(); + self.info.getElement('h2.filemanager-headline').setStyle('display', 'none'); + self.info.adopt(self.upload.uploader); + self.upload.uploader.fade(1); + }, + onComplete: function(){ + self.load(self.Directory, true); + }, + onFail: function(error){ + $$(self.upload.button, self.upload.label).dispose(); + new Dialog(new Element('div', {html: self.language.flash[error] || self.language.flash.flash}), {language: {confirm: self.language.ok}, buttons: ['confirm']}); + } + }); + } + +}); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Fx.ProgressBar.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Fx.ProgressBar.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Fx.ProgressBar.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,78 @@ +/* +--- +description: Fx.Progressbar + +authors: + - Harald Kirschner + +requires: + core/1.2.4: '*' + +provides: + - filemanager.swiff.progressbar + +license: + MIT-style license +... +*/ + +Fx.ProgressBar = new Class({ + + Extends: Fx, + + options: { + text: null, + url: null, + transition: Fx.Transitions.Circ.easeOut, + fit: true, + link: 'cancel' + }, + + initialize: function(element, options) { + this.element = $(element); + this.parent(options); + + var url = this.options.url; + if (url) { + this.element.setStyles({ + 'background-image': 'url(' + url + ')', + 'background-repeat': 'no-repeat' + }); + } + + if (this.options.fit) { + url = url || this.element.getStyle('background-image').replace(/^url\(["']?|["']?\)$/g, ''); + if (url) { + var fill = new Image(); + fill.onload = function() { + this.fill = fill.width; + fill = fill.onload = null; + this.set(this.now || 0); + }.bind(this); + fill.src = url; + if (!this.fill && fill.width) fill.onload(); + } + } else { + this.set(0); + } + }, + + start: function(to, total) { + return this.parent(this.now, (arguments.length == 1) ? to.limit(0, 100) : to / total * 100); + }, + + set: function(to) { + this.now = to; + var css = (this.fill) + ? (((this.fill / -2) + (to / 100) * (this.element.width || 1) || 0).round() + 'px') + : ((100 - to) + '%'); + + this.element.setStyle('backgroundPosition', css + ' 0px').title = Math.round(to) + '%'; + + var text = $(this.options.text); + if (text) text.set('text', Math.round(to) + '%'); + + return this; + } + +}); \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Swiff.Uploader.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Swiff.Uploader.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/MootoolsFileManager/mootools-filemanager/Source/Uploader/Swiff.Uploader.js 23 May 2010 12:00:02 -0000 1.1 @@ -0,0 +1,494 @@ +/* +--- +description: Swiff.Uploader + +authors: + - Harald Kirschner + +requires: + core/1.2.4: '*' + +provides: + - filemanager.swiff.uploader + +license: + MIT-style license +... +*/ + +Swiff.Uploader = new Class({ + + Extends: Swiff, + + Implements: Events, + + options: { + path: 'Swiff.Uploader.swf', + + target: null, + zIndex: 9999, + + height: 30, + width: 100, + callBacks: null, + params: { + wMode: 'opaque', + menu: 'false', + allowScriptAccess: 'always' + }, + + typeFilter: null, + multiple: true, + queued: true, + verbose: false, + + url: null, + method: null, + data: null, + mergeData: true, + fieldName: null, + + fileSizeMin: 1, + fileSizeMax: null, // Official limit is 100 MB for FileReference, but I tested up to 2Gb! + allowDuplicates: false, + timeLimit: (Browser.Platform.linux) ? 0 : 30, + + buttonImage: null, + policyFile: null, + + fileListMax: 0, + fileListSizeMax: 0, + + instantStart: false, + appendCookieData: false, + + fileClass: null + /* + onLoad: $empty, + onFail: $empty, + onStart: $empty, + onQueue: $empty, + onComplete: $empty, + onBrowse: $empty, + onDisabledBrowse: $empty, + onCancel: $empty, + onSelect: $empty, + onSelectSuccess: $empty, + onSelectFail: $empty, + + onButtonEnter: $empty, + onButtonLeave: $empty, + onButtonDown: $empty, + onButtonDisable: $empty, + + onFileStart: $empty, + onFileStop: $empty, + onFileRequeue: $empty, + onFileOpen: $empty, + onFileProgress: $empty, + onFileComplete: $empty, + onFileRemove: $empty, + + onBeforeStart: $empty, + onBeforeStop: $empty, + onBeforeRemove: $empty + */ + }, + + initialize: function(options) { + // protected events to control the class, added + // before setting options (which adds own events) + this.addEvent('load', this.initializeSwiff, true) + .addEvent('select', this.processFiles, true) + .addEvent('complete', this.update, true) + .addEvent('fileRemove', function(file) { + this.fileList.erase(file); + }.bind(this), true); + + this.setOptions(options); + + // callbacks are no longer in the options, every callback + // is fired as event, this is just compat + if (this.options.callBacks) { + Hash.each(this.options.callBacks, function(fn, name) { + this.addEvent(name, fn); + }, this); + } + + this.options.callBacks = { + fireCallback: this.fireCallback.bind(this) + }; + + var path = this.options.path; + if (!path.contains('?')) path += '?noCache=' + $time(); // cache in IE + + // container options for Swiff class + this.options.container = this.box = new Element('span', {'class': 'swiff-uploader-box'}).inject($(this.options.container) || document.body); + + // target + this.target = $(this.options.target); + if (this.target) { + var scroll = window.getScroll(); + this.box.setStyles({ + position: 'absolute', + visibility: 'visible', + zIndex: this.options.zIndex, + overflow: 'hidden', + height: 1, width: 1, + top: scroll.y, left: scroll.x + }); + + // we force wMode to transparent for the overlay effect + this.parent(path, { + params: { + wMode: 'transparent' + }, + height: '100%', + width: '100%' + }); + + this.target.addEvent('mouseenter', this.reposition.bind(this, [])); + + // button interactions, relayed to to the target + this.addEvents({ + buttonEnter: this.targetRelay.bind(this, ['mouseenter']), + buttonLeave: this.targetRelay.bind(this, ['mouseleave']), + buttonDown: this.targetRelay.bind(this, ['mousedown']), + buttonDisable: this.targetRelay.bind(this, ['disable']) + }); + + this.reposition(); + window.addEvent('resize', this.reposition.bind(this, [])); + } else { + this.parent(path); + } + + this.inject(this.box); + + this.fileList = []; + + this.size = this.uploading = this.bytesLoaded = this.percentLoaded = 0; + + if (Browser.Plugins.Flash.version < 9) { + this.fireEvent('fail', ['flash']); + } else { + this.verifyLoad.delay(1000, this); + } + }, + + verifyLoad: function() { + if (this.loaded) return; + if (!this.object.parentNode) { + this.fireEvent('fail', ['disabled']); + } else if (this.object.style.display == 'none') { + this.fireEvent('fail', ['hidden']); + } else if (!this.object.offsetWidth) { + this.fireEvent('fail', ['empty']); + } + }, + + fireCallback: function(name, args) { + // file* callbacks are relayed to the specific file + if (name.substr(0, 4) == 'file') { + // updated queue data is the second argument + if (args.length > 1) this.update(args[1]); + var data = args[0]; + + var file = this.findFile(data.id); + this.fireEvent(name, file || data, 5); + if (file) { + var fire = name.replace(/^file([A-Z])/, function($0, $1) { + return $1.toLowerCase(); + }); + file.update(data).fireEvent(fire, [data], 10); + } + } else { + this.fireEvent(name, args, 5); + } + }, + + update: function(data) { + // the data is saved right to the instance + $extend(this, data); + this.fireEvent('queue', [this], 10); + return this; + }, + + findFile: function(id) { + for (var i = 0; i < this.fileList.length; i++) { + if (this.fileList[i].id == id) return this.fileList[i]; + } + return null; + }, + + initializeSwiff: function() { + // extracted options for the swf + this.remote('initialize', { + width: this.options.width, + height: this.options.height, + typeFilter: this.options.typeFilter, + multiple: this.options.multiple, + queued: this.options.queued, + url: this.options.url, + method: this.options.method, + data: this.options.data, + mergeData: this.options.mergeData, + fieldName: this.options.fieldName, + verbose: this.options.verbose, + fileSizeMin: this.options.fileSizeMin, + fileSizeMax: this.options.fileSizeMax, + allowDuplicates: this.options.allowDuplicates, + timeLimit: this.options.timeLimit, + buttonImage: this.options.buttonImage, + policyFile: this.options.policyFile + }); + + this.loaded = true; + + this.appendCookieData(); + }, + + targetRelay: function(name) { + if (this.target) this.target.fireEvent(name); + }, + + reposition: function(coords) { + // update coordinates, manual or automatically + coords = coords || (this.target && this.target.offsetHeight) + ? this.target.getCoordinates(this.box.getOffsetParent()) + : {top: window.getScrollTop(), left: 0, width: 40, height: 40}; + this.box.setStyles(coords); + this.fireEvent('reposition', [coords, this.box, this.target]); + }, + + setOptions: function(options) { + if (options) { + if (options.url) options.url = Swiff.Uploader.qualifyPath(options.url); + if (options.buttonImage) options.buttonImage = Swiff.Uploader.qualifyPath(options.buttonImage); + this.parent(options); + if (this.loaded) this.remote('setOptions', options); + } + return this; + }, + + setEnabled: function(status) { + this.remote('setEnabled', status); + }, + + start: function() { + this.fireEvent('beforeStart'); + this.remote('start'); + }, + + stop: function() { + this.fireEvent('beforeStop'); + this.remote('stop'); + }, + + remove: function() { + this.fireEvent('beforeRemove'); + this.remote('remove'); + }, + + fileStart: function(file) { + this.remote('fileStart', file.id); + }, + + fileStop: function(file) { + this.remote('fileStop', file.id); + }, + + fileRemove: function(file) { + this.remote('fileRemove', file.id); + }, + + fileRequeue: function(file) { + this.remote('fileRequeue', file.id); + }, + + appendCookieData: function() { + var append = this.options.appendCookieData; + if (!append) return; + + var hash = {}; + document.cookie.split(/;\s*/).each(function(cookie) { + cookie = cookie.split('='); + if (cookie.length == 2) { + hash[decodeURIComponent(cookie[0])] = decodeURIComponent(cookie[1]); + } + }); + + var data = this.options.data || {}; + if ($type(append) == 'string') data[append] = hash; + else $extend(data, hash); + + this.setOptions({data: data}); + }, + + processFiles: function(successraw, failraw, queue) { + var cls = this.options.fileClass || Swiff.Uploader.File; + + var fail = [], success = []; + + if (successraw) { + successraw.each(function(data) { + var ret = new cls(this, data); + if (!ret.validate()) { + ret.remove.delay(10, ret); + fail.push(ret); + } else { + this.size += data.size; + this.fileList.push(ret); + success.push(ret); + ret.render(); + } + }, this); + + this.fireEvent('selectSuccess', [success], 10); + } + + if (failraw || fail.length) { + fail.extend((failraw) ? failraw.map(function(data) { + return new cls(this, data); + }, this) : []).each(function(file) { + file.invalidate().render(); + }); + + this.fireEvent('selectFail', [fail], 10); + } + + this.update(queue); + + if (this.options.instantStart && success.length) this.start(); + } + +}); + +$extend(Swiff.Uploader, { + + STATUS_QUEUED: 0, + STATUS_RUNNING: 1, + STATUS_ERROR: 2, + STATUS_COMPLETE: 3, + STATUS_STOPPED: 4, + + log: function() { + if (window.console && console.info) console.info.apply(console, arguments); + }, + + unitLabels: { + b: [{min: 1, unit: 'B'}, {min: 1024, unit: 'kB'}, {min: 1048576, unit: 'MB'}, {min: 1073741824, unit: 'GB'}], + s: [{min: 1, unit: 's'}, {min: 60, unit: 'm'}, {min: 3600, unit: 'h'}, {min: 86400, unit: 'd'}] + }, + + formatUnit: function(base, type, join) { + var labels = Swiff.Uploader.unitLabels[(type == 'bps') ? 'b' : type]; + var append = (type == 'bps') ? '/s' : ''; + var i, l = labels.length, value; + + if (base < 1) return '0 ' + labels[0].unit + append; + + if (type == 's') { + var units = []; + + for (i = l - 1; i >= 0; i--) { + value = Math.floor(base / labels[i].min); + if (value) { + units.push(value + ' ' + labels[i].unit); + base -= value * labels[i].min; + if (!base) break; + } + } + + return (join === false) ? units : units.join(join || ', '); + } + + for (i = l - 1; i >= 0; i--) { + value = labels[i].min; + if (base >= value) break; + } + + return (base / value).toFixed(1) + ' ' + labels[i].unit + append; + } + +}); + +Swiff.Uploader.qualifyPath = (function() { + + var anchor; + + return function(path) { + (anchor || (anchor = new Element('a'))).href = path; + return anchor.href; + }; + +})(); + +Swiff.Uploader.File = new Class({ + + Implements: Events, + + initialize: function(base, data) { + this.base = base; + this.update(data); + }, + + update: function(data) { + return $extend(this, data); + }, + + validate: function() { + var options = this.base.options; + + if (options.fileListMax && this.base.fileList.length >= options.fileListMax) { + this.validationError = 'fileListMax'; + return false; + } + + if (options.fileListSizeMax && (this.base.size + this.size) > options.fileListSizeMax) { + this.validationError = 'fileListSizeMax'; + return false; + } + + return true; + }, + + invalidate: function() { + this.invalid = true; + this.base.fireEvent('fileInvalid', this, 10); + return this.fireEvent('invalid', this, 10); + }, + + render: function() { + return this; + }, + + setOptions: function(options) { + if (options) { + if (options.url) options.url = Swiff.Uploader.qualifyPath(options.url); + this.base.remote('fileSetOptions', this.id, options); + this.options = $merge(this.options, options); + } + return this; + }, + + start: function() { + this.base.fileStart(this); + return this; + }, + + stop: function() { + this.base.fileStop(this); + return this; + }, + + remove: function() { + this.base.fileRemove(this); + return this; + }, + + requeue: function() { + this.base.fileRequeue(this); + } + +}); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSFixed/PSFixed.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSFixed/PSFixed.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSFixed/PSFixed.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSFixed/PSFixed.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,147 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -(function(){var b=window.PSFixed=function b(c){this.editor=c};b._pluginInfo={name:"PSFixed",version:"2.0",developer:"Douglas Mayle",developer_url:"http://xinha.org",license:"BSD"};b.prototype.onGenerateOnce=function(){this._registerBackend()};b.prototype._registerBackend=function(f){var e=this.editor;var c=this;if(!f){f=0}var d=10000;if(f>d){return}if(!e.plugins.PersistentStorage||!e.plugins.PersistentStorage.instance||!e.plugins.PersistentStorage.instance.ready){window.setTimeout(function(){c._registerBackend(f?f*2:50)},f?f:50);return}e.plugins.PersistentStorage.instance.registerBackend("PSFixed",this)};b.prototype.loadData=function(c){if(!this.config.$type){this.config.$type="folder"}c(this.config)};var a=function a(c,f,d){if(typeof d=="undefined"){d="/";f("/","",c)}for(var e in c){f(d,e,c[e]);if(c[e].$type=="folder"){a(c[e],f,d+e+"/")}}};b.prototype.getFilters=function(c){var d=[];a(c,function(h,f,g){if(g.$type!="folder"){return}var e=f.length?h+f+"/":h;d.push({value:e,display:e})});return d};b.prototype.getMetadata=function(d,g){var f=this.editor;var c=this;var e=[];a(d,function(j,h,i){if(!i.$type||!h){return}if(j!=g){return}if(i.$type=="folder"){e.push({URL:c.editor.imgURL("folder.gif","PersistentStorage"),name:h,key:j+h,$type:i.$type})}else{e.push({URL:i.URL,name:h,key:j+h,$type:i.$type})}});return e}})(); \ No newline at end of file +/** + * PSFixed PSFixed.js file. + * This plugin is a fake persistent storage backed. It is configured with a + * fixed list of stored objects and presents them to the user for insertion. + * A sample config is below: + * + * PSFixed.config = { + * 'xinha.png': { + * $type: 'image', + * URL: 'http://trac.xinha.org/chrome/common/trac_banner.png' + * }, + * 'browser': { + * $type: 'folder', + * 'firefox.png': { + * $type: 'image', + * URL: 'http://www.mozilla.com/img/tignish/firefox/vs-firefox-logo.png' + * } + * } + * } + */ +(function() { +var PSFixed = window.PSFixed = function PSFixed(editor) { + this.editor = editor; +} + +PSFixed._pluginInfo = { + name : "PSFixed", + version : "2.0", + developer : "Douglas Mayle", + developer_url : "http://xinha.org", + license : "BSD" +}; + +PSFixed.prototype.onGenerateOnce = function () { + // We use _prepareDialog to asynchronously load the dialog markup and then + // perform necessary processing. + this._registerBackend(); +}; + +PSFixed.prototype._registerBackend = function(timeWaited) { + var editor = this.editor; + var self = this; + + if (!timeWaited) { + timeWaited = 0; + } + + // Retry over a period of ten seconds to register. We back off exponentially + // to limit resouce usage in the case of misconfiguration. + var registerTimeout = 10000; + + if (timeWaited > registerTimeout) { + // This is most likely a configuration error. We're loaded and + // PersistentStorage is not. + return; + } + + if (!editor.plugins['PersistentStorage'] || + !editor.plugins['PersistentStorage'].instance || + !editor.plugins['PersistentStorage'].instance.ready) { + + window.setTimeout(function() {self._registerBackend(timeWaited ? timeWaited*2 : 50);}, timeWaited ? timeWaited : 50); + return; + } + editor.plugins['PersistentStorage'].instance.registerBackend('PSFixed', this); +} + +PSFixed.prototype.loadData = function (asyncCallback) { + // We don't expect the user to set the type on the root folder, so we set it + // ourselves. + if (!this.config.$type) { + this.config.$type = 'folder'; + } + asyncCallback(this.config); +} + +var treeRecurse = function treeRecurse(tree, callback, root) { + if (typeof root == 'undefined') { + root = '/'; + callback('/', '', tree); + } + + for (var key in tree) { + callback(root, key, tree[key]); + + if (tree[key].$type == 'folder') { + treeRecurse(tree[key], callback, root + key + '/'); + } + } +}; + +PSFixed.prototype.getFilters = function(dirTree) { + var filters = []; + + treeRecurse(dirTree, function(path, key, value) { + if (value.$type != 'folder') { + return; + } + + var filePath = key.length ? path + key + '/' : path; + filters.push({ + value: filePath, + display: filePath + }); + }); + + return filters; +} + +PSFixed.prototype.getMetadata = function(dirTree, filterPath) { + var editor = this.editor; + var self = this; + + var metadata = []; + + treeRecurse(dirTree, function(path, key, value) { + if (!value.$type || !key) { + // This is a builtin property of objects, not one returned by the + // backend. + return; + } + + if (path != filterPath) { + return; + } + + if (value.$type == 'folder') { + metadata.push({ + URL: self.editor.imgURL('folder.gif', 'PersistentStorage'), + name: key, + key: path + key, + $type: value.$type + }); + } else { + metadata.push({ + URL: value.URL, + name: key, + key: path + key, + $type: value.$type + }); + } + }); + + return metadata; +} + +})(); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/PSLocal.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/PSLocal.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/PSLocal.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/PSLocal.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,355 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -(function(){var PSLocal=window.PSLocal=function PSLocal(editor){this.editor=editor;this.config={capabilities:{directory_operations:true,file_operations:true,image_operations:false,upload_operations:true,import_operations:false,user_publish:false,shared_publish:false,user_storage:true},displayName:"Local"}};PSLocal._pluginInfo={name:"PSLocal",version:"2.0",developer:"Douglas Mayle",developer_url:"http://xinha.org",license:"BSD"};PSLocal.prototype.onGenerateOnce=function(){this._prepareBackend()};PSLocal.prototype._showGearsButton=function(){var self=this;var editor=this.editor;editor.config.registerButton({id:"localstorage",tooltip:Xinha._lc("Learn About Local Storage","PSLocal"),image:[_editor_url+editor.config.imgURL+"ed_buttons_main.png",2,8],textMode:true,action:function(){self.learnDialog()}});editor.config.addToolbarElement("localstorage","fullscreen",1);editor._rebuildToolbar()};PSLocal.prototype._prepareBackend=function(){var self=this;var editor=this.editor;if(!this.gears_init){this.gears_init=true;Xinha._loadback(Xinha.getPluginDir("PSLocal")+"/gears_init.js",function(){self._prepareBackend()});return}if(!window.google||!google.gears){this._showGearsButton();return}if(!google.gears.factory.hasPermission){if(!google.gears.factory.getPermission("Xinha",editor.imgURL("/images/xinha-small-icon.gif"),Xinha._lc("Enable Gears in order to use local document storage and configuration.","PSLocal"))){this._showGearsButton();return}}this.workerPool=google.gears.factory.create("beta.workerpool","1.0");this.remoteStorageWorker=this.workerPool.createWorkerFromUrl("http://xinhadocs.org/worker.js");this._registerBackend()};PSLocal.prototype.learnDialog=function(timeWaited){var self=this;var editor=this.editor;if(!this.html){Xinha._getback(Xinha.getPluginDir("PSLocal")+"/dialog.html",function(getback){self.html=getback;self.learnDialog()});return}if(this.dialog){this.dialog.show();return}this.dialog=new Xinha.Dialog(editor,this.html,"PersistentStorage",{width:700,closeOnEscape:true,resizable:true,centered:true,modal:true});var link=this.dialog.getElementById("GearsLink");link.href+=location.href;var button=this.dialog.getElementById("confirm");if(window.google&&google.gears){Xinha._addClass(this.dialog.getElementById("InstallText"),"hidden");button.value=Xinha._lc("Enable","PSLocal");button.onclick=function(){if(confirm(Xinha._lc('This will reload the page, causing you to lose any unsaved work. Press "OK" to reload.',"PSLocal"))){window.location.reload(true)}}}else{Xinha._addClass(this.dialog.getElementById("EnableText"),"hidden");button.value=Xinha._lc("Install","PSLocal");button.onclick=function(){location.href=link.href}}var cancel=this.dialog.getElementById("cancel");cancel.onclick=function(){self.dialog.hide()};this.dialog.show()};PSLocal.prototype._registerBackend=function(timeWaited){var editor=this.editor;var self=this;if(!timeWaited){timeWaited=0}var registerTimeout=10000;if(timeWaited>registerTimeout){return}if(!editor.plugins.PersistentStorage||!editor.plugins.PersistentStorage.instance||!editor.plugins.PersistentStorage.instance.ready){window.setTimeout(function(){self._registerBackend(timeWaited?timeWaited*2:50)},timeWaited?timeWaited:50);return}var PS=editor.plugins.PersistentStorage.instance;var self=this;this.config.thumbURL=this.editor.imgURL("images/tango/32x32/places/folder.png");this.loadDocument({URL:"",name:"config.js",key:"/config.js"},function(json){var userconfig=json?eval("("+json+")"):false;PS.registerBackend("PSLocal",self,self.config,userconfig)})};PSLocal.prototype.loadDocument=function(entry,asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback("")}if(message.body.response){asyncCallback(message.body.response)}else{if(entry.URL){Xinha._getback(entry.URL,function(documentSource){asyncCallback(documentSource)})}else{asyncCallback("")}}};this.workerPool.sendMessage({func:"loadDocument",entry:entry},this.remoteStorageWorker)};PSLocal.prototype.loadData=function(asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback("")}asyncCallback({dirs:message.body.dirs,files:message.body.files})};this.workerPool.sendMessage({func:"loadData"},this.remoteStorageWorker)};PSLocal.prototype.getFilters=function(filedata){var filters=[],paths={};var dirList=filedata.dirs;for(var index=0;index2){pathpart=pathpart.slice(0,pathpart.length-1).join("/")}else{pathpart="/"}var filepart=fileList[index].fullpath.split("/").slice(-1)[0];if(filterPath==pathpart){metadata.push({URL:fileList[index].url,thumbURL:editor.imgURL("images/tango/32x32/mimetypes/text-x-generic.png"),name:filepart,key:fileList[index].fullpath,$type:fileList[index].filetype})}}var dirList=filedata.dirs;for(var index=0;index1&&dirList[index].split("/").length==2}else{var matches=dirList[index].split("/").slice(0,-1).join("/")==filterPath}if(matches){metadata.push({name:dirList[index].split("/").slice(-1),key:dirList[index],$type:"folder"})}}return metadata};PSLocal.prototype.saveDocument=function(parentpath,filename,documentSource,asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback(false)}if(asyncCallback){asyncCallback(message.body.response)}};this.workerPool.sendMessage({func:"saveDocument",parentpath:parentpath,filename:filename,content:documentSource},this.remoteStorageWorker)};PSLocal.prototype.deleteEntry=function(entry,asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback(false)}if(asyncCallback){asyncCallback(message.body.response)}};this.workerPool.sendMessage({func:"deleteEntry",entry:entry},this.remoteStorageWorker)};PSLocal.prototype.makeFolder=function(currentPath,folderName,asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback(false)}if(asyncCallback){asyncCallback(true)}};this.workerPool.sendMessage({func:"makeFolder",parentpath:currentPath,dirname:folderName},this.remoteStorageWorker)};PSLocal.prototype.copyEntry=function(entry,asyncCallback){this.workerPool.onmessage=function(a,b,message){if(!message.body||!message.body.authorized){asyncCallback(false)}if(asyncCallback){asyncCallback(message.body.response,message.body.entry)}};this.workerPool.sendMessage({func:"copyEntry",entry:entry},this.remoteStorageWorker)}})(); \ No newline at end of file +/** + * PSLocal PSLocal.js file. + * This plugin is a Gears based local persistent storage backend. + */ +(function() { +var PSLocal = window.PSLocal = function PSLocal(editor) { + this.editor = editor; + + this.config = { + capabilities: { + directory_operations: true, + file_operations: true, + image_operations: false, + upload_operations: true, + import_operations: false, + user_publish: false, + shared_publish: false, + user_storage: true + }, + displayName: 'Local' + } +} + +PSLocal._pluginInfo = { + name : "PSLocal", + version : "2.0", + developer : "Douglas Mayle", + developer_url : "http://xinha.org", + license : "BSD" +}; + +PSLocal.prototype.onGenerateOnce = function () { + // We use _prepareBackend to asynchronously load the Gears backend. + this._prepareBackend(); +}; + +PSLocal.prototype._showGearsButton = function() { + var self = this; + var editor = this.editor; + + editor.config.registerButton({ + id : 'localstorage', + tooltip : Xinha._lc( 'Learn About Local Storage', 'PSLocal' ), + image : [_editor_url + editor.config.imgURL + 'ed_buttons_main.png',2,8], + textMode : true, + action : function() { self.learnDialog(); } + } + ); + editor.config.addToolbarElement('localstorage', 'fullscreen', 1); + + // Since this is after the editor load, we have to trigger an udate manually... + editor._rebuildToolbar(); +} + +PSLocal.prototype._prepareBackend = function() { + var self = this; + var editor = this.editor; + + if (!this.gears_init) { + this.gears_init = true; + Xinha._loadback(Xinha.getPluginDir("PSLocal") + "/gears_init.js", + function() { + self._prepareBackend(); + }); + return; + } + + if (!window.google || !google.gears) { + // No gears, so no need to register. We'll register a button, however, to + // enable users to learn about the support we offer. + this._showGearsButton(); + return; + } + + if (!google.gears.factory.hasPermission) { + if (!google.gears.factory.getPermission('Xinha', editor.imgURL('/images/xinha-small-icon.gif'), Xinha._lc( 'Enable Gears in order to use local document storage and configuration.', 'PSLocal' ))) { + // The user has denied access to Gears. We'll give them a UI to allow + // them to change their mind. + this._showGearsButton(); + return; + } + } + + this.workerPool = google.gears.factory.create('beta.workerpool', '1.0'); + + this.remoteStorageWorker = this.workerPool.createWorkerFromUrl("http://xinhadocs.org/worker.js"); + + this._registerBackend(); +} + +PSLocal.prototype.learnDialog = function(timeWaited) { + var self = this; + var editor = this.editor; + + if (!this.html) { + Xinha._getback(Xinha.getPluginDir("PSLocal") + "/dialog.html", + function(getback) { + self.html = getback; + self.learnDialog(); + }); + return; + } + + if (this.dialog) { + this.dialog.show(); + return; + } + + this.dialog = new Xinha.Dialog(editor, this.html, "PersistentStorage", + {width: 700, + closeOnEscape: true, + resizable: true, + centered: true, + modal: true + }); + + var link = this.dialog.getElementById('GearsLink'); + + // Tack on our URL so that Google will return here after installation. + link.href += location.href; + + var button = this.dialog.getElementById("confirm"); + if (window.google && google.gears) { + Xinha._addClass(this.dialog.getElementById('InstallText'), 'hidden'); + // The user has gears installed, but has denied us access to it, so we'll + // give them the option to change their mind. + button.value = Xinha._lc('Enable', 'PSLocal'); + + button.onclick = function() { + // The user gave us permission, so we'll reload the page. + if (confirm(Xinha._lc('This will reload the page, causing you to lose any unsaved work. Press "OK" to reload.', 'PSLocal' ))) { + window.location.reload(true); + } + } + } else { + Xinha._addClass(this.dialog.getElementById('EnableText'), 'hidden'); + // Gears isn't installed, so we'll build the dialog to prompt installation. + button.value = Xinha._lc('Install', 'PSLocal'); + + button.onclick = function() { + location.href = link.href; + } + } + + var cancel = this.dialog.getElementById('cancel'); + cancel.onclick = function() { + self.dialog.hide(); + } + + this.dialog.show(); +} + +PSLocal.prototype._registerBackend = function(timeWaited) { + var editor = this.editor; + var self = this; + + if (!timeWaited) { + timeWaited = 0; + } + + // Retry over a period of ten seconds to register. We back off exponentially + // to limit resouce usage in the case of misconfiguration. + var registerTimeout = 10000; + + if (timeWaited > registerTimeout) { + // This is most likely a configuration error. We're loaded and + // PersistentStorage is not. + return; + } + + if (!editor.plugins['PersistentStorage'] || + !editor.plugins['PersistentStorage'].instance || + !editor.plugins['PersistentStorage'].instance.ready) { + + window.setTimeout(function() {self._registerBackend(timeWaited ? timeWaited*2 : 50);}, timeWaited ? timeWaited : 50); + return; + } + var PS = editor.plugins['PersistentStorage'].instance; + var self = this; + + this.config.thumbURL = this.editor.imgURL('images/tango/32x32/places/folder.png'); + this.loadDocument({URL:'', name:'config.js', key:'/config.js'}, function(json) { + var userconfig = json ? eval('(' + json + ')') : false; + PS.registerBackend('PSLocal', self, self.config, userconfig); + }); +} + +PSLocal.prototype.loadDocument = function(entry, asyncCallback) { + + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(''); + } + + if (message.body.response) { + asyncCallback(message.body.response); + } else if (entry.URL) { + Xinha._getback(entry.URL, + function(documentSource) { + asyncCallback(documentSource); + }); + } else { + // Oops, no data :-( + asyncCallback(''); + } + } + + this.workerPool.sendMessage({func: 'loadDocument', entry: entry}, this.remoteStorageWorker); +} + +PSLocal.prototype.loadData = function (asyncCallback) { + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(''); + } + + asyncCallback({dirs: message.body.dirs, files: message.body.files}); + } + + this.workerPool.sendMessage({func: 'loadData'}, this.remoteStorageWorker); +} + +PSLocal.prototype.getFilters = function(filedata) { + // Clear out the previous directory listing. + var filters = [], paths = {}; + var dirList = filedata.dirs; + + for (var index=0; index 2) { + pathpart = pathpart.slice(0,pathpart.length-1).join('/'); + } else { + pathpart = '/'; + } + + var filepart = fileList[index].fullpath.split('/').slice(-1)[0]; + if (filterPath == pathpart) { + metadata.push({ + URL: fileList[index].url, + thumbURL: editor.imgURL('images/tango/32x32/mimetypes/text-x-generic.png'), + name: filepart, + key: fileList[index].fullpath, + $type: fileList[index].filetype + }); + } + } + + var dirList = filedata.dirs; + + for (var index=0; index 1 && dirList[index].split('/').length == 2; + } else { + // Chop the last component of the directory and compare against the filter. + var matches = dirList[index].split('/').slice(0,-1).join('/') == filterPath; + } + if (matches) { + metadata.push({ + name: dirList[index].split('/').slice(-1), + key: dirList[index], + $type: 'folder' + }); + } + } + + return metadata; +} + +PSLocal.prototype.saveDocument = function(parentpath, filename, documentSource, asyncCallback) { + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(false); + } + + if (asyncCallback) { + asyncCallback(message.body.response); + } + } + + this.workerPool.sendMessage({func: 'saveDocument', parentpath: parentpath, filename: filename, content:documentSource}, this.remoteStorageWorker); +} +PSLocal.prototype.deleteEntry = function(entry, asyncCallback) { + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(false); + } + + if (asyncCallback) { + asyncCallback(message.body.response); + } + } + + this.workerPool.sendMessage({func: 'deleteEntry', entry: entry}, this.remoteStorageWorker); +} + +PSLocal.prototype.makeFolder = function(currentPath, folderName, asyncCallback) { + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(false); + } + + if (asyncCallback) { + asyncCallback(true); + } + } + + this.workerPool.sendMessage({func: 'makeFolder', parentpath: currentPath, dirname: folderName}, this.remoteStorageWorker); +} + +PSLocal.prototype.copyEntry = function(entry, asyncCallback) { + this.workerPool.onmessage = function(a, b, message) { + if (!message.body || !message.body.authorized) { + // Fail + asyncCallback(false); + } + + if (asyncCallback) { + asyncCallback(message.body.response, message.body.entry); + } + } + + this.workerPool.sendMessage({func: 'copyEntry', entry: entry}, this.remoteStorageWorker); +} + +})(); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/gears_init.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/gears_init.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/gears_init.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSLocal/gears_init.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,86 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -(function(){if(window.google&&google.gears){return}var a=null;if(typeof GearsFactory!="undefined"){a=new GearsFactory()}else{try{a=new ActiveXObject("Gears.Factory");if(a.getBuildInfo().indexOf("ie_mobile")!=-1){a.privateSetGlobalObject(this)}}catch(b){if((typeof navigator.mimeTypes!="undefined")&&navigator.mimeTypes["application/x-googlegears"]){a=document.createElement("object");a.style.display="none";a.width=0;a.height=0;a.type="application/x-googlegears";document.documentElement.appendChild(a)}}}if(!a){return}if(!window.google){google={}}if(!google.gears){google.gears={factory:a}}})(); \ No newline at end of file +// Copyright 2007, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Sets up google.gears.*, which is *the only* supported way to access Gears. +// +// Circumvent this file at your own risk! +// +// In the future, Gears may automatically define google.gears.* without this +// file. Gears may use these objects to transparently fix bugs and compatibility +// issues. Applications that use the code below will continue to work seamlessly +// when that happens. + +(function() { + // We are already defined. Hooray! + if (window.google && google.gears) { + return; + } + + var factory = null; + + // Firefox + if (typeof GearsFactory != 'undefined') { + factory = new GearsFactory(); + } else { + // IE + try { + factory = new ActiveXObject('Gears.Factory'); + // privateSetGlobalObject is only required and supported on WinCE. + if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { + factory.privateSetGlobalObject(this); + } + } catch (e) { + // Safari + if ((typeof navigator.mimeTypes != 'undefined') + && navigator.mimeTypes["application/x-googlegears"]) { + factory = document.createElement("object"); + factory.style.display = "none"; + factory.width = 0; + factory.height = 0; + factory.type = "application/x-googlegears"; + document.documentElement.appendChild(factory); + } + } + } + + // *Do not* define any objects if Gears is not installed. This mimics the + // behavior of Gears defining the objects in the future. + if (!factory) { + return; + } + + // Now set up the objects, being careful not to overwrite anything. + // + // Note: In Internet Explorer for Windows Mobile, you can't add properties to + // the window object. However, global objects are automatically added as + // properties of the window object in all browsers. + if (!window.google) { + google = {}; + } + + if (!google.gears) { + google.gears = {factory: factory}; + } +})(); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSServer/PSServer.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSServer/PSServer.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSServer/PSServer.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PSServer/PSServer.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,282 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -(function(){var PSServer=window.PSServer=function PSServer(editor){this.editor=editor};PSServer._pluginInfo={name:"PSServer",version:"2.0",developer:"Douglas Mayle",developer_url:"http://xinha.org",license:"MIT"};PSServer.prototype.onGenerateOnce=function(){this._loadConfig()};PSServer.prototype._loadConfig=function(){var self=this;if(!this._serverConfig){Xinha._getback(Xinha.getPluginDir("PSServer")+"/config.inc.php",function(config){self._serverConfig=eval("("+config+")");self._serverConfig.user_affinity=20;self._serverConfig.displayName="Server";self._loadConfig()});return}this._registerBackend()};PSServer.prototype._registerBackend=function(timeWaited){var editor=this.editor;var self=this;if(!timeWaited){timeWaited=0}var registerTimeout=10000;if(timeWaited>registerTimeout){return}if(!editor.plugins.PersistentStorage||!editor.plugins.PersistentStorage.instance||!editor.plugins.PersistentStorage.instance.ready){window.setTimeout(function(){self._registerBackend(timeWaited?timeWaited*2:50)},timeWaited?timeWaited:50);return}editor.plugins.PersistentStorage.instance.registerBackend("PSServer",this,this._serverConfig)};PSServer.prototype.loadData=function(asyncCallback){var self=this;Xinha._getback(Xinha.getPluginDir("PSServer")+"/backend.php?directory&listing",function(json){self.dirTree=eval("("+json+")");asyncCallback(self.dirTree)})};var treeRecurse=function treeRecurse(tree,callback,root){if(typeof root=="undefined"){root="/";callback("/","",tree)}for(var key in tree){callback(root,key,tree[key]);if(tree[key].$type=="folder"){treeRecurse(tree[key],callback,root+key+"/")}}};PSServer.prototype.getFilters=function(dirTree){var filters=[];treeRecurse(dirTree,function(path,key,value){if(value.$type!="folder"){return}var filePath=key.length?path+key+"/":path;var filePathDisplay=key.length?path+key+"/":path;if(filePathDisplay.length>1){filePathDisplay=filePathDisplay.substring(0,filePathDisplay.length-1)}filters.push({value:filePath,display:filePathDisplay})});return filters};PSServer.prototype.loadDocument=function(entry,asyncCallback){Xinha._getback(entry.URL,function(documentSource){asyncCallback(documentSource)})};PSServer.prototype.getMetadata=function(dirTree,pathFilter,typeFilter){var editor=this.editor;var self=this;var metadata=[];var typeKeys={};for(var index=0;index registerTimeout) { + // This is most likely a configuration error. We're loaded and + // PersistentStorage is not. + return; + } + + if (!editor.plugins['PersistentStorage'] || + !editor.plugins['PersistentStorage'].instance || + !editor.plugins['PersistentStorage'].instance.ready) { + + window.setTimeout(function() {self._registerBackend(timeWaited ? timeWaited*2 : 50);}, timeWaited ? timeWaited : 50); + return; + } + editor.plugins['PersistentStorage'].instance.registerBackend('PSServer', this, this._serverConfig); +} + +PSServer.prototype.loadData = function (asyncCallback) { + var self = this; + Xinha._getback(Xinha.getPluginDir("PSServer") + "/backend.php?directory&listing", + function(json) { + self.dirTree = eval('(' + json + ')'); + asyncCallback(self.dirTree); + }); +} + +var treeRecurse = function treeRecurse(tree, callback, root) { + if (typeof root == 'undefined') { + root = '/'; + callback('/', '', tree); + } + + for (var key in tree) { + callback(root, key, tree[key]); + + if (tree[key].$type == 'folder') { + treeRecurse(tree[key], callback, root + key + '/'); + } + } +}; + +PSServer.prototype.getFilters = function(dirTree) { + // Clear out the previous directory listing. + var filters = []; + + treeRecurse(dirTree, function(path, key, value) { + if (value.$type != 'folder') { + return; + } + + var filePath = key.length ? path + key + '/' : path; + var filePathDisplay = key.length ? path + key + '/' : path; + if (filePathDisplay.length > 1) { + filePathDisplay = filePathDisplay.substring(0, filePathDisplay.length-1); + } + filters.push({ + value: filePath, + display: filePathDisplay + }); + }); + + return filters; +} + +PSServer.prototype.loadDocument = function(entry, asyncCallback) { + + Xinha._getback(entry.URL, + function(documentSource) { + asyncCallback(documentSource); + }); +} +PSServer.prototype.getMetadata = function(dirTree, pathFilter, typeFilter) { + var editor = this.editor; + var self = this; + + var metadata = []; + + var typeKeys = {}; + for (var index=0; index + // File: + // + // + var iframeID = dialog.createId('importFrame'); + + var form = document.createElement('form'); + form.setAttribute('enctype', 'multipart/form-data'); + form.setAttribute('method', 'post'); + form.setAttribute('action', Xinha.getPluginDir("PSServer") + "/backend.php?upload&replace=true&"); + + var fileentry = document.createElement('input'); + fileentry.setAttribute('type', 'file'); + fileentry.setAttribute('name', 'filedata'); + + var submitbutton = document.createElement('input'); + submitbutton.setAttribute('type', 'submit'); + submitbutton.setAttribute('value',Xinha._lc('Import', 'PSServer')); + + var filetext = document.createTextNode(Xinha._lc('File: ', 'PSServer')); + filetext = form.appendChild(filetext); + + fileentry = form.appendChild(fileentry); + + submitbutton = form.appendChild(submitbutton); + + form = element.appendChild(form); + form.setAttribute('target', iframeID); + + // The iframe must be added to the document after the form has been, or the targeting fails. + var iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'about:blank'); + iframe.style.display = 'none'; + iframe.id = iframe.name = iframeID; + iframe.onload = function() { + var docCheck = iframe.contentDocument || iframe.contentWindow; + if (docCheck.location.href == 'about:blank') { + return; + } + // What to do on import? Add an entry to the UI, I guess... + alert('Add entry here'); + } + iframe = element.appendChild(iframe); + +} + +PSServer.prototype.saveDocument = function(path, filename, documentSource, asyncCallback) { + Xinha._postback(Xinha.getPluginDir("PSServer") + "/backend.php?upload&replace=true&filedata=" + escape(documentSource)+"&filename="+escape(path + filename), + null, + function(response) { + asyncCallback(true); + }, + function(response) { + asyncCallback(false); + }); +} + +PSServer.prototype.makeFolder = function(currentPath, folderName, asyncCallback) { + Xinha._postback(Xinha.getPluginDir("PSServer") + "/backend.php?directory&create&dirname="+escape(currentPath + '/' + folderName), + null, + function(response) { + asyncCallback(true); + }, + function(response) { + asyncCallback(false); + }); +} + +PSServer.prototype.deleteEntry = function(entry, asyncCallback) { + Xinha._postback(Xinha.getPluginDir("PSServer") + "/backend.php?file&delete&filename="+escape(entry.key), + null, + function(response) { + asyncCallback(true); + }, + function(response) { + asyncCallback(false); + }); +} + +PSServer.prototype.moveEntry = function(entry, container, asyncCallback) { + Xinha._postback(Xinha.getPluginDir("PSServer") + "/backend.php?file&rename&filename="+escape(entry.key)+'&newname='+escape(container.key + '/' + entry.name), + null, + function(json) { + asyncCallback(true); + }, + function(json) { + asyncCallback(false); + }); +} + +PSServer.prototype.copyEntry = function(entry, asyncCallback) { + Xinha._postback(Xinha.getPluginDir("PSServer") + "/backend.php?file©&filename="+escape(entry.key), + null, + function(json) { + var newentry = eval('(' + json + ')'); + asyncCallback(true, newentry); + }, + function(json) { + var newentry = eval('(' + json + ')'); + asyncCallback(false, newentry); + }); +} + +})(); Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PasteText/PasteText.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PasteText/PasteText.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PasteText/PasteText.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PasteText/PasteText.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,140 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -function PasteText(c){this.editor=c;var a=c.config;var b=this;a.registerButton({id:"pastetext",tooltip:this._lc("Paste as Plain Text"),image:c.imgURL("ed_paste_text.gif","PasteText"),textMode:false,action:function(){b.show()}});a.addToolbarElement("pastetext",["paste","killword"],1)}PasteText._pluginInfo={name:"PasteText",version:"1.2",developer:"Michael Harris",developer_url:"http://www.jonesadvisorygroup.com",c_owner:"Jones Advisory Group",sponsor:"Jones International University",sponsor_url:"http://www.jonesinternational.edu",license:"htmlArea"};PasteText.prototype._lc=function(a){return Xinha._lc(a,"PasteText")};Xinha.Config.prototype.PasteText={showParagraphOption:true,newParagraphDefault:true};PasteText.prototype.onGenerateOnce=function(){var a=PasteText;if(a.loading){return}a.loading=true;Xinha._getback(Xinha.getPluginDir("PasteText")+"/popups/paste_text.html",function(b){a.html=b})};PasteText.prototype._prepareDialog=function(){var a=this;var b=this.editor;var a=this;this.dialog=new Xinha.Dialog(b,PasteText.html,"PasteText",{width:350});this.dialog.getElementById("ok").onclick=function(){a.apply()};this.dialog.getElementById("cancel").onclick=function(){a.dialog.hide()};if(b.config.PasteText.showParagraphOption){this.dialog.getElementById("paragraphOption").style.display=""}if(b.config.PasteText.newParagraphDefault){this.dialog.getElementById("insertParagraphs").checked=true}this.dialog.onresize=function(){this.getElementById("inputArea").style.height=parseInt(this.height,10)-this.getElementById("h1").offsetHeight-this.getElementById("buttons").offsetHeight-parseInt(this.rootElem.style.paddingBottom,10)+"px";this.getElementById("inputArea").style.width=(this.width-2)+"px"}};PasteText.prototype.show=function(){if(!this.dialog){this._prepareDialog()}var a={inputArea:""};this.dialog.show(a);this.dialog.onresize();this.dialog.getElementById("inputArea").focus()};PasteText.prototype.apply=function(){var a=this.dialog.hide();var b=a.inputArea;var c=a.insertParagraphs;b=b.replace(//g,">");if(a.insertParagraphs){b=b.replace(/\t/g,"    ");b=b.replace(/\n/g,"

");b="

"+b+"

";if(Xinha.is_ie){this.editor.insertHTML(b)}else{this.editor.execCommand("inserthtml",false,b)}}else{b=b.replace(/\n/g,"
");this.editor.insertHTML(b)}}; \ No newline at end of file +// Paste Plain Text plugin for Xinha + +// Distributed under the same terms as Xinha itself. +// This notice MUST stay intact for use (see license.txt). + +function PasteText(editor) { + this.editor = editor; + var cfg = editor.config; + var self = this; + + cfg.registerButton({ + id : "pastetext", + tooltip : this._lc("Paste as Plain Text"), + image : editor.imgURL("ed_paste_text.gif", "PasteText"), + textMode : false, + action : function() { self.show(); } + }); + + cfg.addToolbarElement("pastetext", ["paste", "killword"], 1); +} + +PasteText._pluginInfo = { + name : "PasteText", + version : "1.2", + developer : "Michael Harris", + developer_url : "http://www.jonesadvisorygroup.com", + c_owner : "Jones Advisory Group", + sponsor : "Jones International University", + sponsor_url : "http://www.jonesinternational.edu", + license : "htmlArea" +}; + +PasteText.prototype._lc = function(string) { + return Xinha._lc(string, 'PasteText'); +}; + +Xinha.Config.prototype.PasteText = +{ + showParagraphOption : true, + newParagraphDefault :true +} + +PasteText.prototype.onGenerateOnce = function() +{ + var self = PasteText; + if (self.loading) return; + self.loading = true; + Xinha._getback(Xinha.getPluginDir("PasteText") + '/popups/paste_text.html', function(getback) { self.html = getback;}); +}; + +PasteText.prototype._prepareDialog = function() +{ + var self = this; + var editor = this.editor; + + var self = this; + +/// Now we have everything we need, so we can build the dialog. + this.dialog = new Xinha.Dialog(editor, PasteText.html, 'PasteText',{width:350}) + + // Connect the OK and Cancel buttons + this.dialog.getElementById('ok').onclick = function() {self.apply();} + + this.dialog.getElementById('cancel').onclick = function() { self.dialog.hide()}; + + // do some tweaking + if (editor.config.PasteText.showParagraphOption) + { + this.dialog.getElementById("paragraphOption").style.display = ""; + } + if (editor.config.PasteText.newParagraphDefault) + { + this.dialog.getElementById("insertParagraphs").checked = true; + } + + // we can setup a custom function that cares for sizes etc. when the dialog is resized + this.dialog.onresize = function () + { + this.getElementById("inputArea").style.height = + parseInt(this.height,10) // the actual height of the dialog + - this.getElementById('h1').offsetHeight // the title bar + - this.getElementById('buttons').offsetHeight // the buttons + - parseInt(this.rootElem.style.paddingBottom,10) // we have a padding at the bottom, gotta take this into acount + + 'px'; // don't forget this ;) + + this.getElementById("inputArea").style.width =(this.width - 2) + 'px'; // and the width + + } +}; + +PasteText.prototype.show = function() +{ + if (!this.dialog) this._prepareDialog(); + + // here we can pass values to the dialog + // each property pair consists of the "name" of the input we want to populate, and the value to be set + var inputs = + { + inputArea : '' // we want the textarea always to be empty on showing + } + // now calling the show method of the Xinha.Dialog object to set the values and show the actual dialog + this.dialog.show(inputs); + + // Init the sizes (only if we have set up the custom resize function) + this.dialog.onresize(); + + this.dialog.getElementById("inputArea").focus(); +}; + +// and finally ... take some action +PasteText.prototype.apply = function() +{ + // the hide method of the dialog object returns the values of the inputs AND hides the dialog + // could also use this.dialog.getValues() here and hide it at the end + var returnValues = this.dialog.hide(); + + var html = returnValues.inputArea; + var insertParagraphs = returnValues.insertParagraphs; + html = html.replace(//g, ">"); + if ( returnValues.insertParagraphs) + { + html = html.replace(/\t/g,"    "); + html = html.replace(/\n/g,"

"); + html="

" + html + "

"; + if (Xinha.is_ie) + { + this.editor.insertHTML(html); + } + else + { + this.editor.execCommand("inserthtml",false,html); + } + } + else + { + html = html.replace(/\n/g,"
"); + this.editor.insertHTML(html); + } +}; \ No newline at end of file Index: openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PersistentStorage/PersistentStorage.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PersistentStorage/PersistentStorage.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PersistentStorage/PersistentStorage.js 27 Mar 2009 08:20:44 -0000 1.2 +++ openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/PersistentStorage/PersistentStorage.js 23 May 2010 12:00:02 -0000 1.3 @@ -1,3 +1,1135 @@ -/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */ -/* This file is part of version 0.96beta2 released Fri, 20 Mar 2009 11:01:14 +0100 */ -(function(e){var c=window.PersistentStorage=function(h){this.editor=h;var g=this};c._pluginInfo={name:"PersistentStorage",version:"1.0",developer:"Douglas Mayle",developer_url:"http://douglas.mayle.org",license:"BSD"};c.prototype._backends={};c.prototype._userconfigs=[];c.prototype._activeBackend="";c.prototype._typeFilter="";c.prototype._viewType="thumbnail";c.prototype.onGenerateOnce=function(){this._prepareDialog()};function d(g,h){var i=new RegExp(" ?"+h+" ?");if(!i.test(g.className)){g.className+=" "+h}}function f(g,h){var i=new RegExp(" ?"+h+" ?");if(i.test(g.className)){g.className=g.className.replace(i," ")}}function a(g,h){var i=new RegExp(" ?"+h+" ?");if(i.test(g.className)){g.className=g.className.replace(i," ")}else{g.className+=" "+h}}c.prototype._registerDocumentUI=function(){if(this._documentEnabled){return}this._documentEnabled=true;var g=this;var h=this.editor;h.config.registerButton({id:"newdocument",tooltip:b._lc("New Document","PersistentStorage"),image:[_editor_url+h.config.imgURL+"ed_buttons_main.png",0,5],textMode:true,action:function(){g.newDocument()}});h.config.registerButton({id:"opendocument",tooltip:b._lc("Open Document","PersistentStorage"),image:[_editor_url+h.config.imgURL+"ed_buttons_main.png",1,5],textMode:true,action:function(){g.openDialog()}});h.config.registerButton({id:"savedocument",tooltip:b._lc("Save Document","PersistentStorage"),image:[_editor_url+h.config.imgURL+"ed_buttons_main.png",9,1],textMode:true,action:function(){g.saveDialog()}});h.config.addToolbarElement("newdocument","fullscreen",1);h.config.addToolbarElement("opendocument","newdocument",1);h.config.addToolbarElement("savedocument","opendocument",1);h._rebuildToolbar()};c.prototype.registerBackend=function(h,j,g,i){this._backends[h]={module:j,config:g,name:h};if(!this._activeBackend){this.setBackend(h)}if(g.capabilities.upload_operations&&g.capabilities.file_operations){this._registerDocumentUI()}if(i){this._userconfigs.push(i);this.configureUser()}this.updatePlacesDisplay()};c.prototype.configureUser=function(){var g=this;for(var i=0;i + * @version 1.0 + */ + +/** + * The global namespace + * @name window + */ +(function($) { +/** + * @name PersistentStorage + * @class Provides an interface for persistant storage options to the user. + * @param editor A reference to the Xinha Editor this plugin instance is attached to. + */ +var PersistentStorage = window.PersistentStorage = function (editor) { + /** + * @memberOf Xinha + */ + this.editor = editor; + var self = this; +} + +/** + * Plugin Metadata + * @namespace + * @static + */ +PersistentStorage._pluginInfo = { + /** Plugin name */ + name : "PersistentStorage", + /** Plugin version */ + version : "1.0", + /** Plugin author */ + developer : "Douglas Mayle", + /** Plugin author's website */ + developer_url : "http://douglas.mayle.org", + /** Plugin license */ + license : "BSD" +}; + +/** + * The list of backend modules registered with this instance. + */ +PersistentStorage.prototype._backends = {}; + +/** + * The list of user config files received from backends. + */ +PersistentStorage.prototype._userconfigs = []; + +/** + * The name of the currently active backend. + */ +PersistentStorage.prototype._activeBackend = ''; + +/** + * The value of the type filter that's currently in effect. + */ +PersistentStorage.prototype._typeFilter = ''; + +/** + * The currently displayed view type. + */ +PersistentStorage.prototype._viewType = 'thumbnail'; + +/** + * On Xinha activation, this get's called so that we can prepare any resources + * we need to function. + */ +PersistentStorage.prototype.onGenerateOnce = function () { + // We use _prepareDialog to asynchronously load the dialog markup and then + // perform necessary processing. + this._prepareDialog(); +}; + +function addClass(element, className) { + var classRegex = new RegExp(' ?' + className + ' ?'); + + if (!classRegex.test(element.className)) { + element.className += ' ' + className; + } +} + +function removeClass(element, className) { + var classRegex = new RegExp(' ?' + className + ' ?'); + + if (classRegex.test(element.className)) { + element.className = element.className.replace(classRegex, ' '); + } +} + +function toggleClass(element, className) { + var classRegex = new RegExp(' ?' + className + ' ?'); + + if (classRegex.test(element.className)) { + element.className = element.className.replace(classRegex, ' '); + } else { + element.className += ' ' + className; + } +} + +/** + * Once we're sure we have a backend that supports document functionality, + * we'll load the interface that exposes it. + */ +PersistentStorage.prototype._registerDocumentUI = function () { + if (this._documentEnabled) { + // No need to repeated rebuild the UI. + return; + } + + this._documentEnabled = true; + var self = this; + + var editor = this.editor; + + editor.config.registerButton({ + id : 'newdocument', + tooltip : Xinha._lc( 'New Document', 'PersistentStorage' ), + image : [_editor_url + editor.config.imgURL + 'ed_buttons_main.png',0,5], + textMode : true, + action : function() { self.newDocument(); } + } + ); + editor.config.registerButton({ + id : 'opendocument', + tooltip : Xinha._lc( 'Open Document', 'PersistentStorage' ), + image : [_editor_url + editor.config.imgURL + 'ed_buttons_main.png',1,5], + textMode : true, + action : function() { self.openDialog(); } + } + ); + editor.config.registerButton({ + id : 'savedocument', + tooltip : Xinha._lc( 'Save Document', 'PersistentStorage' ), + image : [_editor_url + editor.config.imgURL + 'ed_buttons_main.png',9,1], + textMode : true, + action : function() { self.saveDialog(); } + } + ); + editor.config.addToolbarElement('newdocument', 'fullscreen', 1); + editor.config.addToolbarElement('opendocument', 'newdocument', 1); + editor.config.addToolbarElement('savedocument', 'opendocument', 1); + + // Since this is after the editor load, we have to trigger an udate manually... + editor._rebuildToolbar(); +}; + +/** + * Backend storage plugins should call this method so that they can be exposed + * to the user. Because of possible quirks in plugin loading, you should use + * the following example code when registering. + * @param name The name of the module + * @param module The module instance + * @param config Configuration information that tells us about the module + * @param user_config AN object representing the user configuration loaded from + * this module. + * @example + + * PSBackend.prototype.onGenerateOnce = function () { + * // Register with the Persistent Storage plugin. + * this._registerBackend(); + * }; + * PSBackend.prototype._registerBackend = function(timeWaited) { + * var editor = this.editor; + * var self = this; + * + * if (!timeWaited) { + * timeWaited = 0; + * } + * + * // Retry over a period of ten seconds to register. We back off exponentially + * // to limit resouce usage in the case of misconfiguration. + * var registerTimeout = 10000; + * + * if (timeWaited > registerTimeout) { + * // This is most likely a configuration error. We're loaded and + * // PersistentStorage is not. + * return; + * } + * + * if (!editor.plugins['PersistentStorage'] || + * !editor.plugins['PersistentStorage'].instance || + * !editor.plugins['PersistentStorage'].instance.ready) { + * + * window.setTimeout(function() { + * self._registerBackend(timeWaited ? timeWaited*2 : 50); + * }, timeWaited ? timeWaited : 50); + * + * return; + * } + * var PS = editor.plugins['PersistentStorage'].instance; + * + * // Support user configuration. This loading should be moved into PersistentStorage... + * this.loadDocument({URL:'', name:'config.js', key:'/config.js'}, function(json) { + * var userconfig = json ? eval('(' + json + ')') : false; + * PS.registerBackend('PSLocal', self, self.config, userconfig); + * }); + */ +PersistentStorage.prototype.registerBackend = function (name, module, config, user_config) { + this._backends[name] = {module: module, config: config, name: name}; + + // TODO I'd like something more than just whoever calls back first wins for ordering. + if (!this._activeBackend) { + this.setBackend(name); + } + + if (config.capabilities.upload_operations && + config.capabilities.file_operations) { + this._registerDocumentUI(); + } + + // Handle user configuration + if (user_config) { + this._userconfigs.push(user_config); + this.configureUser(); + } + + this.updatePlacesDisplay(); +} + +/** + * Go through the list of user configs and reconfigure Xinha. + */ +PersistentStorage.prototype.configureUser = function () { + // Temp code does not handle user affinity + var self = this; + for (var index=0; index # # *(Delete) * *(Delete) * *(Delete) * *(Delete) * # * + * * # \/ # # *********** *********** *********** *********** # * + * * # Gears # # # * + * * # # ############################################################## * + * * # # * + * * # # *Import-(Collapsed)******************************************* * + * * # # * + * * # # #File Name -or- File Details################################## * + * * # # # # * + * * # # # # * + * * # # # # * + * * # # # # * + * * ######### ############################################################## * + * * * + * **************************************************************************** + */ + +PersistentStorage.prototype.showDialog = function (options) { + // Create a reference to this PS instance to allow for asynchronous + // continuation (if we're not ready.) + var self = this; + + if (!this.ready) { + window.setTimeout(function() {self.showDialog(options);}, 80); + return; + } + + // We hide and show the various elements of the dialog depending on usage. + removeClass(this.dialog.getElementById("WWW"), 'hidden'); + addClass(this.dialog.getElementById("namefield"), 'hidden'); + addClass(this.dialog.getElementById("placeWww"), 'hidden'); + addClass(this.dialog.getElementById("placeBackend"), 'hidden'); + + switch (options.styleFor) { + case 'link': + removeClass(this.dialog.getElementById("placeWww"), 'hidden'); + this.updatePlacesDisplay('shared_publish'); + break; + case 'insertion': + removeClass(this.dialog.getElementById("placeBackend"), 'hidden'); + this.updatePlacesDisplay('shared_publish'); + break; + case 'documentsave': + addClass(this.dialog.getElementById("WWW"), 'hidden'); + removeClass(this.dialog.getElementById("namefield"), 'hidden'); + removeClass(this.dialog.getElementById("placeBackend"), 'hidden'); + this.updatePlacesDisplay('file_operations'); + break; + case 'documentload': + addClass(this.dialog.getElementById("WWW"), 'hidden'); + removeClass(this.dialog.getElementById("placeBackend"), 'hidden'); + this.updatePlacesDisplay('file_operations'); + break; + } + + var directories = this.dialog.getElementById("filters"); + var fileBrowser = this.dialog.getElementById("fileList"); + + // Store the type filter so that view updates will correctly filter the contents. + this._typeFilter = options.typeFilter; + + var module = this._backends[this._activeBackend].module; + + this.updateFileBrowser(); +} + +/** + * Take the list of filters and build the contents of the select element. + * @param filters {Filter[]} An array of filter choices to display to the user. + * @param filters[n].value The unique key that represents this filter to the backend. + * @param filters[n].display {String} A text string to display to the user to + * represent the given filter. + * @param select {HTMLElement} The select node to update. + */ +PersistentStorage.prototype.displayFilters = function(filters, viewFilter) { + // Clear out the previous directory listing. + var select = this.dialog.getElementById("filters"); + while (select.lastChild) { + select.removeChild(select.lastChild); + } + + // For each element in the array, we extract out the display text and the + // value and put them into an option element to add to the select element. + for (var index=0; index