diff --git a/e107_admin/header.php b/e107_admin/header.php index 4010b70c7..3304b9f27 100644 --- a/e107_admin/header.php +++ b/e107_admin/header.php @@ -12,9 +12,9 @@ | GNU General Public License (http://gnu.org). | | $Source: /cvs_backup/e107_0.8/e107_admin/header.php,v $ -| $Revision: 1.17 $ -| $Date: 2008-08-11 20:45:01 $ -| $Author: e107steved $ +| $Revision: 1.18 $ +| $Date: 2008-11-09 20:31:10 $ +| $Author: secretr $ +---------------------------------------------------------------+ */ @@ -140,9 +140,14 @@ if (varset($pref['wysiwyg'],FALSE) && check_class($pref['post_html']) && varset( define("e_WYSIWYG",FALSE); } +// Load Javascript Libraries +$hash = md5(serialize(varset($pref['e_jslib'])).serialize(varset($THEME_JSLIB)).THEME.e_LANGUAGE.ADMIN).'_admin'; +//echo "\n"; +echo "\n"; + if (strpos(e_SELF.'?'.e_QUERY, 'menus.php?configure') === FALSE) { - echo "\n"; - echo "\n"; + + //echo "\n"; } if (file_exists(THEME.'theme.js')) { echo "\n"; } if (is_readable(e_FILE.'user.js') && filesize(e_FILE.'user.js')) { echo "\n"; } @@ -169,6 +174,23 @@ function savepreset(ps,pid){ \n"; } +//iepngfix - IE6 only +if((isset($pref['enable_png_image_fix']) && $pref['enable_png_image_fix'] == true) || (isset($sleight) && $sleight == true)) { + /* + * The only problem is that the browser is REALLY, + * REALLY slow when it has to render more elements + * try e.g. "div, img, td, input" (or just *) instead only img rule + * However I hope this will force IE6 user to hate it :) + */ + echo "\n"; +} + if (function_exists('headerjs')){echo headerjs(); } // @@ -258,6 +280,20 @@ $body_onload = ""; // // J: Send end of and start of // + + +/* + * Fire Event e107:loaded + */ +echo "\n"; + + echo " \n"; $sql->db_Mark_Time("End Head, Start Body"); diff --git a/e107_admin/userclass2.php b/e107_admin/userclass2.php index e83526ff8..09498f60d 100644 --- a/e107_admin/userclass2.php +++ b/e107_admin/userclass2.php @@ -11,12 +11,23 @@ | GNU General Public License (http://gnu.org). | | $Source: /cvs_backup/e107_0.8/e107_admin/userclass2.php,v $ -| $Revision: 1.12 $ -| $Date: 2008-07-09 20:37:18 $ -| $Author: e107steved $ +| $Revision: 1.13 $ +| $Date: 2008-11-09 20:31:10 $ +| $Author: secretr $ +----------------------------------------------------------------------------+ */ +//AJAX check +if(isset($_REQUEST['ajax_used'])) +{ + define('e_AJAX_REQUEST', true); + $E107['minimal'] = true; +} +else +{ + define('e_AJAX_REQUEST', false); +} + require_once("../class2.php"); if (!getperms("4")) { @@ -25,7 +36,7 @@ if (!getperms("4")) } $e_sub_cat = 'userclass'; //define('UC_DEBUG_OPTS',FALSE); -require_once("auth.php"); + require_once(e_HANDLER."userclass_class.php"); // Modified class handler $uclass = new e_userclass; // Class management functions - legacy stuff from 0.7 $e_userclass = new user_class_admin; // Admin functions - should just obliterate any previous object created in class2.php @@ -33,26 +44,25 @@ $e_userclass = new user_class_admin; // Admin functions - should just obliter $message = ''; - - -function check_allowed($class_id) +function check_allowed($class_id, $redirect = true) { global $sql; if (!$sql->db_Select('userclass_classes', '*', "userclass_id = {$class_id}")) { - header("location:".SITEURL); + if(!$redirect) return false; + header("location:".SITEURL); exit; } $row = $sql->db_Fetch(); if (!getperms('0') && !check_class($row['userclass_editclass'])) { + if(!$redirect) return false; header("location:".SITEURL); exit; } + return true; } - - if (e_QUERY) { $uc_qs = explode(".", e_QUERY); @@ -60,8 +70,47 @@ if (e_QUERY) $action = varset($uc_qs[0],'config'); $params = varset($uc_qs[1],''); +if(e_AJAX_REQUEST) +{ + $class_num = varset($uc_qs[2],0); + if(!$class_num && isset($_POST['edit'])) + { + $params = 'edit'; + $class_num = varset($_POST['existing'],0); + } + if ($params == 'edit') + { + require_once(e_HANDLER.'js_helper.php'); + $jshelper = new e_jshelper(); + if(!check_allowed($class_num, false)) { + //This will raise an error + //'Access denied' is the message which will be thrown + //by the JS AJAX handler + e_jshelper::sendAjaxError('403', 'Access denied. Form update failed!'); + } + $sql->db_Select('userclass_classes', '*', "userclass_id='".intval($class_num)."' "); + $row = $sql->db_Fetch(MYSQL_ASSOC); + unset($row['userclass_accum']); + $row['createclass'] = UCSLAN_14; //update the submit button value + $row['existing'] = $class_num; //required when user tree is clicked + //icon + $row['iconview'] = $row['userclass_icon'] ? e_IMAGE_ABS.'userclasses/'.$row['userclass_icon'] : e_IMAGE_ABS."generic/blank.gif"; + $row["uc_icon_select"] = $row['userclass_icon']; //icons select box + + //Send the prefered response type + //echo $jshelper->sendJSONResponse('fill-form', $row); + echo $jshelper->sendXMLResponse('fill-form', $row); + exit; + } +} +/* + * Authorization should be done a bit later! + * FIXME - should we call auth.php and header.php separate? + * Definitely yes if AJAX is in the game. + */ +require_once("auth.php"); //--------------------------------------------------- // Set Initial Classes @@ -148,7 +197,7 @@ if (isset($_POST['updateclass']) || isset($_POST['createclass'])) $do_tree = FALSE; - if (isset($_POST['updateclass'])) + if (isset($_POST['createclass']) && $_POST['userclass_id']) { check_allowed($_POST['userclass_id']); $class_record['userclass_id'] = intval($_POST['userclass_id']); @@ -263,7 +312,7 @@ switch ($action) $text .= "".UCSLAN_8.":"; $text .= "'; $text .= " - + ".UCSLAN_11." @@ -361,12 +410,18 @@ switch ($action) if($params == 'edit') { - $text .= "   - "; + $text .= "   + + + "; } else { - $text .= ""; + $text .= "   + "; } $text .= ""; @@ -899,13 +954,50 @@ require_once("footer.php"); function headerjs() { - if (!e_QUERY) return ''; + /* + * e107Ajax.fillForm demonstration + * Open Firebug console for Ajax transaction details + * + */ + $script_js = "\n"; + if (!e_QUERY) return $script_js; $qs = explode('.',e_QUERY); - if ($qs[0] != 'membs') return ''; - + if ($qs[0] != 'membs') return $script_js; + // We only want this JS on the class membership selection page - $script_js = " + diff --git a/e107_files/jslib/core/debug.js b/e107_files/jslib/core/debug.js new file mode 100644 index 000000000..73f4dd1c6 --- /dev/null +++ b/e107_files/jslib/core/debug.js @@ -0,0 +1,231 @@ +print_a = function(){ + if(window.console) + $A(arguments).each( function(a) {console.log(a) }); +}; + +var_dump = print_a; + +var e107Debug = { + init: function() { + //always on top! + this.debugE = new Element('div', { 'id': 'e-debug-console', 'style': 'z-index: 9991' } ).update(this._console_header); + this.cont = new Element('div', { 'id': 'e-debug-console-cont', 'style': 'z-index: 9990' } ).insert(this.debugE); + this.input = new Element('input', { 'id': 'e-debug-console-input', 'type': 'text' } ); + this.controlC = new Element('a', { 'id': 'e-debug-console-controls-close', 'href': '#' } ).update(' X'); + this.controlE = new Element('a', { 'id': 'e-debug-console-controls-eval', 'href': '#' } ).update(' Run '); + //var controlCC = new Element('div', { 'float': 'right' }).insert(this.controlC); + this.cont.insert( new Element('div', { 'id': 'e-debug-console-controls' }).update('>> ').insert(this.input).insert(this.controlE).insert(this.controlC) ); + + + this.commands = new Array(''); + this.clen = this.commands.length; + this.cindex = 0; + + var C = this; + (function() { + C.controlC.observe('click', function(e) { + e.stop(); + C.hide(); + }); + + C.controlE.observe('click', function(e) { + e.stop(); + C.evalInput(); C.setFocus(); + }); + C.input.observe('keydown', function(e) { //supported in all modern browsers + var keycode = e.keyCode; + var enterKey, escapeKey, keyUp, keyDown; + if (e.DOM_VK_RETURN) { // mozilla + enterKey = e.DOM_VK_RETURN; + escapeKey = e.DOM_VK_ESCAPE; + keyUp = e.DOM_VK_UP; + keyDown = e.DOM_VK_DOWN; + } else { // ie && friends + escapeKey = 27; + enterKey = 13; + keyUp = 38; + keyDown = 40; + } + switch (keycode) { + case enterKey: + C.evalInput(); + break; + case keyUp: + C.chistory(-1); + break; + case keyDown: + C.chistory(1); + break; + case escapeKey: + C.input.value = ''; C.input.blur(); C.input.focus(); + break; + } + + }); + //TODO - destroy method, console commands (e.g. \run -help), better key navigation (e.g. Ctrl + Shift + Key) + }).defer(); + + document.observe('dom:loaded', function() { + $(document.body).insert(this.cont.hide()); + if(Prototype.Browser.IE6) this.iecenter(); + else this.center(); + }.bind(this)); + + this.keyboardNav = this.keyboardNav.bindAsEventListener(this); + this.re_center = this.center.bindAsEventListener(this); + this.re_iecenter = this.iecenter.bindAsEventListener(this); + this.startKeyboardNav(); + }, + + show: function() { + if(!this.visible()) { + this.startPosObserve(); + this._toggle(); + } + }, + + hide: function() { + if(this.visible()) { + this.stopPosObserve(); + this._toggle(); + } + }, + + _toggle: function() { + var C = this; + Effect.toggle(this.cont, 'blind', { + duration: 0.4, + beforeStart: this.setFocus.bind(C), + afterFinish: this.setFocus.bind(C) + }); + this.cindex = 0; //reset commands index + }, + + visible: function() { + return this.cont.visible(); + }, + + center: function() { + var w = document.viewport.getWidth(), cw = this.cont.getWidth(); + var pos = parseInt(w/2 - cw/2); + this.cont.setStyle({ 'left': pos + 'px'}); + + }, + + + iecenter: function() { + var offset = document.body.scrollTop; + var w = document.body.clientWidth; + if(!this.cd) this.cd = this.cont.getWidth(); + var left = parseInt(w/2 - this.cd/2); + if(left < 0) { //ie6 - sick of it + left = 0; + } + this.cont.setStyle( { + 'position': 'absolute', + 'top': offset + 'px', + 'left': left + 'px' + }); + }, + + setFocus: function() { + if(this.visible()) { this.input.blur(); this.input.focus(); this.scrollDown(); } + else { this.input.value = ''; this.scrollDown(); this.input.blur(); } + }, + + scrollDown: function() { + this.debugE.scrollTop = this.debugE.scrollHeight; + }, + + log: function(d) { + this.show(); + this.debugE.insert( new Element('div', { 'class': 'console-output' }).update(d) ); //TODO check the type + this.scrollDown(); + }, + + syslog: function(msg, error) { + var logcol = '#333300'; + if(error) logcol = '#cc3300'; + this.log('>> ' + msg + ''); + }, + + clearLog: function(d) { + this.debugE.update(''); + }, + + evalInput: function() { + var src = this.input.value; + if(!src.length) return; + + this.syslog(src); + this.input.value = ''; + try { + var ret = eval.call(window, src); + + if(ret) this.log(ret); + //setTimeout(src, 0); - Safari only! Not implemented anyway + this.clen = this.commands.push(src); + this.cindex = 0; + } catch(e) { + this.syslog(e, true); + this.clen = this.commands.push(src); + this.cindex = 0; + } + this.setFocus(); + }, + + startKeyboardNav: function() { + document.observe('keydown', this.keyboardNav); + return this; + }, + + + startPosObserve: function() { + if(Prototype.Browser.IE6) { + Event.observe(window,"resize", this.re_iecenter); + Event.observe(window,"scroll", this.re_iecenter); + return this; + } + Event.observe(window,"resize", this.re_center); + return this; + }, + + stopPosObserve: function() { + if(Prototype.Browser.IE6) { + Event.stopObserving(window,"scroll", this.re_iecenter); + Event.stopObserving(window,"resize", this.re_iecenter); + return this; + } + Event.stopObserving(window,"resize", this.re_center); + return this; + }, + + keyboardNav: function(event) { + //TODO - find out what kind of shortcuts are safe to be used (Ctrl + Alt + Shift brings me too much irritation) + var keycode = event.keyCode; + var key = String.fromCharCode(keycode).toLowerCase(); + var isShifthPressed = event.shiftKey || (event.keyIdentifier && event.keyIdentifier.toLowerCase() == 'shift'); //ie & friends + var isCtrlPressed = event.ctrlKey || (event.keyIdentifier && event.keyIdentifier.toLowerCase() == 'control'); //ie & friends + var isAltPressed = event.altKey || (event.keyIdentifier && event.keyIdentifier.toLowerCase() == 'alt'); //ie & friends + if(isShifthPressed && isCtrlPressed && isAltPressed && key.match(/c|l/) /* && event.element() != this.input */ ) { + if(this.visible()) this.stopPosObserve()._toggle(); + else this.startPosObserve()._toggle(); + } + }, + + chistory: function(index) { + var ci = this.clen + this.cindex + index; + if(this.commands[ci] || ci === 0 || ci === this.clen) { + this.input.value = this.commands[ci] || ''; + this.cindex += index; + } + }, + + _console_header: '--- e107 Debug Console v1.0.0: session started ---
' + +} + +e107Debug.init(); +echo = function() { + $A(arguments).each( function(a) { e107Debug.log(a) }); +} \ No newline at end of file diff --git a/e107_files/jslib/core/decorate.js b/e107_files/jslib/core/decorate.js new file mode 100644 index 000000000..b9797d5a6 --- /dev/null +++ b/e107_files/jslib/core/decorate.js @@ -0,0 +1,147 @@ +/* + * DECORATE HTML ELEMENTS + * Inspired by Magento' decorate JS functions (www.magentocommerce.com) +*/ + +var e107Decorate = { + + /** + * Decorate table rows and cells, tbody etc + * @see eDecorate() + */ + table: function(table) { + var table = $(table); + if (!table) return; + + //default options + this._options = { + 'tbody': false, + 'tbody tr': 'odd,even,first,last', + 'thead tr': 'first,last', + 'tfoot tr': 'first,last', + 'tr td': 'last' + }; + + // overload options + Object.extend(this._options, (arguments[1] || {})); + + // decorate + if (this._options['tbody']) { + this._decorate(table.select('tbody'), this._options['tbody']); + } + if (this._options['tbody_tr']) { + this._decorate(table.select('tbody tr'), this._options['tbody tr']); + } + if (this._options['thead_tr']) { + this._decorate(table.select('thead tr'), this._options['thead tr']); + } + if (this._options['tfoot_tr']) { + this._decorate(table.select('tfoot tr'), this._options['tfoot tr']); + } + if (this._options['tr_td']) { + table.select('tr').each( function(tr) { + this._decorate(tr.select('td'), this._options['tr td']); + }.bind(this)); + } + }, + + /** + * Decorate list (ul) + * Default decorate CSS classes for list items are "odd", "even" and "last" + * + * Examples: + * eDecorateList('mylist'); //default decorate options over element with id 'mylist' + * eDecorateList('mylist', 'odd,even'); //decorate options odd and even only over element with id 'mylist' + * + * @param list - id/DOM object of list element (ul) to be decorated + * [@param options] - string|array decorate options - @see eDecorate() + * [@param recursive] - boolean decorate all childs if present + */ + list: function(list) { + list = $(list); + if (list) { + if (typeof(arguments[2]) == 'undefined') { + var items = list.select('li') + } else { + var items = list.childElements(); + } + this._decorate(items, (arguments[1] || 'odd,even,last')); + } + }, + + /** + * Set "odd", "even" and "last" CSS classes for list items + * + * Examples: + * eDecorateDataList('mydatalist'); //default decorate options over element with id 'mydatalist' + * eDecorateDataList('mydatalist', 'odd,even'); //decorate options odd and even for dt elements, default for dd elements + * + * [@param dt_options] - string|array dt element decorate options - @see eDecorate() + * [@param dd_options] - string|array dd element decorate options - @see eDecorate() + */ + dataList: function(list) { + list = $(list); + if (list) { + this._decorate(list.select('dt'), (arguments[1] || 'odd,even,last')); + this._decorate(list.select('dd'), (arguments[2] || 'odd,even,last')); + } + }, + + /** + * Add classes to specified elements. + * Supported classes are: 'odd', 'even', 'first', 'last' + * + * @param elements - array of elements to be decorated + * [@param decorateParams] - array of classes to be set. If omitted or empty, all available will be used + */ + _decorate: function(elements) { + var decorateAllParams = ['odd', 'even', 'first', 'last']; + this.decorateParams = []; + this.params = {}; + + if (!elements.length) return; + + if(!varset(arguments[1])) { + this.decorateParams = decorateAllParams; + } else if(typeof(arguments[1]) == 'string') { + this.decorateParams = arguments[1].replace(/[\s]/, '').split(','); + } else { + this.decorateParams = arguments[1]; + } + + decorateAllParams.each( function(v) { + this.params[v] = this.decorateParams.include(v); + }.bind(this)); + + // decorate first + if(this.params.first) { + Element.addClassName(elements[0], 'first'); + } + // decorate last + if(this.params.last) { + Element.addClassName(elements[elements.length-1], 'last'); + } + + if(!this.params.even && !this.params.odd) { + return; + } + //elements.select(_eDecorateIsEven).invoke('addClassName', 'even'); + var selections = elements.partition(this._isEven); + // decorate even + if(this.params.even) { + selections[0].invoke('addClassName', 'even'); + } + if(this.params.odd) { + selections[1].invoke('addClassName', 'odd'); + } + }, + + /** + * Select/Reject/Partition callback function + * + * @see eDecorate() + */ + _isEven: function(dummy, i) { + return ((i+1) % 2 == 0); + } +} \ No newline at end of file diff --git a/e107_files/jslib/e107.js.php b/e107_files/jslib/e107.js.php new file mode 100644 index 000000000..e342bf9d3 --- /dev/null +++ b/e107_files/jslib/e107.js.php @@ -0,0 +1,2380 @@ +/* + * 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 Used to retrieve the browser version + */ +(function() { + var nav = navigator; + var userAgent = ua = navigator.userAgent; + var v = nav.appVersion; + var version = parseFloat(v); + + Prototype.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: '', + e_IMAGE_PACK: '', + e_PLUGIN: '', + e_FILE: '', + + e_THEME: '', + THEME: '' + }, + + //Language Constants + Lan: {}, + + //Global Templates + Template: { + Core: { + //e107Helper#duplicateHTML method + //TODO CSS - icon , icon.d16, icon.d32, icon.d64, top, middle, bottom definitions + 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: 100 //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) { + 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 Easly event manager for creating custom event 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 an 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'); + } + + var i = this.events.get(name).keys().length; + observers.set(i, callback.bind(this.scope)); + + 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); + observers.each(function(callback) { + if(Object.isFunction(callback[1])) { + callback[1].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 ''; + }, + + setPref: 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.set(cache_str, cache_item); + return this; + }, + + getCache: function(cache_str, def) { + return varset(e107Registry.Cache.get(cache_str), def); + }, + + clearCache: function(cache_str, def) { + var cached = this.getCache(cache_str); + if(null !== cached) { + if(cached.destroy) { + cached.destroy(); + } + } + return varset(e107Registry.Cache.unset(cache_str), def); + }, + + 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({ + + initMod: function(modId, options, inherit) { + + this.mod = e107Base.toModName(modId, true); + if(!this.mod) { + throw 'Illegal Mod ID'; + } + + var methods = 'setTemplate addTemplate getTemplate parseTemplate setPref 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(e107Base, this.mod); + //console.log(mod_method, parent_method); + }.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) { + return e107Base.setCache(this.getModName(true) + cache_str, cache_item); + }, + + getModCache: function(cache_str) { + return e107Base.getCache(this.getModName(true) + cache_str); + }, + + clearModCache: function(cache_str) { + return e107Base.clearCache(this.getModName(true) + cache_str); + } + }); + + //Merge option object (recursive) + this.setOptions(options, inherit); + }, + + + 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(Object.isElement(el) && ($(el).readAttribute('href')) || $(el).nodeName.toLowerCase() == 'a' || $(el).readAttribute('type').toLowerCase() == 'input') { + eltoggle = (function(el) { + return Try.these( + function() { var ret= $(el.readAttribute('href').match(/#(\w.+)$/)[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';}, + 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; + + var fx = varset(arguments[1], null); + + if(null !== fx) + this.fxToggle(eltoggle, fx || {}); + else + $(eltoggle).toggle(); + }, + + /** + * 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 expandthem = event.memo.element ? $(event.memo.element) : $$('body')[0]; + expandthem.select('.e-expandit').invoke('observe', 'click', function(e) { + var relval = e.element().getAttribute('rel') ? '{' + String(e.element().getAttribute('rel').toJSON()) + '}' : '{}'; + e.stop(); + //security - evalJSON(true) + this.toggle(e.element(), relval.evalJSON(true) || {}); + }.bindAsEventListener(e107Helper)); + }, + + /** + * Add fx scroll on click event + * on all 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 +}); + +// ------------------------------------------------------------------- + +/** + * 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); + if(this.insertIE(eField, text, tags)) return; + + var scrollPos = eField.scrollTop, sel = (eField.value).substring(eField.selectionStart, eField.selectionEnd); + if (eField.selectionEnd <= 2 && typeof(eField.textLength) != 'undefined') { + eField.selectionEnd = eField.textLength; + } + + var 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.value).substring(eField.selectionEnd, eField.textLength); + + 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(varset(helpb)) { + $('dataform').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: absolute'}).update(help); + $(tagid).update(wrapper).fxToggle();//TODO - fx + } else { + $(tagid).update('').fxToggle();//TODO - fx + } + } +}; + +//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'); + +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.addModLan('loading_text', 'Loading, please wait...').addModLan('loading_alt', 'Loading'); + 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(Prototype.Browser.IE && Prototype.Browser.IE <= 6) + Event.observe(window,"scroll", this.re_center); + return this; + }, + + stopObserving: function() { + Event.stopObserving(window, "resize", this.re_center); + if(Prototype.Browser.IE && Prototype.Browser.IE <= 6) + 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': 0.8, 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() { + if(Prototype.Browser.IE && Prototype.Browser.IE <= 6) { + //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(!this.iframeShim) { + this.iframeShim = new e107Utils.IframeShim().hide(); + this.setModCache(this.cacheStr +'-iframe', this.iframeShim); + } + + return this; + }, + + positionShim: function(hide) { + if(hide) { + this.iframeShim.hide(); return this; + } + this.iframeShim.positionUnder(this.loading_mask).show(); + return this; + } +}); + +/** + * Register core loading 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.overlayElement).show(); +}); + +e107Event.register('ajax_loading_end', function(event) { + var loadingObj = e107.getModCache('ajax-loader'); + if(loadingObj) { + window.setTimeout( function(){ loadingObj.hide() }, 200); + } +}); + +// ------------------------------------------------------------------- + +// ###### 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).addClassName(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 () { + e107Helper.externalLinks(); +}; +// ###### 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(Prototype.Browser.IE && Prototype.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(Prototype.Browser.IE && Prototype.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(Prototype.Browser.IE && Prototype.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 == true) { + 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()) { + e107History.hash.each(function(pair) { + var registry = e107History.Registry.get(pair.key); + if(registry) { + 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(); + // console.log(this.cacheString + id, e107.getModCache(this.cacheString + id).get('0')); + // Set history altered state to true : force dispatch + e107History.__altered = true; + + // 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) { + e107Event.trigger('ajax_update_before', request.options); + } + if(request.options.overlayElement){ + e107Event.trigger('ajax_loading_start', request.options); + } + }, + + onComplete: function(request) { + if(request.options.updateElement) { + e107Event.trigger('ajax_update_after', request.options); + } + /*Ajax.activeRequestCount == 0 && */ + if(request.options.overlayElement) { + e107Event.trigger('ajax_loading_end', request.options); + } + }, + + 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(transport.responseXML) { + this._handleXMLResponse(transport.responseXML); + } else if(transport.responseJSON) { + this._handleJSONResponse(transport.responseJSON); + } else { + this._handleTextResponse(transport.responseText); + } + + }, + + _handleXMLResponse: function (response) { + var xfields = $A(response.childNodes[0].childNodes); + //getElementsByTagName('e107response')[0] + 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