mirror of
https://github.com/e107inc/e107.git
synced 2025-01-18 13:14:55 +01:00
2766 lines
77 KiB
JavaScript
2766 lines
77 KiB
JavaScript
/*
|
|
* e107 website system
|
|
*
|
|
* Copyright (C) 2008-2012 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
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
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, path, domain)
|
|
{
|
|
if (serverTime)
|
|
{
|
|
/* update time difference cookie */
|
|
var serverDelta=Math.floor(localTime-serverTime);
|
|
if(!path) path = '/';
|
|
if(!domain) domain = '';
|
|
else domain = '; domain=' + domain;
|
|
document.cookie = 'e107_tdOffset='+serverDelta+'; path='+path+domain;
|
|
document.cookie = 'e107_tdSetTime='+(localTime-serverDelta)+'; path='+path+domain; /* 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='+path+domain;
|
|
// }
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
/**
|
|
* Prototype Xtensions
|
|
* @author Simon Martins
|
|
* @copyright (c) 2008 Netatoo SARL <http://www.netatoo.fr>
|
|
* @license MIT License <http://www.prototypextensions.com/#main=license>
|
|
*
|
|
* @desc Retrieve the browser version
|
|
*/
|
|
(function() {
|
|
var nav = navigator,
|
|
userAgent = ua = navigator.userAgent,
|
|
v = nav.appVersion,
|
|
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: e107Path,
|
|
|
|
//Language Constants
|
|
Lan: {},
|
|
|
|
//Global Templates
|
|
Template: {
|
|
Core: {
|
|
//e107Helper#duplicateHTML method
|
|
duplicateHTML: '<div><div class="clear"><!-- --></div>' +
|
|
'#{duplicateBody}' +
|
|
'<a href="#" id="#{removeId}"><img src="#{e_IMAGE_PACK}admin_images/delete_16.png" class="icon action" style="vertical-align: middle" /></a>' +
|
|
'</div>'
|
|
},
|
|
|
|
//e107Helper#LoadingStatus class
|
|
CoreLoading: {
|
|
template: '<div id="loading-mask">' +
|
|
'<p id="loading-mask-loader" class="loader">' +
|
|
'<img src="#{e_IMAGE_PACK}generic/loading_32.gif" alt="#{JSLAN_CORE_LOADING_ALT}" />' +
|
|
'<br /> <span class="loading-text">#{JSLAN_CORE_LOADING_TEXT}</span>' +
|
|
'</p>' +
|
|
'</div>'
|
|
}
|
|
},
|
|
|
|
//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);
|
|
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) {
|
|
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: <a href="#some-id"> 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 '<a href="#something" class="scroll-to"></a>' 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.findElement('a').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();
|
|
}
|
|
if(el.hasClassName('reset')) el.selectedIndex = 0;
|
|
},
|
|
|
|
/**
|
|
* 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,
|
|
|
|
// -- more useful extensions - taken from Prototype UI --
|
|
getScrollDimensions: function(element) {
|
|
element = $(element);
|
|
return {
|
|
width: element.scrollWidth,
|
|
height: element.scrollHeight
|
|
}
|
|
},
|
|
|
|
getScrollOffset: function(element) {
|
|
element = $(element);
|
|
return Element._returnOffset(element.scrollLeft, element.scrollTop);
|
|
},
|
|
|
|
setScrollOffset: function(element, offset) {
|
|
element = $(element);
|
|
if (arguments.length == 3)
|
|
offset = { left: offset, top: arguments[2] };
|
|
element.scrollLeft = offset.left;
|
|
element.scrollTop = offset.top;
|
|
return element;
|
|
},
|
|
|
|
// returns "clean" numerical style (without "px") or null if style can not be resolved
|
|
// or is not numeric
|
|
getNumStyle: function(element, style) {
|
|
var value = parseFloat($(element).getStyle(style));
|
|
return isNaN(value) ? null : value;
|
|
},
|
|
|
|
// (http://tobielangel.com/2007/5/22/prototype-quick-tip)
|
|
appendText: function(element, text) {
|
|
element = $(element);
|
|
element.appendChild(document.createTextNode(String.interpret(text)));
|
|
return element;
|
|
}
|
|
});
|
|
|
|
Object.extend(document.viewport, {
|
|
// Alias this method for consistency
|
|
getScrollOffset: document.viewport.getScrollOffsets,
|
|
|
|
setScrollOffset: function(offset) {
|
|
Element.setScrollOffset(Prototype.Browser.WebKit ? document.body : document.documentElement, offset);
|
|
},
|
|
|
|
getScrollDimensions: function() {
|
|
return Element.getScrollDimensions(Prototype.Browser.WebKit ? document.body : document.documentElement);
|
|
}
|
|
});
|
|
|
|
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, newEnd = '';
|
|
if(this.insertIE(eField, text, tags)) return;
|
|
|
|
scrollPos = eField.scrollTop, sel = (eField.value).substring(eField.selectionStart, eField.selectionEnd);
|
|
|
|
newStart = eField.selectionStart + tags.start.length + sel.length + tags.end.length;
|
|
if(eField.selectionStart || (!eField.selectionStart && eField.selectionEnd != eField.textLength)) {
|
|
newEnd = (eField.value).substring(eField.selectionEnd, eField.textLength);
|
|
}
|
|
eField.value = (eField.value).substring(0, eField.selectionStart) + tags.start + sel + tags.end + newEnd;
|
|
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(!tagid || !$(tagid)) return;
|
|
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 || !$(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),
|
|
offset = element.cumulativeOffset(),
|
|
dimensions = element.getDimensions(),
|
|
style = {
|
|
left: offset[0] + 'px',
|
|
top: offset[1] + 'px',
|
|
width: dimensions.width + 'px',
|
|
height: dimensions.height + 'px',
|
|
zIndex: element.getStyle('zIndex') - 1
|
|
};
|
|
|
|
this.element.setStyle(style).show();
|
|
return this;
|
|
},
|
|
setBounds: function(bounds) {
|
|
for(prop in bounds)
|
|
bounds[prop] += 'px';
|
|
this.element.setStyle(bounds);
|
|
return this;
|
|
},
|
|
setSize: function(width, height) {
|
|
this.element.style.width = parseInt(width) + 'px';
|
|
this.element.style.height = parseInt(height) + 'px';
|
|
return this;
|
|
},
|
|
setPosition: function(top, left) {
|
|
this.element.style.top = parseInt(top) + 'px';
|
|
this.element.style.left = parseInt(left) + 'px';
|
|
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;
|
|
}
|
|
|
|
// Prompt for user input value
|
|
var addinput = function(text) {
|
|
|
|
// quick fix to prevent JS errors - proper match was done only for latin words
|
|
var rep = text.match(/\=([^\]]*)\]/);
|
|
var val = rep ? prompt(rep[1]) : prompt('http://');
|
|
|
|
if(!val)
|
|
{
|
|
return;
|
|
}
|
|
var newtext = text.replace(rep[1], val);
|
|
emote = '';
|
|
e107Helper.BB.insert(newtext, 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('<html><body id="history">' + hash + '</body></html>');
|
|
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);
|
|
if(window.console) window.console.log('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<len; i++) {
|
|
var field = items[i];
|
|
|
|
if(field.nodeType!=1)
|
|
continue;
|
|
|
|
if(field.getAttribute('name')) {
|
|
var type = field.getAttribute('type'), //not used yet
|
|
name = field.getAttribute('name'),
|
|
eldata = field.firstChild
|
|
val = eldata ? eldata.data : '';
|
|
if(parsed[action][name] && Object.isArray(parsed[action][name]))
|
|
parsed[action][name].push(val);
|
|
else if(parsed[action][name] && Object.isString(parsed[action][name]))
|
|
parsed[action][name] = [parsed[action][name], val];
|
|
else
|
|
parsed[action][name]= val;
|
|
}
|
|
|
|
}
|
|
}
|
|
}.bind(this));
|
|
this._handleResponse(parsed);
|
|
},
|
|
|
|
_handleJSONResponse: function (response) {
|
|
this._handleResponse(response);
|
|
},
|
|
|
|
_handleTextResponse: function (response) {
|
|
this._handleResponse({ 'auto': response} );
|
|
},
|
|
|
|
_handleResponse: function(parsed) {
|
|
|
|
Object.keys(parsed).each(function(method) {
|
|
try{
|
|
this['_processResponse' + ('-' + method).camelize()](parsed[method]);
|
|
} catch(e) {
|
|
//
|
|
}
|
|
}.bind(this));
|
|
|
|
},
|
|
|
|
_processResponseAuto: function(response) {
|
|
//find by keys as IDs & update
|
|
Object.keys(response).each(function(key) {
|
|
this._updateElement(key, response[key]);
|
|
}.bind(this));
|
|
},
|
|
|
|
/**
|
|
* Reset checked property of form elements by selector name attribute (checkbox, radio)
|
|
*/
|
|
_processResponseResetChecked: function(response) {
|
|
Object.keys(response).each(function(key) {
|
|
var checked = parseInt(response[key]) ? true : false;
|
|
$$('input[name^=' + key + ']').each( function(felement) {
|
|
var itype = String(felement.type);
|
|
if(itype && 'checkbox radio'.include(itype.toLowerCase()))
|
|
felement.checked = checked;
|
|
});
|
|
}.bind(this));
|
|
},
|
|
|
|
/**
|
|
* Invoke methods/set properties on element or element collections by id
|
|
*
|
|
* Examples:
|
|
* {'show': 'id1,id2,id3'} -> 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) {
|
|
if(form)
|
|
$(form).submitForm(container, null, handler);
|
|
else
|
|
new e107Ajax.Updater(container, handler);
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
/*
|
|
* Core Auto-load
|
|
*/
|
|
$w('autoExternalLinks autoNoHistory autoHide toggleObserver toggleManyObserver scrollToObserver executeAutoSubmit').each( function(f) {
|
|
e107.runOnLoad(e107Helper[f], null, true);
|
|
});
|