/* * e107 website system * * Copyright (C) 2008-2009 e107 Inc (e107.org) * Released under the terms and conditions of the * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * e107 Javascript API * * $Source: /cvs_backup/e107_0.8/e107_files/jslib/e107.js.php,v $ * $Revision: 1.38 $ * $Date: 2009-11-18 01:04:43 $ * $Author: e107coders $ * */ var e107API = { Version: '1.0.1', ServerVersion: '0.8.1' } /* * Old stuff * FIXME ASAP */ var nowLocal = new Date(); /* time at very beginning of js execution */ var localTime = Math.floor(nowLocal.getTime()/1000); /* time, in ms -- recorded at top of jscript */ /** * NOTE: if serverDelta is needed for js functions, you must pull it from * the cookie (as calculated during a previous page load!) * The value calculated in SyncWithServerTime is not known until after the * entire page has been processed. */ function SyncWithServerTime(serverTime) { if (serverTime) { /* update time difference cookie */ var serverDelta=Math.floor(localTime-serverTime); document.cookie = 'e107_tdOffset='+serverDelta+'; path=/'; document.cookie = 'e107_tdSetTime='+(localTime-serverDelta)+'; path=/'; /* server time when set */ } var tzCookie = 'e107_tzOffset='; // if (document.cookie.indexOf(tzCookie) < 0) { /* set if not already set */ var timezoneOffset = nowLocal.getTimezoneOffset(); /* client-to-GMT in minutes */ document.cookie = tzCookie + timezoneOffset+'; path=/'; // } } // ------------------------------------------------------------------- /** * Prototype Xtensions * @author Simon Martins * @copyright (c) 2008 Netatoo SARL * @license MIT License * * @desc Retrieve the browser version */ (function() { var nav = navigator; var userAgent = ua = navigator.userAgent; var v = nav.appVersion; var version = parseFloat(v); e107API.Browser = { IE : (Prototype.Browser.IE) ? parseFloat(v.split("MSIE ")[1]) || 0 : 0, Firefox : (Prototype.Browser.Gecko) ? parseFloat(ua.split("Firefox/")[1]) || 0 : 0, Camino : (Prototype.Browser.Gecko) ? parseFloat(ua.split("Camino/")[1]) || 0 : 0, Flock : (Prototype.Browser.Gecko) ? parseFloat(ua.split("Flock/")[1]) || 0 : 0, Opera : (Prototype.Browser.Opera) ? version : 0, AIR : (ua.indexOf("AdobeAIR") >= 0) ? 1 : 0, Mozilla : (Prototype.Browser.Gecko || !this.Khtml) ? version : 0, Khtml : (v.indexOf("Konqueror") >= 0 && this.safari) ? version : 0, Safari : (function() { var safari = Math.max(v.indexOf("WebKit"), v.indexOf("Safari"), 0); return (safari) ? ( parseFloat(v.split("Version/")[1]) || ( ( parseFloat(v.substr(safari+7)) >= 419.3 ) ? 3 : 2 ) || 2 ) : 0; })() }; })(); // ------------------------------------------------------------------- /** * Main registry object */ var e107Registry = { //System Path Path: { e_IMAGE: '', SITEURL: '', SITEURLBASE: '', e_HTTP: '', e_IMAGE_PACK: '', e_PLUGIN: '', e_FILE: '', e_ADMIN: '', e_THEME: '', THEME: '' }, //Language Constants Lan: {}, //Global Templates Template: { Core: { //e107Helper#duplicateHTML method duplicateHTML: '
' + '#{duplicateBody}' + '' + '
' }, //e107Helper#LoadingStatus class CoreLoading: { template: '
' + '

' + '#{JSLAN_CORE_LOADING_ALT}' + '
#{JSLAN_CORE_LOADING_TEXT}' + '

' + '
' } }, //Cache Cache: new Hash, //Cached vars CachedVars: new Hash, //Global Preferences Pref: { Core: { zIndex: 5 //base system z-index } } } // ------------------------------------------------------------------- /** * Global helpers - server side clonings */ var isset = function(varname) { return !Object.isUndefined(varname); } var varset = function(varname) { if(Object.isUndefined(varname)) { return (Object.isUndefined(arguments[1]) ? null : arguments[1]); } return varname; } var varsettrue = function(varname) { if(Object.isUndefined(varname) || !varname) { return (Object.isUndefined(arguments[1]) ? null : arguments[1]); } return varname; } var cachevars = function(varname, data) { e107Registry.CachedVars.set(data) } var getcachedvars = function(varname, destroy) { if(destroy) return clearcachedvars(varname); return e107Registry.CachedVars.get(varname); } var clearcachedvars = function(varname) { return e107Registry.CachedVars.unset(varname); } var echo = Prototype.emptyFunction, print_a = Prototype.emptyFunction, var_dump = Prototype.emptyFunction; // ------------------------------------------------------------------- /** * e107 custom events */ var e107Event = { fire: function(eventName, memo, element) { if ((!element || element == document) && !document.createEvent) { element = $(document.documentElement); } else element = $(element) || document; memo = memo || {}; return element.fire('e107:' + eventName, memo); }, observe: function(eventName, handler, element) { element = $(element) || document; element.observe('e107:' + eventName, handler); return this; }, stopObserving: function(eventName, handler, element) { element = $(element) || document; element.stopObserving('e107:' + eventName, handler); return this; }, //Server side - e107_event aliases trigger: function(eventName, memo, element) { this.fire(eventName, memo, element); }, register: function(eventName, handler, element) { this.observe(eventName, handler, element); }, unregister: function(eventName, handler, element) { this.stopObserving(eventName, handler, element); } } /** * EventManager * Prototype Xtensions http://www.prototypextensions.com * * @desc Create custom events on your own class */ var e107EventManager = Class.create({ /** * Initialize * * @desc Set scope and events hash */ initialize: function(scope) { this.scope = scope; this.events = new Hash(); }, /** * addListener * * @desc Add event observer */ addObserver: function(name) { return this.events.set(name, new Hash()); }, /** * observe * * @desc Add a callback for listener 'name' */ observe: function(name, callback) { var observers = this.events.get(name); if(!observers) observers = this.addObserver(name); if(!Object.isFunction(callback)) { //throw('e107EventManager.observe : callback must be an js function'); //surpess error return this; } var i = this.events.get(name).keys().length; observers.set(i, callback.bind(this.scope)); return this; }, /** * stopObserving (class improvements) * * @desc Remove callback for listener 'name' */ stopObserving: function(name, callback) { var observers = this.events.get(name); if(!observers) return this; observers.each( function(pair) { if(pair.value == callback) { observers.unset(pair.key); $break; } }); return this; }, /** * notify * * @desc Launch all callbacks for listener 'name' */ notify: function(name) { var observers = this.events.get(name); //console.log('notifying ' + name); if(observers) { var args = $A(arguments).slice(1); //Fix - preserve order observers.keys().sort().each( function(key) { var callback = observers.get(key); if(Object.isFunction(callback)) { callback.apply(this.scope, args); } }); } return this; } }); // ------------------------------------------------------------------- /** * Base e107 Object - interacts with the registry object */ var e107Base = { setPath: function(path_object) { e107Registry.Path = Object.extend( this.getPathVars(), path_object || {}); return this; }, addPath: function(path_var, path) { //don't allow overwrite if(!e107Registry.Path[path_var]) e107Registry.Path[path_var] = path; return this; }, getPathVars: function() { return e107Registry.Path; }, getPath: function(path_name) { return varset(e107Registry.Path[path_name]); }, _addLan: function(lan_name, lan_value) { e107Registry.Lan[lan_name] = lan_value; return this; }, _getLan: function(lan_name) { return varsettrue(e107Registry.Lan[lan_name], lan_name); }, setLan: function(lan_object) { if(!arguments[1]) { Object.keys(lan_object).each(function(key) { this.addLan(key, lan_object[key]); }, this); return this } Object.extend(e107Registry.Lan, (lan_object || {})); return this; }, addLan: function(lan_name, lan_value) { this._addLan(this.toLanName(lan_name), lan_value); return this; }, setModLan: function(mod, lan_object) { Object.keys(lan_object).each( function(key) { this.addModLan(mod, key, lan_object[key]); }, this); return this; }, addModLan: function(mod, lan_name, lan_value) { return this._addLan(this.toModLanName(mod, lan_name), lan_value); }, getLan: function(lan_name) { return this._getLan(this.toLanName(lan_name)); }, getModLan: function(mod, lan_name) { return this._getLan(this.toModLanName(mod, lan_name)); }, getLanVars: function() { return e107Registry.Lan; }, getModLanVars: function(mod) { return this.getLanFilter(this.toModLanName(mod)); }, //Example e107.getLanRange('lan1 lan2 ...'); -- { LAN1: 'lan value1', LAN2: 'lan value2', ... } getLanRange: function(lan_keys) { var ret = {}; $w(lan_keys).each( function(key) { this[key.toUpperCase()] = e107.getLan(key); }, ret); return ret; }, //Example e107.getLanFilter('lan_myplug'); -- { LAN_MYPLUG_1: 'lan value1', LAN_MYPLUG_2: 'lan value2', ... } getLanFilter: function(filter) { var ret = {}; filter = filter.toUpperCase(); $H(e107Registry.Lan).keys().each( function(key) { if(key.startsWith(filter)) { this[key] = e107Registry.Lan[key]; } }, ret); return ret; }, setTemplate: function(mod, tmpl_object) { mod = this.toModName(mod); if(!varset(e107Registry.Template[mod])) { e107Registry.Template[mod] = {}; } Object.extend(e107Registry.Template[mod], (tmpl_object || {})); return this; }, addTemplate: function(mod, name, tmpl_string) { mod = this.toModName(mod); if(!varset(e107Registry.Template[mod])) { e107Registry.Template[mod] = {}; } e107Registry.Template[mod][name] = tmpl_string; return this; }, getTemplates: function(mod) { return varsettrue(e107Registry.Template[this.toModName(mod)], {}); }, getTemplate: function(mod, name) { mod = this.toModName(mod); if(varset(e107Registry.Template[mod])) { return varsettrue(e107Registry.Template[mod][name], ''); } return ''; }, setPrefs: function(mod, pref_object) { mod = this.toModName(mod); if(!varset(e107Registry.Pref[mod])) { e107Registry.Pref[mod] = {}; } Object.extend(e107Registry.Pref[mod], (pref_object || {})); return this; }, addPref: function(mod, pref_name, pref_value) { mod = this.toModName(mod); if(!varset(e107Registry.Pref[mod])) { e107Registry.Pref[mod] = {}; } e107Registry.Pref[mod][pref_name] = pref_value; return this; }, getPrefs: function(mod) { return varsettrue(e107Registry.Pref[this.toModName(mod)], {}); }, getPref: function(mod, pref_name, def) { mod = this.toModName(mod); if(varset(e107Registry.Pref[mod])) { return varsettrue(e107Registry.Pref[mod][pref_name], varset(def, null)); } return varset(def, null); }, setCache: function(cache_str, cache_item) { this.clearCache(cache_str); e107Registry.Cache['cache-' + cache_str] = cache_item; return this; }, getCache: function(cache_str, def) { return varset(e107Registry.Cache['cache-' + cache_str], def); }, clearCache: function(cache_str, nodestroy) { var cached = this.getCache(cache_str); if(!nodestroy && cached && Object.isFunction(cached['destroy'])) cached.destroy(); e107Registry.Cache['cache-' + cache_str] = null; delete e107Registry.Cache['cache-' + cache_str]; return this; }, parseTemplate: function(mod, name, data) { var cacheStr = mod + '_' + name; var cached = this.getCache(cacheStr); if(null === cached) { var tmp = this.getTemplate(mod, name); cached = new Template(tmp); this.setCache(cacheStr, cached); } if(varsettrue(arguments[3])) { data = this.getParseData(Object.clone(data || {})); } try{ return cached.evaluate(data || {}); } catch(e) { return ''; } }, getParseData: function (data) { Object.extend(data || {}, Object.extend(this.getLanVars(), this.getPathVars()) ); return data; }, parseLan: function(str) { return String(str).interpolate(this.getLanVars()); }, parsePath: function(str) { return String(str).interpolate(this.getPathVars()); }, toModName: function(mod, raw) { return raw ? mod.dasherize() : mod.dasherize().camelize().ucfirst(); }, toLanName: function(lan) { return 'JSLAN_' + lan.underscore().toUpperCase(); }, toModLanName: function(raw_mod, lan) { return this.toLanName(raw_mod + '_' + varset(lan, '')); } }; // ------------------------------------------------------------------- /** * String Extensions * * Methods used later in the core + e107base shorthands */ Object.extend(String.prototype, { //php like ucfirst: function() { return this.charAt(0).toUpperCase() + this.substring(1); }, //Create element from string - Prototype UI createElement: function() { var wrapper = new Element('div'); wrapper.innerHTML = this; return wrapper.down(); }, parseToElement: function(data) { return this.parseTemplate(data).createElement(); }, parseTemplate: function(data) { return this.interpolate(e107Base.getParseData(data || {})); }, parsePath: function() { return e107Base.parsePath(this); }, parseLan: function() { return e107Base.parseLan(this); }, addLan: function(lan_name) { if(lan_name) e107Base.addLan(lan_name, this); return e107Base.toLanName(lan_name); }, addModLan: function(mod, lan_name) { if(mod && lan_name) e107Base.addModLan(mod, lan_name, this); return e107Base.toModLanName(mod, lan_name); }, getLan: function() { return e107Base.getLan(this); }, getModLan: function(mod) { if(mod) return e107Base.getModLan(mod, this); return this; } }); // ------------------------------------------------------------------- /** * e107WidgetAbstract Class */ var e107WidgetAbstract = Class.create(e107Base); var e107WidgetAbstract = Class.create(e107WidgetAbstract, { initMod: function(modId, options, inherit) { this.mod = e107Base.toModName(modId, true); if(!this.mod) { throw 'Illegal Mod ID'; } var methods = 'setTemplate addTemplate getTemplate parseTemplate setPrefs addPref getPref getPrefs getLan getLanVars addLan setLan'; var that = this; //Some magic $w(methods).each(function(method){ var mod_method = method.gsub(/^(set|get|add|parse)(.*)$/, function(match){ return match[1] + 'Mod' + match[2]; }); var parent_method = !e107Base[mod_method] ? method : mod_method; this[mod_method] = e107Base[parent_method].bind(this, this.mod); }.bind(that)); Object.extend(that, { getModName: function(raw) { return raw ? this.mod : e107Base.toModName(this.mod); }, parseModLan: function(str) { return String(str).interpolate(e107Base.getModLan(this.mod)); }, setModCache: function(cache_str, cache_item) { e107Base.setCache(this.getModName(true) + varsettrue(cache_str, ''), cache_item); return this; }, getModCache: function(cache_str) { return e107Base.getCache(this.getModName(true) + varsettrue(cache_str, '')); }, clearModCache: function(cache_str) { e107Base.clearCache(this.getModName(true) + varsettrue(cache_str, '')); return this; } }); //Merge option object (recursive) this.setOptions(options, inherit); return this; }, setOptions: function(options, inherit) { this.options = {}; var c = this.constructor; if (c.superclass && inherit) { var chain = [], klass = c; while (klass = klass.superclass) chain.push(klass); chain = chain.reverse(); for (var i = 0, len = chain.length; i < len; i++) { if(!chain[i].getModPrefs) chain[i].getModPrefs = Prototype.emptyFunction; //global options if available Object.extend(this.options, chain[i].getModPrefs() || {}); } } //global options if available if(!this.getModPrefs) { this.getModPrefs = Prototype.emptyFunction; } Object.extend(this.options, this.getModPrefs() || {}); return Object.extend(this.options, options || {}); } }); // ------------------------------------------------------------------- /** * Core - everything's widget! */ var e107Core = Class.create(e107WidgetAbstract, { initialize: function() { this.initMod('core'); }, /** * e107:loaded Event observer */ runOnLoad: function(handler, element, reload) { e107Event.register('loaded', handler, element || document); if(reload) this.runOnReload(handler, element); return this; }, /** * Ajax after update Event observer */ runOnReload: function(handler, element) { e107Event.register('ajax_update_after', handler, element || document); return this; } }); //e107Core instance var e107 = new e107Core(); // ------------------------------------------------------------------- /* * Widgets namespace * @descr should contain only high-level classes */ var e107Widgets = {}; /** * Utils namespace * @descr contains low-level classes and non-widget high-level classes/objects */ var e107Utils = {} /** * Helper namespace * @descr includes all old e107 functions + some new helper methods/classes */ var e107Helper = { fxToggle: function(el, fx) { var opt = Object.extend( { effect: 'blind' , options: {duration: 0.5} }, fx || {}); Effect.toggle(el, opt.effect, opt.options); } } // ------------------------------------------------------------------- /* * Element extension */ Element.addMethods( { fxToggle: function(element, options) { e107Helper.fxToggle(element, options); } }); // ------------------------------------------------------------------- /** * Backward compatibility */ Object.extend(e107Helper, { toggle: function(el) { var eltoggle; /** * (SecretR) Notice * * Logic mismatch! * Passed element/string should be always the target element (which will be toggled) * OR * anchor: where 'some-id' is the id of the target element * This method will be rewritten after the core is cleaned up. After this point * the target element will be auto-hidden (no need of class="e-hideme") */ if(false === Object.isString(el) || ( ($(el) && $(el).nodeName.toLowerCase() == 'a' && $(el).readAttribute('href')) || ($(el) && $(el).readAttribute('type') && $(el).readAttribute('type').toLowerCase() == 'input') /* deprecated */ )) { eltoggle = (function(el) { return Try.these( function() { var ret = $(el.readAttribute('href').substr(1)); if(ret) { return ret; } throw 'Error';}, //This will be the only valid case in the near future function() { var ret = el.next('.e-expandme'); if(ret) { return ret; } throw 'Error';},// maybe this too? function() { var ret = el.next('div'); if(ret) { return ret; } throw 'Error'; }, //backward compatibality - DEPRECATED function() { return null; } //break ) || false; })($(el)); } else { var eltoggle = $(el); } if(!eltoggle) return false; var fx = varset(arguments[1], null); if(false !== fx) this.fxToggle(eltoggle, fx || {}); else $(eltoggle).toggle(); return true; }, /** * added as Element method below * No toggle effects! */ downToggle: function(element, selector) { $(element).select(varsettrue(selector, '.e-expandme')).invoke('toggle'); return element; }, /** * Event listener - e107:loaded|e107:ajax_update_after * @see e107Core#addOnLoad */ toggleObserver: function(event) { var element = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; Element.select(element, '.e-expandit').invoke('observe', 'click', function(e) { var element = e.findElement('a'); if(!element) element = e.element(); if(this.toggle(element, {})) e.stop(); }.bindAsEventListener(e107Helper)); }, /** * Event listener - e107:loaded|e107:ajax_update_after * Runs fxToggle against multiple elements. The trigger element is an anchor tag, IDs of the elements to be toggled are defined in * the 'href' attribute separated by a hash character (including a leading hash), e.g. href='#id1#id2#id3' * @see e107Core#addOnLoad */ toggleManyObserver: function(event) { var element = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; Element.select(element, '.e-swapit').invoke('observe', 'click', function(e) { var element = e.findElement('a'); var els = element.readAttribute('href').split('#').without(''); els.each(function(el) { if ($(el)) { $(el).fxToggle({ options: { duration: 0.5, queue: { position: 'end', scope: 'toggleManyObserver'} } }); } }); e.stop(); }.bindAsEventListener(e107Helper)); }, /** * Add fx scroll on click event * on all '' elements */ scrollToObserver: function(event) { var element = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; Element.select(element, 'a[href^=#].scroll-to:not([href=#])').invoke('observe', 'click', function(e) { new Effect.ScrollTo(e.element().hash.substr(1)); e.stop(); }); }, /** * * */ executeAutoSubmit: function(event) { var element = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; Element.select(element, 'select.e-autosubmit').invoke('observe', 'change', function(e) { e107Helper.selectAutoSubmit(e.element()); }); }, selectAutoSubmit: function(el) { var frm = el.up('form'); if (frm) { if(el.value == '___reset___') { frm.getInputs('text').each(function(r) { r.value = '' }); frm.getInputs('password').each(function(r) { r.value = '' }); el.value = ''; } frm.submit(); } }, /** * added as Element method below */ downHide: function(element, selector) { $(element).select(varsettrue(selector, '.e-hideme')).invoke('hide'); return element; }, /** * added as Element method below */ downShow: function(element, selector) { $(element).select(varsettrue(selector, '.e-hideme')).invoke('show'); return element; }, //event listener autoHide: function(event) { var hideunder = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; if(hideunder) hideunder.downHide(); }, /** * added as Element method below * autocomplete="off" - all major browsers except Opera(?!) */ noHistory: function(element) { $(element).writeAttribute('autocomplete', 'off'); return element; }, /** * added as Element method below */ downNoHistory: function(element, selector) { $(element).select(varsettrue(selector, 'input.e-nohistory')).invoke('noHistory'); return element; }, //event listener autoNoHistory: function(event) { var down = event.memo['element'] ? $(event.memo.element) : $$('body')[0]; if(down) down.downNoHistory(); }, /** * added as Element method below */ externalLink: function (element) { $(element).writeAttribute('target', '_blank'); return element; }, /** * added as Element method below */ downExternalLinks: function(element) { $(element).select('a[rel~=external]').invoke('externalLink'); return element; }, //event listener autoExternalLinks: function (event) { //event.element() works for IE now! //TODO - remove memo.element references //event.memo['element'] ? $(event.memo.element) : $$('body')[0]; var down = event.element() != document ? event.element() : $$('body')[0]; if(down) down.downExternalLinks(); }, urlJump: function(url) { top.window.location = url; }, //TODO Widget - e107Window#confirm; confirm: function(thetext) { return confirm(thetext); }, autoConfirm: function(event) { }, imagePreload: function(ejs_path, ejs_imageString) { var ejs_imageArray = ejs_imageString.split(','); for(var ejs_loadall = 0, len = ejs_imageArray.length; ejs_loadall < len; ejs_loadall++){ var ejs_LoadedImage = new Image(); ejs_LoadedImage.src=ejs_path + ejs_imageArray[ejs_loadall]; } }, toggleChecked: function(form, state, selector, byId) { form = $(form); if(!form) { return; } if(byId) selector = 'id^=' + selector; $A(form.select('input[type=checkbox][' + selector + ']')).each(function(element) { if(!element.disabled) element.checked=state }); }, //This will be replaced later with upload_ui.php own JS method //and moved to a separate class __dupCounter: 1, __dupTmpTemplate: '', //FIXME duplicateHTML: function(copy, paste, baseid) { if(!$(copy) || !$(paste)) { return; } this.__dupCounter++; var source = $($(copy).cloneNode(true)), newentry, newid, containerId, clearB; source.writeAttribute('id', source.readAttribute('id') + this.__dupCounter); newid = (baseid || 'duplicated') + '-' + this.__dupCounter; var tmpl = this.getDuplicateTemplate(); if(tmpl) { var sourceInnerHTML = source.innerHTML; source = source.update(tmpl.parseToElement({ duplicateBody: sourceInnerHTML, removeId: 'remove-' + newid, baseId: baseid || '', newId: newid, counter: this.__dupCounter })).down().hide(); clearB = $(source.select('#remove-' + newid)[0]); } else { //see clear, clearL and clearR CSS definitions clearB = new Element('input', { 'class': 'button', 'value': 'x', 'type': 'button', 'id': 'remove-' + newid }); //backward compat. - subject of removal source.insert({ top: new Element('div', {'class': 'clear'}), bottom: clearB }).hide(); } if(baseid) { source.innerHTML = source.innerHTML.replace(new RegExp(baseid, 'g'), newid); } var containerId = source.identify(); $(paste).insert(source); //Again - the EVIL IE6 if(!clearB) { clearB = $('remove-' + newid); } clearB.observe('click', function(e) { e.stop(); var el = e.element().up('#'+containerId); el.fxToggle({ effect: 'appear', options: { duration: 0.4, afterFinish: function(o) { o.element.remove(); } } }); }.bind(this)); source.fxToggle({ effect: 'appear', options: { duration: 0.5 } }); }, getDuplicateTemplate: function() { if(this.__dupTmpTemplate) { var tmpl = this.__dupTmpTemplate; this.__dupTmpTemplate = ''; return tmpl; } return e107.getModTemplate('duplicateHTML'); }, setDuplicateTemplate: function(tmpl) { return this.__dupTmpTemplate = tmpl; }, previewImage: function(src_val, img_path, not_found) { $(src_val + '_prev').src = $(src_val).value ? img_path + $(src_val).value : not_found; return; }, insertText: function(str, tagid, display) { $(tagid).value = str.escapeHTML(); if($(display)) { $(display).fxToggle(); } }, appendText: function(str, tagid, display) { $(tagid).focus().value += str.escapeHTML(); if($(display)) { $(display).fxToggle(); } }, //by Lokesh Dhakar - http://www.lokeshdhakar.com getPageSize: function() { var xScroll, yScroll; if (window.innerHeight && window.scrollMaxY) { xScroll = window.innerWidth + window.scrollMaxX; yScroll = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac xScroll = document.body.scrollWidth; yScroll = document.body.scrollHeight; } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari xScroll = document.body.offsetWidth; yScroll = document.body.offsetHeight; } var windowWidth, windowHeight; if (self.innerHeight) { // all except Explorer if(document.documentElement.clientWidth){ windowWidth = document.documentElement.clientWidth; } else { windowWidth = self.innerWidth; } windowHeight = self.innerHeight; } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode windowWidth = document.documentElement.clientWidth; windowHeight = document.documentElement.clientHeight; } else if (document.body) { // other Explorers windowWidth = document.body.clientWidth; windowHeight = document.body.clientHeight; } // for small pages with total height less then height of the viewport if(yScroll < windowHeight){ pageHeight = windowHeight; } else { pageHeight = yScroll; } // for small pages with total width less then width of the viewport if(xScroll < windowWidth){ pageWidth = xScroll; } else { pageWidth = windowWidth; } return [pageWidth,pageHeight]; } }); // ------------------------------------------------------------------- /* * Element extensions */ Element.addMethods( { downNoHistory: e107Helper.downNoHistory, downHide: e107Helper.downHide, downShow: e107Helper.downShow, downToggle: e107Helper.downToggle, downExternalLinks: e107Helper.downExternalLinks }); Element.addMethods('INPUT', { noHistory: e107Helper.noHistory }); Element.addMethods('A', { externalLink: e107Helper.externalLink }); Element.addMethods('FORM', { toggleChecked: e107Helper.toggleChecked }); // ------------------------------------------------------------------- /** * e107BB helper */ e107Helper.BB = { __selectedInputArea: null, store: function(textAr){ this.__selectedInputArea = $(textAr); }, /** * New improved version - fixed scroll to top behaviour when inserting BBcodes * @TODO - improve it further */ insert: function(text, emote) { if (!this.__selectedInputArea) { return; //[SecretR] TODO - alert the user } var eField = this.__selectedInputArea, tags = this.parse(text, emote), scrollPos, sel, newStart; if(this.insertIE(eField, text, tags)) return; scrollPos = eField.scrollTop, sel = (eField.value).substring(eField.selectionStart, eField.selectionEnd); if (eField.selectionEnd <= 2 && typeof(eField.textLength) != 'undefined') { eField.selectionEnd = eField.textLength; } newStart = eField.selectionStart + tags.start.length + sel.length + tags.end.length; eField.value = (eField.value).substring(0, eField.selectionStart) + tags.start + sel + tags.end + ( eField.selectionStart ? (eField.value).substring(eField.selectionEnd, eField.textLength) : eField.value ); eField.focus(); eField.selectionStart = newStart; eField.selectionEnd = newStart; eField.scrollTop = scrollPos; return; }, insertIE: function(area, text, tags) { // IE fix if (!document.selection) return false; var eSelection = document.selection.createRange().text; area.focus(); if (eSelection) { document.selection.createRange().text = tags.start + eSelection + tags.end; } else { document.selection.createRange().text = tags.start + tags.end; } eSelection = ''; area.blur(); area.focus(); return true; }, parse: function(text, isEmote) { var tOpen = text, tClose = ''; if (isEmote != true) { // Split if its a paired bbcode var tmp = text.split('][', 2); tOpen = varset(tmp[1]) ? tmp[0] + ']' : text; tClose = varset(tmp[1]) ? '[' + tmp[1] : ''; } return { start: tOpen, end: tClose }; }, //TODO VERY BAD - make it right ASAP! help_old: function(help, tagid, nohtml){ if(nohtml) { help = help.escapeHTML(); } if($(tagid)) { $(tagid).value = help; } else if($('helpb')) { $('helpb').value = help; } }, //FIXME - The new BB help system help: function(help, tagid, nohtml){ if(nohtml) { help = help.escapeHTML(); } if(!$(tagid)) return; if(help) { var wrapper = new Element('div', {'style': 'position: relative'}).update(help); $(tagid).update(wrapper).fxToggle(); } else { $(tagid).update('').fxToggle(); } } }; //Iframe Shim - from PrototypeUI e107Utils.IframeShim = Class.create({ initialize: function() { this.element = new Element('iframe',{ style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none;', src: 'javascript:void(0);', frameborder: 0 }); $(document.body).insert(this.element); }, hide: function() { this.element.hide(); return this; }, show: function() { this.element.show(); return this; }, positionUnder: function(element) { var element = $(element); var offset = element.cumulativeOffset(); var dimensions = element.getDimensions(); this.element.setStyle({ left: offset[0] + 'px', top: offset[1] + 'px', width: dimensions.width + 'px', height: dimensions.height + 'px', zIndex: element.getStyle('zIndex') - 1 }).show(); return this; }, setBounds: function(bounds) { for(prop in bounds) bounds[prop] += 'px'; this.element.setStyle(bounds); return this; }, destroy: function() { if(this.element) this.element.remove(); return this; } }); // ------------------------------------------------------------------- /** * Show Page/Element loading status (during AJAX call) * * @class e107Utils.LoadingStatus * @widget: core-loading * @version 1.0 * @author SecretR * @extends e107WidgetAbstract * @template: 'template' * @cache_string: 'instance-loading-status' */ ('Loading') .addModLan('core-loading', 'alt'); ('Loading, please wait...').addModLan('core-loading', 'text'); /** * Global Prefs */ e107Base.setPrefs('core-loading', { opacity: 0.8 //TODO - more to come! }); e107Utils.LoadingStatus = Class.create(e107WidgetAbstract, { initialize: function(dest_element, options) { this.initMod('core-loading', options); this.cacheStr = 'instance-loading-status'; this.loading_mask_loader = false; this.loading_mask = $('loading-mask'); this.iframeShim = this.getModCache(this.cacheStr + '-iframe'); this.destElement = ($(dest_element) || $$('body')[0]); this.re_center = this.recenter.bindAsEventListener(this); this.create(); if(this.options.show_auto) this.show(); }, startObserving: function() { Event.observe(window,"resize", this.re_center); if(e107API.Browser.IE && e107API.Browser.IE <= 7) Event.observe(window,"scroll", this.re_center); return this; }, stopObserving: function() { Event.stopObserving(window, "resize", this.re_center); if(e107API.Browser.IE && e107API.Browser.IE <= 7) Event.stopObserving(window, "scroll", this.re_center); return this; }, set_destination: function(dest_element) { this.destElement = $(dest_element) || $$('body')[0]; return this; }, create: function() { if(!this.loading_mask) { var objBody = $$('body')[0]; this.loading_mask = this.getModTemplate('template').parseToElement().hide(); objBody.insert({ bottom: this.loading_mask }); } this.loading_mask.setStyle( { 'opacity': this.options.opacity, zIndex: 9000 } ); this.loading_mask_loader = this.loading_mask.down('#loading-mask-loader'); this.loading_mask_loader.setStyle( { /*'position': 'fixed', */zIndex: 9100 } ); //Create iframeShim if required this.createShim(); return this; }, show: function () { if(this.loading_mask.visible()) return; this.startObserving(); this.center(); this.loading_mask.show(); return this; }, hide: function () { this.loading_mask.hide(); this.stopObserving().positionShim(true); return this; }, center: function() { //Evil IE6 if(!this.iecenter()) { Element.clonePosition(this.loading_mask, this.destElement); this.fixBody().positionShim(false); } return this; }, recenter: function() { if(!this.iecenter()) { Element.clonePosition(this.loading_mask, this.destElement); this.fixBody().positionShim(false); } return this; }, iecenter: function() { //TODO - actually ie7 should work without this - investigate if(e107API.Browser.IE && e107API.Browser.IE <= 7) { //The 'freezing' problem solved (opacity = 1 ?!) this.loading_mask.show(); var offset = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop; var destdim = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; if(!this.lmh) this.lmh = this.loading_mask_loader.getHeight(); var eldim = this.lmh; var toph = parseInt(destdim/2 - eldim/2 + offset ); this.loading_mask.setStyle({top: 0, left: 0, 'opacity': 1}); this.fixBody(true); this.loading_mask_loader.setStyle( { 'position': 'absolute', 'top': toph + 'px', 'opacity': 1 }); this.positionShim(false); return true; } return false; }, fixBody: function(force) { if(force || this.destElement.nodeName.toLowerCase() == 'body') { var ps = e107Helper.getPageSize(); this.loading_mask.setStyle({ 'width': parseInt(ps[0]) + 'px', 'height': parseInt(ps[1]) + 'px' }); } return this; }, createShim: function() { if(e107API.Browser.IE && e107API.Browser.IE <= 7 && !this.iframeShim) { this.iframeShim = new e107Utils.IframeShim().hide(); this.setModCache(this.cacheStr +'-iframe', this.iframeShim); } return this; }, positionShim: function(hide) { if(!e107API.Browser.IE || e107API.Browser.IE > 6) return this; if(hide) { this.iframeShim.hide(); return this; } this.iframeShim.positionUnder(this.loading_mask).show(); return this; } }); /** * Register page loading core events */ e107Event.register('ajax_loading_start', function(event) { var loadingObj = e107.getModCache('ajax-loader'); if(!loadingObj) { loadingObj = new e107Utils.LoadingStatus(false, { show_auto: false }); e107.setModCache('ajax-loader', loadingObj); } loadingObj.set_destination(event.memo.overlayPage).show(); }); e107Event.register('ajax_loading_end', function(event) { var loadingObj = e107.getModCache('ajax-loader'); if(loadingObj) { window.setTimeout( function(){ loadingObj.hide() }, 200); } }); /** * e107Utils.LoadingElement * based on Protoload by Andreas Kalsch */ e107Base.setPrefs('core-loading-element', { overlayDelay: 50, opacity: 0.8, zIndex: 10, className: 'element-loading-mask', backgroundImage: '#{e_IMAGE}generic/loading_32.gif' }); e107Utils.LoadingElement = { startLoading: function(element, options) { if(!options) options = {}; Object.extend(options, e107Base.getPrefs('core-loading-element') || {}); element = $(element); var zindex = parseInt(e107.getModPref('zIndex')) + parseInt(options.zIndex); var cacheStr = 'core-loading-element-' + $(element).identify(); element._waiting = true; //can't use element._eloading for storing objects because of IE6 memory leak var _eloading = e107Base.getCache(cacheStr); if (!_eloading) { _eloading = new Element('div', { 'class': options.className }).setStyle({ position: 'absolute', opacity: options.opacity, zIndex: zindex //backgroundImage: 'url(' + options.backgroundImage.parsePath() + ')' }); $$('body')[0].insert({ bottom: _eloading }); var imgcheck = _eloading.getStyle('background-image'); //console.log(options.backgroundImage.parsePath()); if(!imgcheck || imgcheck == 'none') //only if not specified by CSS _eloading.setStyle( {backgroundImage: 'url(' + options.backgroundImage.parsePath() + ')'}); e107Base.setCache(cacheStr, _eloading); } window.setTimeout(( function() { if (this._waiting) { Element.clonePosition(_eloading, this); _eloading.show(); } }).bind(element), options.overlayDelay); }, stopLoading: function(element) { if (element._waiting) { element._waiting = false; var cacheStr = 'core-loading-element-' + $(element).identify(), _eloading = e107Base.getCache(cacheStr); if($(_eloading)) $(_eloading).hide();//remove it or not? //e107Base.clearCache(cacheStr); } } }; Element.addMethods(e107Utils.LoadingElement); /** * Register element loading core events */ e107Event.register('ajax_loading_element_start', function(event) { var element = $(event.memo.overlayElement); if(element) element.startLoading(); }); e107Event.register('ajax_loading_element_end', function(event) { var element = $(event.memo.overlayElement); if(element) window.setTimeout( function(){ element.stopLoading() }.bind(element), 50); }); // ------------------------------------------------------------------- // ###### START DEPRECATED - subject of removal!!! ###### //@see e107Helper#toggle, e107Helper#autoToggle var expandit = function(curobj, hide) { e107Helper.toggle(curobj, {}); if(hide) { //don't use it - will be removed hide.replace(/[\s]?,[\s]?/, ' ').strip(); $w(hide).each(function(h) { if(Object.isElement($(h))) { $(h).hide(); } }); } } //Use Prototype JS instead: $(id).update(txt); var setInner = function(id, txt) { $(id).update(txt); } //@see e107Helper#confirm TODO @see e107ModalConfirm#confirm var jsconfirm = function(thetext){ return e107Helper.confirm(thetext); } //Use Prototype JS instead e.g.: $(tagid).value = str; $(display).hide(); var insertext = function(str, tagid, display) { e107Helper.insertText(str, tagid, display); } //Use Prototype JS instead e.g.: $(tagid).focus().value += str; $(display).hide(); var appendtext = function(str, tagid, display) { e107Helper.appendText(str, tagid, display); } //TODO - e107Window class, e107Helper#openWindow proxy var open_window = function(url, wth, hgt) { if('full' == wth){ pwindow = window.open(url); } else { mywidth = varset(wth, 600); myheight = varset(wth, 400); pwindow = window.open(url,'Name', 'top=100,left=100,resizable=yes,width='+mywidth+',height='+myheight+',scrollbars=yes,menubar=yes') } pwindow.focus(); } //TODO Window class var closeWindow = function(form){ if((window.opener!=null)&&(!window.opener.closed)){ window.opener.location.reload(); } if(window.opener!=null) { window.close(); }else{setWinType(form);form.whatAction.value="Close";form.submit();} } //@see e107Helper#urljump var urljump = function(url) { e107Helper.urlJump(url); } //@see e107Helper#imagePreload var ejs_preload = function(ejs_path, ejs_imageString){ e107Helper.imagePreload(ejs_path, ejs_imageString) } //Use Prototype JS e.g.: $(cntfield).value = $(field).value.length; var textCounter = function(field,cntfield) { cntfield.value = field.value.length; } //Not used anymore - seek & remove /* function openwindow() { opener = window.open("htmlarea/index.php", "popup","top=50,left=100,resizable=no,width=670,height=520,scrollbars=no,menubar=no"); opener.focus(); } */ //@see e107Helper#toggleChecked var setCheckboxes = function(the_form, do_check, the_cb) { //backward compatibility e107Helper.toggleChecked(the_form, do_check, 'name^=' + the_cb.gsub(/[\[\]]/, ''), false); } //@see e107Helper.BB#storeCaret var storeCaret = function(textAr) { e107Helper.BB.store(textAr); return; } //@see e107Helper.BB#insert var addtext = function(text, emote) { e107Helper.BB.insert(text, emote); return; } //@see e107Helper.BB#help var help = function(help,tagid) { e107Helper.BB.help_old(help, tagid, true); } //Use Prototype JS e.g.: $(object).addClassName(over); $(object).removeClassName(over); var eover = function(object, over) { $(object).writeAttribute('class', over); } //@see e107Helper#duplicateHTML var duplicateHTML = function(copy, paste, baseid) { e107Helper.duplicateHTML(copy,paste,baseid); } var preview_image = function(src_val,img_path, not_found) { e107Helper.previewImage(src_val, img_path, not_found) } var externalLinks = function () { //already event listener }; // ###### END DEPRECATED ###### // ------------------------------------------------------------------- /** * e107History * * Prototype Xtensions http://www.prototypextensions.com/ */ var e107History = { __altered: false, __currentHash: null, __previousHash: null, __iframe: false, __title: false, /** * init() * @desc Initialize the hash. Call this method in first */ init: function() { var inst = this; var hash = location.hash.substring(1); this.hash = $H(hash.toQueryParams()); this.__currentHash = hash; this.__previousHash = hash; this.__title = document.title; if(e107API.Browser.IE && e107API.Browser.IE < 8) { document.observe('dom:loaded', function(e) { if(!$('e107-px-historyframe')) { e107History.__iframe = new Element('iframe', { name : 'e107-px-historyframe', id : 'e107-px-historyframe', src : '', width : '0', height : '0', style : { visibility: 'hidden' } }); document.body.appendChild(e107History.__iframe); e107History.setHashOnIframe(inst.hash.toQueryString()); } }); } }, /** * set( string name, string value ) * * @desc Set new value value for parameter name */ set: function(name, value) { this.__previousHash = this.hash.toQueryString(); this.hash.set(name, value); this.apply(); }, /** * get( string $name ) * * @desc Get value parameter $name */ get: function(name) { return this.hash.get(name); }, /** * unset( string $name ) * * @desc Unset parameter $name */ unset: function(name) { this.hash.unset(name); this.apply(); }, /** * update() * * @desc Updates this.hash with the current hash */ update: function() { this.__previousHash = this.hash.toQueryString(); var hash = window.location.hash.substring(1); // If IE, look in the iframe if the hash is updated if(e107API.Browser.IE && e107API.Browser.IE < 8 && this.__iframe) { var hashInFrame = this.getHashOnIframe(); if(hashInFrame != hash) { hash = hashInFrame; } } this.hash = $H(hash.toQueryParams()); this.__currentHash = hash; }, /** * apply() * * @desc Apply this.hash to location.hash */ apply: function() { var newHash = this.hash.toQueryString(); // set new hash window.location.hash = newHash; // If IE, apply new hash to frame for history if(e107API.Browser.IE && e107API.Browser.IE < 8 && this.__iframe) { if(this.__currentHash != newHash) { this.setHashOnIframe(newHash); } else if(newHash != this.getHashOnIframe()) { this.setHashOnIframe(newHash); } } }, /** * isAltered() * * @desc Return true if current hash is different of previous hash. * this.__altered allows to force the dispatch. */ isAltered: function() { if(this.__altered) { return true; } this.__altered = false; return (e107History.__currentHash != e107History.__previousHash); }, /** * setHashOnIframe() * * @use For IE compatibility * @desc Set hash value on iframe */ setHashOnIframe: function(hash) { try { var doc = e107History.__iframe.contentWindow.document; doc.open(); doc.write('' + hash + ''); doc.close(); } catch(e) {} }, /** * getHashOnIframe() * * @use For IE compatibility * @desc Get hash value on iframe */ getHashOnIframe: function() { var doc = this.__iframe.contentWindow.document; if (doc && doc.body.id == 'history') { return doc.body.innerText; } else { return this.hash.toQueryString(); } }, /** * setTitle() * * @desc Set a new title for window */ setTitle: function(title) { if(document.title) { document.title = title; } }, /** * getTitle() * * @desc Return current window title */ getTitle: function() { return this.__title; } }; e107History.init(); /** * History.Registry * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Used to register a callback for a parameter */ e107History.Registry = { /** * @desc Hash */ hash : new Hash(), /** * set( string $config ) * * @desc Set new value historyId for parameter config */ set: function(config) { if(typeof(config) != 'object') { throw('e107History.Registry.set : config must be an javascript object'); } // id if(!config.id || !Object.isString(config.id)) { throw('e107History.Registry.set : config.id must be an string'); } // onChange if(!config.onStateChange || !Object.isFunction(config.onStateChange)) { throw('e107History.Registry.set : config.onStateChange ' + 'must be an javascript callback function'); } // defaultValue if(!config.defaultValue || !Object.isString(config.defaultValue)) { config.defaultValue = ''; } this.hash.set(config.id, config); }, /** * flat version of set method * * @desc Register callback function for historyId */ register: function(historyId, callback, defval) { var config = { id: historyId, onStateChange: callback, defaultValue: defval }; this.set(config); }, /** * get( string $id ) * * @desc Get value parameter $id */ get: function(id) { return this.hash.get(id); }, /** * unset( string $id ) * * @desc Unset parameter $id */ unset: function(id) { this.hash.unset(id); } } /** * History.Observer * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Used to perform actions defined in the registry, * according to the hash of the url. */ e107History.Observer = { /** * @desc Interval delay in seconds */ delay : 0.4, /** * @desc Interval timer instance */ interval : null, /** * @desc If interval is started : true, else false */ started : false, /** * start() * * @desc Start a interval timer */ start: function() { if(this.started) return; this.interval = new PeriodicalExecuter(e107History.Observer.dispatch, this.delay); this.started = true; }, /** * stop() * * @desc Stop the interval timer */ stop: function() { if(!this.started) return; this.interval.stop(); this.started = false; }, /** * dispatch() * * @desc This method is called each time interval, * the dispatch of the registry is implemented only if * the hash has been amended (optimisiation) */ dispatch: function() { // Update the hash e107History.update(); // Dispatch only if location.hash has been altered if(e107History.isAltered()) { var oldstate = String(e107History.__previousHash).toQueryParams(); //FIXME - possible bugs/performance issues here - investigate further e107History.hash.each(function(pair) { var registry = e107History.Registry.get(pair.key); //Bugfix - notify callbacks only when required if(registry && (e107History.__altered === pair.key || oldstate[pair.key] !== pair.value)) { registry.onStateChange.bind(e107History)( pair.value ); } }); } } }; // ------------------------------------------------------------------- /* * AJAX related */ var e107Ajax = {}; /** * Ajax.History * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Provides core methods to easily manage browsing history * with Ajax.History.Request / Updater. */ e107Ajax.History = { /** * @desc Allowed Ajax.History prefix (for validation) */ types : ['Request', 'Updater'], cacheString: 'ajax-history-', /** * observe( string type, string id, string url, object options ) * * @desc This method helps manage the browsing history */ observe: function(type, id, url, options) { var getter = e107.getModCache(this.cacheString + id); var currentVersion = 0; var output = false; // Type validation if(this.types.indexOf(type) == -1) { throw('e107Ajax.History.observer: type ' + type + ' is invalid !'); } // Registry management if(!getter) { currentVersion = (options.history.state) ? options.history.state : 0; var hash = new Hash(); hash.set(currentVersion, options); e107.setModCache(this.cacheString + id, hash); //console.log(id, e107.getModCache(this.cacheString + id)); } else { currentVersion = (options.history.state) ? options.history.state : this.getCurrentVersion(id); getter.set(currentVersion, options); } // add handler on registry this.addCallback(type, id); return currentVersion; }, /** * addCallback( string type, string id ) * * @desc This method adds a state for request on History.Registry */ addCallback: function(type, id) { e107History.Observer.start(); // Set history altered state to true : force dispatch e107History.__altered = id; // Return void if registry is already set if(!Object.isUndefined(e107History.Registry.get(id))) return; // Add this id to history registry var cacheS = this.cacheString + id; e107History.Registry.set({ id: id, onStateChange: function(state) { var options = e107.getModCache(cacheS).get(state.toString()); var request = null; if(Object.isUndefined(options)) return; if(options.history.cache == true && options.history.__request) { new Ajax.Cache(options.history.__request); } else { //make a request if(type == 'Request') { request = new Ajax.Request(options.history.__url, options); } else if(type == 'Updater') { request = new Ajax.Updater(options.container, options.history.__url, options); } options.history.__request = request; } e107History.__altered = false; if (Object.isFunction(options.history.onStateChange)) { options.history.onStateChange(state); } } }); }, /** * getCurrentVersion( string id ) * * @desc This method returns the current state in history * (if the state is not defined) */ getCurrentVersion: function(id) { var getter = e107.getModCache(this.cacheString + id); return Object.isUndefined(getter) ? 0 : getter.keys().length; } }; e107Ajax.ObjectMap = { id : null, // set custom history value for this instance state : false, // set custom state value for this instance cache : false, // enable/disable history cache onStateChange : null, // handler called on history change __url : null, __request : null }; /** * Ajax.Cache * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Ajax.Cache can "simulate" an Ajax request from an * Ajax.Request/Updater made beforehand. */ Ajax.Cache = Class.create(Ajax.Base, { _complete: false, initialize: function($super, request) { $super(request.options); request._complete = false; this.transport = request.transport; this.request(request.url); return this; }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.onStateChange(); } catch (e) { this.dispatchException(e); } } }); Object.extend(Ajax.Cache.prototype, { respondToReadyState : Ajax.Request.prototype.respondToReadyState, onStateChange : Ajax.Request.prototype.onStateChange, success : Ajax.Request.prototype.getStatus, getStatus : Ajax.Request.prototype.getStatus, isSameOrigin : Ajax.Request.prototype.isSameOrigin, getHeader : Ajax.Request.prototype.getHeader, evalResponse : Ajax.Request.prototype.evalResponse, dispatchException : Ajax.Request.prototype.dispatchException }); /** * Ajax.Request Extended * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Just a small change: now Ajax.Request return self scope. * It is required by Ajax.Cache */ Ajax.Request = Class.create(Ajax.Request, { initialize: function($super, url, options) { $super(url, options); return this; } }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; /** * Ajax.Updater Extended * Prototype Xtensions http://www.prototypextensions.com/ * * @desc Just a small change: now Ajax.Updater return self scope * It is required by Ajax.Cache */ Ajax.Updater = Class.create(Ajax.Updater, { initialize: function($super, container, url, options) { $super(container, url, options); return this; } }); //Register Ajax Responder (function() { var e_responder = { onCreate: function(request) { if(request.options['updateElement']) { request.options.element = request.options.updateElement; e107Event.trigger('ajax_update_before', request.options, request.options.updateElement); } if(request.options['overlayPage']){ e107Event.trigger('ajax_loading_start', request.options, request.options.overlayPage); } else if(request.options['overlayElement']) { e107Event.trigger('ajax_loading_element_start', request.options, request.options.overlayElement); } }, onComplete: function(request) { /*Ajax.activeRequestCount == 0 && */ if(request.options['overlayPage']) { e107Event.trigger('ajax_loading_end', request.options, request.options.overlayPage); } else if(request.options['overlayElement']) { e107Event.trigger('ajax_loading_element_end', request.options, request.options.overlayElement); } if(request.options['updateElement']) { request.options.element = request.options.updateElement; e107Event.trigger('ajax_update_after', request.options, request.options.updateElement); } }, onException: function(request, e) { //TODO handle exceptions alert('e107Ajax Exception: ' + e); } } Ajax.Responders.register(e_responder); })(); /** * e107AjaxAbstract */ var e107AjaxAbstract = Class.create ({ _processResponse: function(transport) { if(null !== transport.responseXML) { this._handleXMLResponse(transport.responseXML); } else if(null !== transport.responseJSON) { this._handleJSONResponse(transport.responseJSON); } else { this._handleTextResponse(transport.responseText); } }, _handleXMLResponse: function (response) { var xfields = $A(response.getElementsByTagName('e107response')[0].childNodes); var parsed = {}; xfields.each( function(el) { if (el.nodeType == 1 && el.nodeName == 'e107action' && el.getAttribute('name') && el.childNodes) { var action = el.getAttribute('name'), items = el.childNodes; if(!varsettrue(parsed[action])) { parsed[action] = {}; } for(var i=0, len=items.length; i show elements with id id1,id2 and id3 * {'writeAttribute,rel,external': 'id1,id2,id3'} -> invoke writeAttribute('rel', 'external') on elements with id id1,id2 and id3 * {'disabled,true': 'button-el,other-button-el'} -> set disabled property of elements with id button-el,other-button-el to true * */ _processResponseElementInvokeById: function(response) { //response.key is comma separated list representing method -> args to be invoked on every element Object.keys(response).each(function(key) { var tmp = $A(key.split(',')), method = tmp[0], args = tmp.slice(1); //search for boolean type $A(args).each( function(arg, i) { switch(arg) { case 'false': args[i] = false; break; case 'true': args[i] = true; break; case 'null': args[i] = null; break; } }); //response.value is comma separated element id list $A(response[key].split(',')).each( function(el) { el = el ? $(el.strip()) : null; if(!el) return; if(Object.isFunction(el[method])) el[method].apply(el, args); else if(typeof el[method] !== 'undefined') { //XXX - should we allow adding values to undefined yet properties? At this time not allowed el[method] = varset(args[0], null); } }); }); }, /** * Update element by type */ _updateElement: function(el, data) { el = $(el); if(!el) return; var type = el.nodeName.toLowerCase(), itype = el.type; if(type == 'input' || type == 'textarea') { if(itype) itype = itype.toLowerCase(); switch (itype) { case 'checkbox': case 'radio': el.checked = (el.value == data); break; default: el.value = data.unescapeHTML(); //browsers doesn't unescape entities on JS update, why?! break; } } else if(type == 'select') { if(el.options) { var opt = $A(el.options).find( function(op, ind) { return op.value == data; }); if(opt) el.selectedIndex = opt.index; } } else if(type == 'img') { el.writeAttribute('src', data).show(); //show if hidden }else if(el.nodeType == 1) { el.update(data); } } }); // ------------------------------------------------------------------- /** * e107Ajax.Request * Prototype Xtensions http://www.prototypextensions.com/ * * @desc @desc e107Ajax.Update wrapper, used to execute an Ajax.Request by integrating * the management of browsing history */ e107Ajax.Request = Class.create({ initialize: function(url, options) { this.options = {}; Object.extend(this.options, options || {}); if(!this.options['parameters']) this.options['parameters'] = { 'ajax_used': 1 } else if(!this.options.parameters['ajax_used']) this.options['parameters']['ajax_used'] = 1; // only if required if(this.options.history) { var tmpOpt = Object.clone(e107Ajax.ObjectMap); Object.extend(tmpOpt, this.options.history); this.options.history = tmpOpt; this.options.history.__url = url; // History id if(Object.isUndefined(options.history.id)) throw('e107Ajax.Request error : you must define historyId'); var id = this.options.history.id; // Enable history observer var version = e107Ajax.History.observe('Request', id, url, this.options); // Set current version value for container e107History.set(id, version); } else { return new Ajax.Request(url, this.options); } } }); /** * e107Ajax.Updater * * @desc e107Ajax.Updater wrapper, used to execute an Ajax.Updater by integrating * the management of browsing history */ e107Ajax.Updater = Class.create({ initialize: function(container, url, options) { this.options = {}; Object.extend(this.options, options || {}); if(!this.options['parameters']) this.options['parameters'] = { 'ajax_used': 1 } else if(!this.options.parameters['ajax_used']) this.options['parameters']['ajax_used'] = 1; //required for ajax_update event trigger this.options.updateElement = container; // only if required if(this.options.history) { var tmpOpt = Object.clone(e107Ajax.ObjectMap); Object.extend(tmpOpt, this.options.history); this.options.history = tmpOpt; this.options.history.__url = url; // History id if(Object.isUndefined(options.history.id)) { var id = (Object.isString(container)) ? container : container.identify(); this.options.history.id = id; } else { var id = this.options.history.id; } // Add container to this.options this.options.container = container; // Enable history observer var version = e107Ajax.History.observe('Updater', id, url, this.options); // Set current version value for container e107History.set(id, version); } else { return new Ajax.Updater(container, url, this.options); } } }); Object.extend(e107Ajax, { /** * Ajax Submit Form method * * @descr e107 analog to Prototpye native Form.request method */ submitForm: function(form, container, options, handler) { var parm = $(form).serialize(true), opt = Object.clone(options || {}), url = !handler ? $(form).readAttribute('action') : String(handler).parsePath(); if(!opt.parameters) opt.parameters = {}; Object.extend(opt.parameters, parm || {}); if ($(form).hasAttribute('method') && !opt.method) opt.method = $(form).method; if(!opt.method) opt.method = 'post'; if(container) return new e107Ajax.Updater(container, url, opt); return new e107Ajax.Request(url, opt); }, /** * Ajax Submit Form method and auto-replace SC method */ submitFormSC: function(form, sc, scfile, container) { var handler = ('#{e_FILE}e_ajax.php'), parm = { 'ajax_sc': sc, 'ajax_scfile': scfile }; return this.submitForm(form, varsettrue(container, sc), { parameters: parm, overlayElement: varsettrue(container, sc) }, handler); }, toggleUpdate: function(toggle, container, url, cacheid, options) { container = $(container); toggle = $(toggle); opt = Object.clone(options || {}); opt.method = 'post'; if(!toggle) return; if(!toggle.visible()) { if(cacheid && $(cacheid)) return toggle.fxToggle(); opt.onComplete = function() { toggle.fxToggle() }; if(url.startsWith('sc:')) { return e107Ajax.scUpdate(url.substring(3), container, opt); } return new e107Ajax.Updater(container, url, opt); } return toggle.fxToggle(); }, scUpdate: function(sc, container, options) { var handler = ('#{e_FILE}e_ajax.php').parsePath(), parm = { 'ajax_sc': sc }; opt = Object.clone(options || {}); opt.method = 'post'; if(!opt.parameters) opt.parameters = {}; Object.extend(opt.parameters, parm || {}); return new e107Ajax.Updater(container, handler, opt); } }); /** * e107Ajax.fillForm * * @desc */ e107Ajax.fillForm = Class.create(e107AjaxAbstract, { initialize: function(form, overlay_dest, options) { //TODO - options this.options = Object.extend({ start: true }, options || {}); this.form = $(form); if(!this.form) return; if(this.options['start']) this.start(overlay_dest); }, start: function(overlay_dest) { e107Event.trigger("ajax_fillForm_start", {form: this.form}); var destEl = $(overlay_dest) || false; var C = this; //Ajax history is NOT supported (and shouldn't be) var options = { overlayPage: destEl, history: false, onSuccess: function(transport) { try { this._processResponse(transport); } catch(e) { var err_obj = { message: 'Callback Error!', extended: e, code: -1 } e107Event.trigger("ajax_fillForm_error", {form: this.form, error: err_obj}); } }.bind(C), onFailure: function(transport) { //We don't use transport.statusText only because of Safari!!! var err = transport.getHeader('e107ErrorMessage') || ''; //TODO - move error messages to the ajax responder object, convert it to an 'error' object (message, extended, code) //Add Ajax option e.g. printErrors (true|false) var err_obj = { message: err, extended: transport.responseText, code: transport.status } e107Event.trigger("ajax_fillForm_error", {form: this.form, error: err_obj }); }.bind(C) } Object.extend(options, this.options.request || {}); //update - allow passing request options this.form.submitForm(null, options, this.options.handler); }, _processResponseFillForm: function(response) { if(!response || !this.form) return; var C = this, left_response = Object.clone(response); this.form.getElements().each(function(el) { var elid = el.identify(), elname = el.readAttribute('name'), data, elnameid = String(elname).gsub(/[\[\]\_]/, '-'); if(isset(response[elname])) { data = response[elname]; if(left_response[elname]) delete left_response[elname]; } else if(isset(response[elnameid])) { data = response[elnameid]; if(left_response[elnameid]) delete left_response[elnameid]; } else if(isset(response[elid])) { data = response[elid]; if(left_response[elid]) delete left_response[elid]; } else { return; } this._updateElement(el, data); }.bind(C)); if(left_response) { //update non-form elements (by id) Object.keys(left_response).each( function(el) { this._updateElement(el, left_response[el]); }.bind(C)); } e107Event.trigger("ajax_fillForm_success", {form: this.form}); } }); Element.addMethods('FORM', { submitForm: e107Ajax.submitForm.bind(e107Ajax), submitFormSC: e107Ajax.submitFormSC.bind(e107Ajax), fillForm: function(form, overlay_element, options) { new e107Ajax.fillForm(form, overlay_element, options); } }); // ------------------------------------------------------------------- //DEPRECATED!!! Use e107Ajax.submitFormSC() || form.submitFormSC() instead function replaceSC(sc, form, container, scfile) { $(form).submitFormSC(sc, scfile, container); } //DEPRECATED!!! Use e107Ajax.submitForm() || form.submitForm() instead function sendInfo(handler, container, form) { $(form).submitForm(container, null, handler); } // ------------------------------------------------------------------- /* * Core Auto-load */ $w('autoExternalLinks autoNoHistory autoHide toggleObserver toggleManyObserver scrollToObserver executeAutoSubmit').each( function(f) { e107.runOnLoad(e107Helper[f], null, true); });