diff --git a/lib/ajax/ajaxlib.php b/lib/ajax/ajaxlib.php index 80a7badda96..e6ca8625414 100644 --- a/lib/ajax/ajaxlib.php +++ b/lib/ajax/ajaxlib.php @@ -21,15 +21,15 @@ function ajax_get_lib($libname) { 'yui_calendar' => '/lib/yui/calendar/calendar-min.js', 'yui_charts' => '/lib/yui/charts/charts-experimental-min.js', 'yui_colorpicker' => '/lib/yui/colorpicker/colorpicker-min.js', - 'yui_cookie' => '/lib/yui/cookie/cookie-beta-min.js', 'yui_connection' => '/lib/yui/connection/connection-min.js', 'yui_container' => '/lib/yui/container/container-min.js', - 'yui_datasource' => '/lib/yui/datasource/datasource-beta-min.js', - 'yui_datatable' => '/lib/yui/datatable/datatable-beta-min.js', + 'yui_cookie' => '/lib/yui/cookie/cookie-min.js', + 'yui_datasource' => '/lib/yui/datasource/datasource-min.js', + 'yui_datatable' => '/lib/yui/datatable/datatable-min.js', 'yui_dom' => '/lib/yui/dom/dom-min.js', 'yui_dom-event' => '/lib/yui/yahoo-dom-event/yahoo-dom-event.js', 'yui_dragdrop' => '/lib/yui/dragdrop/dragdrop-min.js', - 'yui_editor' => '/lib/yui/editor/editor-beta-min.js', + 'yui_editor' => '/lib/yui/editor/editor-min.js', 'yui_element' => '/lib/yui/element/element-beta-min.js', 'yui_event' => '/lib/yui/event/event-min.js', 'yui_get' => '/lib/yui/get/get-min.js', @@ -37,21 +37,21 @@ function ajax_get_lib($libname) { 'yui_imagecropper' => '/lib/yui/imagecropper/imagecropper-beta-min.js', 'yui_imageloader' => '/lib/yui/imageloader/imageloader-min.js', 'yui_json' => '/lib/yui/json/json-min.js', - 'yui_layout' => '/lib/yui/layout/layout-beta-min.js', + 'yui_layout' => '/lib/yui/layout/layout-min.js', 'yui_logger' => '/lib/yui/logger/logger-min.js', 'yui_menu' => '/lib/yui/menu/menu-min.js', - 'yui_profiler' => '/lib/yui/profiler/profiler-beta-min.js', + 'yui_profiler' => '/lib/yui/profiler/profiler-min.js', 'yui_profilerviewer' => '/lib/yui/profilerviewer/profilerviewer-beta-min.js', - 'yui_resize' => '/lib/yui/resize/resize-beta-min.js', + 'yui_resize' => '/lib/yui/resize/resize-min.js', 'yui_selector' => '/lib/yui/selector/selector-beta-min.js', - 'yui_simpleeditor' => '/lib/yui/editor/simpleeditor-beta-min.js', + 'yui_simpleeditor' => '/lib/yui/editor/simpleeditor-min.js', 'yui_slider' => '/lib/yui/slider/slider-min.js', 'yui_tabview' => '/lib/yui/tabview/tabview-min.js', 'yui_treeview' => '/lib/yui/treeview/treeview-min.js', 'yui_uploader' => '/lib/yui/uploader/uploader-experimental-min.js', 'yui_utilities' => '/lib/yui/utilities/utilities.js', - 'yui_yuiloader' => '/lib/yui/yuiloader/yuiloader-beta-min.js', - 'yui_yuitest' => '/lib/yui/yuitest/yuitest-beta-min.js', + 'yui_yuiloader' => '/lib/yui/yuiloader/yuiloader-min.js', + 'yui_yuitest' => '/lib/yui/yuitest/yuitest-min.js', 'ajaxcourse_blocks' => '/lib/ajax/block_classes.js', 'ajaxcourse_sections' => '/lib/ajax/section_classes.js', 'ajaxcourse' => '/lib/ajax/ajaxcourse.js' diff --git a/lib/yui/cookie/cookie-debug.js b/lib/yui/cookie/cookie-debug.js new file mode 100644 index 00000000000..fd1c30f0759 --- /dev/null +++ b/lib/yui/cookie/cookie-debug.js @@ -0,0 +1,424 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +/** + * Utilities for cookie management + * @namespace YAHOO.util + * @module cookie + */ +YAHOO.namespace("util"); + +/** + * Cookie utility. + * @class Cookie + * @static + */ +YAHOO.util.Cookie = { + + //------------------------------------------------------------------------- + // Private Methods + //------------------------------------------------------------------------- + + /** + * Creates a cookie string that can be assigned into document.cookie. + * @param {String} name The name of the cookie. + * @param {String} value The value of the cookie. + * @param {encodeValue} encodeValue True to encode the value, false to leave as-is. + * @param {Object} options (Optional) Options for the cookie. + * @return {String} The formatted cookie string. + * @method _createCookieString + * @private + * @static + */ + _createCookieString : function (name /*:String*/, value /*:Variant*/, encodeValue /*:Boolean*/, options /*:Object*/) /*:String*/ { + + //shortcut + var lang = YAHOO.lang; + + var text /*:String*/ = encodeURIComponent(name) + "=" + (encodeValue ? encodeURIComponent(value) : value); + + + if (lang.isObject(options)){ + //expiration date + if (options.expires instanceof Date){ + text += "; expires=" + options.expires.toGMTString(); + } + + //path + if (lang.isString(options.path) && options.path != ""){ + text += "; path=" + options.path; + } + + //domain + if (lang.isString(options.domain) && options.domain != ""){ + text += "; domain=" + options.domain; + } + + //secure + if (options.secure === true){ + text += "; secure"; + } + } + + return text; + }, + + /** + * Formats a cookie value for an object containing multiple values. + * @param {Object} hash An object of key-value pairs to create a string for. + * @return {String} A string suitable for use as a cookie value. + * @method _createCookieHash + * @private + * @static + */ + _createCookieHashString : function (hash /*:Object*/) /*:String*/ { + + //shortcuts + var lang = YAHOO.lang; + + if (!lang.isObject(hash)){ + throw new TypeError("Cookie._createCookieHashString(): Argument must be an object."); + } + + var text /*:Array*/ = new Array(); + + for (var key in hash){ + if (lang.hasOwnProperty(hash, key) && !lang.isFunction(hash[key]) && !lang.isUndefined(hash[key])){ + text.push(encodeURIComponent(key) + "=" + encodeURIComponent(String(hash[key]))); + } + } + + return text.join("&"); + }, + + /** + * Parses a cookie hash string into an object. + * @param {String} text The cookie hash string to parse. The string should already be URL-decoded. + * @return {Object} An object containing entries for each cookie value. + * @method _parseCookieHash + * @private + * @static + */ + _parseCookieHash : function (text /*:String*/) /*:Object*/ { + + var hashParts /*:Array*/ = text.split("&"), + hashPart /*:Array*/ = null, + hash /*:Object*/ = new Object(); + + if (text.length > 0){ + for (var i=0, len=hashParts.length; i < len; i++){ + hashPart = hashParts[i].split("="); + hash[decodeURIComponent(hashPart[0])] = decodeURIComponent(hashPart[1]); + } + } + + return hash; + }, + + /** + * Parses a cookie string into an object representing all accessible cookies. + * @param {String} text The cookie string to parse. + * @param {Boolean} decode (Optional) Indicates if the cookie values should be decoded or not. Default is true. + * @return {Object} An object containing entries for each accessible cookie. + * @method _parseCookieString + * @private + * @static + */ + _parseCookieString : function (text /*:String*/, decode /*:Boolean*/) /*:Object*/ { + + var cookies /*:Object*/ = new Object(); + + if (YAHOO.lang.isString(text) && text.length > 0) { + + var decodeValue = (decode === false ? function(s){return s;} : decodeURIComponent); + + if (/[^=]+=[^=;]?(?:; [^=]+=[^=]?)?/.test(text)){ + var cookieParts /*:Array*/ = text.split(/;\s/g); + var cookieName /*:String*/ = null; + var cookieValue /*:String*/ = null; + var cookieNameValue /*:Array*/ = null; + + for (var i=0, len=cookieParts.length; i < len; i++){ + + //check for normally-formatted cookie (name-value) + cookieNameValue = cookieParts[i].match(/([^=]+)=/i); + if (cookieNameValue instanceof Array){ + cookieName = decodeURIComponent(cookieNameValue[1]); + cookieValue = decodeValue(cookieParts[i].substring(cookieNameValue[1].length+1)); + } else { + //means the cookie does not have an "=", so treat it as a boolean flag + cookieName = decodeURIComponent(cookieParts[i]); + cookieValue = cookieName; + } + cookies[cookieName] = cookieValue; + } + } + } + + return cookies; + }, + + //------------------------------------------------------------------------- + // Public Methods + //------------------------------------------------------------------------- + + /** + * Returns the cookie value for the given name. + * @param {String} name The name of the cookie to retrieve. + * @param {Function} converter (Optional) A function to run on the value before returning + * it. The function is not used if the cookie doesn't exist. + * @return {Variant} If no converter is specified, returns a string or null if + * the cookie doesn't exist. If the converter is specified, returns the value + * returned from the converter or null if the cookie doesn't exist. + * @method get + * @static + */ + get : function (name /*:String*/, converter /*:Function*/) /*:Variant*/{ + + var lang = YAHOO.lang; + var cookies /*:Object*/ = this._parseCookieString(document.cookie); + + if (!lang.isString(name) || name === ""){ + throw new TypeError("Cookie.get(): Cookie name must be a non-empty string."); + } + + if (lang.isUndefined(cookies[name])) { + return null; + } + + if (!lang.isFunction(converter)){ + return cookies[name]; + } else { + return converter(cookies[name]); + } + }, + + /** + * Returns the value of a subcookie. + * @param {String} name The name of the cookie to retrieve. + * @param {String} subName The name of the subcookie to retrieve. + * @param {Function} converter (Optional) A function to run on the value before returning + * it. The function is not used if the cookie doesn't exist. + * @return {Variant} If the cookie doesn't exist, null is returned. If the subcookie + * doesn't exist, null if also returned. If no converter is specified and the + * subcookie exists, a string is returned. If a converter is specified and the + * subcookie exists, the value returned from the converter is returned. + * @method getSub + * @static + */ + getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/) /*:Variant*/ { + + var lang = YAHOO.lang; + var hash /*:Variant*/ = this.getSubs(name); + + if (hash !== null) { + + if (!lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.getSub(): Subcookie name must be a non-empty string."); + } + + if (lang.isUndefined(hash[subName])){ + return null; + } + + if (!lang.isFunction(converter)){ + return hash[subName]; + } else { + return converter(hash[subName]); + } + } else { + return null; + } + + }, + + /** + * Returns an object containing name-value pairs stored in the cookie with the given name. + * @param {String} name The name of the cookie to retrieve. + * @return {Object} An object of name-value pairs if the cookie with the given name + * exists, null if it does not. + * @method getHash + * @static + */ + getSubs : function (name /*:String*/) /*:Object*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.getSubs(): Cookie name must be a non-empty string."); + } + + var cookies = this._parseCookieString(document.cookie, false); + if (YAHOO.lang.isString(cookies[name])){ + return this._parseCookieHash(cookies[name]); + } + return null; + }, + + /** + * Removes a cookie from the machine by setting its expiration date to + * sometime in the past. + * @param {String} name The name of the cookie to remove. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), + * and secure (true/false). The expires option will be overwritten + * by the method. + * @return {String} The created cookie string. + * @method remove + * @static + */ + remove : function (name /*:String*/, options /*:Object*/) /*:String*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.remove(): Cookie name must be a non-empty string."); + } + + //set options + options = options || {}; + options.expires = new Date(0); + + //set cookie + return this.set(name, "", options); + }, + + /** + * Removes a sub cookie with a given name. + * @param {String} name The name of the cookie in which the subcookie exists. + * @param {String} subName The name of the subcookie to remove. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). This must be the same settings as the original + * subcookie. + * @return {String} The created cookie string. + * @method removeSub + * @static + */ + removeSub : function(name /*:String*/, subName /*:String*/, options /*:Object*/) /*:String*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.removeSub(): Cookie name must be a non-empty string."); + } + + //check subcookie name + if (!YAHOO.lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.removeSub(): Subcookie name must be a non-empty string."); + } + + //get all subcookies for this cookie + var subs = this.getSubs(name); + + //delete the indicated subcookie + if (YAHOO.lang.isObject(subs) && YAHOO.lang.hasOwnProperty(subs, subName)){ + delete subs[subName]; + + //reset the cookie + return this.setSubs(name, subs, options); + } else { + return ""; + } + + }, + + /** + * Sets a cookie with a given name and value. + * @param {String} name The name of the cookie to set. + * @param {Variant} value The value to set for the cookie. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method set + * @static + */ + set : function (name /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name)){ + throw new TypeError("Cookie.set(): Cookie name must be a string."); + } + + if (lang.isUndefined(value)){ + throw new TypeError("Cookie.set(): Value cannot be undefined."); + } + + + var text /*:String*/ = this._createCookieString(name, value, true, options); + document.cookie = text; + return text; + }, + + /** + * Sets a sub cookie with a given name to a particular value. + * @param {String} name The name of the cookie to set. + * @param {String} subName The name of the subcookie to set. + * @param {Variant} value The value to set. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method setSub + * @static + */ + setSub : function (name /*:String*/, subName /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name) || name === ""){ + throw new TypeError("Cookie.setSub(): Cookie name must be a non-empty string."); + } + + if (!lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.setSub(): Subcookie name must be a non-empty string."); + } + + if (lang.isUndefined(value)){ + throw new TypeError("Cookie.setSub(): Subcookie value cannot be undefined."); + } + + var hash /*:Object*/ = this.getSubs(name); + + if (!lang.isObject(hash)){ + hash = new Object(); + } + + hash[subName] = value; + + return this.setSubs(name, hash, options); + + }, + + /** + * Sets a cookie with a given name to contain a hash of name-value pairs. + * @param {String} name The name of the cookie to set. + * @param {Object} value An object containing name-value pairs. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method setSubs + * @static + */ + setSubs : function (name /*:String*/, value /*:Object*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name)){ + throw new TypeError("Cookie.setSubs(): Cookie name must be a string."); + } + + if (!lang.isObject(value)){ + throw new TypeError("Cookie.setSubs(): Cookie value must be an object."); + } + + var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options); + document.cookie = text; + return text; + } + +}; +YAHOO.register("cookie", YAHOO.util.Cookie, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/cookie/cookie-min.js b/lib/yui/cookie/cookie-min.js new file mode 100644 index 00000000000..0e020ebdbed --- /dev/null +++ b/lib/yui/cookie/cookie-min.js @@ -0,0 +1,7 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +YAHOO.namespace("util");YAHOO.util.Cookie={_createCookieString:function(B,D,C,A){var F=YAHOO.lang;var E=encodeURIComponent(B)+"="+(C?encodeURIComponent(D):D);if(F.isObject(A)){if(A.expires instanceof Date){E+="; expires="+A.expires.toGMTString();}if(F.isString(A.path)&&A.path!=""){E+="; path="+A.path;}if(F.isString(A.domain)&&A.domain!=""){E+="; domain="+A.domain;}if(A.secure===true){E+="; secure";}}return E;},_createCookieHashString:function(B){var D=YAHOO.lang;if(!D.isObject(B)){throw new TypeError("Cookie._createCookieHashString(): Argument must be an object.");}var C=new Array();for(var A in B){if(D.hasOwnProperty(B,A)&&!D.isFunction(B[A])&&!D.isUndefined(B[A])){C.push(encodeURIComponent(A)+"="+encodeURIComponent(String(B[A])));}}return C.join("&");},_parseCookieHash:function(E){var D=E.split("&"),F=null,C=new Object();if(E.length>0){for(var B=0,A=D.length;B0){var B=(A===false?function(K){return K;}:decodeURIComponent);if(/[^=]+=[^=;]?(?:; [^=]+=[^=]?)?/.test(I)){var G=I.split(/;\s/g);var H=null;var C=null;var E=null;for(var D=0,F=G.length;D 0){ + for (var i=0, len=hashParts.length; i < len; i++){ + hashPart = hashParts[i].split("="); + hash[decodeURIComponent(hashPart[0])] = decodeURIComponent(hashPart[1]); + } + } + + return hash; + }, + + /** + * Parses a cookie string into an object representing all accessible cookies. + * @param {String} text The cookie string to parse. + * @param {Boolean} decode (Optional) Indicates if the cookie values should be decoded or not. Default is true. + * @return {Object} An object containing entries for each accessible cookie. + * @method _parseCookieString + * @private + * @static + */ + _parseCookieString : function (text /*:String*/, decode /*:Boolean*/) /*:Object*/ { + + var cookies /*:Object*/ = new Object(); + + if (YAHOO.lang.isString(text) && text.length > 0) { + + var decodeValue = (decode === false ? function(s){return s;} : decodeURIComponent); + + if (/[^=]+=[^=;]?(?:; [^=]+=[^=]?)?/.test(text)){ + var cookieParts /*:Array*/ = text.split(/;\s/g); + var cookieName /*:String*/ = null; + var cookieValue /*:String*/ = null; + var cookieNameValue /*:Array*/ = null; + + for (var i=0, len=cookieParts.length; i < len; i++){ + + //check for normally-formatted cookie (name-value) + cookieNameValue = cookieParts[i].match(/([^=]+)=/i); + if (cookieNameValue instanceof Array){ + cookieName = decodeURIComponent(cookieNameValue[1]); + cookieValue = decodeValue(cookieParts[i].substring(cookieNameValue[1].length+1)); + } else { + //means the cookie does not have an "=", so treat it as a boolean flag + cookieName = decodeURIComponent(cookieParts[i]); + cookieValue = cookieName; + } + cookies[cookieName] = cookieValue; + } + } + } + + return cookies; + }, + + //------------------------------------------------------------------------- + // Public Methods + //------------------------------------------------------------------------- + + /** + * Returns the cookie value for the given name. + * @param {String} name The name of the cookie to retrieve. + * @param {Function} converter (Optional) A function to run on the value before returning + * it. The function is not used if the cookie doesn't exist. + * @return {Variant} If no converter is specified, returns a string or null if + * the cookie doesn't exist. If the converter is specified, returns the value + * returned from the converter or null if the cookie doesn't exist. + * @method get + * @static + */ + get : function (name /*:String*/, converter /*:Function*/) /*:Variant*/{ + + var lang = YAHOO.lang; + var cookies /*:Object*/ = this._parseCookieString(document.cookie); + + if (!lang.isString(name) || name === ""){ + throw new TypeError("Cookie.get(): Cookie name must be a non-empty string."); + } + + if (lang.isUndefined(cookies[name])) { + return null; + } + + if (!lang.isFunction(converter)){ + return cookies[name]; + } else { + return converter(cookies[name]); + } + }, + + /** + * Returns the value of a subcookie. + * @param {String} name The name of the cookie to retrieve. + * @param {String} subName The name of the subcookie to retrieve. + * @param {Function} converter (Optional) A function to run on the value before returning + * it. The function is not used if the cookie doesn't exist. + * @return {Variant} If the cookie doesn't exist, null is returned. If the subcookie + * doesn't exist, null if also returned. If no converter is specified and the + * subcookie exists, a string is returned. If a converter is specified and the + * subcookie exists, the value returned from the converter is returned. + * @method getSub + * @static + */ + getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/) /*:Variant*/ { + + var lang = YAHOO.lang; + var hash /*:Variant*/ = this.getSubs(name); + + if (hash !== null) { + + if (!lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.getSub(): Subcookie name must be a non-empty string."); + } + + if (lang.isUndefined(hash[subName])){ + return null; + } + + if (!lang.isFunction(converter)){ + return hash[subName]; + } else { + return converter(hash[subName]); + } + } else { + return null; + } + + }, + + /** + * Returns an object containing name-value pairs stored in the cookie with the given name. + * @param {String} name The name of the cookie to retrieve. + * @return {Object} An object of name-value pairs if the cookie with the given name + * exists, null if it does not. + * @method getHash + * @static + */ + getSubs : function (name /*:String*/) /*:Object*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.getSubs(): Cookie name must be a non-empty string."); + } + + var cookies = this._parseCookieString(document.cookie, false); + if (YAHOO.lang.isString(cookies[name])){ + return this._parseCookieHash(cookies[name]); + } + return null; + }, + + /** + * Removes a cookie from the machine by setting its expiration date to + * sometime in the past. + * @param {String} name The name of the cookie to remove. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), + * and secure (true/false). The expires option will be overwritten + * by the method. + * @return {String} The created cookie string. + * @method remove + * @static + */ + remove : function (name /*:String*/, options /*:Object*/) /*:String*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.remove(): Cookie name must be a non-empty string."); + } + + //set options + options = options || {}; + options.expires = new Date(0); + + //set cookie + return this.set(name, "", options); + }, + + /** + * Removes a sub cookie with a given name. + * @param {String} name The name of the cookie in which the subcookie exists. + * @param {String} subName The name of the subcookie to remove. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). This must be the same settings as the original + * subcookie. + * @return {String} The created cookie string. + * @method removeSub + * @static + */ + removeSub : function(name /*:String*/, subName /*:String*/, options /*:Object*/) /*:String*/ { + + //check cookie name + if (!YAHOO.lang.isString(name) || name === ""){ + throw new TypeError("Cookie.removeSub(): Cookie name must be a non-empty string."); + } + + //check subcookie name + if (!YAHOO.lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.removeSub(): Subcookie name must be a non-empty string."); + } + + //get all subcookies for this cookie + var subs = this.getSubs(name); + + //delete the indicated subcookie + if (YAHOO.lang.isObject(subs) && YAHOO.lang.hasOwnProperty(subs, subName)){ + delete subs[subName]; + + //reset the cookie + return this.setSubs(name, subs, options); + } else { + return ""; + } + + }, + + /** + * Sets a cookie with a given name and value. + * @param {String} name The name of the cookie to set. + * @param {Variant} value The value to set for the cookie. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method set + * @static + */ + set : function (name /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name)){ + throw new TypeError("Cookie.set(): Cookie name must be a string."); + } + + if (lang.isUndefined(value)){ + throw new TypeError("Cookie.set(): Value cannot be undefined."); + } + + + var text /*:String*/ = this._createCookieString(name, value, true, options); + document.cookie = text; + return text; + }, + + /** + * Sets a sub cookie with a given name to a particular value. + * @param {String} name The name of the cookie to set. + * @param {String} subName The name of the subcookie to set. + * @param {Variant} value The value to set. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method setSub + * @static + */ + setSub : function (name /*:String*/, subName /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name) || name === ""){ + throw new TypeError("Cookie.setSub(): Cookie name must be a non-empty string."); + } + + if (!lang.isString(subName) || subName === ""){ + throw new TypeError("Cookie.setSub(): Subcookie name must be a non-empty string."); + } + + if (lang.isUndefined(value)){ + throw new TypeError("Cookie.setSub(): Subcookie value cannot be undefined."); + } + + var hash /*:Object*/ = this.getSubs(name); + + if (!lang.isObject(hash)){ + hash = new Object(); + } + + hash[subName] = value; + + return this.setSubs(name, hash, options); + + }, + + /** + * Sets a cookie with a given name to contain a hash of name-value pairs. + * @param {String} name The name of the cookie to set. + * @param {Object} value An object containing name-value pairs. + * @param {Object} options (Optional) An object containing one or more + * cookie options: path (a string), domain (a string), expires (a Date object), + * and secure (true/false). + * @return {String} The created cookie string. + * @method setSubs + * @static + */ + setSubs : function (name /*:String*/, value /*:Object*/, options /*:Object*/) /*:String*/ { + + var lang = YAHOO.lang; + + if (!lang.isString(name)){ + throw new TypeError("Cookie.setSubs(): Cookie name must be a string."); + } + + if (!lang.isObject(value)){ + throw new TypeError("Cookie.setSubs(): Cookie value must be an object."); + } + + var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options); + document.cookie = text; + return text; + } + +}; +YAHOO.register("cookie", YAHOO.util.Cookie, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/editor/editor-debug.js b/lib/yui/editor/editor-debug.js new file mode 100644 index 00000000000..3fa8b06aeff --- /dev/null +++ b/lib/yui/editor/editor-debug.js @@ -0,0 +1,8994 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +(function() { + /** + * @private + **/ +var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang; + /** + * @description

Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

+ * @class ToolbarButtonAdvanced + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, menu, button + * @beta + * + * Provides a toolbar button based on the button and menu widgets. + * @constructor + * @param {String/HTMLElement} el The element to turn into a button. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + if (YAHOO.widget.Button) { + YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button; + /** + * @property buttonType + * @private + * @description Tells if the Button is a Rich Button or a Simple Button + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich'; + /** + * @method checkValue + * @param {String} value The value of the option that we want to mark as selected + * @description Select an option by value + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) { + var _menuItems = this.getMenu().getItems(); + if (_menuItems.length === 0) { + this.getMenu()._onBeforeShow(); + _menuItems = this.getMenu().getItems(); + } + for (var i = 0; i < _menuItems.length; i++) { + _menuItems[i].cfg.setProperty('checked', false); + if (_menuItems[i].value == value) { + _menuItems[i].cfg.setProperty('checked', true); + } + } + }; + } else { + YAHOO.widget.ToolbarButtonAdvanced = function() {}; + } + + + /** + * @description

Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

+ * @class ToolbarButton + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event + * @Extends YAHOO.util.Element + * @beta + * + * Provides a toolbar button based on the button and menu widgets, '); + } else { + html = html.replace(/]*)>/g, ''); + html = html.replace(/]*)>/g, ''); + } + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_UL>/g, '<\/ul>'); + + html = this.filter_invalid_lists(html); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>'); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>'); + + //This should fix &s in URL's + html = html.replace(' & ', 'YUI_AMP'); + html = html.replace('&', '&'); + html = html.replace('YUI_AMP', '&'); + + //Trim the output, removing whitespace from the beginning and end + html = YAHOO.lang.trim(html); + + if (this.get('removeLineBreaks')) { + html = html.replace(/\n/g, '').replace(/\r/g, ''); + html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single + } + + //First empty span + if (html.substring(0, 6).toLowerCase() == '') { + html = html.substring(6); + //Last empty span + if (html.substring(html.length - 7, html.length).toLowerCase() == '') { + html = html.substring(0, html.length - 7); + } + } + + for (var v in this.invalidHTML) { + if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) { + if (Lang.isObject(v) && v.keepContents) { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1'); + } else { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), ''); + } + } + } + + this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html }); + + return html; + }, + /** + * @method filter_invalid_lists + * @param String html The HTML string to filter + * @description Filters invalid ol and ul list markup, converts this:
    1. ..
    to this:
    1. ..
  • + */ + filter_invalid_lists: function(html) { + html = html.replace(/<\/li>\n/gi, ''); + + html = html.replace(/<\/li>
      /gi, '
      1. '); + html = html.replace(/<\/ol>/gi, '
    1. '); + html = html.replace(/<\/ol><\/li>\n/gi, "
    \n"); + + html = html.replace(/<\/li>
      /gi, '
      • '); + html = html.replace(/<\/ul>/gi, '
    • '); + html = html.replace(/<\/ul><\/li>\n?/gi, "
    \n"); + + html = html.replace(/<\/li>/gi, "\n"); + html = html.replace(/<\/ol>/gi, "\n"); + html = html.replace(/
      /gi, "
        \n"); + html = html.replace(/
          /gi, "
            \n"); + return html; + }, + /** + * @method filter_safari + * @param String html The HTML string to filter + * @description Filters strings specific to Safari + * @return String + */ + filter_safari: function(html) { + if (this.browser.webkit) { + // + html = html.replace(/([^>])<\/span>/gi, '    '); + html = html.replace(/Apple-style-span/gi, ''); + html = html.replace(/style="line-height: normal;"/gi, ''); + //Remove bogus LI's + html = html.replace(/
          • <\/li>/gi, ''); + html = html.replace(/
          • <\/li>/gi, ''); + html = html.replace(/
          • <\/li>/gi, ''); + //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break + if (this.get('ptags')) { + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/div>/gi, '

            '); + } else { + html = html.replace(/
            /gi, ''); + html = html.replace(/<\/div>/gi, '
            '); + } + } + return html; + }, + /** + * @method filter_internals + * @param String html The HTML string to filter + * @description Filters internal RTE strings and bogus attrs we don't want + * @return String + */ + filter_internals: function(html) { + html = html.replace(/\r/g, ''); + //Fix stuff we don't want + html = html.replace(/<\/?(body|head|html)[^>]*>/gi, ''); + //Fix last BR in LI + html = html.replace(/<\/li>/gi, '
          • '); + + html = html.replace(/yui-tag-span/gi, ''); + html = html.replace(/yui-tag/gi, ''); + html = html.replace(/yui-non/gi, ''); + html = html.replace(/yui-img/gi, ''); + html = html.replace(/ tag="span"/gi, ''); + html = html.replace(/ class=""/gi, ''); + html = html.replace(/ style=""/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ target=""/gi, ''); + html = html.replace(/ title=""/gi, ''); + + if (this.browser.ie) { + html = html.replace(/ class= /gi, ''); + html = html.replace(/ class= >/gi, ''); + html = html.replace(/_height="([^>])"/gi, ''); + html = html.replace(/_width="([^>])"/gi, ''); + } + + return html; + }, + /** + * @method filter_all_rgb + * @param String str The HTML string to filter + * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00" + * @return String + */ + filter_all_rgb: function(str) { + var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi"); + var arr = str.match(exp); + if (Lang.isArray(arr)) { + for (var i = 0; i < arr.length; i++) { + var color = this.filter_rgb(arr[i]); + str = str.replace(arr[i].toString(), color); + } + } + + return str; + }, + /** + * @method filter_rgb + * @param String css The CSS string containing rgb(#,#,#); + * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00 + * @return String + */ + filter_rgb: function(css) { + if (css.toLowerCase().indexOf('rgb') != -1) { + var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi"); + var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(','); + + if (rgb.length == 5) { + var r = parseInt(rgb[1], 10).toString(16); + var g = parseInt(rgb[2], 10).toString(16); + var b = parseInt(rgb[3], 10).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + css = "#" + r + g + b; + } + } + return css; + }, + /** + * @method pre_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + pre_filter_linebreaks: function(html, markup) { + if (this.browser.webkit) { + html = html.replace(/
            /gi, ''); + html = html.replace(/
            /gi, ''); + } + html = html.replace(/
            /gi, ''); + html = html.replace(/
            /gi, ''); + html = html.replace(//gi, ''); + html = html.replace(/
            /gi, ''); + html = html.replace(/
            <\/div>/gi, ''); + html = html.replace(/

            ( | )<\/p>/g, ''); + html = html.replace(/


             <\/p>/gi, ''); + html = html.replace(/

             <\/p>/gi, ''); + //Fix last BR + html = html.replace(/$/, ''); + //Fix last BR in P + html = html.replace(/<\/p>/g, '

            '); + if (this.browser.ie) { + html = html.replace(/    /g, '\t'); + } + return html; + }, + /** + * @method post_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + post_filter_linebreaks: function(html, markup) { + if (markup == 'xhtml') { + html = html.replace(//g, '
            '); + } else { + html = html.replace(//g, '
            '); + } + return html; + }, + /** + * @method clearEditorDoc + * @description Clear the doc of the Editor + */ + clearEditorDoc: function() { + this._getDoc().body.innerHTML = ' '; + }, + /** + * @method openWindow + * @description Override Method for Advanced Editor + */ + openWindow: function(win) { + }, + /** + * @method moveWindow + * @description Override Method for Advanced Editor + */ + moveWindow: function() { + }, + /** + * @private + * @method _closeWindow + * @description Override Method for Advanced Editor + */ + _closeWindow: function() { + }, + /** + * @method closeWindow + * @description Override Method for Advanced Editor + */ + closeWindow: function() { + //this.unsubscribeAll('afterExecCommand'); + this.toolbar.resetAllButtons(); + this._focusWindow(); + }, + /** + * @method destroy + * @description Destroys the editor, all of it's elements and objects. + * @return {Boolean} + */ + destroy: function() { + YAHOO.log('Destroying Editor', 'warn', 'SimpleEditor'); + if (this.resize) { + YAHOO.log('Destroying Resize', 'warn', 'SimpleEditor'); + this.resize.destroy(); + } + if (this.dd) { + YAHOO.log('Unreg DragDrop Instance', 'warn', 'SimpleEditor'); + this.dd.unreg(); + } + if (this.get('panel')) { + YAHOO.log('Destroying Editor Panel', 'warn', 'SimpleEditor'); + this.get('panel').destroy(); + } + this.saveHTML(); + this.toolbar.destroy(); + YAHOO.log('Restoring TextArea', 'info', 'SimpleEditor'); + this.setStyle('visibility', 'visible'); + this.setStyle('position', 'static'); + this.setStyle('top', ''); + this.setStyle('left', ''); + var textArea = this.get('element'); + this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element')); + this.get('element_cont').get('element').innerHTML = ''; + this.set('handleSubmit', false); //Remove the submit handler + return true; + }, + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'SimpleEditor'; + if (this.get && this.get('element_cont')) { + str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + +/** +* @event toolbarLoaded +* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event cleanHTML +* @description Event is fired after the cleanHTML method is called. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterRender +* @description Event is fired after the render process finishes. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorContentLoaded +* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeNodeChange +* @description Event fires at the beginning of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterNodeChange +* @description Event fires at the end of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeExecCommand +* @description Event fires at the beginning of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterExecCommand +* @description Event fires at the end of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ + + + /** + * @description Singleton object used to track the open window objects and panels across the various open editors + * @class EditorInfo + * @static + */ + YAHOO.widget.EditorInfo = { + /** + * @private + * @property _instances + * @description A reference to all editors on the page. + * @type Object + */ + _instances: {}, + /** + * @private + * @property blankImage + * @description A reference to the blankImage url + * @type String + */ + blankImage: '', + /** + * @private + * @property window + * @description A reference to the currently open window object in any editor on the page. + * @type Object YAHOO.widget.EditorWindow + */ + window: {}, + /** + * @private + * @property panel + * @description A reference to the currently open panel in any editor on the page. + * @type Object YAHOO.widget.Overlay + */ + panel: null, + /** + * @method getEditorById + * @description Returns a reference to the Editor object associated with the given textarea + * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of + * @return Object YAHOO.widget.Editor + */ + getEditorById: function(id) { + if (!YAHOO.lang.isString(id)) { + //Not a string, assume a node Reference + id = id.id; + } + if (this._instances[id]) { + return this._instances[id]; + } + return false; + }, + /** + * @method toString + * @description Returns a string representing the EditorInfo. + * @return {String} + */ + toString: function() { + var len = 0; + for (var i in this._instances) { + if (Lang.hasOwnProperty(this._instances, i)) { + len++; + } + } + return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')'; + } + }; + + + + +})(); +/** + * @module editor + * @description

            The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.

            + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, simpleeditor + * @optional dragdrop, animation, menu, button + * @beta + */ + +(function() { +var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang, + Toolbar = YAHOO.widget.Toolbar; + + /** + * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization. + * @constructor + * @class Editor + * @extends YAHOO.widget.SimpleEditor + * @param {String/HTMLElement} el The textarea element to turn into an editor. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + + YAHOO.widget.Editor = function(el, attrs) { + YAHOO.log('Editor Initalizing', 'info', 'Editor'); + YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs); + }; + + YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, { + /** + * @private + * @property _undoCache + * @description An Array hash of the Undo Levels. + * @type Array + */ + _undoCache: null, + /** + * @private + * @property _undoLevel + * @description The index of the current undo state. + * @type Number + */ + _undoLevel: null, + /** + * @private + * @method _hasUndoLevel + * @description Checks to see if we have an undo level available + * @return Boolean + */ + _hasUndoLevel: function() { + return (this._undoCache.length && this._undoLevel); + }, + /** + * @private + * @method _undoNodeChange + * @description nodeChange listener for undo processing + */ + _undoNodeChange: function() { + var undo_button = this.toolbar.getButtonByValue('undo'), + redo_button = this.toolbar.getButtonByValue('redo'); + if (undo_button && redo_button) { + if (this._hasUndoLevel()) { + this.toolbar.enableButton(undo_button); + } + if (this._undoLevel < this._undoCache.length) { + this.toolbar.enableButton(redo_button); + } + } + }, + /** + * @private + * @method _checkUndo + * @description Prunes the undo cache when it reaches the maxUndo config + */ + _checkUndo: function() { + var len = this._undoCache.length, + tmp = []; + if (len >= this.get('maxUndo')) { + //YAHOO.log('Undo cache too large (' + len + '), pruning..', 'info', 'SimpleEditor'); + for (var i = (len - this.get('maxUndo')); i < len; i++) { + tmp.push(this._undoCache[i]); + } + this._undoCache = tmp; + } + }, + /** + * @private + * @method _putUndo + * @description Puts the content of the Editor into the _undoCache. + * //TODO Convert the hash to a series of TEXTAREAS to store state in. + * @param {String} str The content of the Editor + */ + _putUndo: function(str) { + this._undoCache.push(str); + }, + /** + * @private + * @method _getUndo + * @description Get's a level from the undo cache. + * @param {Number} index The index of the undo level we want to get. + * @return {String} + */ + _getUndo: function(index) { + return this._undoCache[index]; + }, + /** + * @private + * @method _storeUndo + * @description Method to call when you want to store an undo state. Currently called from nodeChange and _handleKeyUp + */ + _storeUndo: function() { + if (this._lastCommand === 'undo' || this._lastCommand === 'redo') { + return false; + } + if (!this._undoCache) { + this._undoCache = []; + } + this._checkUndo(); + var str = this.getEditorHTML(); + var last = this._undoCache[this._undoCache.length - 1]; + if (last) { + if (str !== last) { + //YAHOO.log('Storing Undo', 'info', 'SimpleEditor'); + this._putUndo(str); + } + } else { + //YAHOO.log('Storing Undo', 'info', 'SimpleEditor'); + this._putUndo(str); + } + this._undoLevel = this._undoCache.length; + this._undoNodeChange(); + }, + /** + * @property STR_BEFORE_EDITOR + * @description The accessibility string for the element before the iFrame + * @type String + */ + STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names.

            Common formatting keyboard shortcuts:

            • Control Shift B sets text to bold
            • Control Shift I sets text to italic
            • Control Shift U underlines text
            • Control Shift [ aligns text left
            • Control Shift | centers text
            • Control Shift ] aligns text right
            • Control Shift L adds an HTML link
            • To exit this text editor use the keyboard shortcut Control + Shift + ESC.
            ', + /** + * @property STR_CLOSE_WINDOW + * @description The Title of the close button in the Editor Window + * @type String + */ + STR_CLOSE_WINDOW: 'Close Window', + /** + * @property STR_CLOSE_WINDOW_NOTE + * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window + * @type String + */ + STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key', + /** + * @property STR_IMAGE_PROP_TITLE + * @description The title for the Image Property Editor Window + * @type String + */ + STR_IMAGE_PROP_TITLE: 'Image Options', + /** + * @property STR_IMAGE_URL + * @description The label string for Image URL + * @type String + */ + STR_IMAGE_URL: 'Image URL', + /** + * @property STR_IMAGE_TITLE + * @description The label string for Image Description + * @type String + */ + STR_IMAGE_TITLE: 'Description', + /** + * @property STR_IMAGE_SIZE + * @description The label string for Image Size + * @type String + */ + STR_IMAGE_SIZE: 'Size', + /** + * @property STR_IMAGE_ORIG_SIZE + * @description The label string for Original Image Size + * @type String + */ + STR_IMAGE_ORIG_SIZE: 'Original Size', + /** + * @property STR_IMAGE_COPY + * @description The label string for the image copy and paste message for Opera and Safari + * @type String + */ + STR_IMAGE_COPY: 'Note:To move this image just highlight it, cut, and paste where ever you\'d like.', + /** + * @property STR_IMAGE_PADDING + * @description The label string for the image padding. + * @type String + */ + STR_IMAGE_PADDING: 'Padding', + /** + * @property STR_IMAGE_BORDER + * @description The label string for the image border. + * @type String + */ + STR_IMAGE_BORDER: 'Border', + /** + * @property STR_IMAGE_BORDER_SIZE + * @description The label string for the image border size. + * @type String + */ + STR_IMAGE_BORDER_SIZE: 'Border Size', + /** + * @property STR_IMAGE_BORDER_TYPE + * @description The label string for the image border type. + * @type String + */ + STR_IMAGE_BORDER_TYPE: 'Border Type', + /** + * @property STR_IMAGE_TEXTFLOW + * @description The label string for the image text flow. + * @type String + */ + STR_IMAGE_TEXTFLOW: 'Text Flow', + /** + * @property STR_LOCAL_FILE_WARNING + * @description The label string for the local file warning. + * @type String + */ + STR_LOCAL_FILE_WARNING: 'Note:This image/link points to a file on your computer and will not be accessible to others on the internet.', + /** + * @property STR_LINK_PROP_TITLE + * @description The label string for the Link Property Editor Window. + * @type String + */ + STR_LINK_PROP_TITLE: 'Link Options', + /** + * @property STR_LINK_PROP_REMOVE + * @description The label string for the Remove link from text link inside the property editor. + * @type String + */ + STR_LINK_PROP_REMOVE: 'Remove link from text', + /** + * @property STR_LINK_NEW_WINDOW + * @description The string for the open in a new window label. + * @type String + */ + STR_LINK_NEW_WINDOW: 'Open in a new window.', + /** + * @property STR_LINK_TITLE + * @description The string for the link description. + * @type String + */ + STR_LINK_TITLE: 'Description', + /** + * @protected + * @property CLASS_LOCAL_FILE + * @description CSS class applied to an element when it's found to have a local url. + * @type String + */ + CLASS_LOCAL_FILE: 'warning-localfile', + /** + * @protected + * @property CLASS_HIDDEN + * @description CSS class applied to the body when the hiddenelements button is pressed. + * @type String + */ + CLASS_HIDDEN: 'yui-hidden', + /** + * @method init + * @description The Editor class' initialization method + */ + init: function(p_oElement, p_oAttributes) { + YAHOO.log('init', 'info', 'Editor'); + + this._windows = {}; + this._defaultToolbar = { + collapse: true, + titlebar: 'Text Editing Tools', + draggable: false, + buttonType: 'advanced', + buttons: [ + { group: 'fontstyle', label: 'Font Name and Size', + buttons: [ + { type: 'select', label: 'Arial', value: 'fontname', disabled: true, + menu: [ + { text: 'Arial', checked: true }, + { text: 'Arial Black' }, + { text: 'Comic Sans MS' }, + { text: 'Courier New' }, + { text: 'Lucida Console' }, + { text: 'Tahoma' }, + { text: 'Times New Roman' }, + { text: 'Trebuchet MS' }, + { text: 'Verdana' } + ] + }, + { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true } + ] + }, + { type: 'separator' }, + { group: 'textstyle', label: 'Font Style', + buttons: [ + { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' }, + { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' }, + { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' }, + { type: 'separator' }, + { type: 'push', label: 'Subscript', value: 'subscript', disabled: true }, + { type: 'push', label: 'Superscript', value: 'superscript', disabled: true } + ] + }, + { type: 'separator' }, + { group: 'textstyle2', label: ' ', + buttons: [ + { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }, + { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }, + { type: 'separator' }, + { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true }, + { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' } + ] + }, + { type: 'separator' }, + { group: 'undoredo', label: 'Undo/Redo', + buttons: [ + { type: 'push', label: 'Undo', value: 'undo', disabled: true }, + { type: 'push', label: 'Redo', value: 'redo', disabled: true } + + ] + }, + { type: 'separator' }, + { group: 'alignment', label: 'Alignment', + buttons: [ + { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' }, + { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' }, + { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' }, + { type: 'push', label: 'Justify', value: 'justifyfull' } + ] + }, + { type: 'separator' }, + { group: 'parastyle', label: 'Paragraph Style', + buttons: [ + { type: 'select', label: 'Normal', value: 'heading', disabled: true, + menu: [ + { text: 'Normal', value: 'none', checked: true }, + { text: 'Header 1', value: 'h1' }, + { text: 'Header 2', value: 'h2' }, + { text: 'Header 3', value: 'h3' }, + { text: 'Header 4', value: 'h4' }, + { text: 'Header 5', value: 'h5' }, + { text: 'Header 6', value: 'h6' } + ] + } + ] + }, + { type: 'separator' }, + + { group: 'indentlist2', label: 'Indenting and Lists', + buttons: [ + { type: 'push', label: 'Indent', value: 'indent', disabled: true }, + { type: 'push', label: 'Outdent', value: 'outdent', disabled: true }, + { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' }, + { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' } + ] + }, + { type: 'separator' }, + { group: 'insertitem', label: 'Insert Item', + buttons: [ + { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true }, + { type: 'push', label: 'Insert Image', value: 'insertimage' } + ] + } + ] + }; + + this._defaultImageToolbarConfig = { + buttonType: this._defaultToolbar.buttonType, + buttons: [ + { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':', + buttons: [ + { type: 'push', label: 'Left', value: 'left' }, + { type: 'push', label: 'Inline', value: 'inline' }, + { type: 'push', label: 'Block', value: 'block' }, + { type: 'push', label: 'Right', value: 'right' } + ] + }, + { type: 'separator' }, + { group: 'padding', label: this.STR_IMAGE_PADDING + ':', + buttons: [ + { type: 'spin', label: '0', value: 'padding', range: [0, 50] } + ] + }, + { type: 'separator' }, + { group: 'border', label: this.STR_IMAGE_BORDER + ':', + buttons: [ + { type: 'select', label: this.STR_IMAGE_BORDER_SIZE, value: 'bordersize', + menu: [ + { text: 'none', value: '0', checked: true }, + { text: '1px', value: '1' }, + { text: '2px', value: '2' }, + { text: '3px', value: '3' }, + { text: '4px', value: '4' }, + { text: '5px', value: '5' } + ] + }, + { type: 'select', label: this.STR_IMAGE_BORDER_TYPE, value: 'bordertype', disabled: true, + menu: [ + { text: 'Solid', value: 'solid', checked: true }, + { text: 'Dashed', value: 'dashed' }, + { text: 'Dotted', value: 'dotted' } + ] + }, + { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true } + ] + } + ] + }; + + YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes); + }, + _render: function() { + YAHOO.widget.Editor.superclass._render.apply(this, arguments); + var self = this; + //Render the panel in another thread and delay it a little.. + window.setTimeout(function() { + self._renderPanel.call(self); + }, 800); + }, + /** + * @method initAttributes + * @description Initializes all of the configuration attributes used to create + * the editor. + * @param {Object} attr Object literal specifying a set of + * configuration attributes used to create the editor. + */ + initAttributes: function(attr) { + YAHOO.widget.Editor.superclass.initAttributes.call(this, attr); + + /** + * @attribute localFileWarning + * @description Should we throw the warning if we detect a file that is local to their machine? + * @default true + * @type Boolean + */ + this.setAttributeConfig('localFileWarning', { + value: attr.locaFileWarning || true + }); + + /** + * @attribute hiddencss + * @description The CSS used to show/hide hidden elements on the page, these rules must be prefixed with the class provided in this.CLASS_HIDDEN + * @default
            +            .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table {
            +                border: 1px dotted #ccc;
            +            }
            +            .yui-hidden .yui-non {
            +                border: none;
            +            }
            +            .yui-hidden img {
            +                padding: 2px;
            +            }
            + * @type String + */ + this.setAttributeConfig('hiddencss', { + value: attr.hiddencss || '.yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }', + writeOnce: true + }); + + }, + /** + * @private + * @method _windows + * @description A reference to the HTML elements used for the body of Editor Windows. + */ + _windows: null, + /** + * @private + * @method _defaultImageToolbar + * @description A reference to the Toolbar Object inside Image Editor Window. + */ + _defaultImageToolbar: null, + /** + * @private + * @method _defaultImageToolbarConfig + * @description Config to be used for the default Image Editor Window. + */ + _defaultImageToolbarConfig: null, + /** + * @private + * @method _fixNodes + * @description Fix href and imgs as well as remove invalid HTML. + */ + _fixNodes: function() { + YAHOO.widget.Editor.superclass._fixNodes.call(this); + var url = ''; + + var imgs = this._getDoc().getElementsByTagName('img'); + for (var im = 0; im < imgs.length; im++) { + if (imgs[im].getAttribute('href', 2)) { + url = imgs[im].getAttribute('src', 2); + if (this._isLocalFile(url)) { + Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE); + } else { + Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE); + } + } + } + var fakeAs = this._getDoc().body.getElementsByTagName('a'); + for (var a = 0; a < fakeAs.length; a++) { + if (fakeAs[a].getAttribute('href', 2)) { + url = fakeAs[a].getAttribute('href', 2); + if (this._isLocalFile(url)) { + Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE); + } else { + Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE); + } + } + } + }, + /** + * @private + * @property _disabled + * @description The Toolbar items that should be disabled if there is no selection present in the editor. + * @type Array + */ + _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ], + /** + * @private + * @property _alwaysDisabled + * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor. + * @type Object + */ + _alwaysDisabled: { 'outdent': true }, + /** + * @private + * @property _alwaysEnabled + * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor. + * @type Object + */ + _alwaysEnabled: { hiddenelements: true }, + /** + * @private + * @method _handleKeyDown + * @param {Event} ev The event we are working on. + * @description Override method that handles some new keydown events inside the iFrame document. + */ + _handleKeyDown: function(ev) { + YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev); + var doExec = false, + action = null, + exec = false; + + switch (ev.keyCode) { + //case 219: //Left + case this._keyMap.JUSTIFY_LEFT.key: //Left + if (this._checkKey(this._keyMap.JUSTIFY_LEFT, ev)) { + action = 'justifyleft'; + doExec = true; + } + break; + //case 220: //Center + case this._keyMap.JUSTIFY_CENTER.key: + if (this._checkKey(this._keyMap.JUSTIFY_CENTER, ev)) { + action = 'justifycenter'; + doExec = true; + } + break; + case 221: //Right + case this._keyMap.JUSTIFY_RIGHT.key: + if (this._checkKey(this._keyMap.JUSTIFY_RIGHT, ev)) { + action = 'justifyright'; + doExec = true; + } + break; + } + if (doExec && action) { + this.execCommand(action, null); + Event.stopEvent(ev); + this.nodeChange(); + } + }, + /** + * @private + * @method _renderCreateLinkWindow + * @description Pre renders the CreateLink window so we get faster window opening. + */ + _renderCreateLinkWindow: function() { + var str = ''; + str += ''; + str += ''; + + var body = document.createElement('div'); + body.innerHTML = str; + + var unlinkCont = document.createElement('div'); + unlinkCont.className = 'removeLink'; + var unlink = document.createElement('a'); + unlink.href = '#'; + unlink.innerHTML = this.STR_LINK_PROP_REMOVE; + unlink.title = this.STR_LINK_PROP_REMOVE; + Event.on(unlink, 'click', function(ev) { + Event.stopEvent(ev); + this.execCommand('unlink'); + this.closeWindow(); + }, this, true); + unlinkCont.appendChild(unlink); + body.appendChild(unlinkCont); + + this._windows.createlink = {}; + this._windows.createlink.body = body; + body.style.display = 'none'; + this.get('panel').editor_form.appendChild(body); + this.fireEvent('windowCreateLinkRender', { type: 'windowCreateLinkRender', panel: this.get('panel'), body: body }); + return body; + }, + _handleCreateLinkClick: function() { + var el = this._getSelectedElement(); + if (this._isElement(el, 'img')) { + this.STOP_EXEC_COMMAND = true; + this.currentElement[0] = el; + this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar }); + this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this }); + return false; + } + if (this.get('limitCommands')) { + if (!this.toolbar.getButtonByValue('createlink')) { + YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'Editor'); + return false; + } + } + + this.on('afterExecCommand', function() { + var win = new YAHOO.widget.EditorWindow('createlink', { + width: '350px' + }); + + var el = this.currentElement[0], + url = '', + title = '', + target = '', + localFile = false; + if (el) { + win.el = el; + if (el.getAttribute('href', 2) !== null) { + url = el.getAttribute('href', 2); + if (this._isLocalFile(url)) { + //Local File throw Warning + YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor'); + win.setFooter(this.STR_LOCAL_FILE_WARNING); + localFile = true; + } else { + win.setFooter(' '); + } + } + if (el.getAttribute('title') !== null) { + title = el.getAttribute('title'); + } + if (el.getAttribute('target') !== null) { + target = el.getAttribute('target'); + } + } + var body = null; + if (this._windows.createlink && this._windows.createlink.body) { + body = this._windows.createlink.body; + } else { + body = this._renderCreateLinkWindow(); + } + + win.setHeader(this.STR_LINK_PROP_TITLE); + win.setBody(body); + + Event.purgeElement(this.get('id') + '_createlink_url'); + + Dom.get(this.get('id') + '_createlink_url').value = url; + Dom.get(this.get('id') + '_createlink_title').value = title; + Dom.get(this.get('id') + '_createlink_target').checked = ((target) ? true : false); + + + Event.onAvailable(this.get('id') + '_createlink_url', function() { + var id = this.get('id'); + window.setTimeout(function() { + try { + YAHOO.util.Dom.get(id + '_createlink_url').focus(); + } catch (e) {} + }, 50); + + if (this._isLocalFile(url)) { + //Local File throw Warning + Dom.addClass(this.get('id') + '_createlink_url', 'warning'); + YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(this.get('id') + '_createlink_url', 'warning'); + this.get('panel').setFooter(' '); + } + Event.on(this.get('id') + '_createlink_url', 'blur', function() { + var url = Dom.get(this.get('id') + '_createlink_url'); + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + } + }, this, true); + }, this, true); + + this.openWindow(win); + + }); + }, + /** + * @private + * @method _handleCreateLinkWindowClose + * @description Handles the closing of the Link Properties Window. + */ + _handleCreateLinkWindowClose: function() { + + var url = Dom.get(this.get('id') + '_createlink_url'), + target = Dom.get(this.get('id') + '_createlink_target'), + title = Dom.get(this.get('id') + '_createlink_title'), + el = arguments[0].win.el, + a = el; + + if (url && url.value) { + var urlValue = url.value; + if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + //Found an @ sign, prefix with mailto: + urlValue = 'mailto:' + urlValue; + } else { + // :// not found adding + if (urlValue.substring(0, 1) != '#') { + urlValue = 'http:/'+'/' + urlValue; + } + + } + } + el.setAttribute('href', urlValue); + if (target.checked) { + el.setAttribute('target', target.value); + } else { + el.setAttribute('target', ''); + } + el.setAttribute('title', ((title.value) ? title.value : '')); + + } else { + var _span = this._getDoc().createElement('span'); + _span.innerHTML = el.innerHTML; + Dom.addClass(_span, 'yui-non'); + el.parentNode.replaceChild(_span, el); + } + Dom.removeClass(url, 'warning'); + Dom.get(this.get('id') + '_createlink_url').value = ''; + Dom.get(this.get('id') + '_createlink_title').value = ''; + Dom.get(this.get('id') + '_createlink_target').checked = false; + this.nodeChange(); + this.currentElement = []; + + }, + /** + * @private + * @method _renderInsertImageWindow + * @description Pre renders the InsertImage window so we get faster window opening. + */ + _renderInsertImageWindow: function() { + var el = this.currentElement[0]; + var str = ''; + var body = document.createElement('div'); + body.innerHTML = str; + + var tbarCont = document.createElement('div'); + tbarCont.id = this.get('id') + '_img_toolbar'; + body.appendChild(tbarCont); + + var str2 = ''; + str2 += ''; + str2 += ''; + var div = document.createElement('div'); + div.innerHTML = str2; + body.appendChild(div); + + var o = {}; + Lang.augmentObject(o, this._defaultImageToolbarConfig); //Break the config reference + + var tbar = new YAHOO.widget.Toolbar(tbarCont, o); + tbar.editor_el = el; + this._defaultImageToolbar = tbar; + + var cont = tbar.get('cont'); + var hw = document.createElement('div'); + hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width'; + hw.innerHTML = '

            ' + this.STR_IMAGE_SIZE + ':

            '; + /* + var orgSize = ''; + if ((height != oheight) || (width != owidth)) { + orgSize = '' + this.STR_IMAGE_ORIG_SIZE + '
            '+ owidth +' x ' + oheight + '
            '; + } + */ + hw.innerHTML += ' x '; + cont.insertBefore(hw, cont.firstChild); + + Event.onAvailable(this.get('id') + '_insertimage_width', function() { + Event.on(this.get('id') + '_insertimage_width', 'blur', function() { + var value = parseInt(Dom.get(this.get('id') + '_insertimage_width').value, 10); + if (value > 5) { + this._defaultImageToolbar.editor_el.style.width = value + 'px'; + //Removed moveWindow call so the window doesn't jump + //this.moveWindow(); + } + }, this, true); + }, this, true); + Event.onAvailable(this.get('id') + '_insertimage_height', function() { + Event.on(this.get('id') + '_insertimage_height', 'blur', function() { + var value = parseInt(Dom.get(this.get('id') + '_insertimage_height').value, 10); + if (value > 5) { + this._defaultImageToolbar.editor_el.style.height = value + 'px'; + //Removed moveWindow call so the window doesn't jump + //this.moveWindow(); + } + }, this, true); + }, this, true); + + + tbar.on('colorPickerClicked', function(o) { + var size = '1', type = 'solid', color = 'black', el = this._defaultImageToolbar.editor_el; + + if (el.style.borderLeftWidth) { + size = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + type = el.style.borderLeftStyle; + } + if (el.style.borderLeftColor) { + color = el.style.borderLeftColor; + } + var borderString = size + 'px ' + type + ' #' + o.color; + el.style.border = borderString; + }, this, true); + + tbar.on('buttonClick', function(o) { + var value = o.button.value, + el = this._defaultImageToolbar.editor_el, + borderString = ''; + if (o.button.menucmd) { + value = o.button.menucmd; + } + var size = '1', type = 'solid', color = 'black'; + + /* All border calcs are done on the left border + since our default interface only supports + one border size/type and color */ + if (el.style.borderLeftWidth) { + size = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + type = el.style.borderLeftStyle; + } + if (el.style.borderLeftColor) { + color = el.style.borderLeftColor; + } + switch(value) { + case 'bordersize': + if (this.browser.webkit && this._lastImage) { + Dom.removeClass(this._lastImage, 'selected'); + this._lastImage = null; + } + + borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color; + el.style.border = borderString; + if (parseInt(o.button.value, 10) > 0) { + tbar.enableButton('bordertype'); + tbar.enableButton('bordercolor'); + } else { + tbar.disableButton('bordertype'); + tbar.disableButton('bordercolor'); + } + break; + case 'bordertype': + if (this.browser.webkit && this._lastImage) { + Dom.removeClass(this._lastImage, 'selected'); + this._lastImage = null; + } + borderString = size + 'px ' + o.button.value + ' ' + color; + el.style.border = borderString; + break; + case 'right': + case 'left': + tbar.deselectAllButtons(); + el.style.display = ''; + el.align = o.button.value; + break; + case 'inline': + tbar.deselectAllButtons(); + el.style.display = ''; + el.align = ''; + break; + case 'block': + tbar.deselectAllButtons(); + el.style.display = 'block'; + el.align = 'center'; + break; + case 'padding': + var _button = tbar.getButtonById(o.button.id); + el.style.margin = _button.get('label') + 'px'; + break; + } + tbar.selectButton(o.button.value); + if (value !== 'padding') { + this.moveWindow(); + } + }, this, true); + + + + if (this.get('localFileWarning')) { + Event.on(this.get('id') + '_insertimage_link', 'blur', function() { + var url = Dom.get(this.get('id') + '_insertimage_link'); + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + this.get('panel').setFooter(this.STR_IMAGE_COPY); + } + } + }, this, true); + } + + Event.on(this.get('id') + '_insertimage_url', 'blur', function() { + var url = Dom.get(this.get('id') + '_insertimage_url'); + if (url.value && el) { + if (url.value == el.getAttribute('src', 2)) { + YAHOO.log('Images are the same, bail on blur handler', 'info', 'Editor'); + return false; + } + } + YAHOO.log('Images are different, process blur handler', 'info', 'Editor'); + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else if (this.currentElement[0]) { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + this.get('panel').setFooter(this.STR_IMAGE_COPY); + } + + if (url && url.value && (url.value != this.STR_IMAGE_HERE)) { + this.currentElement[0].setAttribute('src', url.value); + var self = this, + img = new Image(); + + img.onerror = function() { + url.value = self.STR_IMAGE_HERE; + img.setAttribute('src', self.get('blankimage')); + self.currentElement[0].setAttribute('src', self.get('blankimage')); + YAHOO.util.Dom.get(self.get('id') + '_insertimage_height').value = img.height; + YAHOO.util.Dom.get(self.get('id') + '_insertimage_width').value = img.width; + }; + var id = this.get('id'); + window.setTimeout(function() { + YAHOO.util.Dom.get(id + '_insertimage_height').value = img.height; + YAHOO.util.Dom.get(id + '_insertimage_width').value = img.width; + if (self.currentElement && self.currentElement[0]) { + if (!self.currentElement[0]._height) { + self.currentElement[0]._height = img.height; + } + if (!self.currentElement[0]._width) { + self.currentElement[0]._width = img.width; + } + } + //Removed moveWindow call so the window doesn't jump + //self.moveWindow(); + }, 800); //Bumped the timeout up to account for larger images.. + + if (url.value != this.STR_IMAGE_HERE) { + img.src = url.value; + } + } + } + }, this, true); + + + + this._windows.insertimage = {}; + this._windows.insertimage.body = body; + body.style.display = 'none'; + this.get('panel').editor_form.appendChild(body); + this.fireEvent('windowInsertImageRender', { type: 'windowInsertImageRender', panel: this.get('panel'), body: body, toolbar: tbar }); + return body; + }, + /** + * @private + * @method _handleInsertImageClick + * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked. + */ + _handleInsertImageClick: function() { + if (this.get('limitCommands')) { + if (!this.toolbar.getButtonByValue('insertimage')) { + YAHOO.log('Toolbar Button for (insertimage) was not found, skipping exec.', 'info', 'Editor'); + return false; + } + } + this.on('afterExecCommand', function() { + var el = this.currentElement[0], + body = null, + link = '', + target = '', + tbar = null, + title = '', + src = '', + align = '', + height = 75, + width = 75, + padding = 0, + oheight = 0, + owidth = 0, + blankimage = false, + win = new YAHOO.widget.EditorWindow('insertimage', { + width: '415px' + }); + + if (!el) { + el = this._getSelectedElement(); + } + if (el) { + win.el = el; + if (el.getAttribute('src')) { + src = el.getAttribute('src', 2); + if (src.indexOf(this.get('blankimage')) != -1) { + src = this.STR_IMAGE_HERE; + blankimage = true; + } + } + if (el.getAttribute('alt', 2)) { + title = el.getAttribute('alt', 2); + } + if (el.getAttribute('title', 2)) { + title = el.getAttribute('title', 2); + } + + if (el.parentNode && this._isElement(el.parentNode, 'a')) { + link = el.parentNode.getAttribute('href', 2); + if (el.parentNode.getAttribute('target') !== null) { + target = el.parentNode.getAttribute('target'); + } + } + height = parseInt(el.height, 10); + width = parseInt(el.width, 10); + if (el.style.height) { + height = parseInt(el.style.height, 10); + } + if (el.style.width) { + width = parseInt(el.style.width, 10); + } + if (el.style.margin) { + padding = parseInt(el.style.margin, 10); + } + if (!el._height) { + el._height = height; + } + if (!el._width) { + el._width = width; + } + oheight = el._height; + owidth = el._width; + } + if (this._windows.insertimage && this._windows.insertimage.body) { + body = this._windows.insertimage.body; + this._defaultImageToolbar.resetAllButtons(); + } else { + body = this._renderInsertImageWindow(); + } + + tbar = this._defaultImageToolbar; + tbar.editor_el = el; + + + var bsize = '0'; + var btype = 'solid'; + if (el.style.borderLeftWidth) { + bsize = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + btype = el.style.borderLeftStyle; + } + var bs_button = tbar.getButtonByValue('bordersize'); + var bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : 'none'); + bs_button.set('label', ''+bSizeStr+''); + this._updateMenuChecked('bordersize', bsize, tbar); + + var bt_button = tbar.getButtonByValue('bordertype'); + bt_button.set('label', ''); + this._updateMenuChecked('bordertype', btype, tbar); + if (parseInt(bsize, 10) > 0) { + tbar.enableButton(bt_button); + tbar.enableButton(bs_button); + tbar.enableButton('bordercolor'); + } + + if ((el.align == 'right') || (el.align == 'left')) { + tbar.selectButton(el.align); + } else if (el.style.display == 'block') { + tbar.selectButton('block'); + } else { + tbar.selectButton('inline'); + } + if (parseInt(el.style.marginLeft, 10) > 0) { + tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10)); + } + if (el.style.borderSize) { + tbar.selectButton('bordersize'); + tbar.selectButton(parseInt(el.style.borderSize, 10)); + } + tbar.getButtonByValue('padding').set('label', ''+padding); + + + + win.setHeader(this.STR_IMAGE_PROP_TITLE); + win.setBody(body); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + win.setFooter(this.STR_IMAGE_COPY); + } + this.openWindow(win); + Dom.get(this.get('id') + '_insertimage_url').value = src; + Dom.get(this.get('id') + '_insertimage_title').value = title; + Dom.get(this.get('id') + '_insertimage_link').value = link; + Dom.get(this.get('id') + '_insertimage_target').checked = ((target) ? true : false); + Dom.get(this.get('id') + '_insertimage_width').value = width; + Dom.get(this.get('id') + '_insertimage_height').value = height; + + + var orgSize = ''; + if ((height != oheight) || (width != owidth)) { + var s = document.createElement('span'); + s.className = 'info'; + //s.innerHTML = this.STR_IMAGE_ORIG_SIZE + '
            '+ owidth +' x ' + oheight; + s.innerHTML = this.STR_IMAGE_ORIG_SIZE + ': ('+ owidth +' x ' + oheight + ')'; + if (Dom.get(this.get('id') + '_insertimage_height').nextSibling) { + var old = Dom.get(this.get('id') + '_insertimage_height').nextSibling; + old.parentNode.removeChild(old); + } + Dom.get(this.get('id') + '_insertimage_height').parentNode.appendChild(s); + } + + this.toolbar.selectButton('insertimage'); + var id = this.get('id'); + window.setTimeout(function() { + try { + YAHOO.util.Dom.get(id + '_insertimage_url').focus(); + if (blankimage) { + YAHOO.util.Dom.get(id + '_insertimage_url').select(); + } + } catch (e) {} + }, 50); + + }); + }, + /** + * @private + * @method _handleInsertImageWindowClose + * @description Handles the closing of the Image Properties Window. + */ + _handleInsertImageWindowClose: function() { + var url = Dom.get(this.get('id') + '_insertimage_url'), + title = Dom.get(this.get('id') + '_insertimage_title'), + link = Dom.get(this.get('id') + '_insertimage_link'), + target = Dom.get(this.get('id') + '_insertimage_target'), + el = arguments[0].win.el; + + if (url && url.value && (url.value != this.STR_IMAGE_HERE)) { + el.setAttribute('src', url.value); + el.setAttribute('title', title.value); + el.setAttribute('alt', title.value); + var par = el.parentNode; + if (link.value) { + var urlValue = link.value; + if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + //Found an @ sign, prefix with mailto: + urlValue = 'mailto:' + urlValue; + } else { + // :// not found adding + urlValue = 'http:/'+'/' + urlValue; + } + } + if (par && this._isElement(par, 'a')) { + par.setAttribute('href', urlValue); + if (target.checked) { + par.setAttribute('target', target.value); + } else { + par.setAttribute('target', ''); + } + } else { + var _a = this._getDoc().createElement('a'); + _a.setAttribute('href', urlValue); + if (target.checked) { + _a.setAttribute('target', target.value); + } else { + _a.setAttribute('target', ''); + } + el.parentNode.replaceChild(_a, el); + _a.appendChild(el); + } + } else { + if (par && this._isElement(par, 'a')) { + par.parentNode.replaceChild(el, par); + } + } + } else { + //No url/src given, remove the node from the document + el.parentNode.removeChild(el); + } + Dom.get(this.get('id') + '_insertimage_url').value = ''; + Dom.get(this.get('id') + '_insertimage_title').value = ''; + Dom.get(this.get('id') + '_insertimage_link').value = ''; + Dom.get(this.get('id') + '_insertimage_target').checked = false; + Dom.get(this.get('id') + '_insertimage_width').value = 0; + Dom.get(this.get('id') + '_insertimage_height').value = 0; + this._defaultImageToolbar.resetAllButtons(); + this.currentElement = []; + this.nodeChange(); + }, + /** + * @property EDITOR_PANEL_ID + * @description HTML id to give the properties window in the DOM. + * @type String + */ + EDITOR_PANEL_ID: '-panel', + /** + * @private + * @method _renderPanel + * @description Renders the panel used for Editor Windows to the document so we can start using it.. + * @return {YAHOO.widget.Overlay} + */ + _renderPanel: function() { + var panel = new YAHOO.widget.Overlay(this.get('id') + this.EDITOR_PANEL_ID, { + width: '300px', + iframe: true, + visible: false, + underlay: 'none', + draggable: false, + close: false + }); + this.set('panel', panel); + + this.get('panel').setBody('---'); + this.get('panel').setHeader(' '); + this.get('panel').setFooter(' '); + + + var body = document.createElement('div'); + body.className = this.CLASS_PREFIX + '-body-cont'; + for (var b in this.browser) { + if (this.browser[b]) { + Dom.addClass(body, b); + break; + } + } + Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button')); + + var _note = document.createElement('h3'); + _note.className = 'yui-editor-skipheader'; + _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE; + body.appendChild(_note); + var form = document.createElement('form'); + form.setAttribute('method', 'GET'); + panel.editor_form = form; + + Event.on(form, 'submit', function(ev) { + Event.stopEvent(ev); + }, this, true); + body.appendChild(form); + var _close = document.createElement('span'); + _close.innerHTML = 'X'; + _close.title = this.STR_CLOSE_WINDOW; + _close.className = 'close'; + + Event.on(_close, 'click', this.closeWindow, this, true); + + var _knob = document.createElement('span'); + _knob.innerHTML = '^'; + _knob.className = 'knob'; + panel.editor_knob = _knob; + + var _header = document.createElement('h3'); + panel.editor_header = _header; + _header.innerHTML = ''; + + panel.setHeader(' '); //Clear the current header + panel.appendToHeader(_header); + _header.appendChild(_close); + _header.appendChild(_knob); + panel.setBody(' '); //Clear the current body + panel.setFooter(' '); //Clear the current footer + panel.appendToBody(body); //Append the new DOM node to it + + Event.on(panel.element, 'click', function(ev) { + Event.stopPropagation(ev); + }); + + var fireShowEvent = function() { + //panel.bringToTop(); + }; + panel.showEvent.subscribe(fireShowEvent, this, true); + panel.renderEvent.subscribe(function() { + this._renderInsertImageWindow(); + this._renderCreateLinkWindow(); + this.fireEvent('windowRender', { type: 'windowRender', panel: panel }); + }, this, true); + + if (this.DOMReady) { + this.get('panel').render(document.body); + //Render to the element_cont so we can skin it better + //this.get('panel').render(this.get('element_cont').get('element')); + Dom.addClass(this.get('panel').element, 'yui-editor-panel'); + } else { + Event.onDOMReady(function() { + this.get('panel').render(document.body); + //Render to the element_cont so we can skin it better + //this.get('panel').render(this.get('element_cont').get('element')); + Dom.addClass(this.get('panel').element, 'yui-editor-panel'); + }, this, true); + } + this.get('panel').showEvent.subscribe(function() { + YAHOO.util.Dom.setStyle(this.element, 'display', 'block'); + }); + return this.get('panel'); + }, + /** + * @method openWindow + * @param {YAHOO.widget.EditorWindow} win A YAHOO.widget.EditorWindow instance + * @description Opens a new "window/panel" + */ + openWindow: function(win) { + YAHOO.log('openWindow: ' + win.name, 'info', 'Editor'); + var self = this; + window.setTimeout(function() { + self.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open.. + }, 10); + Event.on(document, 'keydown', this._closeWindow, this, true); + + if (this.currentWindow) { + this.closeWindow(); + } + + + var xy = Dom.getXY(this.currentElement[0]), + elXY = Dom.getXY(this.get('iframe').get('element')), + panel = this.get('panel'), + newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)], + wWidth = (parseInt(win.attrs.width, 10) / 2), + align = 'center', + body = null; + + this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel }); + + var form = panel.editor_form; + + var wins = this._windows; + for (var b in wins) { + if (Lang.hasOwnProperty(wins, b)) { + if (wins[b] && wins[b].body) { + if (b == win.name) { + Dom.setStyle(wins[b].body, 'display', 'block'); + } else { + Dom.setStyle(wins[b].body, 'display', 'none'); + } + } + } + } + + if (this._windows[win.name].body) { + Dom.setStyle(this._windows[win.name].body, 'display', 'block'); + form.appendChild(this._windows[win.name].body); + } else { + if (Lang.isObject(win.body)) { //Assume it's a reference + form.appendChild(win.body); + } else { //Assume it's a string + var _tmp = document.createElement('div'); + _tmp.innerHTML = win.body; + form.appendChild(_tmp); + } + } + panel.editor_header.firstChild.innerHTML = win.header; + if (win.footer !== null) { + panel.setFooter(win.footer); + Dom.addClass(panel.footer, 'open'); + } else { + Dom.removeClass(panel.footer, 'open'); + } + panel.cfg.setProperty('width', win.attrs.width); + + this.currentWindow = win; + this.moveWindow(true); + panel.show(); + this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel }); + }, + /** + * @method moveWindow + * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.) + * @description Realign the window with the currentElement and reposition the knob above the panel. + */ + moveWindow: function(force) { + if (!this.currentWindow) { + return false; + } + var win = this.currentWindow, + xy = Dom.getXY(this.currentElement[0]), + elXY = Dom.getXY(this.get('iframe').get('element')), + panel = this.get('panel'), + //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)], + newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])], + wWidth = (parseInt(win.attrs.width, 10) / 2), + align = 'center', + orgXY = panel.cfg.getProperty('xy') || [0,0], + _knob = panel.editor_knob, + xDiff = 0, + yDiff = 0, + anim = false; + + + newXY[0] = ((newXY[0] - wWidth) + 20); + //Account for the Scroll bars in a scrolled editor window. + newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc()); + newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc()); + + if (this._isElement(this.currentElement[0], 'img')) { + if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) { + newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size + newXY[1] = (newXY[1] + 75); //Placeholder sizea + } else { + var w = parseInt(this.currentElement[0].width, 10); + var h = parseInt(this.currentElement[0].height, 10); + newXY[0] = (newXY[0] + (w / 2)); + newXY[1] = (newXY[1] + h); + } + newXY[1] = newXY[1] + 15; + } else { + var fs = Dom.getStyle(this.currentElement[0], 'fontSize'); + if (fs && fs.indexOf && fs.indexOf('px') != -1) { + newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5; + } else { + newXY[1] = newXY[1] + 20; + } + } + if (newXY[0] < elXY[0]) { + newXY[0] = elXY[0] + 5; + align = 'left'; + } + + if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) { + newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5); + align = 'right'; + } + + try { + xDiff = (newXY[0] - orgXY[0]); + yDiff = (newXY[1] - orgXY[1]); + } catch (e) {} + + + if (this.get('autoHeight') === false) { + var iTop = elXY[1] + parseInt(this.get('height'), 10); + var iLeft = elXY[0] + parseInt(this.get('width'), 10); + if (newXY[1] > iTop) { + newXY[1] = iTop; + } + if (newXY[0] > iLeft) { + newXY[0] = (iLeft / 2); + } + } + + //Convert negative numbers to positive so we can get the difference in distance + xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff); + yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff); + + if (((xDiff > 10) || (yDiff > 10)) || force) { //Only move the window if it's supposed to move more than 10px or force was passed (new window) + var _knobLeft = 0, + elW = 0; + + if (this.currentElement[0].width) { + elW = (parseInt(this.currentElement[0].width, 10) / 2); + } + + var leftOffset = xy[0] + elXY[0] + elW; + _knobLeft = leftOffset - newXY[0]; + //Check to see if the knob will go off either side & reposition it + if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) { + _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1); + } else if (_knobLeft < 40) { + _knobLeft = 1; + } + if (isNaN(_knobLeft)) { + _knobLeft = 1; + } + if (force) { + if (_knob) { + _knob.style.left = _knobLeft + 'px'; + } + //Removed Animation from a forced move.. + panel.cfg.setProperty('xy', newXY); + } else { + if (this.get('animate')) { + anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut); + anim.attributes = { + top: { + to: newXY[1] + }, + left: { + to: newXY[0] + } + }; + anim.onComplete.subscribe(function() { + panel.cfg.setProperty('xy', newXY); + }); + //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed .. + var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut); + + var _knobAnim = new YAHOO.util.Anim(_knob, { + left: { + to: _knobLeft + } + }, 0.6, YAHOO.util.Easing.easeOut); + anim.animate(); + iframeAnim.animate(); + _knobAnim.animate(); + } else { + _knob.style.left = _knobLeft + 'px'; + panel.cfg.setProperty('xy', newXY); + } + } + } + }, + /** + * @private + * @method _closeWindow + * @description Close the currently open EditorWindow with the Escape key. + * @param {Event} ev The keypress Event that we are trapping + */ + _closeWindow: function(ev) { + //if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) { + if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) { + if (this.currentWindow) { + this.closeWindow(); + } + } + }, + /** + * @method closeWindow + * @description Close the currently open EditorWindow. + */ + closeWindow: function(keepOpen) { + YAHOO.log('closeWindow: ' + this.currentWindow.name, 'info', 'Editor'); + //YAHOO.widget.EditorInfo.window = {}; + this.fireEvent('window' + this.currentWindow.name + 'Close', { type: 'window' + this.currentWindow.name + 'Close', win: this.currentWindow, el: this.currentElement[0] }); + this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow }); + this.currentWindow = null; + this.get('panel').hide(); + this.get('panel').cfg.setProperty('xy', [-900,-900]); + this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel + this.unsubscribeAll('afterExecCommand'); + this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed + this.toolbar.resetAllButtons(); + this._focusWindow(); + Event.removeListener(document, 'keydown', this._closeWindow); + }, + + /* {{{ Command Overrides - These commands are only over written when we are using the advanced version */ + + /** + * @method cmd_undo + * @description Pulls an item from the Undo stack and updates the Editor + * @param value Value passed from the execCommand method + */ + cmd_undo: function(value) { + if (this._hasUndoLevel()) { + if (!this._undoLevel) { + this._undoLevel = this._undoCache.length; + } + this._undoLevel = (this._undoLevel - 1); + if (this._undoCache[this._undoLevel]) { + var html = this._getUndo(this._undoLevel); + this.setEditorHTML(html); + } else { + this._undoLevel = null; + this.toolbar.disableButton('undo'); + } + } + return [false]; + }, + + /** + * @method cmd_redo + * @description Pulls an item from the Undo stack and updates the Editor + * @param value Value passed from the execCommand method + */ + cmd_redo: function(value) { + this._undoLevel = this._undoLevel + 1; + if (this._undoLevel >= this._undoCache.length) { + this._undoLevel = this._undoCache.length; + } + YAHOO.log(this._undoLevel + ' :: ' + this._undoCache.length, 'warn', 'SimpleEditor'); + if (this._undoCache[this._undoLevel]) { + var html = this._getUndo(this._undoLevel); + this.setEditorHTML(html); + } else { + this.toolbar.disableButton('redo'); + } + return [false]; + }, + + /** + * @method cmd_heading + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used. + */ + cmd_heading: function(value) { + var exec = true, + el = null, + action = 'heading', + _sel = this._getSelection(), + _selEl = this._getSelectedElement(); + + if (_selEl) { + _sel = _selEl; + } + + if (this.browser.ie) { + action = 'formatblock'; + } + if (value == 'none') { + if ((_sel && _sel.tagName && (_sel.tagName.toLowerCase().substring(0,1) == 'h')) || (_sel && _sel.parentNode && _sel.parentNode.tagName && (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h'))) { + if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') { + _sel = _sel.parentNode; + } + if (this._isElement(_sel, 'html')) { + return [false]; + } + el = this._swapEl(_selEl, 'span', function(el) { + el.className = 'yui-non'; + }); + this._selectNode(el); + this.currentElement[0] = el; + } + exec = false; + } else { + if (this._isElement(_selEl, 'h1') || this._isElement(_selEl, 'h2') || this._isElement(_selEl, 'h3') || this._isElement(_selEl, 'h4') || this._isElement(_selEl, 'h5') || this._isElement(_selEl, 'h6')) { + el = this._swapEl(_selEl, value); + this._selectNode(el); + this.currentElement[0] = el; + } else { + this._createCurrentElement(value); + this._selectNode(this.currentElement[0]); + } + exec = false; + } + return [exec, action]; + }, + /** + * @method cmd_hiddenelements + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used. + */ + cmd_hiddenelements: function(value) { + if (this._showingHiddenElements) { + //Don't auto highlight the hidden button + this._lastButton = null; + YAHOO.log('Enabling hidden CSS File', 'info', 'SimpleEditor'); + this._showingHiddenElements = false; + this.toolbar.deselectButton('hiddenelements'); + Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN); + } else { + YAHOO.log('Disabling hidden CSS File', 'info', 'SimpleEditor'); + this._showingHiddenElements = true; + Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN); + this.toolbar.selectButton('hiddenelements'); + } + return [false]; + }, + /** + * @method cmd_removeformat + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used. + */ + cmd_removeformat: function(value) { + var exec = true; + /** + * @knownissue Remove Format issue + * @browser Safari 2.x + * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected. + * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds. + * So here we are making the best possible guess and acting on it. + */ + if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) { + var _txt = this._getSelection()+''; + this._createCurrentElement('span'); + this.currentElement[0].className = 'yui-non'; + this.currentElement[0].innerHTML = _txt; + for (var i = 1; i < this.currentElement.length; i++) { + this.currentElement[i].parentNode.removeChild(this.currentElement[i]); + } + /* + this._createCurrentElement('span'); + YAHOO.util.Dom.addClass(this.currentElement[0], 'yui-non'); + var re= /<\S[^><]*>/g; + var str = this.currentElement[0].innerHTML.replace(re, ''); + var _txt = this._getDoc().createTextNode(str); + this.currentElement[0].parentNode.parentNode.replaceChild(_txt, this.currentElement[0].parentNode); + */ + + exec = false; + } + return [exec]; + }, + /** + * @method cmd_script + * @param action action passed from the execCommand method + * @param value Value passed from the execCommand method + * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods. + */ + cmd_script: function(action, value) { + var exec = true, tag = action.toLowerCase().substring(0, 3), + _span = null, _selEl = this._getSelectedElement(); + + if (this.browser.webkit) { + YAHOO.log('Safari dom fun again (' + action + ')..', 'info', 'EditorSafari'); + if (this._isElement(_selEl, tag)) { + YAHOO.log('we are a child of tag (' + tag + '), reverse process', 'info', 'EditorSafari'); + _span = this._swapEl(this.currentElement[0], 'span', function(el) { + el.className = 'yui-non'; + }); + this._selectNode(_span); + } else { + this._createCurrentElement(tag); + var _sub = this._swapEl(this.currentElement[0], tag); + this._selectNode(_sub); + this.currentElement[0] = _sub; + } + exec = false; + } + return exec; + }, + /** + * @method cmd_superscript + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used. + */ + cmd_superscript: function(value) { + return [this.cmd_script('superscript', value)]; + }, + /** + * @method cmd_subscript + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used. + */ + cmd_subscript: function(value) { + return [this.cmd_script('subscript', value)]; + }, + /** + * @method cmd_indent + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used. + */ + cmd_indent: function(value) { + var exec = true, selEl = this._getSelectedElement(), _bq = null; + + //if (this.browser.webkit || this.browser.ie || this.browser.gecko) { + //if (this.browser.webkit || this.browser.ie) { + if (this.browser.ie) { + if (this._isElement(selEl, 'blockquote')) { + _bq = this._getDoc().createElement('blockquote'); + _bq.innerHTML = selEl.innerHTML; + selEl.innerHTML = ''; + selEl.appendChild(_bq); + this._selectNode(_bq); + } else { + _bq = this._getDoc().createElement('blockquote'); + var html = this._getRange().htmlText; + _bq.innerHTML = html; + this._createCurrentElement('blockquote'); + /* + for (var i = 0; i < this.currentElement.length; i++) { + _bq = this._getDoc().createElement('blockquote'); + _bq.innerHTML = this.currentElement[i].innerHTML; + this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]); + this.currentElement[i] = _bq; + } + */ + this.currentElement[0].parentNode.replaceChild(_bq, this.currentElement[0]); + this.currentElement[0] = _bq; + this._selectNode(this.currentElement[0]); + } + exec = false; + } else { + value = 'blockquote'; + } + return [exec, 'formatblock', value]; + }, + /** + * @method cmd_outdent + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used. + */ + cmd_outdent: function(value) { + var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null; + //if (this.browser.webkit || this.browser.ie || this.browser.gecko) { + if (this.browser.webkit || this.browser.ie) { + //if (this.browser.ie) { + selEl = this._getSelectedElement(); + if (this._isElement(selEl, 'blockquote')) { + var par = selEl.parentNode; + if (this._isElement(selEl.parentNode, 'blockquote')) { + par.innerHTML = selEl.innerHTML; + this._selectNode(par); + } else { + _span = this._getDoc().createElement('span'); + _span.innerHTML = selEl.innerHTML; + YAHOO.util.Dom.addClass(_span, 'yui-non'); + par.replaceChild(_span, selEl); + this._selectNode(_span); + } + } else { + YAHOO.log('Can not outdent, we are not inside a blockquote', 'warn', 'Editor'); + } + exec = false; + } else { + value = false; + } + return [exec, 'outdent', value]; + }, + /** + * @method cmd_justify + * @param dir The direction to justify + * @description This is a factory method for the justify family of commands. + */ + cmd_justify: function(dir) { + if (this.browser.ie) { + if (this._hasSelection()) { + this._createCurrentElement('span'); + this._swapEl(this.currentElement[0], 'div', function(el) { + el.style.textAlign = dir; + }); + + return [false]; + } + } + return [true, 'justify' + dir, '']; + }, + /** + * @method cmd_justifycenter + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifycenter') is used. + */ + cmd_justifycenter: function() { + return [this.cmd_justify('center')]; + }, + /** + * @method cmd_justifyleft + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyleft') is used. + */ + cmd_justifyleft: function() { + return [this.cmd_justify('left')]; + }, + /** + * @method cmd_justifyright + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyright') is used. + */ + cmd_justifyright: function() { + return [this.cmd_justify('right')]; + }, + /* }}}*/ + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'Editor'; + if (this.get && this.get('element_cont')) { + str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + /** + * @description Class to hold Window information between uses. We use the same panel to show the windows, so using this will allow you to configure a window before it is shown. + * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor. + * @class EditorWindow + * @param {String} name The name of the window. + * @param {Object} attrs Attributes for the window. Current attributes used are : height and width + */ + YAHOO.widget.EditorWindow = function(name, attrs) { + /** + * @private + * @property name + * @description A unique name for the window + */ + this.name = name.replace(' ', '_'); + /** + * @private + * @property attrs + * @description The window attributes + */ + this.attrs = attrs; + }; + + YAHOO.widget.EditorWindow.prototype = { + /** + * @private + * @property header + * @description Holder for the header of the window, used in Editor.openWindow + */ + header: null, + /** + * @private + * @property body + * @description Holder for the body of the window, used in Editor.openWindow + */ + body: null, + /** + * @private + * @property footer + * @description Holder for the footer of the window, used in Editor.openWindow + */ + footer: null, + /** + * @method setHeader + * @description Sets the header for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header. + */ + setHeader: function(str) { + this.header = str; + }, + /** + * @method setBody + * @description Sets the body for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body. + */ + setBody: function(str) { + this.body = str; + }, + /** + * @method setFooter + * @description Sets the footer for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer. + */ + setFooter: function(str) { + this.footer = str; + }, + /** + * @method toString + * @description Returns a string representing the EditorWindow. + * @return {String} + */ + toString: function() { + return 'Editor Window (' + this.name + ')'; + } + }; +/** +* @event beforeOpenWindow +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fires before an Editor Window is opened. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterOpenWindow +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fires after an Editor Window is opened. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event closeWindow +* @param {EditorWindow} win The EditorWindow object +* @description Event fires after an Editor Window is closed. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCMDOpen +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Dynamic event fired when an EditorWindow is opened.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkOpen event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCMDClose +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Dynamic event fired when an EditorWindow is closed.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkClose event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowRender +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fired when the initial Overlay is rendered. Can be used to manipulate the content of the panel. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowInsertImageRender +* @param {Overlay} panel The Overlay object that is used to create the window. +* @param {HTMLElement} body The HTML element used as the body of the window.. +* @param {Toolbar} toolbar A reference to the toolbar object used inside this window. +* @description Event fired when the pre render of the Insert Image window has finished. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCreateLinkRender +* @param {Overlay} panel The Overlay object that is used to create the window. +* @param {HTMLElement} body The HTML element used as the body of the window.. +* @description Event fired when the pre render of the Create Link window has finished. +* @type YAHOO.util.CustomEvent +*/ + +})(); +YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/editor/editor-min.js b/lib/yui/editor/editor-min.js new file mode 100644 index 00000000000..4f4e1993b69 --- /dev/null +++ b/lib/yui/editor/editor-min.js @@ -0,0 +1,28 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +(function(){var B=YAHOO.util.Dom,A=YAHOO.util.Event,C=YAHOO.lang;if(YAHOO.widget.Button){YAHOO.widget.ToolbarButtonAdvanced=YAHOO.widget.Button;YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType="rich";YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue=function(F){var E=this.getMenu().getItems();if(E.length===0){this.getMenu()._onBeforeShow();E=this.getMenu().getItems();}for(var D=0;D'+G+"";this._titlebar.appendChild(F);A.on(F.firstChild,"click",function(H){A.stopEvent(H);});A.on([F,F.firstChild],"focus",function(){this._handleFocus();},this,true);}if(this.get("firstChild")){this.insertBefore(this._titlebar,this.get("firstChild"));}else{this.appendChild(this._titlebar);}if(this.get("collapse")){this.set("collapse",true);}}else{if(this._titlebar){if(this._titlebar&&this._titlebar.parentNode){this._titlebar.parentNode.removeChild(this._titlebar);}}}}});this.setAttributeConfig("collapse",{value:false,method:function(H){if(this._titlebar){var G=null;var F=C.getElementsByClassName("collapse","span",this._titlebar);if(H){if(F.length>0){return true;}G=document.createElement("SPAN");G.innerHTML="X";G.title=this.STR_COLLAPSE;C.addClass(G,"collapse");this._titlebar.appendChild(G);A.addListener(G,"click",function(){if(C.hasClass(this.get("cont").parentNode,"yui-toolbar-container-collapsed")){this.collapse(false);}else{this.collapse();}},this,true);}else{G=C.getElementsByClassName("collapse","span",this._titlebar);if(G[0]){if(C.hasClass(this.get("cont").parentNode,"yui-toolbar-container-collapsed")){this.collapse(false);}G[0].parentNode.removeChild(G[0]);}}}}});this.setAttributeConfig("draggable",{value:(E.draggable||false),method:function(F){if(F&&!this.get("titlebar")){if(!this._dragHandle){this._dragHandle=document.createElement("SPAN");this._dragHandle.innerHTML="|";this._dragHandle.setAttribute("title","Click to drag the toolbar");this._dragHandle.id=this.get("id")+"_draghandle";C.addClass(this._dragHandle,this.CLASS_DRAGHANDLE);if(this.get("cont").hasChildNodes()){this.get("cont").insertBefore(this._dragHandle,this.get("cont").firstChild);}else{this.get("cont").appendChild(this._dragHandle);}this.dd=new YAHOO.util.DD(this.get("id"));this.dd.setHandleElId(this._dragHandle.id);}}else{if(this._dragHandle){this._dragHandle.parentNode.removeChild(this._dragHandle);this._dragHandle=null;this.dd=null;}}if(this._titlebar){if(F){this.dd=new YAHOO.util.DD(this.get("id"));this.dd.setHandleElId(this._titlebar);C.addClass(this._titlebar,"draggable");}else{C.removeClass(this._titlebar,"draggable");if(this.dd){this.dd.unreg();this.dd=null;}}}},validator:function(G){var F=true;if(!YAHOO.util.DD){F=false;}return F;}});},addButtonGroup:function(I){if(!this.get("element")){this._queue[this._queue.length]=["addButtonGroup",arguments];return false;}if(!this.hasClass(this.CLASS_PREFIX+"-grouped")){this.addClass(this.CLASS_PREFIX+"-grouped");}var J=document.createElement("DIV");C.addClass(J,this.CLASS_PREFIX+"-group");C.addClass(J,this.CLASS_PREFIX+"-group-"+I.group);if(I.label){var F=document.createElement("h3");F.innerHTML=I.label;J.appendChild(F);}if(!this.get("grouplabels")){C.addClass(this.get("cont"),this.CLASS_PREFIX,"-nogrouplabels");}this.get("cont").appendChild(J);var H=document.createElement("ul");J.appendChild(H);if(!this._buttonGroupList){this._buttonGroupList={};}this._buttonGroupList[I.group]=H;for(var G=0;G'+F.replace("#","")+"";}}G+="X";window.setTimeout(function(){E.innerHTML=G;},0);A.on(E,"mouseover",function(M){var K=this._colorPicker;var L=K.getElementsByTagName("em")[0];var J=K.getElementsByTagName("strong")[0];var I=A.getTarget(M);if(I.tagName.toLowerCase()=="a"){L.style.backgroundColor=I.style.backgroundColor;J.innerHTML=this._colorData["#"+I.innerHTML]+"
            "+I.innerHTML;}},this,true);A.on(E,"focus",function(I){A.stopEvent(I);});A.on(E,"click",function(I){A.stopEvent(I);});A.on(E,"mousedown",function(J){A.stopEvent(J);var I=A.getTarget(J);if(I.tagName.toLowerCase()=="a"){var L=this.fireEvent("colorPickerClicked",{type:"colorPickerClicked",target:this,button:this._colorPicker._button,color:I.innerHTML,colorName:this._colorData["#"+I.innerHTML]});if(L!==false){var K={color:I.innerHTML,colorName:this._colorData["#"+I.innerHTML],value:this._colorPicker._button};this.fireEvent("buttonClick",{type:"buttonClick",target:this.get("element"),button:K});}this.getButtonByValue(this._colorPicker._button).getMenu().hide();}},this,true);},_resetColorPicker:function(){var F=this._colorPicker.getElementsByTagName("em")[0];var E=this._colorPicker.getElementsByTagName("strong")[0];F.style.backgroundColor="transparent"; +E.innerHTML="";},_makeColorButton:function(E){if(!this._colorPicker){this._createColorPicker(this.get("id"));}E.type="color";E.menu=new YAHOO.widget.Overlay(this.get("id")+"_"+E.value+"_menu",{visible:false,position:"absolute",iframe:true});E.menu.setBody("");E.menu.render(this.get("cont"));C.addClass(E.menu.element,"yui-button-menu");C.addClass(E.menu.element,"yui-color-button-menu");E.menu.beforeShowEvent.subscribe(function(){E.menu.cfg.setProperty("zindex",5);E.menu.cfg.setProperty("context",[this.getButtonById(E.id).get("element"),"tl","bl"]);this._resetColorPicker();var F=this._colorPicker;if(F.parentNode){F.parentNode.removeChild(F);}E.menu.setBody("");E.menu.appendToBody(F);this._colorPicker.style.display="block";},this,true);return E;},_makeSpinButton:function(R,L){R.addClass(this.CLASS_PREFIX+"-spinbutton");var S=this,N=R._button.parentNode.parentNode,I=L.range,H=document.createElement("a"),G=document.createElement("a");H.href="#";G.href="#";H.tabIndex="-1";G.tabIndex="-1";H.className="up";H.title=this.STR_SPIN_UP;H.innerHTML=this.STR_SPIN_UP;G.className="down";G.title=this.STR_SPIN_DOWN;G.innerHTML=this.STR_SPIN_DOWN;N.appendChild(H);N.appendChild(G);var M=YAHOO.lang.substitute(this.STR_SPIN_LABEL,{VALUE:R.get("label")});R.set("title",M);var Q=function(T){T=((TI[1])?I[1]:T);return T;};var P=this.browser;var F=false;var K=this.STR_SPIN_LABEL;if(this._titlebar&&this._titlebar.firstChild){F=this._titlebar.firstChild;}var E=function(U){YAHOO.util.Event.stopEvent(U);if(!R.get("disabled")&&(U.keyCode!=9)){var V=parseInt(R.get("label"),10);V++;V=Q(V);R.set("label",""+V);var T=YAHOO.lang.substitute(K,{VALUE:R.get("label")});R.set("title",T);if(!P.webkit&&F){}S._buttonClick(U,L);}};var O=function(U){YAHOO.util.Event.stopEvent(U);if(!R.get("disabled")&&(U.keyCode!=9)){var V=parseInt(R.get("label"),10);V--;V=Q(V);R.set("label",""+V);var T=YAHOO.lang.substitute(K,{VALUE:R.get("label")});R.set("title",T);if(!P.webkit&&F){}S._buttonClick(U,L);}};var J=function(T){if(T.keyCode==38){E(T);}else{if(T.keyCode==40){O(T);}else{if(T.keyCode==107&&T.shiftKey){E(T);}else{if(T.keyCode==109&&T.shiftKey){O(T);}}}}};R.on("keydown",J,this,true);A.on(H,"mousedown",function(T){A.stopEvent(T);},this,true);A.on(G,"mousedown",function(T){A.stopEvent(T);},this,true);A.on(H,"click",E,this,true);A.on(G,"click",O,this,true);},_buttonClick:function(L,F){var E=true;if(L&&L.type=="keypress"){if(L.keyCode==9){E=false;}else{if((L.keyCode===13)||(L.keyCode===0)||(L.keyCode===32)){}else{E=false;}}}if(E){var N=true,H=false;F.isSelected=this.isSelected(F.id);if(F.value){H=this.fireEvent(F.value+"Click",{type:F.value+"Click",target:this.get("element"),button:F});if(H===false){N=false;}}if(F.menucmd&&N){H=this.fireEvent(F.menucmd+"Click",{type:F.menucmd+"Click",target:this.get("element"),button:F});if(H===false){N=false;}}if(N){this.fireEvent("buttonClick",{type:"buttonClick",target:this.get("element"),button:F});}if(F.type=="select"){var K=this.getButtonById(F.id);if(K.buttonType=="rich"){var J=F.value;for(var I=0;I'+J+"");var M=K.getMenu().getItems();for(var G=0;G(this._buttonList.length-1)){this._navCounter=0;}if(this._navCounter<0){this._navCounter=(this._buttonList.length-1);}if(this._buttonList[this._navCounter]){var E=this._buttonList[this._navCounter].get("element");if(this.browser.ie){E=this._buttonList[this._navCounter].get("element").getElementsByTagName("a")[0];}if(this._buttonList[this._navCounter].get("disabled")){this._navigateButtons(F);}else{E.focus();}}break;}},_handleFocus:function(){if(!this._keyNav){var E="keypress";if(this.browser.ie){E="keydown";}A.on(this.get("element"),E,this._navigateButtons,this,true);this._keyNav=true;this._navCounter=-1;}},getButtonById:function(G){var E=this._buttonList.length;for(var F=0;F'+H[E]._oText.nodeValue+"");}else{H[E].cfg.setProperty("checked",false); +}}}}}else{return false;}},deselectButton:function(F){var E=B.call(this,F);if(E){E.removeClass("yui-button-selected");E.removeClass("yui-button-"+E.get("value")+"-selected");E.removeClass("yui-button-hover");E._selected=false;}else{return false;}},deselectAllButtons:function(){var E=this._buttonList.length;for(var F=0;F0)){var I=0;for(var G=0;G',editorDirty:null,_defaultCSS:"html { height: 95%; } body { padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a, a:visited, a:hover { color: blue !important; text-decoration: underline !important; cursor: text !important; } .warning-localfile { border-bottom: 1px dashed red !important; } .yui-busy { cursor: wait !important; } img.selected { border: 2px dotted #808080; } img { cursor: pointer !important; border: none; } body.ptags.webkit div { margin: 11px 0; }",_defaultToolbar:null,_lastButton:null,_baseHREF:function(){var E=document.location.href;if(E.indexOf("?")!==-1){E=E.substring(0,E.indexOf("?"));}E=E.substring(0,E.lastIndexOf("/"))+"/";return E; +}(),_lastImage:null,_blankImageLoaded:null,_fixNodesTimer:null,_nodeChangeTimer:null,_lastNodeChangeEvent:null,_lastNodeChange:0,_rendered:null,DOMReady:null,_selection:null,_mask:null,_showingHiddenElements:null,currentWindow:null,currentEvent:null,operaEvent:null,currentFont:null,currentElement:null,dompath:null,beforeElement:null,afterElement:null,invalidHTML:{form:true,input:true,button:true,select:true,link:true,html:true,body:true,iframe:true,script:true,style:true,textarea:true},toolbar:null,_contentTimer:null,_contentTimerCounter:0,_disabled:["createlink","fontname","fontsize","forecolor","backcolor"],_alwaysDisabled:{undo:true,redo:true},_alwaysEnabled:{},_semantic:{"bold":true,"italic":true,"underline":true},_tag2cmd:{"b":"bold","strong":"bold","i":"italic","em":"italic","u":"underline","sup":"superscript","sub":"subscript","img":"insertimage","a":"createlink","ul":"insertunorderedlist","ol":"insertorderedlist"},_createIframe:function(){var I=document.createElement("iframe");I.id=this.get("id")+"_editor";var G={border:"0",frameBorder:"0",marginWidth:"0",marginHeight:"0",leftMargin:"0",topMargin:"0",allowTransparency:"true",width:"100%"};if(this.get("autoHeight")){G.scrolling="no";}for(var H in G){if(D.hasOwnProperty(G,H)){I.setAttribute(H,G[H]);}}var F="javascript:;";if(this.browser.ie){F="javascript:false;";}I.setAttribute("src",F);var E=new YAHOO.util.Element(I);E.setStyle("visibility","hidden");return E;},_isElement:function(F,E){if(F&&F.tagName&&(F.tagName.toLowerCase()==E)){return true;}if(F&&F.getAttribute&&(F.getAttribute("tag")==E)){return true;}return false;},_hasParent:function(F,E){if(!F||!F.parentNode){return false;}while(F.parentNode){if(this._isElement(F,E)){return F;}if(F.parentNode){F=F.parentNode;}else{return false;}}return false;},_getDoc:function(){var E=false;if(this.get){if(this.get("iframe")){if(this.get("iframe").get){if(this.get("iframe").get("element")){try{if(this.get("iframe").get("element").contentWindow){if(this.get("iframe").get("element").contentWindow.document){E=this.get("iframe").get("element").contentWindow.document;return E;}}}catch(F){}}}}}return false;},_getWindow:function(){return this.get("iframe").get("element").contentWindow;},_focusWindow:function(E){if(this.browser.webkit){if(E){this._getSelection().setBaseAndExtent(this._getDoc().body.firstChild,0,this._getDoc().body.firstChild,1);if(this.browser.webkit3){this._getSelection().collapseToStart();}else{this._getSelection().collapse(false);}}else{this._getSelection().setBaseAndExtent(this._getDoc().body,1,this._getDoc().body,1);if(this.browser.webkit3){this._getSelection().collapseToStart();}else{this._getSelection().collapse(false);}}this._getWindow().focus();}else{this._getWindow().focus();}},_hasSelection:function(){var G=this._getSelection();var E=this._getRange();var F=false;if(!G||!E){return F;}if(this.browser.ie||this.browser.opera){if(E.text){F=true;}if(E.html){F=true;}}else{if(this.browser.webkit){if(G+""!==""){F=true;}}else{if(G&&(G.toString()!=="")&&(G!==undefined)){F=true;}}}return F;},_getSelection:function(){var E=null;if(this._getDoc()&&this._getWindow()){if(this._getDoc().selection){E=this._getDoc().selection;}else{E=this._getWindow().getSelection();}if(this.browser.webkit){if(E.baseNode){this._selection={};this._selection.baseNode=E.baseNode;this._selection.baseOffset=E.baseOffset;this._selection.extentNode=E.extentNode;this._selection.extentOffset=E.extentOffset;}else{if(this._selection!==null){E=this._getWindow().getSelection();E.setBaseAndExtent(this._selection.baseNode,this._selection.baseOffset,this._selection.extentNode,this._selection.extentOffset);this._selection=null;}}}}return E;},_selectNode:function(F,I){if(!F){return false;}var G=this._getSelection(),E=null;if(this.browser.ie){try{E=this._getDoc().body.createTextRange();E.moveToElementText(F);E.select();}catch(H){}}else{if(this.browser.webkit){if(I){G.setBaseAndExtent(F,1,F,F.innerText.length);}else{G.setBaseAndExtent(F,0,F,F.innerText.length);}}else{if(this.browser.opera){G=this._getWindow().getSelection();E=this._getDoc().createRange();E.selectNode(F);G.removeAllRanges();G.addRange(E);}else{E=this._getDoc().createRange();E.selectNodeContents(F);G.removeAllRanges();G.addRange(E);}}}this.nodeChange();},_getRange:function(){var E=this._getSelection();if(E===null){return null;}if(this.browser.webkit&&!E.getRangeAt){var H=this._getDoc().createRange();try{H.setStart(E.anchorNode,E.anchorOffset);H.setEnd(E.focusNode,E.focusOffset);}catch(G){H=this._getWindow().getSelection()+"";}return H;}if(this.browser.ie||this.browser.opera){try{return E.createRange();}catch(F){return null;}}if(E.rangeCount>0){return E.getRangeAt(0);}return null;},_setDesignMode:function(E){try{var G=true;if(this.browser.ie&&(E.toLowerCase()=="off")){G=false;}if(G){this._getDoc().designMode=E;}}catch(F){}},_toggleDesignMode:function(){var F=this._getDoc().designMode.toLowerCase(),E="on";if(F=="on"){E="off";}this._setDesignMode(E);return E;},_initEditorEvents:function(){var E=this._getDoc();A.on(E,"mouseup",this._handleMouseUp,this,true);A.on(E,"mousedown",this._handleMouseDown,this,true);A.on(E,"click",this._handleClick,this,true);A.on(E,"dblclick",this._handleDoubleClick,this,true);A.on(E,"keypress",this._handleKeyPress,this,true);A.on(E,"keyup",this._handleKeyUp,this,true);A.on(E,"keydown",this._handleKeyDown,this,true);},_removeEditorEvents:function(){var E=this._getDoc();A.removeListener(E,"mouseup",this._handleMouseUp,this,true);A.removeListener(E,"mousedown",this._handleMouseDown,this,true);A.removeListener(E,"click",this._handleClick,this,true);A.removeListener(E,"dblclick",this._handleDoubleClick,this,true);A.removeListener(E,"keypress",this._handleKeyPress,this,true);A.removeListener(E,"keyup",this._handleKeyUp,this,true);A.removeListener(E,"keydown",this._handleKeyDown,this,true);},_initEditor:function(){if(this.browser.ie){this._getDoc().body.style.margin="0";}if(!this.get("disabled")){if(this._getDoc().designMode.toLowerCase()!="on"){this._setDesignMode("on"); +this._contentTimerCounter=0;}}if(!this._getDoc().body){this._contentTimerCounter=0;this._checkLoaded();return false;}this.toolbar.on("buttonClick",this._handleToolbarClick,this,true);if(!this.get("disabled")){this._initEditorEvents();this.toolbar.set("disabled",false);}this.fireEvent("editorContentLoaded",{type:"editorLoaded",target:this});if(this.get("dompath")){var E=this;setTimeout(function(){E._writeDomPath.call(E);E._setupResize.call(E);},150);}var G=[];for(var F in this.browser){if(this.browser[F]){G.push(F);}}if(this.get("ptags")){G.push("ptags");}C.addClass(this._getDoc().body,G.join(" "));this.nodeChange(true);},_checkLoaded:function(){this._contentTimerCounter++;if(this._contentTimer){clearTimeout(this._contentTimer);}if(this._contentTimerCounter>500){return false;}var G=false;try{if(this._getDoc()&&this._getDoc().body){if(this.browser.ie){if(this._getDoc().body.readyState=="complete"){G=true;}}else{if(this._getDoc().body._rteLoaded===true){G=true;}}}}catch(F){G=false;}if(G===true){this._initEditor();}else{var E=this;this._contentTimer=setTimeout(function(){E._checkLoaded.call(E);},20);}},_setInitialContent:function(){var H=((this._textarea)?this.get("element").value:this.get("element").innerHTML),J=null;var F=D.substitute(this.get("html"),{TITLE:this.STR_TITLE,CONTENT:this._cleanIncomingHTML(H),CSS:this.get("css"),HIDDEN_CSS:((this.get("hiddencss"))?this.get("hiddencss"):"/* No Hidden CSS */"),EXTRA_CSS:((this.get("extracss"))?this.get("extracss"):"/* No Extra CSS */")}),E=true;if(document.compatMode!="BackCompat"){F=this._docType+"\n"+F;}else{}if(this.browser.ie||this.browser.webkit||this.browser.opera||(navigator.userAgent.indexOf("Firefox/1.5")!=-1)){try{if(this.browser.air){J=this._getDoc().implementation.createHTMLDocument();var K=this._getDoc();K.open();K.close();J.open();J.write(F);J.close();var G=K.importNode(J.getElementsByTagName("html")[0],true);K.replaceChild(G,K.getElementsByTagName("html")[0]);K.body._rteLoaded=true;}else{J=this._getDoc();J.open();J.write(F);J.close();}}catch(I){E=false;}}else{this.get("iframe").get("element").src="data:text/html;charset=utf-8,"+encodeURIComponent(F);}this.get("iframe").setStyle("visibility","");if(E){this._checkLoaded();}},_setMarkupType:function(E){switch(this.get("markup")){case"css":this._setEditorStyle(true);break;case"default":this._setEditorStyle(false);break;case"semantic":case"xhtml":if(this._semantic[E]){this._setEditorStyle(false);}else{this._setEditorStyle(true);}break;}},_setEditorStyle:function(F){try{this._getDoc().execCommand("useCSS",false,!F);}catch(E){}},_getSelectedElement:function(){var I=this._getDoc(),F=null,G=null,J=null,E=true;if(this.browser.ie){this.currentEvent=this._getWindow().event;F=this._getRange();if(F){J=F.item?F.item(0):F.parentElement();if(this._hasSelection()){}if(J===I.body){J=null;}}if((this.currentEvent!==null)&&(this.currentEvent.keyCode===0)){J=A.getTarget(this.currentEvent);}}else{G=this._getSelection();F=this._getRange();if(!G||!F){return null;}if(!this._hasSelection()&&this.browser.webkit3){}if(this.browser.gecko){if(F.startContainer){E=false;if(F.startContainer.nodeType===3){J=F.startContainer.parentNode;}else{if(F.startContainer.nodeType===1){J=F.startContainer;}else{E=true;}}if(!E){this.currentEvent=null;}}}if(E){if(G.anchorNode&&(G.anchorNode.nodeType==3)){if(G.anchorNode.parentNode){J=G.anchorNode.parentNode;}if(G.anchorNode.nextSibling!=G.focusNode.nextSibling){J=G.anchorNode.nextSibling;}}if(this._isElement(J,"br")){J=null;}if(!J){J=F.commonAncestorContainer;if(!F.collapsed){if(F.startContainer==F.endContainer){if(F.startOffset-F.endOffset<2){if(F.startContainer.hasChildNodes()){J=F.startContainer.childNodes[F.startOffset];}}}}}}}if(this.currentEvent!==null){try{switch(this.currentEvent.type){case"click":case"mousedown":case"mouseup":if(this.browser.webkit){J=A.getTarget(this.currentEvent);}break;default:break;}}catch(H){}}else{if((this.currentElement&&this.currentElement[0])&&(!this.browser.ie)){}}if(this.browser.opera||this.browser.webkit){if(this.currentEvent&&!J){J=YAHOO.util.Event.getTarget(this.currentEvent);}}if(!J||!J.tagName){J=I.body;}if(this._isElement(J,"html")){J=I.body;}if(this._isElement(J,"body")){J=I.body;}if(J&&!J.parentNode){J=I.body;}if(J===undefined){J=null;}return J;},_getDomPath:function(E){if(!E){E=this._getSelectedElement();}var F=[];while(E!==null){if(E.ownerDocument!=this._getDoc()){E=null;break;}if(E.nodeName&&E.nodeType&&(E.nodeType==1)){F[F.length]=E;}if(this._isElement(E,"body")){break;}E=E.parentNode;}if(F.length===0){if(this._getDoc()&&this._getDoc().body){F[0]=this._getDoc().body;}}return F.reverse();},_writeDomPath:function(){var K=this._getDomPath(),I=[],G="",L="";for(var E=0;E10){L=''+L.substring(0,10)+"..."+"";}else{L=''+L+"";}I[I.length]=L;}}var H=I.join(" "+this.SEP_DOMPATH+" ");if(this.dompath.innerHTML!=H){this.dompath.innerHTML=H;}},_fixNodes:function(){var J=this._getDoc(),H=[];for(var E in this.invalidHTML){if(YAHOO.lang.hasOwnProperty(this.invalidHTML,E)){if(E.toLowerCase()!="span"){var F=J.body.getElementsByTagName(E); +if(F.length){for(var G=0;G-1;E--){if(C.hasClass(J[E],this.CLASS_NOEDIT)){try{this._getDoc().execCommand("enableObjectResizing",false,"false");}catch(I){}this.nodeChange();A.stopEvent(G);return true;}}try{this._getDoc().execCommand("enableObjectResizing",false,"true");}catch(H){}}return false;},_setCurrentEvent:function(E){this.currentEvent=E;},_handleClick:function(G){var F=this.fireEvent("beforeEditorClick",{type:"beforeEditorClick",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);if(this.currentWindow){this.closeWindow();}if(this.currentWindow){this.closeWindow();}if(this.browser.webkit){var E=A.getTarget(G);if(this._isElement(E,"a")||this._isElement(E.parentNode,"a")){A.stopEvent(G);this.nodeChange();}}else{this.nodeChange();}this.fireEvent("editorClick",{type:"editorClick",target:this,ev:G});},_handleMouseUp:function(G){var F=this.fireEvent("beforeEditorMouseUp",{type:"beforeEditorMouseUp",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}var E=this;if(this.browser.opera){var H=A.getTarget(G);if(this._isElement(H,"img")){this.nodeChange();if(this.operaEvent){clearTimeout(this.operaEvent);this.operaEvent=null;this._handleDoubleClick(G);}else{this.operaEvent=window.setTimeout(function(){E.operaEvent=false;},700);}}}if(this.browser.webkit||this.browser.opera){if(this.browser.webkit){A.stopEvent(G);}}this.nodeChange();this.fireEvent("editorMouseUp",{type:"editorMouseUp",target:this,ev:G});},_handleMouseDown:function(F){var E=this.fireEvent("beforeEditorMouseDown",{type:"beforeEditorMouseDown",target:this,ev:F});if(E===false){return false;}if(this._isNonEditable(F)){return false;}this._setCurrentEvent(F);var G=A.getTarget(F);if(this.browser.webkit&&this._hasSelection()){var H=this._getSelection();if(!this.browser.webkit3){H.collapse(true);}else{H.collapseToStart();}}if(this.browser.webkit&&this._lastImage){C.removeClass(this._lastImage,"selected");this._lastImage=null;}if(this._isElement(G,"img")||this._isElement(G,"a")){if(this.browser.webkit){A.stopEvent(F);if(this._isElement(G,"img")){C.addClass(G,"selected");this._lastImage=G;}}if(this.currentWindow){this.closeWindow();}this.nodeChange();}this.fireEvent("editorMouseDown",{type:"editorMouseDown",target:this,ev:F});},_handleDoubleClick:function(F){var E=this.fireEvent("beforeEditorDoubleClick",{type:"beforeEditorDoubleClick",target:this,ev:F});if(E===false){return false;}if(this._isNonEditable(F)){return false;}this._setCurrentEvent(F);var G=A.getTarget(F);if(this._isElement(G,"img")){this.currentElement[0]=G;this.toolbar.fireEvent("insertimageClick",{type:"insertimageClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});}else{if(this._hasParent(G,"a")){this.currentElement[0]=this._hasParent(G,"a");this.toolbar.fireEvent("createlinkClick",{type:"createlinkClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});}}this.nodeChange();this.fireEvent("editorDoubleClick",{type:"editorDoubleClick",target:this,ev:F});},_handleKeyUp:function(G){var F=this.fireEvent("beforeEditorKeyUp",{type:"beforeEditorKeyUp",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);switch(G.keyCode){case this._keyMap.SELECT_ALL.key:if(this._checkKey(this._keyMap.SELECT_ALL,G)){this.nodeChange();}break;case 32:case 35:case 36:case 37:case 38:case 39:case 40:case 46:case 8:case this._keyMap.CLOSE_WINDOW.key:if((G.keyCode==this._keyMap.CLOSE_WINDOW.key)&&this.currentWindow){if(this._checkKey(this._keyMap.CLOSE_WINDOW,G)){this.closeWindow();}}else{if(!this.browser.ie){if(this._nodeChangeTimer){clearTimeout(this._nodeChangeTimer);}var E=this;this._nodeChangeTimer=setTimeout(function(){E._nodeChangeTimer=null;E.nodeChange.call(E);},100);}else{this.nodeChange();}this.editorDirty=true;}break;}this.fireEvent("editorKeyUp",{type:"editorKeyUp",target:this,ev:G});this._storeUndo();},_handleKeyPress:function(G){var F=this.fireEvent("beforeEditorKeyPress",{type:"beforeEditorKeyPress",target:this,ev:G});if(F===false){return false;}if(this.get("allowNoEdit")){if(G&&G.keyCode&&(G.keyCode==63272)){A.stopEvent(G);}}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);if(this.browser.opera){if(G.keyCode===13){var E=this._getSelectedElement();if(!this._isElement(E,"li")){this.execCommand("inserthtml","
            ");A.stopEvent(G);}}}if(this.browser.webkit){if(!this.browser.webkit3){if(G.keyCode&&(G.keyCode==122)&&(G.metaKey)){if(this._hasParent(this._getSelectedElement(),"li")){A.stopEvent(G);}}}this._listFix(G);}this.fireEvent("editorKeyPress",{type:"editorKeyPress",target:this,ev:G});},_handleKeyDown:function(M){var J=this.fireEvent("beforeEditorKeyDown",{type:"beforeEditorKeyDown",target:this,ev:M});if(J===false){return false;}var I=null,K=null;if(this._isNonEditable(M)){return false;}this._setCurrentEvent(M);if(this.currentWindow){this.closeWindow();}if(this.currentWindow){this.closeWindow();}var L=false,G=null,F=false;switch(M.keyCode){case this._keyMap.FOCUS_TOOLBAR.key:if(this._checkKey(this._keyMap.FOCUS_TOOLBAR,M)){var H=this.toolbar.getElementsByTagName("h2")[0];if(H&&H.firstChild){H.firstChild.focus();}}else{if(this._checkKey(this._keyMap.FOCUS_AFTER,M)){this.afterElement.focus();}}A.stopEvent(M);L=false;break;case this._keyMap.CREATE_LINK.key:if(this._hasSelection()){if(this._checkKey(this._keyMap.CREATE_LINK,M)){var E=true; +if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("createlink")){E=false;}}if(E){this.execCommand("createlink","");this.toolbar.fireEvent("createlinkClick",{type:"createlinkClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});L=false;}}}break;case this._keyMap.UNDO.key:case this._keyMap.REDO.key:if(this._checkKey(this._keyMap.REDO,M)){G="redo";L=true;}else{if(this._checkKey(this._keyMap.UNDO,M)){G="undo";L=true;}}break;case this._keyMap.BOLD.key:if(this._checkKey(this._keyMap.BOLD,M)){G="bold";L=true;}break;case this._keyMap.ITALIC.key:if(this._checkKey(this._keyMap.ITALIC,M)){G="italic";L=true;}break;case this._keyMap.UNDERLINE.key:if(this._checkKey(this._keyMap.UNDERLINE,M)){G="underline";L=true;}break;case 9:if(this.browser.ie){K=this._getRange();I=this._getSelectedElement();if(!this._isElement(I,"li")){if(K){K.pasteHTML("    ");K.collapse(false);K.select();}A.stopEvent(M);}}if(this.browser.gecko>1.8){I=this._getSelectedElement();if(this._isElement(I,"li")){if(M.shiftKey){this._getDoc().execCommand("outdent",null,"");}else{this._getDoc().execCommand("indent",null,"");}}else{if(!this._hasSelection()){this.execCommand("inserthtml","    ");}}A.stopEvent(M);}break;case 13:if(this.get("ptags")&&!M.shiftKey){if(this.browser.gecko){I=this._getSelectedElement();if(!this._isElement(I,"li")){L=true;G="insertparagraph";A.stopEvent(M);}}if(this.browser.webkit){I=this._getSelectedElement();if(!this._hasParent(I,"li")){L=true;G="insertparagraph";A.stopEvent(M);}}}else{if(this.browser.ie){K=this._getRange();I=this._getSelectedElement();if(!this._isElement(I,"li")){if(K){K.pasteHTML("
            ");K.collapse(false);K.select();}A.stopEvent(M);}}}break;}if(this.browser.ie){this._listFix(M);}if(L&&G){this.execCommand(G,null);A.stopEvent(M);this.nodeChange();}this.fireEvent("editorKeyDown",{type:"editorKeyDown",target:this,ev:M});},_listFix:function(K){var M=null,I=null,E=false,G=null;if(this.browser.webkit){if(K.keyCode&&(K.keyCode==13)){if(this._hasParent(this._getSelectedElement(),"li")){var H=this._hasParent(this._getSelectedElement(),"li");if(H.previousSibling){if(H.firstChild&&(H.firstChild.length==1)){this._selectNode(H);}}}}}if(K.keyCode&&((!this.browser.webkit3&&(K.keyCode==25))||((this.browser.webkit3||!this.browser.webkit)&&((K.keyCode==9)&&K.shiftKey)))){M=this._getSelectedElement();if(this._hasParent(M,"li")){M=this._hasParent(M,"li");if(this._hasParent(M,"ul")||this._hasParent(M,"ol")){I=this._hasParent(M,"ul");if(!I){I=this._hasParent(M,"ol");}if(this._isElement(I.previousSibling,"li")){I.removeChild(M);I.parentNode.insertBefore(M,I.nextSibling);if(this.browser.ie){G=this._getDoc().body.createTextRange();G.moveToElementText(M);G.collapse(false);G.select();}if(this.browser.webkit){this._selectNode(M.firstChild);}A.stopEvent(K);}}}}if(K.keyCode&&((K.keyCode==9)&&(!K.shiftKey))){var F=this._getSelectedElement();if(this._hasParent(F,"li")){E=this._hasParent(F,"li").innerHTML;}if(this.browser.webkit){this._getDoc().execCommand("inserttext",false,"\t");}M=this._getSelectedElement();if(this._hasParent(M,"li")){I=this._hasParent(M,"li");var J=this._getDoc().createElement(I.parentNode.tagName.toLowerCase());if(this.browser.webkit){var L=C.getElementsByClassName("Apple-tab-span","span",I);if(L[0]){I.removeChild(L[0]);I.innerHTML=D.trim(I.innerHTML);if(E){I.innerHTML=''+E+" ";}else{I.innerHTML='  ';}}}else{if(E){I.innerHTML=E+" ";}else{I.innerHTML=" ";}}I.parentNode.replaceChild(J,I);J.appendChild(I);if(this.browser.webkit){this._getSelection().setBaseAndExtent(I.firstChild,1,I.firstChild,I.firstChild.innerText.length);if(!this.browser.webkit3){I.parentNode.parentNode.style.display="list-item";setTimeout(function(){I.parentNode.parentNode.style.display="block";},1);}}else{if(this.browser.ie){G=this._getDoc().body.createTextRange();G.moveToElementText(I);G.collapse(false);G.select();}else{this._selectNode(I);}}A.stopEvent(K);}if(this.browser.webkit){A.stopEvent(K);}this.nodeChange();}},nodeChange:function(E){var F=this;this._storeUndo();if(this.get("nodeChangeDelay")){window.setTimeout(function(){F._nodeChange.apply(F,arguments);},0);}else{this._nodeChange();}},_nodeChange:function(F){var H=parseInt(this.get("nodeChangeThreshold"),10),O=Math.round(new Date().getTime()/1000),R=this;if(F===true){this._lastNodeChange=0;}if((this._lastNodeChange+H)0){for(var V=0;V'+Y+"");this._updateMenuChecked("fontname",Y);}if(L){L.set("label",L._configs.label._initialConfig.value);}var K=this.toolbar.getButtonByValue("heading");if(K){K.set("label",K._configs.label._initialConfig.value);this._updateMenuChecked("heading","none");}var I=this.toolbar.getButtonByValue("insertimage");if(I&&this.currentWindow&&(this.currentWindow.name=="insertimage")){this.toolbar.disableButton(I);}if(this._lastButton&&this._lastButton.isSelected){this.toolbar.deselectButton(this._lastButton.id);}this._undoNodeChange();}}this.fireEvent("afterNodeChange",{type:"afterNodeChange",target:this});},_updateMenuChecked:function(E,F,H){if(!H){H=this.toolbar;}var G=H.getButtonByValue(E);G.checkValue(F);},_handleToolbarClick:function(F){var H="";var I="";var G=F.button.value;if(F.button.menucmd){H=G;G=F.button.menucmd;}this._lastButton=F.button;if(this.STOP_EXEC_COMMAND){this.STOP_EXEC_COMMAND=false;return false;}else{this.execCommand(G,H);if(!this.browser.webkit){var E=this;setTimeout(function(){E._focusWindow.call(E);},5);}}A.stopEvent(F);},_setupAfterElement:function(){if(!this.beforeElement){this.beforeElement=document.createElement("h2");this.beforeElement.className="yui-editor-skipheader";this.beforeElement.tabIndex="-1";this.beforeElement.innerHTML=this.STR_BEFORE_EDITOR;this.get("element_cont").get("firstChild").insertBefore(this.beforeElement,this.toolbar.get("nextSibling"));}if(!this.afterElement){this.afterElement=document.createElement("h2");this.afterElement.className="yui-editor-skipheader";this.afterElement.tabIndex="-1";this.afterElement.innerHTML=this.STR_LEAVE_EDITOR;this.get("element_cont").get("firstChild").appendChild(this.afterElement);}},_disableEditor:function(F){if(F){this._removeEditorEvents();if(!this._mask){if(!!this.browser.ie){this._setDesignMode("off");}if(this.toolbar){this.toolbar.set("disabled",true);}this._mask=document.createElement("DIV");C.setStyle(this._mask,"height","100%");C.setStyle(this._mask,"width","100%");C.setStyle(this._mask,"position","absolute");C.setStyle(this._mask,"top","0");C.setStyle(this._mask,"left","0");C.setStyle(this._mask,"opacity",".5");C.addClass(this._mask,"yui-editor-masked");this.get("iframe").get("parentNode").appendChild(this._mask);}}else{this._initEditorEvents();if(this._mask){this._mask.parentNode.removeChild(this._mask);this._mask=null;if(this.toolbar){this.toolbar.set("disabled",false);}this._setDesignMode("on");this._focusWindow();var E=this;window.setTimeout(function(){E.nodeChange.call(E);},100);}}},SEP_DOMPATH:"<",STR_LEAVE_EDITOR:"You have left the Rich Text Editor.",STR_BEFORE_EDITOR:"This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Shift + Escape to place focus on the toolbar and navigate between options with your arrow keys. To exit this text editor use the Escape key and continue tabbing.

            Common formatting keyboard shortcuts:

            • Control Shift B sets text to bold
            • Control Shift I sets text to italic
            • Control Shift U underlines text
            • Control Shift L adds an HTML link
            ",STR_TITLE:"Rich Text Area.",STR_IMAGE_HERE:"Image URL Here",STR_LINK_URL:"Link URL",STOP_EXEC_COMMAND:false,STOP_NODE_CHANGE:false,CLASS_NOEDIT:"yui-noedit",CLASS_CONTAINER:"yui-editor-container",CLASS_EDITABLE:"yui-editor-editable",CLASS_EDITABLE_CONT:"yui-editor-editable-container",CLASS_PREFIX:"yui-editor",browser:function(){var E=YAHOO.env.ua;if(E.webkit>=420){E.webkit3=E.webkit;}else{E.webkit3=0;}E.mac=false;if(navigator.userAgent.indexOf("Macintosh")!==-1){E.mac=true;}return E;}(),init:function(F,E){if(!this._defaultToolbar){this._defaultToolbar={collapse:true,titlebar:"Text Editing Tools",draggable:false,buttons:[{group:"fontstyle",label:"Font Name and Size",buttons:[{type:"select",label:"Arial",value:"fontname",disabled:true,menu:[{text:"Arial",checked:true},{text:"Arial Black"},{text:"Comic Sans MS"},{text:"Courier New"},{text:"Lucida Console"},{text:"Tahoma"},{text:"Times New Roman"},{text:"Trebuchet MS"},{text:"Verdana"}]},{type:"spin",label:"13",value:"fontsize",range:[9,75],disabled:true}]},{type:"separator"},{group:"textstyle",label:"Font Style",buttons:[{type:"push",label:"Bold CTRL + SHIFT + B",value:"bold"},{type:"push",label:"Italic CTRL + SHIFT + I",value:"italic"},{type:"push",label:"Underline CTRL + SHIFT + U",value:"underline"},{type:"push",label:"Strike Through",value:"strikethrough"},{type:"separator"},{type:"color",label:"Font Color",value:"forecolor",disabled:true},{type:"color",label:"Background Color",value:"backcolor",disabled:true}]},{type:"separator"},{group:"indentlist",label:"Lists",buttons:[{type:"push",label:"Create an Unordered List",value:"insertunorderedlist"},{type:"push",label:"Create an Ordered List",value:"insertorderedlist"}]},{type:"separator"},{group:"insertitem",label:"Insert Item",buttons:[{type:"push",label:"HTML Link CTRL + SHIFT + L",value:"createlink",disabled:true},{type:"push",label:"Insert Image",value:"insertimage"}]}]}; +}YAHOO.widget.SimpleEditor.superclass.init.call(this,F,E);YAHOO.widget.EditorInfo._instances[this.get("id")]=this;this.currentElement=[];this.on("contentReady",function(){this.DOMReady=true;this.fireQueue();},this,true);},initAttributes:function(E){YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this,E);var F=this;this.setAttributeConfig("nodeChangeDelay",{value:((E.nodeChangeDelay===false)?false:true)});this.setAttributeConfig("maxUndo",{writeOnce:true,value:E.maxUndo||30});this.setAttributeConfig("ptags",{writeOnce:true,value:E.ptags||false});this.setAttributeConfig("insert",{writeOnce:true,value:E.insert||false,method:function(K){if(K){var J={fontname:true,fontsize:true,forecolor:true,backcolor:true};var I=this._defaultToolbar.buttons;for(var H=0;H{TITLE}{CONTENT}',writeOnce:true});this.setAttributeConfig("extracss",{value:E.extracss||"",writeOnce:true});this.setAttributeConfig("handleSubmit",{value:E.handleSubmit||false,method:function(G){if(this.get("element").form){if(!this._formButtons){this._formButtons=[];}if(G){A.on(this.get("element").form,"submit",this._handleFormSubmit,this,true);var H=this.get("element").form.getElementsByTagName("input");for(var J=0;J=parseInt(this.get("height"),10))){C.setStyle(this.get("editor_wrapper"),"height",G+"px");if(this.browser.ie){this.get("iframe").setStyle("height","99%");this.get("iframe").setStyle("zoom","1");var H=this;window.setTimeout(function(){H.get("iframe").setStyle("height","100%");},1);}}},_formButtons:null,_formButtonClicked:null,_handleFormButtonClick:function(F){var E=A.getTarget(F);this._formButtonClicked=E;},_handleFormSubmit:function(H){this.saveHTML();var G=this.get("element").form,E=this._formButtonClicked||false;A.removeListener(G,"submit",this._handleFormSubmit);if(YAHOO.env.ua.ie){if(E&&!E.disabled){E.click();}}else{if(E&&!E.disabled){E.click();}var F=document.createEvent("HTMLEvents");F.initEvent("submit",true,true);G.dispatchEvent(F);if(YAHOO.env.ua.webkit){if(YAHOO.lang.isFunction(G.submit)){G.submit();}}}},_handleFontSize:function(G){var E=this.toolbar.getButtonById(G.button.id);var F=E.get("label")+"px";this.execCommand("fontsize",F);this.STOP_EXEC_COMMAND=true;},_handleColorPicker:function(G){var F=G.button;var E="#"+G.color;if((F=="forecolor")||(F=="backcolor")){this.execCommand(F,E);}},_handleAlign:function(H){var G=null;for(var E=0;E'+H+"";if(J.get("label")!=N){J.set("label",N);this._updateMenuChecked("fontname",H);}}if(K){M=parseInt(C.getStyle(L,"fontSize"),10);if((M===null)||isNaN(M)){M=K._configs.label._initialConfig.value;}K.set("label",""+M);}if(!this._isElement(L,"body")&&!this._isElement(L,"img")){this.toolbar.enableButton(J);this.toolbar.enableButton(K);this.toolbar.enableButton("forecolor");this.toolbar.enableButton("backcolor");}if(this._isElement(L,"img")){if(YAHOO.widget.Overlay){this.toolbar.enableButton("createlink");}}if(this._hasParent(L,"blockquote")){this.toolbar.selectButton("indent");this.toolbar.disableButton("indent");this.toolbar.enableButton("outdent");}if(this._hasParent(L,"ol")||this._hasParent(L,"ul")){this.toolbar.disableButton("indent");}this._lastButton=null;},_handleInsertImageClick:function(){if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("insertimage")){return false;}}this.toolbar.set("disabled",true);this.on("afterExecCommand",function(){var E=this.currentElement[0],G="http://";if(!E){E=this._getSelectedElement();}if(E){if(E.getAttribute("src")){G=E.getAttribute("src",2);if(G.indexOf(this.get("blankimage"))!=-1){G=this.STR_IMAGE_HERE;}}}var F=prompt(this.STR_LINK_URL+": ",G);if((F!=="")&&(F!==null)){E.setAttribute("src",F);}else{if(F===null){E.parentNode.removeChild(E);this.currentElement=[];this.nodeChange();}}this.closeWindow();this.toolbar.set("disabled",false);},this,true);},_handleInsertImageWindowClose:function(){this.nodeChange();},_isLocalFile:function(E){if((E)&&(E!=="")&&((E.indexOf("file:/")!=-1)||(E.indexOf(":\\")!=-1))){return true;}return false;},_handleCreateLinkClick:function(){if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("createlink")){return false;}}this.toolbar.set("disabled",true);this.on("afterExecCommand",function(){var G=this.currentElement[0],F="";if(G){if(G.getAttribute("href",2)!==null){F=G.getAttribute("href",2);}}var I=prompt(this.STR_LINK_URL+": ",F);if((I!=="")&&(I!==null)){var H=I;if((H.indexOf(":/"+"/")==-1)&&(H.substring(0,1)!="/")&&(H.substring(0,6).toLowerCase()!="mailto")){if((H.indexOf("@")!=-1)&&(H.substring(0,6).toLowerCase()!="mailto")){H="mailto:"+H;}else{if(H.substring(0,1)!="#"){}}}G.setAttribute("href",H);}else{if(I!==null){var E=this._getDoc().createElement("span");E.innerHTML=G.innerHTML;C.addClass(E,"yui-non");G.parentNode.replaceChild(E,G);}}this.closeWindow();this.toolbar.set("disabled",false);},this);},_handleCreateLinkWindowClose:function(){this.nodeChange();this.currentElement=[]; +},render:function(){if(this._rendered){return false;}if(!this.DOMReady){this._queue[this._queue.length]=["render",arguments];return false;}if(this.get("element")){if(this.get("element").tagName){this._textarea=true;if(this.get("element").tagName.toLowerCase()!=="textarea"){this._textarea=false;}}else{return false;}}else{return false;}this._rendered=true;var E=this;window.setTimeout(function(){E._render.call(E);},4);},_render:function(){var E=this;this.set("textarea",this.get("element"));this.get("element_cont").setStyle("display","none");this.get("element_cont").addClass(this.CLASS_CONTAINER);this.set("iframe",this._createIframe());window.setTimeout(function(){E._setInitialContent.call(E);},10);this.get("editor_wrapper").appendChild(this.get("iframe").get("element"));if(this.get("disabled")){this._disableEditor(true);}var F=this.get("toolbar");if(F instanceof B){this.toolbar=F;this.toolbar.set("disabled",true);}else{F.disabled=true;this.toolbar=new B(this.get("toolbar_cont"),F);}this.fireEvent("toolbarLoaded",{type:"toolbarLoaded",target:this.toolbar});this.toolbar.on("toolbarCollapsed",function(){if(this.currentWindow){this.moveWindow();}},this,true);this.toolbar.on("toolbarExpanded",function(){if(this.currentWindow){this.moveWindow();}},this,true);this.toolbar.on("fontsizeClick",this._handleFontSize,this,true);this.toolbar.on("colorPickerClicked",function(G){this._handleColorPicker(G);return false;},this,true);this.toolbar.on("alignClick",this._handleAlign,this,true);this.on("afterNodeChange",this._handleAfterNodeChange,this,true);this.toolbar.on("insertimageClick",this._handleInsertImageClick,this,true);this.on("windowinsertimageClose",this._handleInsertImageWindowClose,this,true);this.toolbar.on("createlinkClick",this._handleCreateLinkClick,this,true);this.on("windowcreatelinkClose",this._handleCreateLinkWindowClose,this,true);this.get("parentNode").replaceChild(this.get("element_cont").get("element"),this.get("element"));this.setStyle("visibility","hidden");this.setStyle("position","absolute");this.setStyle("top","-9999px");this.setStyle("left","-9999px");this.get("element_cont").appendChild(this.get("element"));this.get("element_cont").setStyle("display","block");C.addClass(this.get("iframe").get("parentNode"),this.CLASS_EDITABLE_CONT);this.get("iframe").addClass(this.CLASS_EDITABLE);this.get("element_cont").setStyle("width",this.get("width"));C.setStyle(this.get("iframe").get("parentNode"),"height",this.get("height"));this.get("iframe").setStyle("width","100%");this.get("iframe").setStyle("height","100%");this._setupDD();window.setTimeout(function(){E._setupAfterElement.call(E);},0);this.fireEvent("afterRender",{type:"afterRender",target:this});},execCommand:function(G,F){var J=this.fireEvent("beforeExecCommand",{type:"beforeExecCommand",target:this,args:arguments});if((J===false)||(this.STOP_EXEC_COMMAND)){this.STOP_EXEC_COMMAND=false;return false;}this._lastCommand=G;this._setMarkupType(G);if(this.browser.ie){this._getWindow().focus();}var E=true;if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue(G)){E=false;}}this.editorDirty=true;if((typeof this["cmd_"+G.toLowerCase()]=="function")&&E){var I=this["cmd_"+G.toLowerCase()](F);E=I[0];if(I[1]){G=I[1];}if(I[2]){F=I[2];}}if(E){try{this._getDoc().execCommand(G,false,F);}catch(H){}}else{}this.on("afterExecCommand",function(){this.unsubscribeAll("afterExecCommand");this.nodeChange();},this,true);this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});},cmd_underline:function(F){if(!this.browser.webkit){var E=this._getSelectedElement();if(E&&this._isElement(E,"span")){if(E.style.textDecoration=="underline"){E.style.textDecoration="none";}else{E.style.textDecoration="underline";}return[false];}}return[true];},cmd_backcolor:function(H){var E=true,F=this._getSelectedElement(),G="backcolor";if(this.browser.gecko||this.browser.opera){this._setEditorStyle(true);G="hilitecolor";}if(!this._isElement(F,"body")&&!this._hasSelection()){C.setStyle(F,"background-color",H);this._selectNode(F);E=false;}else{if(!this._isElement(F,"body")&&this._hasSelection()){C.setStyle(F,"background-color",H);this._selectNode(F);E=false;}else{if(this.get("insert")){F=this._createInsertElement({backgroundColor:H});}else{this._createCurrentElement("span",{backgroundColor:H});this._selectNode(this.currentElement[0]);}E=false;}}return[E,G];},cmd_forecolor:function(G){var E=true,F=this._getSelectedElement();if(!this._isElement(F,"body")&&!this._hasSelection()){C.setStyle(F,"color",G);this._selectNode(F);E=false;}else{if(!this._isElement(F,"body")&&this._hasSelection()){C.setStyle(F,"color",G);this._selectNode(F);E=false;}else{if(this.get("insert")){F=this._createInsertElement({color:G});}else{this._createCurrentElement("span",{color:G});this._selectNode(this.currentElement[0]);}E=false;}}return[E];},cmd_unlink:function(E){this._swapEl(this.currentElement[0],"span",function(F){F.className="yui-non";});return[false];},cmd_createlink:function(G){var F=this._getSelectedElement(),E=null;if(this._hasParent(F,"a")){this.currentElement[0]=this._hasParent(F,"a");}else{if(!this._isElement(F,"a")){this._createCurrentElement("a");E=this._swapEl(this.currentElement[0],"a");this.currentElement[0]=E;}else{this.currentElement[0]=F;}}return[false];},cmd_insertimage:function(J){var E=true,F=null,I="insertimage",H=this._getSelectedElement();if(J===""){J=this.get("blankimage");}if(this._isElement(H,"img")){this.currentElement[0]=H;E=false;}else{if(this._getDoc().queryCommandEnabled(I)){this._getDoc().execCommand("insertimage",false,J);var K=this._getDoc().getElementsByTagName("img");for(var G=0;G"+F[M].innerHTML+"
            ";}V.innerHTML=R;this.currentElement[0]=G;this.currentElement[0].parentNode.replaceChild(V,this.currentElement[0]);}else{this._createCurrentElement(Y.toLowerCase());V=this._getDoc().createElement(Y);for(M=0;M 
             ';V.appendChild(J);if(M>0){this.currentElement[M].parentNode.removeChild(this.currentElement[M]);}}this.currentElement[0].parentNode.replaceChild(V,this.currentElement[0]);this.currentElement[0]=V;var H=this.currentElement[0].firstChild;H=C.getElementsByClassName("yui-non","span",H)[0];this._getSelection().setBaseAndExtent(H,1,H,H.innerText.length);}S=false;}else{G=this._getSelectedElement();if(this._isElement(G,"li")&&this._isElement(G.parentNode,Y)||(this.browser.ie&&this._isElement(this._getRange().parentElement,"li"))||(this.browser.ie&&this._isElement(G,"ul"))||(this.browser.ie&&this._isElement(G,"ol"))){if(this.browser.ie){if((this.browser.ie&&this._isElement(G,"ul"))||(this.browser.ie&&this._isElement(G,"ol"))){G=G.getElementsByTagName("li")[0];}R="";var I=G.parentNode.getElementsByTagName("li");for(var U=0;U";}var X=this._getDoc().createElement("span");X.innerHTML=R;G.parentNode.parentNode.replaceChild(X,G.parentNode);}else{this.nodeChange();this._getDoc().execCommand(T,"",G.parentNode);this.nodeChange();}S=false;}if(this.browser.opera){var Q=this;window.setTimeout(function(){var Z=Q._getDoc().getElementsByTagName("li");for(var a=0;a"){Z[a].parentNode.parentNode.removeChild(Z[a].parentNode);}}},30);}if(this.browser.ie&&S){var K="";if(this._getRange().html){K="
          • "+this._getRange().html+"
          • ";}else{var L=this._getRange().text.split("\n");if(L.length>1){K="";for(var P=0;P"+L[P]+"";}}else{var O=this._getRange().text;if(O===""){K='
          • '+O+"
          • ";}else{K="
          • "+O+"
          • ";}}}this._getRange().pasteHTML("<"+Y+">"+K+"");var E=this._getDoc().getElementById("new_list_item");if(E){var N=this._getDoc().body.createTextRange();N.moveToElementText(E);N.collapse(false);N.select();E.id="";}S=false;}}return S;},cmd_insertorderedlist:function(E){return[this.cmd_list("ol")];},cmd_insertunorderedlist:function(E){return[this.cmd_list("ul")];},cmd_fontname:function(H){var E=true,G=this._getSelectedElement();this.currentFont=H;if(G&&G.tagName&&!this._hasSelection()&&!this._isElement(G,"body")&&!this.get("insert")){YAHOO.util.Dom.setStyle(G,"font-family",H);E=false;}else{if(this.get("insert")&&!this._hasSelection()){var F=this._createInsertElement({fontFamily:H});E=false;}}return[E];},cmd_fontsize:function(G){var E=null;if(this.currentElement&&(this.currentElement.length>0)&&(!this._hasSelection())&&(!this.get("insert"))){YAHOO.util.Dom.setStyle(this.currentElement,"fontSize",G);}else{if(!this._isElement(this._getSelectedElement(),"body")){E=this._getSelectedElement();YAHOO.util.Dom.setStyle(E,"fontSize",G);if(this.get("insert")&&this.browser.ie){var F=this._getRange();F.collapse(false);F.select();}else{this._selectNode(E);}}else{if(this.get("insert")&&!this._hasSelection()){E=this._createInsertElement({fontSize:G});this.currentElement[0]=E;this._selectNode(this.currentElement[0]);}else{this._createCurrentElement("span",{"fontSize":G});this._selectNode(this.currentElement[0]);}}}return[false];},_swapEl:function(F,E,H){var G=this._getDoc().createElement(E);if(F){G.innerHTML=F.innerHTML;}if(typeof H=="function"){H.call(this,G);}if(F){F.parentNode.replaceChild(G,F);}return G;},_createInsertElement:function(E){this._createCurrentElement("span",E);var F=this.currentElement[0];if(this.browser.webkit){F.innerHTML=' ';F=F.firstChild;this._getSelection().setBaseAndExtent(F,1,F,F.innerText.length);}else{if(this.browser.ie||this.browser.opera){F.innerHTML=" ";}}this._focusWindow();this._selectNode(F,true);return F;},_createCurrentElement:function(G,J){G=((G)?G:"a");var R=null,F=[],H=this._getDoc();if(this.currentFont){if(!J){J={};}J.fontFamily=this.currentFont;this.currentFont=null;}this.currentElement=[];var M=function(X,Z){var Y=null;X=((X)?X:"span");X=X.toLowerCase();switch(X){case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":Y=H.createElement(X);break;default:Y=H.createElement(X);if(X==="span"){YAHOO.util.Dom.addClass(Y,"yui-tag-"+X);YAHOO.util.Dom.addClass(Y,"yui-tag");Y.setAttribute("tag",X);}for(var W in Z){if(YAHOO.lang.hasOwnProperty(Z,W)){Y.style[W]=Z[W];}}break;}return Y;};if(!this._hasSelection()){if(this._getDoc().queryCommandEnabled("insertimage")){this._getDoc().execCommand("insertimage",false,"yui-tmp-img");var L=this._getDoc().getElementsByTagName("img");for(var Q=0;Q]*)>/gi,"");E=E.replace(/<\/strong>/gi,"");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/embed>/gi,"");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/em>/gi,"");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/YUI_EMBED>/gi,"");if(this.get("plainText")){E=E.replace(/\n/g,"
            ").replace(/\r/g,"
            ");E=E.replace(/ /gi,"  ");E=E.replace(/\t/gi,"    ");}E=E.replace(/]*)>/gi,"");E=E.replace(/<\/script([^>]*)>/gi,"");E=E.replace(/<script([^>]*)>/gi,"");E=E.replace(/<\/script([^>]*)>/gi,"");E=E.replace(/\n/g,"").replace(/\r/g,"");E=E.replace(new RegExp("]*)>(.*?)","gi"),"");E=E.replace(//g,"\n");return E;},cleanHTML:function(G){if(!G){G=this.getEditorHTML();}var F=this.get("markup");G=this.pre_filter_linebreaks(G,F);G=G.replace(/]*)\/>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/]*)\/>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/ul>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/blockquote>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/embed>/gi,"");if((F=="semantic")||(F=="xhtml")){G=G.replace(/]*)?>/gi,"");G=G.replace(/<\/i>/gi,"");G=G.replace(/]*)?>/gi,"");G=G.replace(/<\/b>/gi,"");}G=G.replace(//gi,"");G=G.replace(//gi,"");if((F=="semantic")||(F=="xhtml")||(F=="css")){G=G.replace(new RegExp(']*)face="([^>]*)">(.*?)',"gi"),'$3');G=G.replace(/([^>]*)',"gi"),"$1");G=G.replace(new RegExp('([^>]*)',"gi"),"$1");}G=G.replace(/\/u>/gi,"/span>");if(F=="css"){G=G.replace(/]*)>/gi,"");G=G.replace(/<\/em>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/strong>/gi,"");G=G.replace(//gi,"/span>");G=G.replace(//gi,"/span>");}G=G.replace(/ /gi," ");}else{G=G.replace(//gi,"/u>");}G=G.replace(/]*)>/gi,"");G=G.replace(/\/ol>/gi,"/ol>");G=G.replace(/
          • /gi,"/li>");G=this.filter_safari(G);G=this.filter_internals(G);G=this.filter_all_rgb(G);G=this.post_filter_linebreaks(G,F);if(F=="xhtml"){G=G.replace(/]*)>/g,"");G=G.replace(/]*)>/g,"");}else{G=G.replace(/]*)>/g,"");G=G.replace(/]*)>/g,"");}G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_UL>/g,"
          ");G=this.filter_invalid_lists(G);G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_BQ>/g,"");G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_EMBED>/g,"");G=G.replace(" & ","YUI_AMP");G=G.replace("&","&");G=G.replace("YUI_AMP","&");G=YAHOO.lang.trim(G);if(this.get("removeLineBreaks")){G=G.replace(/\n/g,"").replace(/\r/g,"");G=G.replace(/ /gi," ");}if(G.substring(0,6).toLowerCase()==""){G=G.substring(6);if(G.substring(G.length-7,G.length).toLowerCase()==""){G=G.substring(0,G.length-7);}}for(var E in this.invalidHTML){if(YAHOO.lang.hasOwnProperty(this.invalidHTML,E)){if(D.isObject(E)&&E.keepContents){G=G.replace(new RegExp("<"+E+"([^>]*)>(.*?)","gi"),"$1");}else{G=G.replace(new RegExp("<"+E+"([^>]*)>(.*?)","gi"),"");}}}this.fireEvent("cleanHTML",{type:"cleanHTML",target:this,html:G});return G;},filter_invalid_lists:function(E){E=E.replace(/<\/li>\n/gi,"");E=E.replace(/<\/li>
            /gi,"
            1. ");E=E.replace(/<\/ol>/gi,"
          1. ");E=E.replace(/<\/ol><\/li>\n/gi,"
          \n");E=E.replace(/<\/li>
            /gi,"
            • ");E=E.replace(/<\/ul>/gi,"
          • ");E=E.replace(/<\/ul><\/li>\n?/gi,"
          \n");E=E.replace(/<\/li>/gi,"\n");E=E.replace(/<\/ol>/gi,"
      \n");E=E.replace(/
        /gi,"
          \n");E=E.replace(/
            /gi,"
              \n");return E;},filter_safari:function(E){if(this.browser.webkit){E=E.replace(/([^>])<\/span>/gi,"    ");E=E.replace(/Apple-style-span/gi,"");E=E.replace(/style="line-height: normal;"/gi,"");E=E.replace(/
            • <\/li>/gi,"");E=E.replace(/
            • <\/li>/gi,"");E=E.replace(/
            • <\/li>/gi,"");if(this.get("ptags")){E=E.replace(/]*)>/g,"");E=E.replace(/<\/div>/gi,"

              ");}else{E=E.replace(/
              /gi,"");E=E.replace(/<\/div>/gi,"
              ");}}return E;},filter_internals:function(E){E=E.replace(/\r/g,"");E=E.replace(/<\/?(body|head|html)[^>]*>/gi,"");E=E.replace(/<\/li>/gi,"
            • ");E=E.replace(/yui-tag-span/gi,"");E=E.replace(/yui-tag/gi,"");E=E.replace(/yui-non/gi,"");E=E.replace(/yui-img/gi,"");E=E.replace(/ tag="span"/gi,"");E=E.replace(/ class=""/gi,"");E=E.replace(/ style=""/gi,"");E=E.replace(/ class=" "/gi,"");E=E.replace(/ class=" "/gi,"");E=E.replace(/ target=""/gi,"");E=E.replace(/ title=""/gi,"");if(this.browser.ie){E=E.replace(/ class= /gi,"");E=E.replace(/ class= >/gi,"");E=E.replace(/_height="([^>])"/gi,"");E=E.replace(/_width="([^>])"/gi,"");}return E;},filter_all_rgb:function(I){var H=new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)","gi");var E=I.match(H);if(D.isArray(E)){for(var G=0;G/gi,"");F=F.replace(/
              /gi,"");}F=F.replace(/
              /gi,"");F=F.replace(/
              /gi,"");F=F.replace(//gi,"");F=F.replace(/
              /gi,"");F=F.replace(/
              <\/div>/gi,"");F=F.replace(/

              ( | )<\/p>/g,"");F=F.replace(/


               <\/p>/gi,"");F=F.replace(/

               <\/p>/gi,"");F=F.replace(/$/,"");F=F.replace(/<\/p>/g,"

              ");if(this.browser.ie){F=F.replace(/    /g,"\t");}return F;},post_filter_linebreaks:function(F,E){if(E=="xhtml"){F=F.replace(//g,"
              ");}else{F=F.replace(//g,"
              ");}return F;},clearEditorDoc:function(){this._getDoc().body.innerHTML=" ";},openWindow:function(E){},moveWindow:function(){},_closeWindow:function(){},closeWindow:function(){this.toolbar.resetAllButtons();this._focusWindow();},destroy:function(){if(this.resize){this.resize.destroy();}if(this.dd){this.dd.unreg();}if(this.get("panel")){this.get("panel").destroy();}this.saveHTML();this.toolbar.destroy();this.setStyle("visibility","visible");this.setStyle("position","static");this.setStyle("top","");this.setStyle("left","");var E=this.get("element");this.get("element_cont").get("parentNode").replaceChild(E,this.get("element_cont").get("element"));this.get("element_cont").get("element").innerHTML="";this.set("handleSubmit",false);return true;},toString:function(){var E="SimpleEditor";if(this.get&&this.get("element_cont")){E="SimpleEditor (#"+this.get("element_cont").get("id")+")"+((this.get("disabled")?" Disabled":""));}return E;}});YAHOO.widget.EditorInfo={_instances:{},blankImage:"",window:{},panel:null,getEditorById:function(E){if(!YAHOO.lang.isString(E)){E=E.id;}if(this._instances[E]){return this._instances[E];}return false;},toString:function(){var E=0;for(var F in this._instances){if(D.hasOwnProperty(this._instances,F)){E++;}}return"Editor Info ("+E+" registered intance"+((E>1)?"s":"")+")"; +}};})();(function(){var C=YAHOO.util.Dom,A=YAHOO.util.Event,D=YAHOO.lang,B=YAHOO.widget.Toolbar;YAHOO.widget.Editor=function(F,E){YAHOO.widget.Editor.superclass.constructor.call(this,F,E);};YAHOO.extend(YAHOO.widget.Editor,YAHOO.widget.SimpleEditor,{_undoCache:null,_undoLevel:null,_hasUndoLevel:function(){return(this._undoCache.length&&this._undoLevel);},_undoNodeChange:function(){var E=this.toolbar.getButtonByValue("undo"),F=this.toolbar.getButtonByValue("redo");if(E&&F){if(this._hasUndoLevel()){this.toolbar.enableButton(E);}if(this._undoLevel=this.get("maxUndo")){for(var F=(E-this.get("maxUndo"));FCommon formatting keyboard shortcuts:
              • Control Shift B sets text to bold
              • Control Shift I sets text to italic
              • Control Shift U underlines text
              • Control Shift [ aligns text left
              • Control Shift | centers text
              • Control Shift ] aligns text right
              • Control Shift L adds an HTML link
              • To exit this text editor use the keyboard shortcut Control + Shift + ESC.
              ",STR_CLOSE_WINDOW:"Close Window",STR_CLOSE_WINDOW_NOTE:"To close this window use the Control + Shift + W key",STR_IMAGE_PROP_TITLE:"Image Options",STR_IMAGE_URL:"Image URL",STR_IMAGE_TITLE:"Description",STR_IMAGE_SIZE:"Size",STR_IMAGE_ORIG_SIZE:"Original Size",STR_IMAGE_COPY:'Note:To move this image just highlight it, cut, and paste where ever you\'d like.',STR_IMAGE_PADDING:"Padding",STR_IMAGE_BORDER:"Border",STR_IMAGE_BORDER_SIZE:"Border Size",STR_IMAGE_BORDER_TYPE:"Border Type",STR_IMAGE_TEXTFLOW:"Text Flow",STR_LOCAL_FILE_WARNING:'Note:This image/link points to a file on your computer and will not be accessible to others on the internet.',STR_LINK_PROP_TITLE:"Link Options",STR_LINK_PROP_REMOVE:"Remove link from text",STR_LINK_NEW_WINDOW:"Open in a new window.",STR_LINK_TITLE:"Description",CLASS_LOCAL_FILE:"warning-localfile",CLASS_HIDDEN:"yui-hidden",init:function(F,E){this._windows={};this._defaultToolbar={collapse:true,titlebar:"Text Editing Tools",draggable:false,buttonType:"advanced",buttons:[{group:"fontstyle",label:"Font Name and Size",buttons:[{type:"select",label:"Arial",value:"fontname",disabled:true,menu:[{text:"Arial",checked:true},{text:"Arial Black"},{text:"Comic Sans MS"},{text:"Courier New"},{text:"Lucida Console"},{text:"Tahoma"},{text:"Times New Roman"},{text:"Trebuchet MS"},{text:"Verdana"}]},{type:"spin",label:"13",value:"fontsize",range:[9,75],disabled:true}]},{type:"separator"},{group:"textstyle",label:"Font Style",buttons:[{type:"push",label:"Bold CTRL + SHIFT + B",value:"bold"},{type:"push",label:"Italic CTRL + SHIFT + I",value:"italic"},{type:"push",label:"Underline CTRL + SHIFT + U",value:"underline"},{type:"separator"},{type:"push",label:"Subscript",value:"subscript",disabled:true},{type:"push",label:"Superscript",value:"superscript",disabled:true}]},{type:"separator"},{group:"textstyle2",label:" ",buttons:[{type:"color",label:"Font Color",value:"forecolor",disabled:true},{type:"color",label:"Background Color",value:"backcolor",disabled:true},{type:"separator"},{type:"push",label:"Remove Formatting",value:"removeformat",disabled:true},{type:"push",label:"Show/Hide Hidden Elements",value:"hiddenelements"}]},{type:"separator"},{group:"undoredo",label:"Undo/Redo",buttons:[{type:"push",label:"Undo",value:"undo",disabled:true},{type:"push",label:"Redo",value:"redo",disabled:true}]},{type:"separator"},{group:"alignment",label:"Alignment",buttons:[{type:"push",label:"Align Left CTRL + SHIFT + [",value:"justifyleft"},{type:"push",label:"Align Center CTRL + SHIFT + |",value:"justifycenter"},{type:"push",label:"Align Right CTRL + SHIFT + ]",value:"justifyright"},{type:"push",label:"Justify",value:"justifyfull"}]},{type:"separator"},{group:"parastyle",label:"Paragraph Style",buttons:[{type:"select",label:"Normal",value:"heading",disabled:true,menu:[{text:"Normal",value:"none",checked:true},{text:"Header 1",value:"h1"},{text:"Header 2",value:"h2"},{text:"Header 3",value:"h3"},{text:"Header 4",value:"h4"},{text:"Header 5",value:"h5"},{text:"Header 6",value:"h6"}]}]},{type:"separator"},{group:"indentlist2",label:"Indenting and Lists",buttons:[{type:"push",label:"Indent",value:"indent",disabled:true},{type:"push",label:"Outdent",value:"outdent",disabled:true},{type:"push",label:"Create an Unordered List",value:"insertunorderedlist"},{type:"push",label:"Create an Ordered List",value:"insertorderedlist"}]},{type:"separator"},{group:"insertitem",label:"Insert Item",buttons:[{type:"push",label:"HTML Link CTRL + SHIFT + L",value:"createlink",disabled:true},{type:"push",label:"Insert Image",value:"insertimage"}]}]};this._defaultImageToolbarConfig={buttonType:this._defaultToolbar.buttonType,buttons:[{group:"textflow",label:this.STR_IMAGE_TEXTFLOW+":",buttons:[{type:"push",label:"Left",value:"left"},{type:"push",label:"Inline",value:"inline"},{type:"push",label:"Block",value:"block"},{type:"push",label:"Right",value:"right"}]},{type:"separator"},{group:"padding",label:this.STR_IMAGE_PADDING+":",buttons:[{type:"spin",label:"0",value:"padding",range:[0,50]}]},{type:"separator"},{group:"border",label:this.STR_IMAGE_BORDER+":",buttons:[{type:"select",label:this.STR_IMAGE_BORDER_SIZE,value:"bordersize",menu:[{text:"none",value:"0",checked:true},{text:"1px",value:"1"},{text:"2px",value:"2"},{text:"3px",value:"3"},{text:"4px",value:"4"},{text:"5px",value:"5"}]},{type:"select",label:this.STR_IMAGE_BORDER_TYPE,value:"bordertype",disabled:true,menu:[{text:"Solid",value:"solid",checked:true},{text:"Dashed",value:"dashed"},{text:"Dotted",value:"dotted"}]},{type:"color",label:"Border Color",value:"bordercolor",disabled:true}]}]}; +YAHOO.widget.Editor.superclass.init.call(this,F,E);},_render:function(){YAHOO.widget.Editor.superclass._render.apply(this,arguments);var E=this;window.setTimeout(function(){E._renderPanel.call(E);},800);},initAttributes:function(E){YAHOO.widget.Editor.superclass.initAttributes.call(this,E);this.setAttributeConfig("localFileWarning",{value:E.locaFileWarning||true});this.setAttributeConfig("hiddencss",{value:E.hiddencss||".yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }",writeOnce:true});},_windows:null,_defaultImageToolbar:null,_defaultImageToolbarConfig:null,_fixNodes:function(){YAHOO.widget.Editor.superclass._fixNodes.call(this);var H="";var I=this._getDoc().getElementsByTagName("img");for(var F=0;F'+this.STR_LINK_URL+': ';H+='";H+='';var E=document.createElement("div");E.innerHTML=H;var G=document.createElement("div");G.className="removeLink";var F=document.createElement("a");F.href="#";F.innerHTML=this.STR_LINK_PROP_REMOVE;F.title=this.STR_LINK_PROP_REMOVE;A.on(F,"click",function(I){A.stopEvent(I);this.execCommand("unlink");this.closeWindow();},this,true);G.appendChild(F);E.appendChild(G);this._windows.createlink={};this._windows.createlink.body=E;E.style.display="none";this.get("panel").editor_form.appendChild(E);this.fireEvent("windowCreateLinkRender",{type:"windowCreateLinkRender",panel:this.get("panel"),body:E});return E;},_handleCreateLinkClick:function(){var E=this._getSelectedElement();if(this._isElement(E,"img")){this.STOP_EXEC_COMMAND=true;this.currentElement[0]=E;this.toolbar.fireEvent("insertimageClick",{type:"insertimageClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});return false;}if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("createlink")){return false;}}this.on("afterExecCommand",function(){var K=new YAHOO.widget.EditorWindow("createlink",{width:"350px"});var I=this.currentElement[0],H="",L="",J="",G=false;if(I){K.el=I;if(I.getAttribute("href",2)!==null){H=I.getAttribute("href",2);if(this._isLocalFile(H)){K.setFooter(this.STR_LOCAL_FILE_WARNING);G=true;}else{K.setFooter(" ");}}if(I.getAttribute("title")!==null){L=I.getAttribute("title");}if(I.getAttribute("target")!==null){J=I.getAttribute("target");}}var F=null;if(this._windows.createlink&&this._windows.createlink.body){F=this._windows.createlink.body;}else{F=this._renderCreateLinkWindow();}K.setHeader(this.STR_LINK_PROP_TITLE);K.setBody(F);A.purgeElement(this.get("id")+"_createlink_url");C.get(this.get("id")+"_createlink_url").value=H;C.get(this.get("id")+"_createlink_title").value=L;C.get(this.get("id")+"_createlink_target").checked=((J)?true:false);A.onAvailable(this.get("id")+"_createlink_url",function(){var M=this.get("id");window.setTimeout(function(){try{YAHOO.util.Dom.get(M+"_createlink_url").focus();}catch(N){}},50);if(this._isLocalFile(H)){C.addClass(this.get("id")+"_createlink_url","warning");this.get("panel").setFooter(this.STR_LOCAL_FILE_WARNING);}else{C.removeClass(this.get("id")+"_createlink_url","warning");this.get("panel").setFooter(" ");}A.on(this.get("id")+"_createlink_url","blur",function(){var N=C.get(this.get("id")+"_createlink_url");if(this._isLocalFile(N.value)){C.addClass(N,"warning");this.get("panel").setFooter(this.STR_LOCAL_FILE_WARNING);}else{C.removeClass(N,"warning");this.get("panel").setFooter(" ");}},this,true);},this,true);this.openWindow(K);});},_handleCreateLinkWindowClose:function(){var G=C.get(this.get("id")+"_createlink_url"),I=C.get(this.get("id")+"_createlink_target"),K=C.get(this.get("id")+"_createlink_title"),H=arguments[0].win.el,E=H;if(G&&G.value){var J=G.value;if((J.indexOf(":/"+"/")==-1)&&(J.substring(0,1)!="/")&&(J.substring(0,6).toLowerCase()!="mailto")){if((J.indexOf("@")!=-1)&&(J.substring(0,6).toLowerCase()!="mailto")){J="mailto:"+J;}else{if(J.substring(0,1)!="#"){J="http:/"+"/"+J; +}}}H.setAttribute("href",J);if(I.checked){H.setAttribute("target",I.value);}else{H.setAttribute("target","");}H.setAttribute("title",((K.value)?K.value:""));}else{var F=this._getDoc().createElement("span");F.innerHTML=H.innerHTML;C.addClass(F,"yui-non");H.parentNode.replaceChild(F,H);}C.removeClass(G,"warning");C.get(this.get("id")+"_createlink_url").value="";C.get(this.get("id")+"_createlink_title").value="";C.get(this.get("id")+"_createlink_target").checked=false;this.nodeChange();this.currentElement=[];},_renderInsertImageWindow:function(){var G=this.currentElement[0];var M='';var K=document.createElement("div");K.innerHTML=M;var J=document.createElement("div");J.id=this.get("id")+"_img_toolbar";K.appendChild(J);var I='';I+='';I+='";var E=document.createElement("div");E.innerHTML=I;K.appendChild(E);var F={};D.augmentObject(F,this._defaultImageToolbarConfig);var H=new YAHOO.widget.Toolbar(J,F);H.editor_el=G;this._defaultImageToolbar=H;var N=H.get("cont");var L=document.createElement("div");L.className="yui-toolbar-group yui-toolbar-group-height-width height-width";L.innerHTML="

              "+this.STR_IMAGE_SIZE+":

              ";L.innerHTML+=' x ';N.insertBefore(L,N.firstChild);A.onAvailable(this.get("id")+"_insertimage_width",function(){A.on(this.get("id")+"_insertimage_width","blur",function(){var O=parseInt(C.get(this.get("id")+"_insertimage_width").value,10);if(O>5){this._defaultImageToolbar.editor_el.style.width=O+"px";}},this,true);},this,true);A.onAvailable(this.get("id")+"_insertimage_height",function(){A.on(this.get("id")+"_insertimage_height","blur",function(){var O=parseInt(C.get(this.get("id")+"_insertimage_height").value,10);if(O>5){this._defaultImageToolbar.editor_el.style.height=O+"px";}},this,true);},this,true);H.on("colorPickerClicked",function(T){var P="1",S="solid",O="black",R=this._defaultImageToolbar.editor_el;if(R.style.borderLeftWidth){P=parseInt(R.style.borderLeftWidth,10);}if(R.style.borderLeftStyle){S=R.style.borderLeftStyle;}if(R.style.borderLeftColor){O=R.style.borderLeftColor;}var Q=P+"px "+S+" #"+T.color;R.style.border=Q;},this,true);H.on("buttonClick",function(V){var T=V.button.value,S=this._defaultImageToolbar.editor_el,R="";if(V.button.menucmd){T=V.button.menucmd;}var P="1",Q="solid",O="black";if(S.style.borderLeftWidth){P=parseInt(S.style.borderLeftWidth,10);}if(S.style.borderLeftStyle){Q=S.style.borderLeftStyle;}if(S.style.borderLeftColor){O=S.style.borderLeftColor;}switch(T){case"bordersize":if(this.browser.webkit&&this._lastImage){C.removeClass(this._lastImage,"selected");this._lastImage=null;}R=parseInt(V.button.value,10)+"px "+Q+" "+O;S.style.border=R;if(parseInt(V.button.value,10)>0){H.enableButton("bordertype");H.enableButton("bordercolor");}else{H.disableButton("bordertype");H.disableButton("bordercolor");}break;case"bordertype":if(this.browser.webkit&&this._lastImage){C.removeClass(this._lastImage,"selected");this._lastImage=null;}R=P+"px "+V.button.value+" "+O;S.style.border=R;break;case"right":case"left":H.deselectAllButtons();S.style.display="";S.align=V.button.value;break;case"inline":H.deselectAllButtons();S.style.display="";S.align="";break;case"block":H.deselectAllButtons();S.style.display="block";S.align="center";break;case"padding":var U=H.getButtonById(V.button.id);S.style.margin=U.get("label")+"px";break;}H.selectButton(V.button.value);if(T!=="padding"){this.moveWindow();}},this,true);if(this.get("localFileWarning")){A.on(this.get("id")+"_insertimage_link","blur",function(){var O=C.get(this.get("id")+"_insertimage_link");if(this._isLocalFile(O.value)){C.addClass(O,"warning");this.get("panel").setFooter(this.STR_LOCAL_FILE_WARNING);}else{C.removeClass(O,"warning");this.get("panel").setFooter(" ");if((this.browser.webkit&&!this.browser.webkit3||this.browser.air)||this.browser.opera){this.get("panel").setFooter(this.STR_IMAGE_COPY);}}},this,true);}A.on(this.get("id")+"_insertimage_url","blur",function(){var Q=C.get(this.get("id")+"_insertimage_url");if(Q.value&&G){if(Q.value==G.getAttribute("src",2)){return false;}}if(this._isLocalFile(Q.value)){C.addClass(Q,"warning");this.get("panel").setFooter(this.STR_LOCAL_FILE_WARNING);}else{if(this.currentElement[0]){C.removeClass(Q,"warning");this.get("panel").setFooter(" ");if((this.browser.webkit&&!this.browser.webkit3||this.browser.air)||this.browser.opera){this.get("panel").setFooter(this.STR_IMAGE_COPY);}if(Q&&Q.value&&(Q.value!=this.STR_IMAGE_HERE)){this.currentElement[0].setAttribute("src",Q.value);var P=this,O=new Image();O.onerror=function(){Q.value=P.STR_IMAGE_HERE;O.setAttribute("src",P.get("blankimage"));P.currentElement[0].setAttribute("src",P.get("blankimage"));YAHOO.util.Dom.get(P.get("id")+"_insertimage_height").value=O.height;YAHOO.util.Dom.get(P.get("id")+"_insertimage_width").value=O.width;};var R=this.get("id");window.setTimeout(function(){YAHOO.util.Dom.get(R+"_insertimage_height").value=O.height;YAHOO.util.Dom.get(R+"_insertimage_width").value=O.width;if(P.currentElement&&P.currentElement[0]){if(!P.currentElement[0]._height){P.currentElement[0]._height=O.height; +}if(!P.currentElement[0]._width){P.currentElement[0]._width=O.width;}}},800);if(Q.value!=this.STR_IMAGE_HERE){O.src=Q.value;}}}}},this,true);this._windows.insertimage={};this._windows.insertimage.body=K;K.style.display="none";this.get("panel").editor_form.appendChild(K);this.fireEvent("windowInsertImageRender",{type:"windowInsertImageRender",panel:this.get("panel"),body:K,toolbar:H});return K;},_handleInsertImageClick:function(){if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("insertimage")){return false;}}this.on("afterExecCommand",function(){var H=this.currentElement[0],P=null,M="",a="",G=null,b="",L="",Y="",S=75,W=75,R=0,N=0,K=0,T=false,J=new YAHOO.widget.EditorWindow("insertimage",{width:"415px"});if(!H){H=this._getSelectedElement();}if(H){J.el=H;if(H.getAttribute("src")){L=H.getAttribute("src",2);if(L.indexOf(this.get("blankimage"))!=-1){L=this.STR_IMAGE_HERE;T=true;}}if(H.getAttribute("alt",2)){b=H.getAttribute("alt",2);}if(H.getAttribute("title",2)){b=H.getAttribute("title",2);}if(H.parentNode&&this._isElement(H.parentNode,"a")){M=H.parentNode.getAttribute("href",2);if(H.parentNode.getAttribute("target")!==null){a=H.parentNode.getAttribute("target");}}S=parseInt(H.height,10);W=parseInt(H.width,10);if(H.style.height){S=parseInt(H.style.height,10);}if(H.style.width){W=parseInt(H.style.width,10);}if(H.style.margin){R=parseInt(H.style.margin,10);}if(!H._height){H._height=S;}if(!H._width){H._width=W;}N=H._height;K=H._width;}if(this._windows.insertimage&&this._windows.insertimage.body){P=this._windows.insertimage.body;this._defaultImageToolbar.resetAllButtons();}else{P=this._renderInsertImageWindow();}G=this._defaultImageToolbar;G.editor_el=H;var F="0";var V="solid";if(H.style.borderLeftWidth){F=parseInt(H.style.borderLeftWidth,10);}if(H.style.borderLeftStyle){V=H.style.borderLeftStyle;}var Z=G.getButtonByValue("bordersize");var X=((parseInt(F,10)>0)?"":"none");Z.set("label",''+X+"");this._updateMenuChecked("bordersize",F,G);var O=G.getButtonByValue("bordertype");O.set("label",'');this._updateMenuChecked("bordertype",V,G);if(parseInt(F,10)>0){G.enableButton(O);G.enableButton(Z);G.enableButton("bordercolor");}if((H.align=="right")||(H.align=="left")){G.selectButton(H.align);}else{if(H.style.display=="block"){G.selectButton("block");}else{G.selectButton("inline");}}if(parseInt(H.style.marginLeft,10)>0){G.getButtonByValue("padding").set("label",""+parseInt(H.style.marginLeft,10));}if(H.style.borderSize){G.selectButton("bordersize");G.selectButton(parseInt(H.style.borderSize,10));}G.getButtonByValue("padding").set("label",""+R);J.setHeader(this.STR_IMAGE_PROP_TITLE);J.setBody(P);if((this.browser.webkit&&!this.browser.webkit3||this.browser.air)||this.browser.opera){J.setFooter(this.STR_IMAGE_COPY);}this.openWindow(J);C.get(this.get("id")+"_insertimage_url").value=L;C.get(this.get("id")+"_insertimage_title").value=b;C.get(this.get("id")+"_insertimage_link").value=M;C.get(this.get("id")+"_insertimage_target").checked=((a)?true:false);C.get(this.get("id")+"_insertimage_width").value=W;C.get(this.get("id")+"_insertimage_height").value=S;var I="";if((S!=N)||(W!=K)){var Q=document.createElement("span");Q.className="info";Q.innerHTML=this.STR_IMAGE_ORIG_SIZE+": ("+K+" x "+N+")";if(C.get(this.get("id")+"_insertimage_height").nextSibling){var E=C.get(this.get("id")+"_insertimage_height").nextSibling;E.parentNode.removeChild(E);}C.get(this.get("id")+"_insertimage_height").parentNode.appendChild(Q);}this.toolbar.selectButton("insertimage");var U=this.get("id");window.setTimeout(function(){try{YAHOO.util.Dom.get(U+"_insertimage_url").focus();if(T){YAHOO.util.Dom.get(U+"_insertimage_url").select();}}catch(c){}},50);});},_handleInsertImageWindowClose:function(){var E=C.get(this.get("id")+"_insertimage_url"),L=C.get(this.get("id")+"_insertimage_title"),I=C.get(this.get("id")+"_insertimage_link"),J=C.get(this.get("id")+"_insertimage_target"),H=arguments[0].win.el;if(E&&E.value&&(E.value!=this.STR_IMAGE_HERE)){H.setAttribute("src",E.value);H.setAttribute("title",L.value);H.setAttribute("alt",L.value);var G=H.parentNode;if(I.value){var K=I.value;if((K.indexOf(":/"+"/")==-1)&&(K.substring(0,1)!="/")&&(K.substring(0,6).toLowerCase()!="mailto")){if((K.indexOf("@")!=-1)&&(K.substring(0,6).toLowerCase()!="mailto")){K="mailto:"+K;}else{K="http:/"+"/"+K;}}if(G&&this._isElement(G,"a")){G.setAttribute("href",K);if(J.checked){G.setAttribute("target",J.value);}else{G.setAttribute("target","");}}else{var F=this._getDoc().createElement("a");F.setAttribute("href",K);if(J.checked){F.setAttribute("target",J.value);}else{F.setAttribute("target","");}H.parentNode.replaceChild(F,H);F.appendChild(H);}}else{if(G&&this._isElement(G,"a")){G.parentNode.replaceChild(H,G);}}}else{H.parentNode.removeChild(H);}C.get(this.get("id")+"_insertimage_url").value="";C.get(this.get("id")+"_insertimage_title").value="";C.get(this.get("id")+"_insertimage_link").value="";C.get(this.get("id")+"_insertimage_target").checked=false;C.get(this.get("id")+"_insertimage_width").value=0;C.get(this.get("id")+"_insertimage_height").value=0;this._defaultImageToolbar.resetAllButtons();this.currentElement=[];this.nodeChange();},EDITOR_PANEL_ID:"-panel",_renderPanel:function(){var E=new YAHOO.widget.Overlay(this.get("id")+this.EDITOR_PANEL_ID,{width:"300px",iframe:true,visible:false,underlay:"none",draggable:false,close:false});this.set("panel",E);this.get("panel").setBody("---");this.get("panel").setHeader(" ");this.get("panel").setFooter(" ");var J=document.createElement("div");J.className=this.CLASS_PREFIX+"-body-cont";for(var K in this.browser){if(this.browser[K]){C.addClass(J,K);break;}}C.addClass(J,((YAHOO.widget.Button&&(this._defaultToolbar.buttonType=="advanced"))?"good-button":"no-button"));var H=document.createElement("h3");H.className="yui-editor-skipheader";H.innerHTML=this.STR_CLOSE_WINDOW_NOTE;J.appendChild(H);var F=document.createElement("form"); +F.setAttribute("method","GET");E.editor_form=F;A.on(F,"submit",function(N){A.stopEvent(N);},this,true);J.appendChild(F);var G=document.createElement("span");G.innerHTML="X";G.title=this.STR_CLOSE_WINDOW;G.className="close";A.on(G,"click",this.closeWindow,this,true);var L=document.createElement("span");L.innerHTML="^";L.className="knob";E.editor_knob=L;var M=document.createElement("h3");E.editor_header=M;M.innerHTML="";E.setHeader(" ");E.appendToHeader(M);M.appendChild(G);M.appendChild(L);E.setBody(" ");E.setFooter(" ");E.appendToBody(J);A.on(E.element,"click",function(N){A.stopPropagation(N);});var I=function(){};E.showEvent.subscribe(I,this,true);E.renderEvent.subscribe(function(){this._renderInsertImageWindow();this._renderCreateLinkWindow();this.fireEvent("windowRender",{type:"windowRender",panel:E});},this,true);if(this.DOMReady){this.get("panel").render(document.body);C.addClass(this.get("panel").element,"yui-editor-panel");}else{A.onDOMReady(function(){this.get("panel").render(document.body);C.addClass(this.get("panel").element,"yui-editor-panel");},this,true);}this.get("panel").showEvent.subscribe(function(){YAHOO.util.Dom.setStyle(this.element,"display","block");});return this.get("panel");},openWindow:function(K){var P=this;window.setTimeout(function(){P.toolbar.set("disabled",true);},10);A.on(document,"keydown",this._closeWindow,this,true);if(this.currentWindow){this.closeWindow();}var Q=C.getXY(this.currentElement[0]),N=C.getXY(this.get("iframe").get("element")),E=this.get("panel"),H=[(Q[0]+N[0]-20),(Q[1]+N[1]+10)],G=(parseInt(K.attrs.width,10)/2),L="center",J=null;this.fireEvent("beforeOpenWindow",{type:"beforeOpenWindow",win:K,panel:E});var F=E.editor_form;var I=this._windows;for(var O in I){if(D.hasOwnProperty(I,O)){if(I[O]&&I[O].body){if(O==K.name){C.setStyle(I[O].body,"display","block");}else{C.setStyle(I[O].body,"display","none");}}}}if(this._windows[K.name].body){C.setStyle(this._windows[K.name].body,"display","block");F.appendChild(this._windows[K.name].body);}else{if(D.isObject(K.body)){F.appendChild(K.body);}else{var M=document.createElement("div");M.innerHTML=K.body;F.appendChild(M);}}E.editor_header.firstChild.innerHTML=K.header;if(K.footer!==null){E.setFooter(K.footer);C.addClass(E.footer,"open");}else{C.removeClass(E.footer,"open");}E.cfg.setProperty("width",K.attrs.width);this.currentWindow=K;this.moveWindow(true);E.show();this.fireEvent("afterOpenWindow",{type:"afterOpenWindow",win:K,panel:E});},moveWindow:function(F){if(!this.currentWindow){return false;}var I=this.currentWindow,J=C.getXY(this.currentElement[0]),a=C.getXY(this.get("iframe").get("element")),O=this.get("panel"),Y=[(J[0]+a[0]),(J[1]+a[1])],R=(parseInt(I.attrs.width,10)/2),U="center",Q=O.cfg.getProperty("xy")||[0,0],G=O.editor_knob,X=0,L=0,T=false;Y[0]=((Y[0]-R)+20);Y[0]=Y[0]-C.getDocumentScrollLeft(this._getDoc());Y[1]=Y[1]-C.getDocumentScrollTop(this._getDoc());if(this._isElement(this.currentElement[0],"img")){if(this.currentElement[0].src.indexOf(this.get("blankimage"))!=-1){Y[0]=(Y[0]+(75/2));Y[1]=(Y[1]+75);}else{var N=parseInt(this.currentElement[0].width,10);var W=parseInt(this.currentElement[0].height,10);Y[0]=(Y[0]+(N/2));Y[1]=(Y[1]+W);}Y[1]=Y[1]+15;}else{var K=C.getStyle(this.currentElement[0],"fontSize");if(K&&K.indexOf&&K.indexOf("px")!=-1){Y[1]=Y[1]+parseInt(C.getStyle(this.currentElement[0],"fontSize"),10)+5;}else{Y[1]=Y[1]+20;}}if(Y[0](a[0]+parseInt(this.get("iframe").get("element").clientWidth,10))){Y[0]=((a[0]+parseInt(this.get("iframe").get("element").clientWidth,10))-(R*2)-5);U="right";}try{X=(Y[0]-Q[0]);L=(Y[1]-Q[1]);}catch(b){}if(this.get("autoHeight")===false){var P=a[1]+parseInt(this.get("height"),10);var H=a[0]+parseInt(this.get("width"),10);if(Y[1]>P){Y[1]=P;}if(Y[0]>H){Y[0]=(H/2);}}X=((X<0)?(X*-1):X);L=((L<0)?(L*-1):L);if(((X>10)||(L>10))||F){var S=0,V=0;if(this.currentElement[0].width){V=(parseInt(this.currentElement[0].width,10)/2);}var M=J[0]+a[0]+V;S=M-Y[0];if(S>(parseInt(I.attrs.width,10)-1)){S=((parseInt(I.attrs.width,10)-30)-1);}else{if(S<40){S=1;}}if(isNaN(S)){S=1;}if(F){if(G){G.style.left=S+"px";}O.cfg.setProperty("xy",Y);}else{if(this.get("animate")){T=new YAHOO.util.Anim(O.element,{},0.5,YAHOO.util.Easing.easeOut);T.attributes={top:{to:Y[1]},left:{to:Y[0]}};T.onComplete.subscribe(function(){O.cfg.setProperty("xy",Y);});var Z=new YAHOO.util.Anim(O.iframe,T.attributes,0.5,YAHOO.util.Easing.easeOut);var E=new YAHOO.util.Anim(G,{left:{to:S}},0.6,YAHOO.util.Easing.easeOut);T.animate();Z.animate();E.animate();}else{G.style.left=S+"px";O.cfg.setProperty("xy",Y);}}}},_closeWindow:function(E){if(this._checkKey(this._keyMap.CLOSE_WINDOW,E)){if(this.currentWindow){this.closeWindow();}}},closeWindow:function(E){this.fireEvent("window"+this.currentWindow.name+"Close",{type:"window"+this.currentWindow.name+"Close",win:this.currentWindow,el:this.currentElement[0]});this.fireEvent("closeWindow",{type:"closeWindow",win:this.currentWindow});this.currentWindow=null;this.get("panel").hide();this.get("panel").cfg.setProperty("xy",[-900,-900]);this.get("panel").syncIframe();this.unsubscribeAll("afterExecCommand");this.toolbar.set("disabled",false);this.toolbar.resetAllButtons();this._focusWindow();A.removeListener(document,"keydown",this._closeWindow);},cmd_undo:function(F){if(this._hasUndoLevel()){if(!this._undoLevel){this._undoLevel=this._undoCache.length;}this._undoLevel=(this._undoLevel-1);if(this._undoCache[this._undoLevel]){var E=this._getUndo(this._undoLevel);this.setEditorHTML(E);}else{this._undoLevel=null;this.toolbar.disableButton("undo");}}return[false];},cmd_redo:function(F){this._undoLevel=this._undoLevel+1;if(this._undoLevel>=this._undoCache.length){this._undoLevel=this._undoCache.length;}if(this._undoCache[this._undoLevel]){var E=this._getUndo(this._undoLevel);this.setEditorHTML(E);}else{this.toolbar.disableButton("redo");}return[false];},cmd_heading:function(I){var F=true,G=null,H="heading",J=this._getSelection(),E=this._getSelectedElement(); +if(E){J=E;}if(this.browser.ie){H="formatblock";}if(I=="none"){if((J&&J.tagName&&(J.tagName.toLowerCase().substring(0,1)=="h"))||(J&&J.parentNode&&J.parentNode.tagName&&(J.parentNode.tagName.toLowerCase().substring(0,1)=="h"))){if(J.parentNode.tagName.toLowerCase().substring(0,1)=="h"){J=J.parentNode;}if(this._isElement(J,"html")){return[false];}G=this._swapEl(E,"span",function(K){K.className="yui-non";});this._selectNode(G);this.currentElement[0]=G;}F=false;}else{if(this._isElement(E,"h1")||this._isElement(E,"h2")||this._isElement(E,"h3")||this._isElement(E,"h4")||this._isElement(E,"h5")||this._isElement(E,"h6")){G=this._swapEl(E,I);this._selectNode(G);this.currentElement[0]=G;}else{this._createCurrentElement(I);this._selectNode(this.currentElement[0]);}F=false;}return[F,H];},cmd_hiddenelements:function(E){if(this._showingHiddenElements){this._lastButton=null;this._showingHiddenElements=false;this.toolbar.deselectButton("hiddenelements");C.removeClass(this._getDoc().body,this.CLASS_HIDDEN);}else{this._showingHiddenElements=true;C.addClass(this._getDoc().body,this.CLASS_HIDDEN);this.toolbar.selectButton("hiddenelements");}return[false];},cmd_removeformat:function(H){var F=true;if(this.browser.webkit&&!this._getDoc().queryCommandEnabled("removeformat")){var E=this._getSelection()+"";this._createCurrentElement("span");this.currentElement[0].className="yui-non";this.currentElement[0].innerHTML=E;for(var G=1;GCreates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

              + * @class ToolbarButtonAdvanced + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, menu, button + * @beta + * + * Provides a toolbar button based on the button and menu widgets. + * @constructor + * @param {String/HTMLElement} el The element to turn into a button. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + if (YAHOO.widget.Button) { + YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button; + /** + * @property buttonType + * @private + * @description Tells if the Button is a Rich Button or a Simple Button + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich'; + /** + * @method checkValue + * @param {String} value The value of the option that we want to mark as selected + * @description Select an option by value + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) { + var _menuItems = this.getMenu().getItems(); + if (_menuItems.length === 0) { + this.getMenu()._onBeforeShow(); + _menuItems = this.getMenu().getItems(); + } + for (var i = 0; i < _menuItems.length; i++) { + _menuItems[i].cfg.setProperty('checked', false); + if (_menuItems[i].value == value) { + _menuItems[i].cfg.setProperty('checked', true); + } + } + }; + } else { + YAHOO.widget.ToolbarButtonAdvanced = function() {}; + } + + + /** + * @description

              Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

              + * @class ToolbarButton + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event + * @Extends YAHOO.util.Element + * @beta + * + * Provides a toolbar button based on the button and menu widgets, '); + } else { + html = html.replace(/]*)>/g, ''); + html = html.replace(/]*)>/g, ''); + } + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_UL>/g, '<\/ul>'); + + html = this.filter_invalid_lists(html); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>'); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>'); + + //This should fix &s in URL's + html = html.replace(' & ', 'YUI_AMP'); + html = html.replace('&', '&'); + html = html.replace('YUI_AMP', '&'); + + //Trim the output, removing whitespace from the beginning and end + html = YAHOO.lang.trim(html); + + if (this.get('removeLineBreaks')) { + html = html.replace(/\n/g, '').replace(/\r/g, ''); + html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single + } + + //First empty span + if (html.substring(0, 6).toLowerCase() == '') { + html = html.substring(6); + //Last empty span + if (html.substring(html.length - 7, html.length).toLowerCase() == '') { + html = html.substring(0, html.length - 7); + } + } + + for (var v in this.invalidHTML) { + if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) { + if (Lang.isObject(v) && v.keepContents) { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1'); + } else { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), ''); + } + } + } + + this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html }); + + return html; + }, + /** + * @method filter_invalid_lists + * @param String html The HTML string to filter + * @description Filters invalid ol and ul list markup, converts this:
              1. ..
              to this:
              1. ..
            • + */ + filter_invalid_lists: function(html) { + html = html.replace(/<\/li>\n/gi, ''); + + html = html.replace(/<\/li>
                /gi, '
                1. '); + html = html.replace(/<\/ol>/gi, '
              1. '); + html = html.replace(/<\/ol><\/li>\n/gi, "
              \n"); + + html = html.replace(/<\/li>
                /gi, '
                • '); + html = html.replace(/<\/ul>/gi, '
              • '); + html = html.replace(/<\/ul><\/li>\n?/gi, "
              \n"); + + html = html.replace(/<\/li>/gi, "\n"); + html = html.replace(/<\/ol>/gi, "
        \n"); + html = html.replace(/
          /gi, "
            \n"); + html = html.replace(/
              /gi, "
                \n"); + return html; + }, + /** + * @method filter_safari + * @param String html The HTML string to filter + * @description Filters strings specific to Safari + * @return String + */ + filter_safari: function(html) { + if (this.browser.webkit) { + // + html = html.replace(/([^>])<\/span>/gi, '    '); + html = html.replace(/Apple-style-span/gi, ''); + html = html.replace(/style="line-height: normal;"/gi, ''); + //Remove bogus LI's + html = html.replace(/
              • <\/li>/gi, ''); + html = html.replace(/
              • <\/li>/gi, ''); + html = html.replace(/
              • <\/li>/gi, ''); + //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break + if (this.get('ptags')) { + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/div>/gi, '

                '); + } else { + html = html.replace(/
                /gi, ''); + html = html.replace(/<\/div>/gi, '
                '); + } + } + return html; + }, + /** + * @method filter_internals + * @param String html The HTML string to filter + * @description Filters internal RTE strings and bogus attrs we don't want + * @return String + */ + filter_internals: function(html) { + html = html.replace(/\r/g, ''); + //Fix stuff we don't want + html = html.replace(/<\/?(body|head|html)[^>]*>/gi, ''); + //Fix last BR in LI + html = html.replace(/<\/li>/gi, '
              • '); + + html = html.replace(/yui-tag-span/gi, ''); + html = html.replace(/yui-tag/gi, ''); + html = html.replace(/yui-non/gi, ''); + html = html.replace(/yui-img/gi, ''); + html = html.replace(/ tag="span"/gi, ''); + html = html.replace(/ class=""/gi, ''); + html = html.replace(/ style=""/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ target=""/gi, ''); + html = html.replace(/ title=""/gi, ''); + + if (this.browser.ie) { + html = html.replace(/ class= /gi, ''); + html = html.replace(/ class= >/gi, ''); + html = html.replace(/_height="([^>])"/gi, ''); + html = html.replace(/_width="([^>])"/gi, ''); + } + + return html; + }, + /** + * @method filter_all_rgb + * @param String str The HTML string to filter + * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00" + * @return String + */ + filter_all_rgb: function(str) { + var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi"); + var arr = str.match(exp); + if (Lang.isArray(arr)) { + for (var i = 0; i < arr.length; i++) { + var color = this.filter_rgb(arr[i]); + str = str.replace(arr[i].toString(), color); + } + } + + return str; + }, + /** + * @method filter_rgb + * @param String css The CSS string containing rgb(#,#,#); + * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00 + * @return String + */ + filter_rgb: function(css) { + if (css.toLowerCase().indexOf('rgb') != -1) { + var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi"); + var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(','); + + if (rgb.length == 5) { + var r = parseInt(rgb[1], 10).toString(16); + var g = parseInt(rgb[2], 10).toString(16); + var b = parseInt(rgb[3], 10).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + css = "#" + r + g + b; + } + } + return css; + }, + /** + * @method pre_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + pre_filter_linebreaks: function(html, markup) { + if (this.browser.webkit) { + html = html.replace(/
                /gi, ''); + html = html.replace(/
                /gi, ''); + } + html = html.replace(/
                /gi, ''); + html = html.replace(/
                /gi, ''); + html = html.replace(//gi, ''); + html = html.replace(/
                /gi, ''); + html = html.replace(/
                <\/div>/gi, ''); + html = html.replace(/

                ( | )<\/p>/g, ''); + html = html.replace(/


                 <\/p>/gi, ''); + html = html.replace(/

                 <\/p>/gi, ''); + //Fix last BR + html = html.replace(/$/, ''); + //Fix last BR in P + html = html.replace(/<\/p>/g, '

                '); + if (this.browser.ie) { + html = html.replace(/    /g, '\t'); + } + return html; + }, + /** + * @method post_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + post_filter_linebreaks: function(html, markup) { + if (markup == 'xhtml') { + html = html.replace(//g, '
                '); + } else { + html = html.replace(//g, '
                '); + } + return html; + }, + /** + * @method clearEditorDoc + * @description Clear the doc of the Editor + */ + clearEditorDoc: function() { + this._getDoc().body.innerHTML = ' '; + }, + /** + * @method openWindow + * @description Override Method for Advanced Editor + */ + openWindow: function(win) { + }, + /** + * @method moveWindow + * @description Override Method for Advanced Editor + */ + moveWindow: function() { + }, + /** + * @private + * @method _closeWindow + * @description Override Method for Advanced Editor + */ + _closeWindow: function() { + }, + /** + * @method closeWindow + * @description Override Method for Advanced Editor + */ + closeWindow: function() { + //this.unsubscribeAll('afterExecCommand'); + this.toolbar.resetAllButtons(); + this._focusWindow(); + }, + /** + * @method destroy + * @description Destroys the editor, all of it's elements and objects. + * @return {Boolean} + */ + destroy: function() { + if (this.resize) { + this.resize.destroy(); + } + if (this.dd) { + this.dd.unreg(); + } + if (this.get('panel')) { + this.get('panel').destroy(); + } + this.saveHTML(); + this.toolbar.destroy(); + this.setStyle('visibility', 'visible'); + this.setStyle('position', 'static'); + this.setStyle('top', ''); + this.setStyle('left', ''); + var textArea = this.get('element'); + this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element')); + this.get('element_cont').get('element').innerHTML = ''; + this.set('handleSubmit', false); //Remove the submit handler + return true; + }, + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'SimpleEditor'; + if (this.get && this.get('element_cont')) { + str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + +/** +* @event toolbarLoaded +* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event cleanHTML +* @description Event is fired after the cleanHTML method is called. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterRender +* @description Event is fired after the render process finishes. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorContentLoaded +* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeNodeChange +* @description Event fires at the beginning of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterNodeChange +* @description Event fires at the end of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeExecCommand +* @description Event fires at the beginning of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterExecCommand +* @description Event fires at the end of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ + + + /** + * @description Singleton object used to track the open window objects and panels across the various open editors + * @class EditorInfo + * @static + */ + YAHOO.widget.EditorInfo = { + /** + * @private + * @property _instances + * @description A reference to all editors on the page. + * @type Object + */ + _instances: {}, + /** + * @private + * @property blankImage + * @description A reference to the blankImage url + * @type String + */ + blankImage: '', + /** + * @private + * @property window + * @description A reference to the currently open window object in any editor on the page. + * @type Object YAHOO.widget.EditorWindow + */ + window: {}, + /** + * @private + * @property panel + * @description A reference to the currently open panel in any editor on the page. + * @type Object YAHOO.widget.Overlay + */ + panel: null, + /** + * @method getEditorById + * @description Returns a reference to the Editor object associated with the given textarea + * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of + * @return Object YAHOO.widget.Editor + */ + getEditorById: function(id) { + if (!YAHOO.lang.isString(id)) { + //Not a string, assume a node Reference + id = id.id; + } + if (this._instances[id]) { + return this._instances[id]; + } + return false; + }, + /** + * @method toString + * @description Returns a string representing the EditorInfo. + * @return {String} + */ + toString: function() { + var len = 0; + for (var i in this._instances) { + if (Lang.hasOwnProperty(this._instances, i)) { + len++; + } + } + return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')'; + } + }; + + + + +})(); +/** + * @module editor + * @description

                The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.

                + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, simpleeditor + * @optional dragdrop, animation, menu, button + * @beta + */ + +(function() { +var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang, + Toolbar = YAHOO.widget.Toolbar; + + /** + * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization. + * @constructor + * @class Editor + * @extends YAHOO.widget.SimpleEditor + * @param {String/HTMLElement} el The textarea element to turn into an editor. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + + YAHOO.widget.Editor = function(el, attrs) { + YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs); + }; + + YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, { + /** + * @private + * @property _undoCache + * @description An Array hash of the Undo Levels. + * @type Array + */ + _undoCache: null, + /** + * @private + * @property _undoLevel + * @description The index of the current undo state. + * @type Number + */ + _undoLevel: null, + /** + * @private + * @method _hasUndoLevel + * @description Checks to see if we have an undo level available + * @return Boolean + */ + _hasUndoLevel: function() { + return (this._undoCache.length && this._undoLevel); + }, + /** + * @private + * @method _undoNodeChange + * @description nodeChange listener for undo processing + */ + _undoNodeChange: function() { + var undo_button = this.toolbar.getButtonByValue('undo'), + redo_button = this.toolbar.getButtonByValue('redo'); + if (undo_button && redo_button) { + if (this._hasUndoLevel()) { + this.toolbar.enableButton(undo_button); + } + if (this._undoLevel < this._undoCache.length) { + this.toolbar.enableButton(redo_button); + } + } + }, + /** + * @private + * @method _checkUndo + * @description Prunes the undo cache when it reaches the maxUndo config + */ + _checkUndo: function() { + var len = this._undoCache.length, + tmp = []; + if (len >= this.get('maxUndo')) { + for (var i = (len - this.get('maxUndo')); i < len; i++) { + tmp.push(this._undoCache[i]); + } + this._undoCache = tmp; + } + }, + /** + * @private + * @method _putUndo + * @description Puts the content of the Editor into the _undoCache. + * //TODO Convert the hash to a series of TEXTAREAS to store state in. + * @param {String} str The content of the Editor + */ + _putUndo: function(str) { + this._undoCache.push(str); + }, + /** + * @private + * @method _getUndo + * @description Get's a level from the undo cache. + * @param {Number} index The index of the undo level we want to get. + * @return {String} + */ + _getUndo: function(index) { + return this._undoCache[index]; + }, + /** + * @private + * @method _storeUndo + * @description Method to call when you want to store an undo state. Currently called from nodeChange and _handleKeyUp + */ + _storeUndo: function() { + if (this._lastCommand === 'undo' || this._lastCommand === 'redo') { + return false; + } + if (!this._undoCache) { + this._undoCache = []; + } + this._checkUndo(); + var str = this.getEditorHTML(); + var last = this._undoCache[this._undoCache.length - 1]; + if (last) { + if (str !== last) { + this._putUndo(str); + } + } else { + this._putUndo(str); + } + this._undoLevel = this._undoCache.length; + this._undoNodeChange(); + }, + /** + * @property STR_BEFORE_EDITOR + * @description The accessibility string for the element before the iFrame + * @type String + */ + STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names.

                Common formatting keyboard shortcuts:

                • Control Shift B sets text to bold
                • Control Shift I sets text to italic
                • Control Shift U underlines text
                • Control Shift [ aligns text left
                • Control Shift | centers text
                • Control Shift ] aligns text right
                • Control Shift L adds an HTML link
                • To exit this text editor use the keyboard shortcut Control + Shift + ESC.
                ', + /** + * @property STR_CLOSE_WINDOW + * @description The Title of the close button in the Editor Window + * @type String + */ + STR_CLOSE_WINDOW: 'Close Window', + /** + * @property STR_CLOSE_WINDOW_NOTE + * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window + * @type String + */ + STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key', + /** + * @property STR_IMAGE_PROP_TITLE + * @description The title for the Image Property Editor Window + * @type String + */ + STR_IMAGE_PROP_TITLE: 'Image Options', + /** + * @property STR_IMAGE_URL + * @description The label string for Image URL + * @type String + */ + STR_IMAGE_URL: 'Image URL', + /** + * @property STR_IMAGE_TITLE + * @description The label string for Image Description + * @type String + */ + STR_IMAGE_TITLE: 'Description', + /** + * @property STR_IMAGE_SIZE + * @description The label string for Image Size + * @type String + */ + STR_IMAGE_SIZE: 'Size', + /** + * @property STR_IMAGE_ORIG_SIZE + * @description The label string for Original Image Size + * @type String + */ + STR_IMAGE_ORIG_SIZE: 'Original Size', + /** + * @property STR_IMAGE_COPY + * @description The label string for the image copy and paste message for Opera and Safari + * @type String + */ + STR_IMAGE_COPY: 'Note:To move this image just highlight it, cut, and paste where ever you\'d like.', + /** + * @property STR_IMAGE_PADDING + * @description The label string for the image padding. + * @type String + */ + STR_IMAGE_PADDING: 'Padding', + /** + * @property STR_IMAGE_BORDER + * @description The label string for the image border. + * @type String + */ + STR_IMAGE_BORDER: 'Border', + /** + * @property STR_IMAGE_BORDER_SIZE + * @description The label string for the image border size. + * @type String + */ + STR_IMAGE_BORDER_SIZE: 'Border Size', + /** + * @property STR_IMAGE_BORDER_TYPE + * @description The label string for the image border type. + * @type String + */ + STR_IMAGE_BORDER_TYPE: 'Border Type', + /** + * @property STR_IMAGE_TEXTFLOW + * @description The label string for the image text flow. + * @type String + */ + STR_IMAGE_TEXTFLOW: 'Text Flow', + /** + * @property STR_LOCAL_FILE_WARNING + * @description The label string for the local file warning. + * @type String + */ + STR_LOCAL_FILE_WARNING: 'Note:This image/link points to a file on your computer and will not be accessible to others on the internet.', + /** + * @property STR_LINK_PROP_TITLE + * @description The label string for the Link Property Editor Window. + * @type String + */ + STR_LINK_PROP_TITLE: 'Link Options', + /** + * @property STR_LINK_PROP_REMOVE + * @description The label string for the Remove link from text link inside the property editor. + * @type String + */ + STR_LINK_PROP_REMOVE: 'Remove link from text', + /** + * @property STR_LINK_NEW_WINDOW + * @description The string for the open in a new window label. + * @type String + */ + STR_LINK_NEW_WINDOW: 'Open in a new window.', + /** + * @property STR_LINK_TITLE + * @description The string for the link description. + * @type String + */ + STR_LINK_TITLE: 'Description', + /** + * @protected + * @property CLASS_LOCAL_FILE + * @description CSS class applied to an element when it's found to have a local url. + * @type String + */ + CLASS_LOCAL_FILE: 'warning-localfile', + /** + * @protected + * @property CLASS_HIDDEN + * @description CSS class applied to the body when the hiddenelements button is pressed. + * @type String + */ + CLASS_HIDDEN: 'yui-hidden', + /** + * @method init + * @description The Editor class' initialization method + */ + init: function(p_oElement, p_oAttributes) { + + this._windows = {}; + this._defaultToolbar = { + collapse: true, + titlebar: 'Text Editing Tools', + draggable: false, + buttonType: 'advanced', + buttons: [ + { group: 'fontstyle', label: 'Font Name and Size', + buttons: [ + { type: 'select', label: 'Arial', value: 'fontname', disabled: true, + menu: [ + { text: 'Arial', checked: true }, + { text: 'Arial Black' }, + { text: 'Comic Sans MS' }, + { text: 'Courier New' }, + { text: 'Lucida Console' }, + { text: 'Tahoma' }, + { text: 'Times New Roman' }, + { text: 'Trebuchet MS' }, + { text: 'Verdana' } + ] + }, + { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true } + ] + }, + { type: 'separator' }, + { group: 'textstyle', label: 'Font Style', + buttons: [ + { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' }, + { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' }, + { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' }, + { type: 'separator' }, + { type: 'push', label: 'Subscript', value: 'subscript', disabled: true }, + { type: 'push', label: 'Superscript', value: 'superscript', disabled: true } + ] + }, + { type: 'separator' }, + { group: 'textstyle2', label: ' ', + buttons: [ + { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }, + { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }, + { type: 'separator' }, + { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true }, + { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' } + ] + }, + { type: 'separator' }, + { group: 'undoredo', label: 'Undo/Redo', + buttons: [ + { type: 'push', label: 'Undo', value: 'undo', disabled: true }, + { type: 'push', label: 'Redo', value: 'redo', disabled: true } + + ] + }, + { type: 'separator' }, + { group: 'alignment', label: 'Alignment', + buttons: [ + { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' }, + { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' }, + { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' }, + { type: 'push', label: 'Justify', value: 'justifyfull' } + ] + }, + { type: 'separator' }, + { group: 'parastyle', label: 'Paragraph Style', + buttons: [ + { type: 'select', label: 'Normal', value: 'heading', disabled: true, + menu: [ + { text: 'Normal', value: 'none', checked: true }, + { text: 'Header 1', value: 'h1' }, + { text: 'Header 2', value: 'h2' }, + { text: 'Header 3', value: 'h3' }, + { text: 'Header 4', value: 'h4' }, + { text: 'Header 5', value: 'h5' }, + { text: 'Header 6', value: 'h6' } + ] + } + ] + }, + { type: 'separator' }, + + { group: 'indentlist2', label: 'Indenting and Lists', + buttons: [ + { type: 'push', label: 'Indent', value: 'indent', disabled: true }, + { type: 'push', label: 'Outdent', value: 'outdent', disabled: true }, + { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' }, + { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' } + ] + }, + { type: 'separator' }, + { group: 'insertitem', label: 'Insert Item', + buttons: [ + { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true }, + { type: 'push', label: 'Insert Image', value: 'insertimage' } + ] + } + ] + }; + + this._defaultImageToolbarConfig = { + buttonType: this._defaultToolbar.buttonType, + buttons: [ + { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':', + buttons: [ + { type: 'push', label: 'Left', value: 'left' }, + { type: 'push', label: 'Inline', value: 'inline' }, + { type: 'push', label: 'Block', value: 'block' }, + { type: 'push', label: 'Right', value: 'right' } + ] + }, + { type: 'separator' }, + { group: 'padding', label: this.STR_IMAGE_PADDING + ':', + buttons: [ + { type: 'spin', label: '0', value: 'padding', range: [0, 50] } + ] + }, + { type: 'separator' }, + { group: 'border', label: this.STR_IMAGE_BORDER + ':', + buttons: [ + { type: 'select', label: this.STR_IMAGE_BORDER_SIZE, value: 'bordersize', + menu: [ + { text: 'none', value: '0', checked: true }, + { text: '1px', value: '1' }, + { text: '2px', value: '2' }, + { text: '3px', value: '3' }, + { text: '4px', value: '4' }, + { text: '5px', value: '5' } + ] + }, + { type: 'select', label: this.STR_IMAGE_BORDER_TYPE, value: 'bordertype', disabled: true, + menu: [ + { text: 'Solid', value: 'solid', checked: true }, + { text: 'Dashed', value: 'dashed' }, + { text: 'Dotted', value: 'dotted' } + ] + }, + { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true } + ] + } + ] + }; + + YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes); + }, + _render: function() { + YAHOO.widget.Editor.superclass._render.apply(this, arguments); + var self = this; + //Render the panel in another thread and delay it a little.. + window.setTimeout(function() { + self._renderPanel.call(self); + }, 800); + }, + /** + * @method initAttributes + * @description Initializes all of the configuration attributes used to create + * the editor. + * @param {Object} attr Object literal specifying a set of + * configuration attributes used to create the editor. + */ + initAttributes: function(attr) { + YAHOO.widget.Editor.superclass.initAttributes.call(this, attr); + + /** + * @attribute localFileWarning + * @description Should we throw the warning if we detect a file that is local to their machine? + * @default true + * @type Boolean + */ + this.setAttributeConfig('localFileWarning', { + value: attr.locaFileWarning || true + }); + + /** + * @attribute hiddencss + * @description The CSS used to show/hide hidden elements on the page, these rules must be prefixed with the class provided in this.CLASS_HIDDEN + * @default
                +            .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table {
                +                border: 1px dotted #ccc;
                +            }
                +            .yui-hidden .yui-non {
                +                border: none;
                +            }
                +            .yui-hidden img {
                +                padding: 2px;
                +            }
                + * @type String + */ + this.setAttributeConfig('hiddencss', { + value: attr.hiddencss || '.yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }', + writeOnce: true + }); + + }, + /** + * @private + * @method _windows + * @description A reference to the HTML elements used for the body of Editor Windows. + */ + _windows: null, + /** + * @private + * @method _defaultImageToolbar + * @description A reference to the Toolbar Object inside Image Editor Window. + */ + _defaultImageToolbar: null, + /** + * @private + * @method _defaultImageToolbarConfig + * @description Config to be used for the default Image Editor Window. + */ + _defaultImageToolbarConfig: null, + /** + * @private + * @method _fixNodes + * @description Fix href and imgs as well as remove invalid HTML. + */ + _fixNodes: function() { + YAHOO.widget.Editor.superclass._fixNodes.call(this); + var url = ''; + + var imgs = this._getDoc().getElementsByTagName('img'); + for (var im = 0; im < imgs.length; im++) { + if (imgs[im].getAttribute('href', 2)) { + url = imgs[im].getAttribute('src', 2); + if (this._isLocalFile(url)) { + Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE); + } else { + Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE); + } + } + } + var fakeAs = this._getDoc().body.getElementsByTagName('a'); + for (var a = 0; a < fakeAs.length; a++) { + if (fakeAs[a].getAttribute('href', 2)) { + url = fakeAs[a].getAttribute('href', 2); + if (this._isLocalFile(url)) { + Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE); + } else { + Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE); + } + } + } + }, + /** + * @private + * @property _disabled + * @description The Toolbar items that should be disabled if there is no selection present in the editor. + * @type Array + */ + _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ], + /** + * @private + * @property _alwaysDisabled + * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor. + * @type Object + */ + _alwaysDisabled: { 'outdent': true }, + /** + * @private + * @property _alwaysEnabled + * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor. + * @type Object + */ + _alwaysEnabled: { hiddenelements: true }, + /** + * @private + * @method _handleKeyDown + * @param {Event} ev The event we are working on. + * @description Override method that handles some new keydown events inside the iFrame document. + */ + _handleKeyDown: function(ev) { + YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev); + var doExec = false, + action = null, + exec = false; + + switch (ev.keyCode) { + //case 219: //Left + case this._keyMap.JUSTIFY_LEFT.key: //Left + if (this._checkKey(this._keyMap.JUSTIFY_LEFT, ev)) { + action = 'justifyleft'; + doExec = true; + } + break; + //case 220: //Center + case this._keyMap.JUSTIFY_CENTER.key: + if (this._checkKey(this._keyMap.JUSTIFY_CENTER, ev)) { + action = 'justifycenter'; + doExec = true; + } + break; + case 221: //Right + case this._keyMap.JUSTIFY_RIGHT.key: + if (this._checkKey(this._keyMap.JUSTIFY_RIGHT, ev)) { + action = 'justifyright'; + doExec = true; + } + break; + } + if (doExec && action) { + this.execCommand(action, null); + Event.stopEvent(ev); + this.nodeChange(); + } + }, + /** + * @private + * @method _renderCreateLinkWindow + * @description Pre renders the CreateLink window so we get faster window opening. + */ + _renderCreateLinkWindow: function() { + var str = ''; + str += ''; + str += ''; + + var body = document.createElement('div'); + body.innerHTML = str; + + var unlinkCont = document.createElement('div'); + unlinkCont.className = 'removeLink'; + var unlink = document.createElement('a'); + unlink.href = '#'; + unlink.innerHTML = this.STR_LINK_PROP_REMOVE; + unlink.title = this.STR_LINK_PROP_REMOVE; + Event.on(unlink, 'click', function(ev) { + Event.stopEvent(ev); + this.execCommand('unlink'); + this.closeWindow(); + }, this, true); + unlinkCont.appendChild(unlink); + body.appendChild(unlinkCont); + + this._windows.createlink = {}; + this._windows.createlink.body = body; + body.style.display = 'none'; + this.get('panel').editor_form.appendChild(body); + this.fireEvent('windowCreateLinkRender', { type: 'windowCreateLinkRender', panel: this.get('panel'), body: body }); + return body; + }, + _handleCreateLinkClick: function() { + var el = this._getSelectedElement(); + if (this._isElement(el, 'img')) { + this.STOP_EXEC_COMMAND = true; + this.currentElement[0] = el; + this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar }); + this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this }); + return false; + } + if (this.get('limitCommands')) { + if (!this.toolbar.getButtonByValue('createlink')) { + return false; + } + } + + this.on('afterExecCommand', function() { + var win = new YAHOO.widget.EditorWindow('createlink', { + width: '350px' + }); + + var el = this.currentElement[0], + url = '', + title = '', + target = '', + localFile = false; + if (el) { + win.el = el; + if (el.getAttribute('href', 2) !== null) { + url = el.getAttribute('href', 2); + if (this._isLocalFile(url)) { + //Local File throw Warning + win.setFooter(this.STR_LOCAL_FILE_WARNING); + localFile = true; + } else { + win.setFooter(' '); + } + } + if (el.getAttribute('title') !== null) { + title = el.getAttribute('title'); + } + if (el.getAttribute('target') !== null) { + target = el.getAttribute('target'); + } + } + var body = null; + if (this._windows.createlink && this._windows.createlink.body) { + body = this._windows.createlink.body; + } else { + body = this._renderCreateLinkWindow(); + } + + win.setHeader(this.STR_LINK_PROP_TITLE); + win.setBody(body); + + Event.purgeElement(this.get('id') + '_createlink_url'); + + Dom.get(this.get('id') + '_createlink_url').value = url; + Dom.get(this.get('id') + '_createlink_title').value = title; + Dom.get(this.get('id') + '_createlink_target').checked = ((target) ? true : false); + + + Event.onAvailable(this.get('id') + '_createlink_url', function() { + var id = this.get('id'); + window.setTimeout(function() { + try { + YAHOO.util.Dom.get(id + '_createlink_url').focus(); + } catch (e) {} + }, 50); + + if (this._isLocalFile(url)) { + //Local File throw Warning + Dom.addClass(this.get('id') + '_createlink_url', 'warning'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(this.get('id') + '_createlink_url', 'warning'); + this.get('panel').setFooter(' '); + } + Event.on(this.get('id') + '_createlink_url', 'blur', function() { + var url = Dom.get(this.get('id') + '_createlink_url'); + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + } + }, this, true); + }, this, true); + + this.openWindow(win); + + }); + }, + /** + * @private + * @method _handleCreateLinkWindowClose + * @description Handles the closing of the Link Properties Window. + */ + _handleCreateLinkWindowClose: function() { + + var url = Dom.get(this.get('id') + '_createlink_url'), + target = Dom.get(this.get('id') + '_createlink_target'), + title = Dom.get(this.get('id') + '_createlink_title'), + el = arguments[0].win.el, + a = el; + + if (url && url.value) { + var urlValue = url.value; + if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + //Found an @ sign, prefix with mailto: + urlValue = 'mailto:' + urlValue; + } else { + // :// not found adding + if (urlValue.substring(0, 1) != '#') { + urlValue = 'http:/'+'/' + urlValue; + } + + } + } + el.setAttribute('href', urlValue); + if (target.checked) { + el.setAttribute('target', target.value); + } else { + el.setAttribute('target', ''); + } + el.setAttribute('title', ((title.value) ? title.value : '')); + + } else { + var _span = this._getDoc().createElement('span'); + _span.innerHTML = el.innerHTML; + Dom.addClass(_span, 'yui-non'); + el.parentNode.replaceChild(_span, el); + } + Dom.removeClass(url, 'warning'); + Dom.get(this.get('id') + '_createlink_url').value = ''; + Dom.get(this.get('id') + '_createlink_title').value = ''; + Dom.get(this.get('id') + '_createlink_target').checked = false; + this.nodeChange(); + this.currentElement = []; + + }, + /** + * @private + * @method _renderInsertImageWindow + * @description Pre renders the InsertImage window so we get faster window opening. + */ + _renderInsertImageWindow: function() { + var el = this.currentElement[0]; + var str = ''; + var body = document.createElement('div'); + body.innerHTML = str; + + var tbarCont = document.createElement('div'); + tbarCont.id = this.get('id') + '_img_toolbar'; + body.appendChild(tbarCont); + + var str2 = ''; + str2 += ''; + str2 += ''; + var div = document.createElement('div'); + div.innerHTML = str2; + body.appendChild(div); + + var o = {}; + Lang.augmentObject(o, this._defaultImageToolbarConfig); //Break the config reference + + var tbar = new YAHOO.widget.Toolbar(tbarCont, o); + tbar.editor_el = el; + this._defaultImageToolbar = tbar; + + var cont = tbar.get('cont'); + var hw = document.createElement('div'); + hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width'; + hw.innerHTML = '

                ' + this.STR_IMAGE_SIZE + ':

                '; + /* + var orgSize = ''; + if ((height != oheight) || (width != owidth)) { + orgSize = '' + this.STR_IMAGE_ORIG_SIZE + '
                '+ owidth +' x ' + oheight + '
                '; + } + */ + hw.innerHTML += ' x '; + cont.insertBefore(hw, cont.firstChild); + + Event.onAvailable(this.get('id') + '_insertimage_width', function() { + Event.on(this.get('id') + '_insertimage_width', 'blur', function() { + var value = parseInt(Dom.get(this.get('id') + '_insertimage_width').value, 10); + if (value > 5) { + this._defaultImageToolbar.editor_el.style.width = value + 'px'; + //Removed moveWindow call so the window doesn't jump + //this.moveWindow(); + } + }, this, true); + }, this, true); + Event.onAvailable(this.get('id') + '_insertimage_height', function() { + Event.on(this.get('id') + '_insertimage_height', 'blur', function() { + var value = parseInt(Dom.get(this.get('id') + '_insertimage_height').value, 10); + if (value > 5) { + this._defaultImageToolbar.editor_el.style.height = value + 'px'; + //Removed moveWindow call so the window doesn't jump + //this.moveWindow(); + } + }, this, true); + }, this, true); + + + tbar.on('colorPickerClicked', function(o) { + var size = '1', type = 'solid', color = 'black', el = this._defaultImageToolbar.editor_el; + + if (el.style.borderLeftWidth) { + size = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + type = el.style.borderLeftStyle; + } + if (el.style.borderLeftColor) { + color = el.style.borderLeftColor; + } + var borderString = size + 'px ' + type + ' #' + o.color; + el.style.border = borderString; + }, this, true); + + tbar.on('buttonClick', function(o) { + var value = o.button.value, + el = this._defaultImageToolbar.editor_el, + borderString = ''; + if (o.button.menucmd) { + value = o.button.menucmd; + } + var size = '1', type = 'solid', color = 'black'; + + /* All border calcs are done on the left border + since our default interface only supports + one border size/type and color */ + if (el.style.borderLeftWidth) { + size = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + type = el.style.borderLeftStyle; + } + if (el.style.borderLeftColor) { + color = el.style.borderLeftColor; + } + switch(value) { + case 'bordersize': + if (this.browser.webkit && this._lastImage) { + Dom.removeClass(this._lastImage, 'selected'); + this._lastImage = null; + } + + borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color; + el.style.border = borderString; + if (parseInt(o.button.value, 10) > 0) { + tbar.enableButton('bordertype'); + tbar.enableButton('bordercolor'); + } else { + tbar.disableButton('bordertype'); + tbar.disableButton('bordercolor'); + } + break; + case 'bordertype': + if (this.browser.webkit && this._lastImage) { + Dom.removeClass(this._lastImage, 'selected'); + this._lastImage = null; + } + borderString = size + 'px ' + o.button.value + ' ' + color; + el.style.border = borderString; + break; + case 'right': + case 'left': + tbar.deselectAllButtons(); + el.style.display = ''; + el.align = o.button.value; + break; + case 'inline': + tbar.deselectAllButtons(); + el.style.display = ''; + el.align = ''; + break; + case 'block': + tbar.deselectAllButtons(); + el.style.display = 'block'; + el.align = 'center'; + break; + case 'padding': + var _button = tbar.getButtonById(o.button.id); + el.style.margin = _button.get('label') + 'px'; + break; + } + tbar.selectButton(o.button.value); + if (value !== 'padding') { + this.moveWindow(); + } + }, this, true); + + + + if (this.get('localFileWarning')) { + Event.on(this.get('id') + '_insertimage_link', 'blur', function() { + var url = Dom.get(this.get('id') + '_insertimage_link'); + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + this.get('panel').setFooter(this.STR_IMAGE_COPY); + } + } + }, this, true); + } + + Event.on(this.get('id') + '_insertimage_url', 'blur', function() { + var url = Dom.get(this.get('id') + '_insertimage_url'); + if (url.value && el) { + if (url.value == el.getAttribute('src', 2)) { + return false; + } + } + if (this._isLocalFile(url.value)) { + //Local File throw Warning + Dom.addClass(url, 'warning'); + this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING); + } else if (this.currentElement[0]) { + Dom.removeClass(url, 'warning'); + this.get('panel').setFooter(' '); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + this.get('panel').setFooter(this.STR_IMAGE_COPY); + } + + if (url && url.value && (url.value != this.STR_IMAGE_HERE)) { + this.currentElement[0].setAttribute('src', url.value); + var self = this, + img = new Image(); + + img.onerror = function() { + url.value = self.STR_IMAGE_HERE; + img.setAttribute('src', self.get('blankimage')); + self.currentElement[0].setAttribute('src', self.get('blankimage')); + YAHOO.util.Dom.get(self.get('id') + '_insertimage_height').value = img.height; + YAHOO.util.Dom.get(self.get('id') + '_insertimage_width').value = img.width; + }; + var id = this.get('id'); + window.setTimeout(function() { + YAHOO.util.Dom.get(id + '_insertimage_height').value = img.height; + YAHOO.util.Dom.get(id + '_insertimage_width').value = img.width; + if (self.currentElement && self.currentElement[0]) { + if (!self.currentElement[0]._height) { + self.currentElement[0]._height = img.height; + } + if (!self.currentElement[0]._width) { + self.currentElement[0]._width = img.width; + } + } + //Removed moveWindow call so the window doesn't jump + //self.moveWindow(); + }, 800); //Bumped the timeout up to account for larger images.. + + if (url.value != this.STR_IMAGE_HERE) { + img.src = url.value; + } + } + } + }, this, true); + + + + this._windows.insertimage = {}; + this._windows.insertimage.body = body; + body.style.display = 'none'; + this.get('panel').editor_form.appendChild(body); + this.fireEvent('windowInsertImageRender', { type: 'windowInsertImageRender', panel: this.get('panel'), body: body, toolbar: tbar }); + return body; + }, + /** + * @private + * @method _handleInsertImageClick + * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked. + */ + _handleInsertImageClick: function() { + if (this.get('limitCommands')) { + if (!this.toolbar.getButtonByValue('insertimage')) { + return false; + } + } + this.on('afterExecCommand', function() { + var el = this.currentElement[0], + body = null, + link = '', + target = '', + tbar = null, + title = '', + src = '', + align = '', + height = 75, + width = 75, + padding = 0, + oheight = 0, + owidth = 0, + blankimage = false, + win = new YAHOO.widget.EditorWindow('insertimage', { + width: '415px' + }); + + if (!el) { + el = this._getSelectedElement(); + } + if (el) { + win.el = el; + if (el.getAttribute('src')) { + src = el.getAttribute('src', 2); + if (src.indexOf(this.get('blankimage')) != -1) { + src = this.STR_IMAGE_HERE; + blankimage = true; + } + } + if (el.getAttribute('alt', 2)) { + title = el.getAttribute('alt', 2); + } + if (el.getAttribute('title', 2)) { + title = el.getAttribute('title', 2); + } + + if (el.parentNode && this._isElement(el.parentNode, 'a')) { + link = el.parentNode.getAttribute('href', 2); + if (el.parentNode.getAttribute('target') !== null) { + target = el.parentNode.getAttribute('target'); + } + } + height = parseInt(el.height, 10); + width = parseInt(el.width, 10); + if (el.style.height) { + height = parseInt(el.style.height, 10); + } + if (el.style.width) { + width = parseInt(el.style.width, 10); + } + if (el.style.margin) { + padding = parseInt(el.style.margin, 10); + } + if (!el._height) { + el._height = height; + } + if (!el._width) { + el._width = width; + } + oheight = el._height; + owidth = el._width; + } + if (this._windows.insertimage && this._windows.insertimage.body) { + body = this._windows.insertimage.body; + this._defaultImageToolbar.resetAllButtons(); + } else { + body = this._renderInsertImageWindow(); + } + + tbar = this._defaultImageToolbar; + tbar.editor_el = el; + + + var bsize = '0'; + var btype = 'solid'; + if (el.style.borderLeftWidth) { + bsize = parseInt(el.style.borderLeftWidth, 10); + } + if (el.style.borderLeftStyle) { + btype = el.style.borderLeftStyle; + } + var bs_button = tbar.getButtonByValue('bordersize'); + var bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : 'none'); + bs_button.set('label', ''+bSizeStr+''); + this._updateMenuChecked('bordersize', bsize, tbar); + + var bt_button = tbar.getButtonByValue('bordertype'); + bt_button.set('label', ''); + this._updateMenuChecked('bordertype', btype, tbar); + if (parseInt(bsize, 10) > 0) { + tbar.enableButton(bt_button); + tbar.enableButton(bs_button); + tbar.enableButton('bordercolor'); + } + + if ((el.align == 'right') || (el.align == 'left')) { + tbar.selectButton(el.align); + } else if (el.style.display == 'block') { + tbar.selectButton('block'); + } else { + tbar.selectButton('inline'); + } + if (parseInt(el.style.marginLeft, 10) > 0) { + tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10)); + } + if (el.style.borderSize) { + tbar.selectButton('bordersize'); + tbar.selectButton(parseInt(el.style.borderSize, 10)); + } + tbar.getButtonByValue('padding').set('label', ''+padding); + + + + win.setHeader(this.STR_IMAGE_PROP_TITLE); + win.setBody(body); + //Adobe AIR Code + if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) { + win.setFooter(this.STR_IMAGE_COPY); + } + this.openWindow(win); + Dom.get(this.get('id') + '_insertimage_url').value = src; + Dom.get(this.get('id') + '_insertimage_title').value = title; + Dom.get(this.get('id') + '_insertimage_link').value = link; + Dom.get(this.get('id') + '_insertimage_target').checked = ((target) ? true : false); + Dom.get(this.get('id') + '_insertimage_width').value = width; + Dom.get(this.get('id') + '_insertimage_height').value = height; + + + var orgSize = ''; + if ((height != oheight) || (width != owidth)) { + var s = document.createElement('span'); + s.className = 'info'; + //s.innerHTML = this.STR_IMAGE_ORIG_SIZE + '
                '+ owidth +' x ' + oheight; + s.innerHTML = this.STR_IMAGE_ORIG_SIZE + ': ('+ owidth +' x ' + oheight + ')'; + if (Dom.get(this.get('id') + '_insertimage_height').nextSibling) { + var old = Dom.get(this.get('id') + '_insertimage_height').nextSibling; + old.parentNode.removeChild(old); + } + Dom.get(this.get('id') + '_insertimage_height').parentNode.appendChild(s); + } + + this.toolbar.selectButton('insertimage'); + var id = this.get('id'); + window.setTimeout(function() { + try { + YAHOO.util.Dom.get(id + '_insertimage_url').focus(); + if (blankimage) { + YAHOO.util.Dom.get(id + '_insertimage_url').select(); + } + } catch (e) {} + }, 50); + + }); + }, + /** + * @private + * @method _handleInsertImageWindowClose + * @description Handles the closing of the Image Properties Window. + */ + _handleInsertImageWindowClose: function() { + var url = Dom.get(this.get('id') + '_insertimage_url'), + title = Dom.get(this.get('id') + '_insertimage_title'), + link = Dom.get(this.get('id') + '_insertimage_link'), + target = Dom.get(this.get('id') + '_insertimage_target'), + el = arguments[0].win.el; + + if (url && url.value && (url.value != this.STR_IMAGE_HERE)) { + el.setAttribute('src', url.value); + el.setAttribute('title', title.value); + el.setAttribute('alt', title.value); + var par = el.parentNode; + if (link.value) { + var urlValue = link.value; + if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) { + //Found an @ sign, prefix with mailto: + urlValue = 'mailto:' + urlValue; + } else { + // :// not found adding + urlValue = 'http:/'+'/' + urlValue; + } + } + if (par && this._isElement(par, 'a')) { + par.setAttribute('href', urlValue); + if (target.checked) { + par.setAttribute('target', target.value); + } else { + par.setAttribute('target', ''); + } + } else { + var _a = this._getDoc().createElement('a'); + _a.setAttribute('href', urlValue); + if (target.checked) { + _a.setAttribute('target', target.value); + } else { + _a.setAttribute('target', ''); + } + el.parentNode.replaceChild(_a, el); + _a.appendChild(el); + } + } else { + if (par && this._isElement(par, 'a')) { + par.parentNode.replaceChild(el, par); + } + } + } else { + //No url/src given, remove the node from the document + el.parentNode.removeChild(el); + } + Dom.get(this.get('id') + '_insertimage_url').value = ''; + Dom.get(this.get('id') + '_insertimage_title').value = ''; + Dom.get(this.get('id') + '_insertimage_link').value = ''; + Dom.get(this.get('id') + '_insertimage_target').checked = false; + Dom.get(this.get('id') + '_insertimage_width').value = 0; + Dom.get(this.get('id') + '_insertimage_height').value = 0; + this._defaultImageToolbar.resetAllButtons(); + this.currentElement = []; + this.nodeChange(); + }, + /** + * @property EDITOR_PANEL_ID + * @description HTML id to give the properties window in the DOM. + * @type String + */ + EDITOR_PANEL_ID: '-panel', + /** + * @private + * @method _renderPanel + * @description Renders the panel used for Editor Windows to the document so we can start using it.. + * @return {YAHOO.widget.Overlay} + */ + _renderPanel: function() { + var panel = new YAHOO.widget.Overlay(this.get('id') + this.EDITOR_PANEL_ID, { + width: '300px', + iframe: true, + visible: false, + underlay: 'none', + draggable: false, + close: false + }); + this.set('panel', panel); + + this.get('panel').setBody('---'); + this.get('panel').setHeader(' '); + this.get('panel').setFooter(' '); + + + var body = document.createElement('div'); + body.className = this.CLASS_PREFIX + '-body-cont'; + for (var b in this.browser) { + if (this.browser[b]) { + Dom.addClass(body, b); + break; + } + } + Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button')); + + var _note = document.createElement('h3'); + _note.className = 'yui-editor-skipheader'; + _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE; + body.appendChild(_note); + var form = document.createElement('form'); + form.setAttribute('method', 'GET'); + panel.editor_form = form; + + Event.on(form, 'submit', function(ev) { + Event.stopEvent(ev); + }, this, true); + body.appendChild(form); + var _close = document.createElement('span'); + _close.innerHTML = 'X'; + _close.title = this.STR_CLOSE_WINDOW; + _close.className = 'close'; + + Event.on(_close, 'click', this.closeWindow, this, true); + + var _knob = document.createElement('span'); + _knob.innerHTML = '^'; + _knob.className = 'knob'; + panel.editor_knob = _knob; + + var _header = document.createElement('h3'); + panel.editor_header = _header; + _header.innerHTML = ''; + + panel.setHeader(' '); //Clear the current header + panel.appendToHeader(_header); + _header.appendChild(_close); + _header.appendChild(_knob); + panel.setBody(' '); //Clear the current body + panel.setFooter(' '); //Clear the current footer + panel.appendToBody(body); //Append the new DOM node to it + + Event.on(panel.element, 'click', function(ev) { + Event.stopPropagation(ev); + }); + + var fireShowEvent = function() { + //panel.bringToTop(); + }; + panel.showEvent.subscribe(fireShowEvent, this, true); + panel.renderEvent.subscribe(function() { + this._renderInsertImageWindow(); + this._renderCreateLinkWindow(); + this.fireEvent('windowRender', { type: 'windowRender', panel: panel }); + }, this, true); + + if (this.DOMReady) { + this.get('panel').render(document.body); + //Render to the element_cont so we can skin it better + //this.get('panel').render(this.get('element_cont').get('element')); + Dom.addClass(this.get('panel').element, 'yui-editor-panel'); + } else { + Event.onDOMReady(function() { + this.get('panel').render(document.body); + //Render to the element_cont so we can skin it better + //this.get('panel').render(this.get('element_cont').get('element')); + Dom.addClass(this.get('panel').element, 'yui-editor-panel'); + }, this, true); + } + this.get('panel').showEvent.subscribe(function() { + YAHOO.util.Dom.setStyle(this.element, 'display', 'block'); + }); + return this.get('panel'); + }, + /** + * @method openWindow + * @param {YAHOO.widget.EditorWindow} win A YAHOO.widget.EditorWindow instance + * @description Opens a new "window/panel" + */ + openWindow: function(win) { + var self = this; + window.setTimeout(function() { + self.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open.. + }, 10); + Event.on(document, 'keydown', this._closeWindow, this, true); + + if (this.currentWindow) { + this.closeWindow(); + } + + + var xy = Dom.getXY(this.currentElement[0]), + elXY = Dom.getXY(this.get('iframe').get('element')), + panel = this.get('panel'), + newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)], + wWidth = (parseInt(win.attrs.width, 10) / 2), + align = 'center', + body = null; + + this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel }); + + var form = panel.editor_form; + + var wins = this._windows; + for (var b in wins) { + if (Lang.hasOwnProperty(wins, b)) { + if (wins[b] && wins[b].body) { + if (b == win.name) { + Dom.setStyle(wins[b].body, 'display', 'block'); + } else { + Dom.setStyle(wins[b].body, 'display', 'none'); + } + } + } + } + + if (this._windows[win.name].body) { + Dom.setStyle(this._windows[win.name].body, 'display', 'block'); + form.appendChild(this._windows[win.name].body); + } else { + if (Lang.isObject(win.body)) { //Assume it's a reference + form.appendChild(win.body); + } else { //Assume it's a string + var _tmp = document.createElement('div'); + _tmp.innerHTML = win.body; + form.appendChild(_tmp); + } + } + panel.editor_header.firstChild.innerHTML = win.header; + if (win.footer !== null) { + panel.setFooter(win.footer); + Dom.addClass(panel.footer, 'open'); + } else { + Dom.removeClass(panel.footer, 'open'); + } + panel.cfg.setProperty('width', win.attrs.width); + + this.currentWindow = win; + this.moveWindow(true); + panel.show(); + this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel }); + }, + /** + * @method moveWindow + * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.) + * @description Realign the window with the currentElement and reposition the knob above the panel. + */ + moveWindow: function(force) { + if (!this.currentWindow) { + return false; + } + var win = this.currentWindow, + xy = Dom.getXY(this.currentElement[0]), + elXY = Dom.getXY(this.get('iframe').get('element')), + panel = this.get('panel'), + //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)], + newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])], + wWidth = (parseInt(win.attrs.width, 10) / 2), + align = 'center', + orgXY = panel.cfg.getProperty('xy') || [0,0], + _knob = panel.editor_knob, + xDiff = 0, + yDiff = 0, + anim = false; + + + newXY[0] = ((newXY[0] - wWidth) + 20); + //Account for the Scroll bars in a scrolled editor window. + newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc()); + newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc()); + + if (this._isElement(this.currentElement[0], 'img')) { + if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) { + newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size + newXY[1] = (newXY[1] + 75); //Placeholder sizea + } else { + var w = parseInt(this.currentElement[0].width, 10); + var h = parseInt(this.currentElement[0].height, 10); + newXY[0] = (newXY[0] + (w / 2)); + newXY[1] = (newXY[1] + h); + } + newXY[1] = newXY[1] + 15; + } else { + var fs = Dom.getStyle(this.currentElement[0], 'fontSize'); + if (fs && fs.indexOf && fs.indexOf('px') != -1) { + newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5; + } else { + newXY[1] = newXY[1] + 20; + } + } + if (newXY[0] < elXY[0]) { + newXY[0] = elXY[0] + 5; + align = 'left'; + } + + if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) { + newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5); + align = 'right'; + } + + try { + xDiff = (newXY[0] - orgXY[0]); + yDiff = (newXY[1] - orgXY[1]); + } catch (e) {} + + + if (this.get('autoHeight') === false) { + var iTop = elXY[1] + parseInt(this.get('height'), 10); + var iLeft = elXY[0] + parseInt(this.get('width'), 10); + if (newXY[1] > iTop) { + newXY[1] = iTop; + } + if (newXY[0] > iLeft) { + newXY[0] = (iLeft / 2); + } + } + + //Convert negative numbers to positive so we can get the difference in distance + xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff); + yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff); + + if (((xDiff > 10) || (yDiff > 10)) || force) { //Only move the window if it's supposed to move more than 10px or force was passed (new window) + var _knobLeft = 0, + elW = 0; + + if (this.currentElement[0].width) { + elW = (parseInt(this.currentElement[0].width, 10) / 2); + } + + var leftOffset = xy[0] + elXY[0] + elW; + _knobLeft = leftOffset - newXY[0]; + //Check to see if the knob will go off either side & reposition it + if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) { + _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1); + } else if (_knobLeft < 40) { + _knobLeft = 1; + } + if (isNaN(_knobLeft)) { + _knobLeft = 1; + } + if (force) { + if (_knob) { + _knob.style.left = _knobLeft + 'px'; + } + //Removed Animation from a forced move.. + panel.cfg.setProperty('xy', newXY); + } else { + if (this.get('animate')) { + anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut); + anim.attributes = { + top: { + to: newXY[1] + }, + left: { + to: newXY[0] + } + }; + anim.onComplete.subscribe(function() { + panel.cfg.setProperty('xy', newXY); + }); + //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed .. + var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut); + + var _knobAnim = new YAHOO.util.Anim(_knob, { + left: { + to: _knobLeft + } + }, 0.6, YAHOO.util.Easing.easeOut); + anim.animate(); + iframeAnim.animate(); + _knobAnim.animate(); + } else { + _knob.style.left = _knobLeft + 'px'; + panel.cfg.setProperty('xy', newXY); + } + } + } + }, + /** + * @private + * @method _closeWindow + * @description Close the currently open EditorWindow with the Escape key. + * @param {Event} ev The keypress Event that we are trapping + */ + _closeWindow: function(ev) { + //if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) { + if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) { + if (this.currentWindow) { + this.closeWindow(); + } + } + }, + /** + * @method closeWindow + * @description Close the currently open EditorWindow. + */ + closeWindow: function(keepOpen) { + //YAHOO.widget.EditorInfo.window = {}; + this.fireEvent('window' + this.currentWindow.name + 'Close', { type: 'window' + this.currentWindow.name + 'Close', win: this.currentWindow, el: this.currentElement[0] }); + this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow }); + this.currentWindow = null; + this.get('panel').hide(); + this.get('panel').cfg.setProperty('xy', [-900,-900]); + this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel + this.unsubscribeAll('afterExecCommand'); + this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed + this.toolbar.resetAllButtons(); + this._focusWindow(); + Event.removeListener(document, 'keydown', this._closeWindow); + }, + + /* {{{ Command Overrides - These commands are only over written when we are using the advanced version */ + + /** + * @method cmd_undo + * @description Pulls an item from the Undo stack and updates the Editor + * @param value Value passed from the execCommand method + */ + cmd_undo: function(value) { + if (this._hasUndoLevel()) { + if (!this._undoLevel) { + this._undoLevel = this._undoCache.length; + } + this._undoLevel = (this._undoLevel - 1); + if (this._undoCache[this._undoLevel]) { + var html = this._getUndo(this._undoLevel); + this.setEditorHTML(html); + } else { + this._undoLevel = null; + this.toolbar.disableButton('undo'); + } + } + return [false]; + }, + + /** + * @method cmd_redo + * @description Pulls an item from the Undo stack and updates the Editor + * @param value Value passed from the execCommand method + */ + cmd_redo: function(value) { + this._undoLevel = this._undoLevel + 1; + if (this._undoLevel >= this._undoCache.length) { + this._undoLevel = this._undoCache.length; + } + if (this._undoCache[this._undoLevel]) { + var html = this._getUndo(this._undoLevel); + this.setEditorHTML(html); + } else { + this.toolbar.disableButton('redo'); + } + return [false]; + }, + + /** + * @method cmd_heading + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used. + */ + cmd_heading: function(value) { + var exec = true, + el = null, + action = 'heading', + _sel = this._getSelection(), + _selEl = this._getSelectedElement(); + + if (_selEl) { + _sel = _selEl; + } + + if (this.browser.ie) { + action = 'formatblock'; + } + if (value == 'none') { + if ((_sel && _sel.tagName && (_sel.tagName.toLowerCase().substring(0,1) == 'h')) || (_sel && _sel.parentNode && _sel.parentNode.tagName && (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h'))) { + if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') { + _sel = _sel.parentNode; + } + if (this._isElement(_sel, 'html')) { + return [false]; + } + el = this._swapEl(_selEl, 'span', function(el) { + el.className = 'yui-non'; + }); + this._selectNode(el); + this.currentElement[0] = el; + } + exec = false; + } else { + if (this._isElement(_selEl, 'h1') || this._isElement(_selEl, 'h2') || this._isElement(_selEl, 'h3') || this._isElement(_selEl, 'h4') || this._isElement(_selEl, 'h5') || this._isElement(_selEl, 'h6')) { + el = this._swapEl(_selEl, value); + this._selectNode(el); + this.currentElement[0] = el; + } else { + this._createCurrentElement(value); + this._selectNode(this.currentElement[0]); + } + exec = false; + } + return [exec, action]; + }, + /** + * @method cmd_hiddenelements + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used. + */ + cmd_hiddenelements: function(value) { + if (this._showingHiddenElements) { + //Don't auto highlight the hidden button + this._lastButton = null; + this._showingHiddenElements = false; + this.toolbar.deselectButton('hiddenelements'); + Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN); + } else { + this._showingHiddenElements = true; + Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN); + this.toolbar.selectButton('hiddenelements'); + } + return [false]; + }, + /** + * @method cmd_removeformat + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used. + */ + cmd_removeformat: function(value) { + var exec = true; + /** + * @knownissue Remove Format issue + * @browser Safari 2.x + * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected. + * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds. + * So here we are making the best possible guess and acting on it. + */ + if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) { + var _txt = this._getSelection()+''; + this._createCurrentElement('span'); + this.currentElement[0].className = 'yui-non'; + this.currentElement[0].innerHTML = _txt; + for (var i = 1; i < this.currentElement.length; i++) { + this.currentElement[i].parentNode.removeChild(this.currentElement[i]); + } + /* + this._createCurrentElement('span'); + YAHOO.util.Dom.addClass(this.currentElement[0], 'yui-non'); + var re= /<\S[^><]*>/g; + var str = this.currentElement[0].innerHTML.replace(re, ''); + var _txt = this._getDoc().createTextNode(str); + this.currentElement[0].parentNode.parentNode.replaceChild(_txt, this.currentElement[0].parentNode); + */ + + exec = false; + } + return [exec]; + }, + /** + * @method cmd_script + * @param action action passed from the execCommand method + * @param value Value passed from the execCommand method + * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods. + */ + cmd_script: function(action, value) { + var exec = true, tag = action.toLowerCase().substring(0, 3), + _span = null, _selEl = this._getSelectedElement(); + + if (this.browser.webkit) { + if (this._isElement(_selEl, tag)) { + _span = this._swapEl(this.currentElement[0], 'span', function(el) { + el.className = 'yui-non'; + }); + this._selectNode(_span); + } else { + this._createCurrentElement(tag); + var _sub = this._swapEl(this.currentElement[0], tag); + this._selectNode(_sub); + this.currentElement[0] = _sub; + } + exec = false; + } + return exec; + }, + /** + * @method cmd_superscript + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used. + */ + cmd_superscript: function(value) { + return [this.cmd_script('superscript', value)]; + }, + /** + * @method cmd_subscript + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used. + */ + cmd_subscript: function(value) { + return [this.cmd_script('subscript', value)]; + }, + /** + * @method cmd_indent + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used. + */ + cmd_indent: function(value) { + var exec = true, selEl = this._getSelectedElement(), _bq = null; + + //if (this.browser.webkit || this.browser.ie || this.browser.gecko) { + //if (this.browser.webkit || this.browser.ie) { + if (this.browser.ie) { + if (this._isElement(selEl, 'blockquote')) { + _bq = this._getDoc().createElement('blockquote'); + _bq.innerHTML = selEl.innerHTML; + selEl.innerHTML = ''; + selEl.appendChild(_bq); + this._selectNode(_bq); + } else { + _bq = this._getDoc().createElement('blockquote'); + var html = this._getRange().htmlText; + _bq.innerHTML = html; + this._createCurrentElement('blockquote'); + /* + for (var i = 0; i < this.currentElement.length; i++) { + _bq = this._getDoc().createElement('blockquote'); + _bq.innerHTML = this.currentElement[i].innerHTML; + this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]); + this.currentElement[i] = _bq; + } + */ + this.currentElement[0].parentNode.replaceChild(_bq, this.currentElement[0]); + this.currentElement[0] = _bq; + this._selectNode(this.currentElement[0]); + } + exec = false; + } else { + value = 'blockquote'; + } + return [exec, 'formatblock', value]; + }, + /** + * @method cmd_outdent + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used. + */ + cmd_outdent: function(value) { + var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null; + //if (this.browser.webkit || this.browser.ie || this.browser.gecko) { + if (this.browser.webkit || this.browser.ie) { + //if (this.browser.ie) { + selEl = this._getSelectedElement(); + if (this._isElement(selEl, 'blockquote')) { + var par = selEl.parentNode; + if (this._isElement(selEl.parentNode, 'blockquote')) { + par.innerHTML = selEl.innerHTML; + this._selectNode(par); + } else { + _span = this._getDoc().createElement('span'); + _span.innerHTML = selEl.innerHTML; + YAHOO.util.Dom.addClass(_span, 'yui-non'); + par.replaceChild(_span, selEl); + this._selectNode(_span); + } + } else { + } + exec = false; + } else { + value = false; + } + return [exec, 'outdent', value]; + }, + /** + * @method cmd_justify + * @param dir The direction to justify + * @description This is a factory method for the justify family of commands. + */ + cmd_justify: function(dir) { + if (this.browser.ie) { + if (this._hasSelection()) { + this._createCurrentElement('span'); + this._swapEl(this.currentElement[0], 'div', function(el) { + el.style.textAlign = dir; + }); + + return [false]; + } + } + return [true, 'justify' + dir, '']; + }, + /** + * @method cmd_justifycenter + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifycenter') is used. + */ + cmd_justifycenter: function() { + return [this.cmd_justify('center')]; + }, + /** + * @method cmd_justifyleft + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyleft') is used. + */ + cmd_justifyleft: function() { + return [this.cmd_justify('left')]; + }, + /** + * @method cmd_justifyright + * @param value Value passed from the execCommand method + * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyright') is used. + */ + cmd_justifyright: function() { + return [this.cmd_justify('right')]; + }, + /* }}}*/ + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'Editor'; + if (this.get && this.get('element_cont')) { + str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + /** + * @description Class to hold Window information between uses. We use the same panel to show the windows, so using this will allow you to configure a window before it is shown. + * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor. + * @class EditorWindow + * @param {String} name The name of the window. + * @param {Object} attrs Attributes for the window. Current attributes used are : height and width + */ + YAHOO.widget.EditorWindow = function(name, attrs) { + /** + * @private + * @property name + * @description A unique name for the window + */ + this.name = name.replace(' ', '_'); + /** + * @private + * @property attrs + * @description The window attributes + */ + this.attrs = attrs; + }; + + YAHOO.widget.EditorWindow.prototype = { + /** + * @private + * @property header + * @description Holder for the header of the window, used in Editor.openWindow + */ + header: null, + /** + * @private + * @property body + * @description Holder for the body of the window, used in Editor.openWindow + */ + body: null, + /** + * @private + * @property footer + * @description Holder for the footer of the window, used in Editor.openWindow + */ + footer: null, + /** + * @method setHeader + * @description Sets the header for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header. + */ + setHeader: function(str) { + this.header = str; + }, + /** + * @method setBody + * @description Sets the body for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body. + */ + setBody: function(str) { + this.body = str; + }, + /** + * @method setFooter + * @description Sets the footer for the window. + * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer. + */ + setFooter: function(str) { + this.footer = str; + }, + /** + * @method toString + * @description Returns a string representing the EditorWindow. + * @return {String} + */ + toString: function() { + return 'Editor Window (' + this.name + ')'; + } + }; +/** +* @event beforeOpenWindow +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fires before an Editor Window is opened. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterOpenWindow +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fires after an Editor Window is opened. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event closeWindow +* @param {EditorWindow} win The EditorWindow object +* @description Event fires after an Editor Window is closed. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCMDOpen +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Dynamic event fired when an EditorWindow is opened.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkOpen event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCMDClose +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Dynamic event fired when an EditorWindow is closed.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkClose event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowRender +* @param {EditorWindow} win The EditorWindow object +* @param {Overlay} panel The Overlay object that is used to create the window. +* @description Event fired when the initial Overlay is rendered. Can be used to manipulate the content of the panel. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowInsertImageRender +* @param {Overlay} panel The Overlay object that is used to create the window. +* @param {HTMLElement} body The HTML element used as the body of the window.. +* @param {Toolbar} toolbar A reference to the toolbar object used inside this window. +* @description Event fired when the pre render of the Insert Image window has finished. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event windowCreateLinkRender +* @param {Overlay} panel The Overlay object that is used to create the window. +* @param {HTMLElement} body The HTML element used as the body of the window.. +* @description Event fired when the pre render of the Create Link window has finished. +* @type YAHOO.util.CustomEvent +*/ + +})(); +YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/editor/simpleeditor-debug.js b/lib/yui/editor/simpleeditor-debug.js new file mode 100644 index 00000000000..e4257e83d0f --- /dev/null +++ b/lib/yui/editor/simpleeditor-debug.js @@ -0,0 +1,6971 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +(function() { + /** + * @private + **/ +var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang; + /** + * @description

                Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

                + * @class ToolbarButtonAdvanced + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, menu, button + * @beta + * + * Provides a toolbar button based on the button and menu widgets. + * @constructor + * @param {String/HTMLElement} el The element to turn into a button. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + if (YAHOO.widget.Button) { + YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button; + /** + * @property buttonType + * @private + * @description Tells if the Button is a Rich Button or a Simple Button + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich'; + /** + * @method checkValue + * @param {String} value The value of the option that we want to mark as selected + * @description Select an option by value + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) { + var _menuItems = this.getMenu().getItems(); + if (_menuItems.length === 0) { + this.getMenu()._onBeforeShow(); + _menuItems = this.getMenu().getItems(); + } + for (var i = 0; i < _menuItems.length; i++) { + _menuItems[i].cfg.setProperty('checked', false); + if (_menuItems[i].value == value) { + _menuItems[i].cfg.setProperty('checked', true); + } + } + }; + } else { + YAHOO.widget.ToolbarButtonAdvanced = function() {}; + } + + + /** + * @description

                Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

                + * @class ToolbarButton + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event + * @Extends YAHOO.util.Element + * @beta + * + * Provides a toolbar button based on the button and menu widgets, '); + } else { + html = html.replace(/]*)>/g, ''); + html = html.replace(/]*)>/g, ''); + } + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_UL>/g, '<\/ul>'); + + html = this.filter_invalid_lists(html); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>'); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>'); + + //This should fix &s in URL's + html = html.replace(' & ', 'YUI_AMP'); + html = html.replace('&', '&'); + html = html.replace('YUI_AMP', '&'); + + //Trim the output, removing whitespace from the beginning and end + html = YAHOO.lang.trim(html); + + if (this.get('removeLineBreaks')) { + html = html.replace(/\n/g, '').replace(/\r/g, ''); + html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single + } + + //First empty span + if (html.substring(0, 6).toLowerCase() == '') { + html = html.substring(6); + //Last empty span + if (html.substring(html.length - 7, html.length).toLowerCase() == '') { + html = html.substring(0, html.length - 7); + } + } + + for (var v in this.invalidHTML) { + if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) { + if (Lang.isObject(v) && v.keepContents) { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1'); + } else { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), ''); + } + } + } + + this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html }); + + return html; + }, + /** + * @method filter_invalid_lists + * @param String html The HTML string to filter + * @description Filters invalid ol and ul list markup, converts this:
                1. ..
                to this:
                1. ..
              • + */ + filter_invalid_lists: function(html) { + html = html.replace(/<\/li>\n/gi, ''); + + html = html.replace(/<\/li>
                  /gi, '
                  1. '); + html = html.replace(/<\/ol>/gi, '
                1. '); + html = html.replace(/<\/ol><\/li>\n/gi, "
                \n"); + + html = html.replace(/<\/li>
                  /gi, '
                  • '); + html = html.replace(/<\/ul>/gi, '
                • '); + html = html.replace(/<\/ul><\/li>\n?/gi, "
                \n"); + + html = html.replace(/<\/li>/gi, "\n"); + html = html.replace(/<\/ol>/gi, "
          \n"); + html = html.replace(/
            /gi, "
              \n"); + html = html.replace(/
                /gi, "
                  \n"); + return html; + }, + /** + * @method filter_safari + * @param String html The HTML string to filter + * @description Filters strings specific to Safari + * @return String + */ + filter_safari: function(html) { + if (this.browser.webkit) { + // + html = html.replace(/([^>])<\/span>/gi, '    '); + html = html.replace(/Apple-style-span/gi, ''); + html = html.replace(/style="line-height: normal;"/gi, ''); + //Remove bogus LI's + html = html.replace(/
                • <\/li>/gi, ''); + html = html.replace(/
                • <\/li>/gi, ''); + html = html.replace(/
                • <\/li>/gi, ''); + //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break + if (this.get('ptags')) { + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/div>/gi, '

                  '); + } else { + html = html.replace(/
                  /gi, ''); + html = html.replace(/<\/div>/gi, '
                  '); + } + } + return html; + }, + /** + * @method filter_internals + * @param String html The HTML string to filter + * @description Filters internal RTE strings and bogus attrs we don't want + * @return String + */ + filter_internals: function(html) { + html = html.replace(/\r/g, ''); + //Fix stuff we don't want + html = html.replace(/<\/?(body|head|html)[^>]*>/gi, ''); + //Fix last BR in LI + html = html.replace(/<\/li>/gi, '
                • '); + + html = html.replace(/yui-tag-span/gi, ''); + html = html.replace(/yui-tag/gi, ''); + html = html.replace(/yui-non/gi, ''); + html = html.replace(/yui-img/gi, ''); + html = html.replace(/ tag="span"/gi, ''); + html = html.replace(/ class=""/gi, ''); + html = html.replace(/ style=""/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ target=""/gi, ''); + html = html.replace(/ title=""/gi, ''); + + if (this.browser.ie) { + html = html.replace(/ class= /gi, ''); + html = html.replace(/ class= >/gi, ''); + html = html.replace(/_height="([^>])"/gi, ''); + html = html.replace(/_width="([^>])"/gi, ''); + } + + return html; + }, + /** + * @method filter_all_rgb + * @param String str The HTML string to filter + * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00" + * @return String + */ + filter_all_rgb: function(str) { + var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi"); + var arr = str.match(exp); + if (Lang.isArray(arr)) { + for (var i = 0; i < arr.length; i++) { + var color = this.filter_rgb(arr[i]); + str = str.replace(arr[i].toString(), color); + } + } + + return str; + }, + /** + * @method filter_rgb + * @param String css The CSS string containing rgb(#,#,#); + * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00 + * @return String + */ + filter_rgb: function(css) { + if (css.toLowerCase().indexOf('rgb') != -1) { + var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi"); + var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(','); + + if (rgb.length == 5) { + var r = parseInt(rgb[1], 10).toString(16); + var g = parseInt(rgb[2], 10).toString(16); + var b = parseInt(rgb[3], 10).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + css = "#" + r + g + b; + } + } + return css; + }, + /** + * @method pre_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + pre_filter_linebreaks: function(html, markup) { + if (this.browser.webkit) { + html = html.replace(/
                  /gi, ''); + html = html.replace(/
                  /gi, ''); + } + html = html.replace(/
                  /gi, ''); + html = html.replace(/
                  /gi, ''); + html = html.replace(//gi, ''); + html = html.replace(/
                  /gi, ''); + html = html.replace(/
                  <\/div>/gi, ''); + html = html.replace(/

                  ( | )<\/p>/g, ''); + html = html.replace(/


                   <\/p>/gi, ''); + html = html.replace(/

                   <\/p>/gi, ''); + //Fix last BR + html = html.replace(/$/, ''); + //Fix last BR in P + html = html.replace(/<\/p>/g, '

                  '); + if (this.browser.ie) { + html = html.replace(/    /g, '\t'); + } + return html; + }, + /** + * @method post_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + post_filter_linebreaks: function(html, markup) { + if (markup == 'xhtml') { + html = html.replace(//g, '
                  '); + } else { + html = html.replace(//g, '
                  '); + } + return html; + }, + /** + * @method clearEditorDoc + * @description Clear the doc of the Editor + */ + clearEditorDoc: function() { + this._getDoc().body.innerHTML = ' '; + }, + /** + * @method openWindow + * @description Override Method for Advanced Editor + */ + openWindow: function(win) { + }, + /** + * @method moveWindow + * @description Override Method for Advanced Editor + */ + moveWindow: function() { + }, + /** + * @private + * @method _closeWindow + * @description Override Method for Advanced Editor + */ + _closeWindow: function() { + }, + /** + * @method closeWindow + * @description Override Method for Advanced Editor + */ + closeWindow: function() { + //this.unsubscribeAll('afterExecCommand'); + this.toolbar.resetAllButtons(); + this._focusWindow(); + }, + /** + * @method destroy + * @description Destroys the editor, all of it's elements and objects. + * @return {Boolean} + */ + destroy: function() { + YAHOO.log('Destroying Editor', 'warn', 'SimpleEditor'); + if (this.resize) { + YAHOO.log('Destroying Resize', 'warn', 'SimpleEditor'); + this.resize.destroy(); + } + if (this.dd) { + YAHOO.log('Unreg DragDrop Instance', 'warn', 'SimpleEditor'); + this.dd.unreg(); + } + if (this.get('panel')) { + YAHOO.log('Destroying Editor Panel', 'warn', 'SimpleEditor'); + this.get('panel').destroy(); + } + this.saveHTML(); + this.toolbar.destroy(); + YAHOO.log('Restoring TextArea', 'info', 'SimpleEditor'); + this.setStyle('visibility', 'visible'); + this.setStyle('position', 'static'); + this.setStyle('top', ''); + this.setStyle('left', ''); + var textArea = this.get('element'); + this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element')); + this.get('element_cont').get('element').innerHTML = ''; + this.set('handleSubmit', false); //Remove the submit handler + return true; + }, + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'SimpleEditor'; + if (this.get && this.get('element_cont')) { + str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + +/** +* @event toolbarLoaded +* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event cleanHTML +* @description Event is fired after the cleanHTML method is called. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterRender +* @description Event is fired after the render process finishes. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorContentLoaded +* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeNodeChange +* @description Event fires at the beginning of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterNodeChange +* @description Event fires at the end of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeExecCommand +* @description Event fires at the beginning of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterExecCommand +* @description Event fires at the end of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ + + + /** + * @description Singleton object used to track the open window objects and panels across the various open editors + * @class EditorInfo + * @static + */ + YAHOO.widget.EditorInfo = { + /** + * @private + * @property _instances + * @description A reference to all editors on the page. + * @type Object + */ + _instances: {}, + /** + * @private + * @property blankImage + * @description A reference to the blankImage url + * @type String + */ + blankImage: '', + /** + * @private + * @property window + * @description A reference to the currently open window object in any editor on the page. + * @type Object YAHOO.widget.EditorWindow + */ + window: {}, + /** + * @private + * @property panel + * @description A reference to the currently open panel in any editor on the page. + * @type Object YAHOO.widget.Overlay + */ + panel: null, + /** + * @method getEditorById + * @description Returns a reference to the Editor object associated with the given textarea + * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of + * @return Object YAHOO.widget.Editor + */ + getEditorById: function(id) { + if (!YAHOO.lang.isString(id)) { + //Not a string, assume a node Reference + id = id.id; + } + if (this._instances[id]) { + return this._instances[id]; + } + return false; + }, + /** + * @method toString + * @description Returns a string representing the EditorInfo. + * @return {String} + */ + toString: function() { + var len = 0; + for (var i in this._instances) { + if (Lang.hasOwnProperty(this._instances, i)) { + len++; + } + } + return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')'; + } + }; + + + + +})(); +YAHOO.register("simpleeditor", YAHOO.widget.SimpleEditor, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/editor/simpleeditor-min.js b/lib/yui/editor/simpleeditor-min.js new file mode 100644 index 00000000000..9d98b88d6f1 --- /dev/null +++ b/lib/yui/editor/simpleeditor-min.js @@ -0,0 +1,23 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +(function(){var B=YAHOO.util.Dom,A=YAHOO.util.Event,C=YAHOO.lang;if(YAHOO.widget.Button){YAHOO.widget.ToolbarButtonAdvanced=YAHOO.widget.Button;YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType="rich";YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue=function(F){var E=this.getMenu().getItems();if(E.length===0){this.getMenu()._onBeforeShow();E=this.getMenu().getItems();}for(var D=0;D'+G+"";this._titlebar.appendChild(F);A.on(F.firstChild,"click",function(H){A.stopEvent(H);});A.on([F,F.firstChild],"focus",function(){this._handleFocus();},this,true);}if(this.get("firstChild")){this.insertBefore(this._titlebar,this.get("firstChild"));}else{this.appendChild(this._titlebar);}if(this.get("collapse")){this.set("collapse",true);}}else{if(this._titlebar){if(this._titlebar&&this._titlebar.parentNode){this._titlebar.parentNode.removeChild(this._titlebar);}}}}});this.setAttributeConfig("collapse",{value:false,method:function(H){if(this._titlebar){var G=null;var F=C.getElementsByClassName("collapse","span",this._titlebar);if(H){if(F.length>0){return true;}G=document.createElement("SPAN");G.innerHTML="X";G.title=this.STR_COLLAPSE;C.addClass(G,"collapse");this._titlebar.appendChild(G);A.addListener(G,"click",function(){if(C.hasClass(this.get("cont").parentNode,"yui-toolbar-container-collapsed")){this.collapse(false);}else{this.collapse();}},this,true);}else{G=C.getElementsByClassName("collapse","span",this._titlebar);if(G[0]){if(C.hasClass(this.get("cont").parentNode,"yui-toolbar-container-collapsed")){this.collapse(false);}G[0].parentNode.removeChild(G[0]);}}}}});this.setAttributeConfig("draggable",{value:(E.draggable||false),method:function(F){if(F&&!this.get("titlebar")){if(!this._dragHandle){this._dragHandle=document.createElement("SPAN");this._dragHandle.innerHTML="|";this._dragHandle.setAttribute("title","Click to drag the toolbar");this._dragHandle.id=this.get("id")+"_draghandle";C.addClass(this._dragHandle,this.CLASS_DRAGHANDLE);if(this.get("cont").hasChildNodes()){this.get("cont").insertBefore(this._dragHandle,this.get("cont").firstChild);}else{this.get("cont").appendChild(this._dragHandle);}this.dd=new YAHOO.util.DD(this.get("id"));this.dd.setHandleElId(this._dragHandle.id);}}else{if(this._dragHandle){this._dragHandle.parentNode.removeChild(this._dragHandle);this._dragHandle=null;this.dd=null;}}if(this._titlebar){if(F){this.dd=new YAHOO.util.DD(this.get("id"));this.dd.setHandleElId(this._titlebar);C.addClass(this._titlebar,"draggable");}else{C.removeClass(this._titlebar,"draggable");if(this.dd){this.dd.unreg();this.dd=null;}}}},validator:function(G){var F=true;if(!YAHOO.util.DD){F=false;}return F;}});},addButtonGroup:function(I){if(!this.get("element")){this._queue[this._queue.length]=["addButtonGroup",arguments];return false;}if(!this.hasClass(this.CLASS_PREFIX+"-grouped")){this.addClass(this.CLASS_PREFIX+"-grouped");}var J=document.createElement("DIV");C.addClass(J,this.CLASS_PREFIX+"-group");C.addClass(J,this.CLASS_PREFIX+"-group-"+I.group);if(I.label){var F=document.createElement("h3");F.innerHTML=I.label;J.appendChild(F);}if(!this.get("grouplabels")){C.addClass(this.get("cont"),this.CLASS_PREFIX,"-nogrouplabels");}this.get("cont").appendChild(J);var H=document.createElement("ul");J.appendChild(H);if(!this._buttonGroupList){this._buttonGroupList={};}this._buttonGroupList[I.group]=H;for(var G=0;G'+F.replace("#","")+"";}}G+="X";window.setTimeout(function(){E.innerHTML=G;},0);A.on(E,"mouseover",function(M){var K=this._colorPicker;var L=K.getElementsByTagName("em")[0];var J=K.getElementsByTagName("strong")[0];var I=A.getTarget(M);if(I.tagName.toLowerCase()=="a"){L.style.backgroundColor=I.style.backgroundColor;J.innerHTML=this._colorData["#"+I.innerHTML]+"
                  "+I.innerHTML;}},this,true);A.on(E,"focus",function(I){A.stopEvent(I);});A.on(E,"click",function(I){A.stopEvent(I);});A.on(E,"mousedown",function(J){A.stopEvent(J);var I=A.getTarget(J);if(I.tagName.toLowerCase()=="a"){var L=this.fireEvent("colorPickerClicked",{type:"colorPickerClicked",target:this,button:this._colorPicker._button,color:I.innerHTML,colorName:this._colorData["#"+I.innerHTML]});if(L!==false){var K={color:I.innerHTML,colorName:this._colorData["#"+I.innerHTML],value:this._colorPicker._button};this.fireEvent("buttonClick",{type:"buttonClick",target:this.get("element"),button:K});}this.getButtonByValue(this._colorPicker._button).getMenu().hide();}},this,true);},_resetColorPicker:function(){var F=this._colorPicker.getElementsByTagName("em")[0];var E=this._colorPicker.getElementsByTagName("strong")[0];F.style.backgroundColor="transparent"; +E.innerHTML="";},_makeColorButton:function(E){if(!this._colorPicker){this._createColorPicker(this.get("id"));}E.type="color";E.menu=new YAHOO.widget.Overlay(this.get("id")+"_"+E.value+"_menu",{visible:false,position:"absolute",iframe:true});E.menu.setBody("");E.menu.render(this.get("cont"));C.addClass(E.menu.element,"yui-button-menu");C.addClass(E.menu.element,"yui-color-button-menu");E.menu.beforeShowEvent.subscribe(function(){E.menu.cfg.setProperty("zindex",5);E.menu.cfg.setProperty("context",[this.getButtonById(E.id).get("element"),"tl","bl"]);this._resetColorPicker();var F=this._colorPicker;if(F.parentNode){F.parentNode.removeChild(F);}E.menu.setBody("");E.menu.appendToBody(F);this._colorPicker.style.display="block";},this,true);return E;},_makeSpinButton:function(R,L){R.addClass(this.CLASS_PREFIX+"-spinbutton");var S=this,N=R._button.parentNode.parentNode,I=L.range,H=document.createElement("a"),G=document.createElement("a");H.href="#";G.href="#";H.tabIndex="-1";G.tabIndex="-1";H.className="up";H.title=this.STR_SPIN_UP;H.innerHTML=this.STR_SPIN_UP;G.className="down";G.title=this.STR_SPIN_DOWN;G.innerHTML=this.STR_SPIN_DOWN;N.appendChild(H);N.appendChild(G);var M=YAHOO.lang.substitute(this.STR_SPIN_LABEL,{VALUE:R.get("label")});R.set("title",M);var Q=function(T){T=((TI[1])?I[1]:T);return T;};var P=this.browser;var F=false;var K=this.STR_SPIN_LABEL;if(this._titlebar&&this._titlebar.firstChild){F=this._titlebar.firstChild;}var E=function(U){YAHOO.util.Event.stopEvent(U);if(!R.get("disabled")&&(U.keyCode!=9)){var V=parseInt(R.get("label"),10);V++;V=Q(V);R.set("label",""+V);var T=YAHOO.lang.substitute(K,{VALUE:R.get("label")});R.set("title",T);if(!P.webkit&&F){}S._buttonClick(U,L);}};var O=function(U){YAHOO.util.Event.stopEvent(U);if(!R.get("disabled")&&(U.keyCode!=9)){var V=parseInt(R.get("label"),10);V--;V=Q(V);R.set("label",""+V);var T=YAHOO.lang.substitute(K,{VALUE:R.get("label")});R.set("title",T);if(!P.webkit&&F){}S._buttonClick(U,L);}};var J=function(T){if(T.keyCode==38){E(T);}else{if(T.keyCode==40){O(T);}else{if(T.keyCode==107&&T.shiftKey){E(T);}else{if(T.keyCode==109&&T.shiftKey){O(T);}}}}};R.on("keydown",J,this,true);A.on(H,"mousedown",function(T){A.stopEvent(T);},this,true);A.on(G,"mousedown",function(T){A.stopEvent(T);},this,true);A.on(H,"click",E,this,true);A.on(G,"click",O,this,true);},_buttonClick:function(L,F){var E=true;if(L&&L.type=="keypress"){if(L.keyCode==9){E=false;}else{if((L.keyCode===13)||(L.keyCode===0)||(L.keyCode===32)){}else{E=false;}}}if(E){var N=true,H=false;F.isSelected=this.isSelected(F.id);if(F.value){H=this.fireEvent(F.value+"Click",{type:F.value+"Click",target:this.get("element"),button:F});if(H===false){N=false;}}if(F.menucmd&&N){H=this.fireEvent(F.menucmd+"Click",{type:F.menucmd+"Click",target:this.get("element"),button:F});if(H===false){N=false;}}if(N){this.fireEvent("buttonClick",{type:"buttonClick",target:this.get("element"),button:F});}if(F.type=="select"){var K=this.getButtonById(F.id);if(K.buttonType=="rich"){var J=F.value;for(var I=0;I'+J+"");var M=K.getMenu().getItems();for(var G=0;G(this._buttonList.length-1)){this._navCounter=0;}if(this._navCounter<0){this._navCounter=(this._buttonList.length-1);}if(this._buttonList[this._navCounter]){var E=this._buttonList[this._navCounter].get("element");if(this.browser.ie){E=this._buttonList[this._navCounter].get("element").getElementsByTagName("a")[0];}if(this._buttonList[this._navCounter].get("disabled")){this._navigateButtons(F);}else{E.focus();}}break;}},_handleFocus:function(){if(!this._keyNav){var E="keypress";if(this.browser.ie){E="keydown";}A.on(this.get("element"),E,this._navigateButtons,this,true);this._keyNav=true;this._navCounter=-1;}},getButtonById:function(G){var E=this._buttonList.length;for(var F=0;F'+H[E]._oText.nodeValue+"");}else{H[E].cfg.setProperty("checked",false); +}}}}}else{return false;}},deselectButton:function(F){var E=B.call(this,F);if(E){E.removeClass("yui-button-selected");E.removeClass("yui-button-"+E.get("value")+"-selected");E.removeClass("yui-button-hover");E._selected=false;}else{return false;}},deselectAllButtons:function(){var E=this._buttonList.length;for(var F=0;F0)){var I=0;for(var G=0;G',editorDirty:null,_defaultCSS:"html { height: 95%; } body { padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a, a:visited, a:hover { color: blue !important; text-decoration: underline !important; cursor: text !important; } .warning-localfile { border-bottom: 1px dashed red !important; } .yui-busy { cursor: wait !important; } img.selected { border: 2px dotted #808080; } img { cursor: pointer !important; border: none; } body.ptags.webkit div { margin: 11px 0; }",_defaultToolbar:null,_lastButton:null,_baseHREF:function(){var E=document.location.href;if(E.indexOf("?")!==-1){E=E.substring(0,E.indexOf("?"));}E=E.substring(0,E.lastIndexOf("/"))+"/";return E; +}(),_lastImage:null,_blankImageLoaded:null,_fixNodesTimer:null,_nodeChangeTimer:null,_lastNodeChangeEvent:null,_lastNodeChange:0,_rendered:null,DOMReady:null,_selection:null,_mask:null,_showingHiddenElements:null,currentWindow:null,currentEvent:null,operaEvent:null,currentFont:null,currentElement:null,dompath:null,beforeElement:null,afterElement:null,invalidHTML:{form:true,input:true,button:true,select:true,link:true,html:true,body:true,iframe:true,script:true,style:true,textarea:true},toolbar:null,_contentTimer:null,_contentTimerCounter:0,_disabled:["createlink","fontname","fontsize","forecolor","backcolor"],_alwaysDisabled:{undo:true,redo:true},_alwaysEnabled:{},_semantic:{"bold":true,"italic":true,"underline":true},_tag2cmd:{"b":"bold","strong":"bold","i":"italic","em":"italic","u":"underline","sup":"superscript","sub":"subscript","img":"insertimage","a":"createlink","ul":"insertunorderedlist","ol":"insertorderedlist"},_createIframe:function(){var I=document.createElement("iframe");I.id=this.get("id")+"_editor";var G={border:"0",frameBorder:"0",marginWidth:"0",marginHeight:"0",leftMargin:"0",topMargin:"0",allowTransparency:"true",width:"100%"};if(this.get("autoHeight")){G.scrolling="no";}for(var H in G){if(D.hasOwnProperty(G,H)){I.setAttribute(H,G[H]);}}var F="javascript:;";if(this.browser.ie){F="javascript:false;";}I.setAttribute("src",F);var E=new YAHOO.util.Element(I);E.setStyle("visibility","hidden");return E;},_isElement:function(F,E){if(F&&F.tagName&&(F.tagName.toLowerCase()==E)){return true;}if(F&&F.getAttribute&&(F.getAttribute("tag")==E)){return true;}return false;},_hasParent:function(F,E){if(!F||!F.parentNode){return false;}while(F.parentNode){if(this._isElement(F,E)){return F;}if(F.parentNode){F=F.parentNode;}else{return false;}}return false;},_getDoc:function(){var E=false;if(this.get){if(this.get("iframe")){if(this.get("iframe").get){if(this.get("iframe").get("element")){try{if(this.get("iframe").get("element").contentWindow){if(this.get("iframe").get("element").contentWindow.document){E=this.get("iframe").get("element").contentWindow.document;return E;}}}catch(F){}}}}}return false;},_getWindow:function(){return this.get("iframe").get("element").contentWindow;},_focusWindow:function(E){if(this.browser.webkit){if(E){this._getSelection().setBaseAndExtent(this._getDoc().body.firstChild,0,this._getDoc().body.firstChild,1);if(this.browser.webkit3){this._getSelection().collapseToStart();}else{this._getSelection().collapse(false);}}else{this._getSelection().setBaseAndExtent(this._getDoc().body,1,this._getDoc().body,1);if(this.browser.webkit3){this._getSelection().collapseToStart();}else{this._getSelection().collapse(false);}}this._getWindow().focus();}else{this._getWindow().focus();}},_hasSelection:function(){var G=this._getSelection();var E=this._getRange();var F=false;if(!G||!E){return F;}if(this.browser.ie||this.browser.opera){if(E.text){F=true;}if(E.html){F=true;}}else{if(this.browser.webkit){if(G+""!==""){F=true;}}else{if(G&&(G.toString()!=="")&&(G!==undefined)){F=true;}}}return F;},_getSelection:function(){var E=null;if(this._getDoc()&&this._getWindow()){if(this._getDoc().selection){E=this._getDoc().selection;}else{E=this._getWindow().getSelection();}if(this.browser.webkit){if(E.baseNode){this._selection={};this._selection.baseNode=E.baseNode;this._selection.baseOffset=E.baseOffset;this._selection.extentNode=E.extentNode;this._selection.extentOffset=E.extentOffset;}else{if(this._selection!==null){E=this._getWindow().getSelection();E.setBaseAndExtent(this._selection.baseNode,this._selection.baseOffset,this._selection.extentNode,this._selection.extentOffset);this._selection=null;}}}}return E;},_selectNode:function(F,I){if(!F){return false;}var G=this._getSelection(),E=null;if(this.browser.ie){try{E=this._getDoc().body.createTextRange();E.moveToElementText(F);E.select();}catch(H){}}else{if(this.browser.webkit){if(I){G.setBaseAndExtent(F,1,F,F.innerText.length);}else{G.setBaseAndExtent(F,0,F,F.innerText.length);}}else{if(this.browser.opera){G=this._getWindow().getSelection();E=this._getDoc().createRange();E.selectNode(F);G.removeAllRanges();G.addRange(E);}else{E=this._getDoc().createRange();E.selectNodeContents(F);G.removeAllRanges();G.addRange(E);}}}this.nodeChange();},_getRange:function(){var E=this._getSelection();if(E===null){return null;}if(this.browser.webkit&&!E.getRangeAt){var H=this._getDoc().createRange();try{H.setStart(E.anchorNode,E.anchorOffset);H.setEnd(E.focusNode,E.focusOffset);}catch(G){H=this._getWindow().getSelection()+"";}return H;}if(this.browser.ie||this.browser.opera){try{return E.createRange();}catch(F){return null;}}if(E.rangeCount>0){return E.getRangeAt(0);}return null;},_setDesignMode:function(E){try{var G=true;if(this.browser.ie&&(E.toLowerCase()=="off")){G=false;}if(G){this._getDoc().designMode=E;}}catch(F){}},_toggleDesignMode:function(){var F=this._getDoc().designMode.toLowerCase(),E="on";if(F=="on"){E="off";}this._setDesignMode(E);return E;},_initEditorEvents:function(){var E=this._getDoc();A.on(E,"mouseup",this._handleMouseUp,this,true);A.on(E,"mousedown",this._handleMouseDown,this,true);A.on(E,"click",this._handleClick,this,true);A.on(E,"dblclick",this._handleDoubleClick,this,true);A.on(E,"keypress",this._handleKeyPress,this,true);A.on(E,"keyup",this._handleKeyUp,this,true);A.on(E,"keydown",this._handleKeyDown,this,true);},_removeEditorEvents:function(){var E=this._getDoc();A.removeListener(E,"mouseup",this._handleMouseUp,this,true);A.removeListener(E,"mousedown",this._handleMouseDown,this,true);A.removeListener(E,"click",this._handleClick,this,true);A.removeListener(E,"dblclick",this._handleDoubleClick,this,true);A.removeListener(E,"keypress",this._handleKeyPress,this,true);A.removeListener(E,"keyup",this._handleKeyUp,this,true);A.removeListener(E,"keydown",this._handleKeyDown,this,true);},_initEditor:function(){if(this.browser.ie){this._getDoc().body.style.margin="0";}if(!this.get("disabled")){if(this._getDoc().designMode.toLowerCase()!="on"){this._setDesignMode("on"); +this._contentTimerCounter=0;}}if(!this._getDoc().body){this._contentTimerCounter=0;this._checkLoaded();return false;}this.toolbar.on("buttonClick",this._handleToolbarClick,this,true);if(!this.get("disabled")){this._initEditorEvents();this.toolbar.set("disabled",false);}this.fireEvent("editorContentLoaded",{type:"editorLoaded",target:this});if(this.get("dompath")){var E=this;setTimeout(function(){E._writeDomPath.call(E);E._setupResize.call(E);},150);}var G=[];for(var F in this.browser){if(this.browser[F]){G.push(F);}}if(this.get("ptags")){G.push("ptags");}C.addClass(this._getDoc().body,G.join(" "));this.nodeChange(true);},_checkLoaded:function(){this._contentTimerCounter++;if(this._contentTimer){clearTimeout(this._contentTimer);}if(this._contentTimerCounter>500){return false;}var G=false;try{if(this._getDoc()&&this._getDoc().body){if(this.browser.ie){if(this._getDoc().body.readyState=="complete"){G=true;}}else{if(this._getDoc().body._rteLoaded===true){G=true;}}}}catch(F){G=false;}if(G===true){this._initEditor();}else{var E=this;this._contentTimer=setTimeout(function(){E._checkLoaded.call(E);},20);}},_setInitialContent:function(){var H=((this._textarea)?this.get("element").value:this.get("element").innerHTML),J=null;var F=D.substitute(this.get("html"),{TITLE:this.STR_TITLE,CONTENT:this._cleanIncomingHTML(H),CSS:this.get("css"),HIDDEN_CSS:((this.get("hiddencss"))?this.get("hiddencss"):"/* No Hidden CSS */"),EXTRA_CSS:((this.get("extracss"))?this.get("extracss"):"/* No Extra CSS */")}),E=true;if(document.compatMode!="BackCompat"){F=this._docType+"\n"+F;}else{}if(this.browser.ie||this.browser.webkit||this.browser.opera||(navigator.userAgent.indexOf("Firefox/1.5")!=-1)){try{if(this.browser.air){J=this._getDoc().implementation.createHTMLDocument();var K=this._getDoc();K.open();K.close();J.open();J.write(F);J.close();var G=K.importNode(J.getElementsByTagName("html")[0],true);K.replaceChild(G,K.getElementsByTagName("html")[0]);K.body._rteLoaded=true;}else{J=this._getDoc();J.open();J.write(F);J.close();}}catch(I){E=false;}}else{this.get("iframe").get("element").src="data:text/html;charset=utf-8,"+encodeURIComponent(F);}this.get("iframe").setStyle("visibility","");if(E){this._checkLoaded();}},_setMarkupType:function(E){switch(this.get("markup")){case"css":this._setEditorStyle(true);break;case"default":this._setEditorStyle(false);break;case"semantic":case"xhtml":if(this._semantic[E]){this._setEditorStyle(false);}else{this._setEditorStyle(true);}break;}},_setEditorStyle:function(F){try{this._getDoc().execCommand("useCSS",false,!F);}catch(E){}},_getSelectedElement:function(){var I=this._getDoc(),F=null,G=null,J=null,E=true;if(this.browser.ie){this.currentEvent=this._getWindow().event;F=this._getRange();if(F){J=F.item?F.item(0):F.parentElement();if(this._hasSelection()){}if(J===I.body){J=null;}}if((this.currentEvent!==null)&&(this.currentEvent.keyCode===0)){J=A.getTarget(this.currentEvent);}}else{G=this._getSelection();F=this._getRange();if(!G||!F){return null;}if(!this._hasSelection()&&this.browser.webkit3){}if(this.browser.gecko){if(F.startContainer){E=false;if(F.startContainer.nodeType===3){J=F.startContainer.parentNode;}else{if(F.startContainer.nodeType===1){J=F.startContainer;}else{E=true;}}if(!E){this.currentEvent=null;}}}if(E){if(G.anchorNode&&(G.anchorNode.nodeType==3)){if(G.anchorNode.parentNode){J=G.anchorNode.parentNode;}if(G.anchorNode.nextSibling!=G.focusNode.nextSibling){J=G.anchorNode.nextSibling;}}if(this._isElement(J,"br")){J=null;}if(!J){J=F.commonAncestorContainer;if(!F.collapsed){if(F.startContainer==F.endContainer){if(F.startOffset-F.endOffset<2){if(F.startContainer.hasChildNodes()){J=F.startContainer.childNodes[F.startOffset];}}}}}}}if(this.currentEvent!==null){try{switch(this.currentEvent.type){case"click":case"mousedown":case"mouseup":if(this.browser.webkit){J=A.getTarget(this.currentEvent);}break;default:break;}}catch(H){}}else{if((this.currentElement&&this.currentElement[0])&&(!this.browser.ie)){}}if(this.browser.opera||this.browser.webkit){if(this.currentEvent&&!J){J=YAHOO.util.Event.getTarget(this.currentEvent);}}if(!J||!J.tagName){J=I.body;}if(this._isElement(J,"html")){J=I.body;}if(this._isElement(J,"body")){J=I.body;}if(J&&!J.parentNode){J=I.body;}if(J===undefined){J=null;}return J;},_getDomPath:function(E){if(!E){E=this._getSelectedElement();}var F=[];while(E!==null){if(E.ownerDocument!=this._getDoc()){E=null;break;}if(E.nodeName&&E.nodeType&&(E.nodeType==1)){F[F.length]=E;}if(this._isElement(E,"body")){break;}E=E.parentNode;}if(F.length===0){if(this._getDoc()&&this._getDoc().body){F[0]=this._getDoc().body;}}return F.reverse();},_writeDomPath:function(){var K=this._getDomPath(),I=[],G="",L="";for(var E=0;E10){L=''+L.substring(0,10)+"..."+"";}else{L=''+L+"";}I[I.length]=L;}}var H=I.join(" "+this.SEP_DOMPATH+" ");if(this.dompath.innerHTML!=H){this.dompath.innerHTML=H;}},_fixNodes:function(){var J=this._getDoc(),H=[];for(var E in this.invalidHTML){if(YAHOO.lang.hasOwnProperty(this.invalidHTML,E)){if(E.toLowerCase()!="span"){var F=J.body.getElementsByTagName(E); +if(F.length){for(var G=0;G-1;E--){if(C.hasClass(J[E],this.CLASS_NOEDIT)){try{this._getDoc().execCommand("enableObjectResizing",false,"false");}catch(I){}this.nodeChange();A.stopEvent(G);return true;}}try{this._getDoc().execCommand("enableObjectResizing",false,"true");}catch(H){}}return false;},_setCurrentEvent:function(E){this.currentEvent=E;},_handleClick:function(G){var F=this.fireEvent("beforeEditorClick",{type:"beforeEditorClick",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);if(this.currentWindow){this.closeWindow();}if(this.currentWindow){this.closeWindow();}if(this.browser.webkit){var E=A.getTarget(G);if(this._isElement(E,"a")||this._isElement(E.parentNode,"a")){A.stopEvent(G);this.nodeChange();}}else{this.nodeChange();}this.fireEvent("editorClick",{type:"editorClick",target:this,ev:G});},_handleMouseUp:function(G){var F=this.fireEvent("beforeEditorMouseUp",{type:"beforeEditorMouseUp",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}var E=this;if(this.browser.opera){var H=A.getTarget(G);if(this._isElement(H,"img")){this.nodeChange();if(this.operaEvent){clearTimeout(this.operaEvent);this.operaEvent=null;this._handleDoubleClick(G);}else{this.operaEvent=window.setTimeout(function(){E.operaEvent=false;},700);}}}if(this.browser.webkit||this.browser.opera){if(this.browser.webkit){A.stopEvent(G);}}this.nodeChange();this.fireEvent("editorMouseUp",{type:"editorMouseUp",target:this,ev:G});},_handleMouseDown:function(F){var E=this.fireEvent("beforeEditorMouseDown",{type:"beforeEditorMouseDown",target:this,ev:F});if(E===false){return false;}if(this._isNonEditable(F)){return false;}this._setCurrentEvent(F);var G=A.getTarget(F);if(this.browser.webkit&&this._hasSelection()){var H=this._getSelection();if(!this.browser.webkit3){H.collapse(true);}else{H.collapseToStart();}}if(this.browser.webkit&&this._lastImage){C.removeClass(this._lastImage,"selected");this._lastImage=null;}if(this._isElement(G,"img")||this._isElement(G,"a")){if(this.browser.webkit){A.stopEvent(F);if(this._isElement(G,"img")){C.addClass(G,"selected");this._lastImage=G;}}if(this.currentWindow){this.closeWindow();}this.nodeChange();}this.fireEvent("editorMouseDown",{type:"editorMouseDown",target:this,ev:F});},_handleDoubleClick:function(F){var E=this.fireEvent("beforeEditorDoubleClick",{type:"beforeEditorDoubleClick",target:this,ev:F});if(E===false){return false;}if(this._isNonEditable(F)){return false;}this._setCurrentEvent(F);var G=A.getTarget(F);if(this._isElement(G,"img")){this.currentElement[0]=G;this.toolbar.fireEvent("insertimageClick",{type:"insertimageClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});}else{if(this._hasParent(G,"a")){this.currentElement[0]=this._hasParent(G,"a");this.toolbar.fireEvent("createlinkClick",{type:"createlinkClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});}}this.nodeChange();this.fireEvent("editorDoubleClick",{type:"editorDoubleClick",target:this,ev:F});},_handleKeyUp:function(G){var F=this.fireEvent("beforeEditorKeyUp",{type:"beforeEditorKeyUp",target:this,ev:G});if(F===false){return false;}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);switch(G.keyCode){case this._keyMap.SELECT_ALL.key:if(this._checkKey(this._keyMap.SELECT_ALL,G)){this.nodeChange();}break;case 32:case 35:case 36:case 37:case 38:case 39:case 40:case 46:case 8:case this._keyMap.CLOSE_WINDOW.key:if((G.keyCode==this._keyMap.CLOSE_WINDOW.key)&&this.currentWindow){if(this._checkKey(this._keyMap.CLOSE_WINDOW,G)){this.closeWindow();}}else{if(!this.browser.ie){if(this._nodeChangeTimer){clearTimeout(this._nodeChangeTimer);}var E=this;this._nodeChangeTimer=setTimeout(function(){E._nodeChangeTimer=null;E.nodeChange.call(E);},100);}else{this.nodeChange();}this.editorDirty=true;}break;}this.fireEvent("editorKeyUp",{type:"editorKeyUp",target:this,ev:G});this._storeUndo();},_handleKeyPress:function(G){var F=this.fireEvent("beforeEditorKeyPress",{type:"beforeEditorKeyPress",target:this,ev:G});if(F===false){return false;}if(this.get("allowNoEdit")){if(G&&G.keyCode&&(G.keyCode==63272)){A.stopEvent(G);}}if(this._isNonEditable(G)){return false;}this._setCurrentEvent(G);if(this.browser.opera){if(G.keyCode===13){var E=this._getSelectedElement();if(!this._isElement(E,"li")){this.execCommand("inserthtml","
                  ");A.stopEvent(G);}}}if(this.browser.webkit){if(!this.browser.webkit3){if(G.keyCode&&(G.keyCode==122)&&(G.metaKey)){if(this._hasParent(this._getSelectedElement(),"li")){A.stopEvent(G);}}}this._listFix(G);}this.fireEvent("editorKeyPress",{type:"editorKeyPress",target:this,ev:G});},_handleKeyDown:function(M){var J=this.fireEvent("beforeEditorKeyDown",{type:"beforeEditorKeyDown",target:this,ev:M});if(J===false){return false;}var I=null,K=null;if(this._isNonEditable(M)){return false;}this._setCurrentEvent(M);if(this.currentWindow){this.closeWindow();}if(this.currentWindow){this.closeWindow();}var L=false,G=null,F=false;switch(M.keyCode){case this._keyMap.FOCUS_TOOLBAR.key:if(this._checkKey(this._keyMap.FOCUS_TOOLBAR,M)){var H=this.toolbar.getElementsByTagName("h2")[0];if(H&&H.firstChild){H.firstChild.focus();}}else{if(this._checkKey(this._keyMap.FOCUS_AFTER,M)){this.afterElement.focus();}}A.stopEvent(M);L=false;break;case this._keyMap.CREATE_LINK.key:if(this._hasSelection()){if(this._checkKey(this._keyMap.CREATE_LINK,M)){var E=true; +if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("createlink")){E=false;}}if(E){this.execCommand("createlink","");this.toolbar.fireEvent("createlinkClick",{type:"createlinkClick",target:this.toolbar});this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});L=false;}}}break;case this._keyMap.UNDO.key:case this._keyMap.REDO.key:if(this._checkKey(this._keyMap.REDO,M)){G="redo";L=true;}else{if(this._checkKey(this._keyMap.UNDO,M)){G="undo";L=true;}}break;case this._keyMap.BOLD.key:if(this._checkKey(this._keyMap.BOLD,M)){G="bold";L=true;}break;case this._keyMap.ITALIC.key:if(this._checkKey(this._keyMap.ITALIC,M)){G="italic";L=true;}break;case this._keyMap.UNDERLINE.key:if(this._checkKey(this._keyMap.UNDERLINE,M)){G="underline";L=true;}break;case 9:if(this.browser.ie){K=this._getRange();I=this._getSelectedElement();if(!this._isElement(I,"li")){if(K){K.pasteHTML("    ");K.collapse(false);K.select();}A.stopEvent(M);}}if(this.browser.gecko>1.8){I=this._getSelectedElement();if(this._isElement(I,"li")){if(M.shiftKey){this._getDoc().execCommand("outdent",null,"");}else{this._getDoc().execCommand("indent",null,"");}}else{if(!this._hasSelection()){this.execCommand("inserthtml","    ");}}A.stopEvent(M);}break;case 13:if(this.get("ptags")&&!M.shiftKey){if(this.browser.gecko){I=this._getSelectedElement();if(!this._isElement(I,"li")){L=true;G="insertparagraph";A.stopEvent(M);}}if(this.browser.webkit){I=this._getSelectedElement();if(!this._hasParent(I,"li")){L=true;G="insertparagraph";A.stopEvent(M);}}}else{if(this.browser.ie){K=this._getRange();I=this._getSelectedElement();if(!this._isElement(I,"li")){if(K){K.pasteHTML("
                  ");K.collapse(false);K.select();}A.stopEvent(M);}}}break;}if(this.browser.ie){this._listFix(M);}if(L&&G){this.execCommand(G,null);A.stopEvent(M);this.nodeChange();}this.fireEvent("editorKeyDown",{type:"editorKeyDown",target:this,ev:M});},_listFix:function(K){var M=null,I=null,E=false,G=null;if(this.browser.webkit){if(K.keyCode&&(K.keyCode==13)){if(this._hasParent(this._getSelectedElement(),"li")){var H=this._hasParent(this._getSelectedElement(),"li");if(H.previousSibling){if(H.firstChild&&(H.firstChild.length==1)){this._selectNode(H);}}}}}if(K.keyCode&&((!this.browser.webkit3&&(K.keyCode==25))||((this.browser.webkit3||!this.browser.webkit)&&((K.keyCode==9)&&K.shiftKey)))){M=this._getSelectedElement();if(this._hasParent(M,"li")){M=this._hasParent(M,"li");if(this._hasParent(M,"ul")||this._hasParent(M,"ol")){I=this._hasParent(M,"ul");if(!I){I=this._hasParent(M,"ol");}if(this._isElement(I.previousSibling,"li")){I.removeChild(M);I.parentNode.insertBefore(M,I.nextSibling);if(this.browser.ie){G=this._getDoc().body.createTextRange();G.moveToElementText(M);G.collapse(false);G.select();}if(this.browser.webkit){this._selectNode(M.firstChild);}A.stopEvent(K);}}}}if(K.keyCode&&((K.keyCode==9)&&(!K.shiftKey))){var F=this._getSelectedElement();if(this._hasParent(F,"li")){E=this._hasParent(F,"li").innerHTML;}if(this.browser.webkit){this._getDoc().execCommand("inserttext",false,"\t");}M=this._getSelectedElement();if(this._hasParent(M,"li")){I=this._hasParent(M,"li");var J=this._getDoc().createElement(I.parentNode.tagName.toLowerCase());if(this.browser.webkit){var L=C.getElementsByClassName("Apple-tab-span","span",I);if(L[0]){I.removeChild(L[0]);I.innerHTML=D.trim(I.innerHTML);if(E){I.innerHTML=''+E+" ";}else{I.innerHTML='  ';}}}else{if(E){I.innerHTML=E+" ";}else{I.innerHTML=" ";}}I.parentNode.replaceChild(J,I);J.appendChild(I);if(this.browser.webkit){this._getSelection().setBaseAndExtent(I.firstChild,1,I.firstChild,I.firstChild.innerText.length);if(!this.browser.webkit3){I.parentNode.parentNode.style.display="list-item";setTimeout(function(){I.parentNode.parentNode.style.display="block";},1);}}else{if(this.browser.ie){G=this._getDoc().body.createTextRange();G.moveToElementText(I);G.collapse(false);G.select();}else{this._selectNode(I);}}A.stopEvent(K);}if(this.browser.webkit){A.stopEvent(K);}this.nodeChange();}},nodeChange:function(E){var F=this;this._storeUndo();if(this.get("nodeChangeDelay")){window.setTimeout(function(){F._nodeChange.apply(F,arguments);},0);}else{this._nodeChange();}},_nodeChange:function(F){var H=parseInt(this.get("nodeChangeThreshold"),10),O=Math.round(new Date().getTime()/1000),R=this;if(F===true){this._lastNodeChange=0;}if((this._lastNodeChange+H)0){for(var V=0;V'+Y+"");this._updateMenuChecked("fontname",Y);}if(L){L.set("label",L._configs.label._initialConfig.value);}var K=this.toolbar.getButtonByValue("heading");if(K){K.set("label",K._configs.label._initialConfig.value);this._updateMenuChecked("heading","none");}var I=this.toolbar.getButtonByValue("insertimage");if(I&&this.currentWindow&&(this.currentWindow.name=="insertimage")){this.toolbar.disableButton(I);}if(this._lastButton&&this._lastButton.isSelected){this.toolbar.deselectButton(this._lastButton.id);}this._undoNodeChange();}}this.fireEvent("afterNodeChange",{type:"afterNodeChange",target:this});},_updateMenuChecked:function(E,F,H){if(!H){H=this.toolbar;}var G=H.getButtonByValue(E);G.checkValue(F);},_handleToolbarClick:function(F){var H="";var I="";var G=F.button.value;if(F.button.menucmd){H=G;G=F.button.menucmd;}this._lastButton=F.button;if(this.STOP_EXEC_COMMAND){this.STOP_EXEC_COMMAND=false;return false;}else{this.execCommand(G,H);if(!this.browser.webkit){var E=this;setTimeout(function(){E._focusWindow.call(E);},5);}}A.stopEvent(F);},_setupAfterElement:function(){if(!this.beforeElement){this.beforeElement=document.createElement("h2");this.beforeElement.className="yui-editor-skipheader";this.beforeElement.tabIndex="-1";this.beforeElement.innerHTML=this.STR_BEFORE_EDITOR;this.get("element_cont").get("firstChild").insertBefore(this.beforeElement,this.toolbar.get("nextSibling"));}if(!this.afterElement){this.afterElement=document.createElement("h2");this.afterElement.className="yui-editor-skipheader";this.afterElement.tabIndex="-1";this.afterElement.innerHTML=this.STR_LEAVE_EDITOR;this.get("element_cont").get("firstChild").appendChild(this.afterElement);}},_disableEditor:function(F){if(F){this._removeEditorEvents();if(!this._mask){if(!!this.browser.ie){this._setDesignMode("off");}if(this.toolbar){this.toolbar.set("disabled",true);}this._mask=document.createElement("DIV");C.setStyle(this._mask,"height","100%");C.setStyle(this._mask,"width","100%");C.setStyle(this._mask,"position","absolute");C.setStyle(this._mask,"top","0");C.setStyle(this._mask,"left","0");C.setStyle(this._mask,"opacity",".5");C.addClass(this._mask,"yui-editor-masked");this.get("iframe").get("parentNode").appendChild(this._mask);}}else{this._initEditorEvents();if(this._mask){this._mask.parentNode.removeChild(this._mask);this._mask=null;if(this.toolbar){this.toolbar.set("disabled",false);}this._setDesignMode("on");this._focusWindow();var E=this;window.setTimeout(function(){E.nodeChange.call(E);},100);}}},SEP_DOMPATH:"<",STR_LEAVE_EDITOR:"You have left the Rich Text Editor.",STR_BEFORE_EDITOR:"This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Shift + Escape to place focus on the toolbar and navigate between options with your arrow keys. To exit this text editor use the Escape key and continue tabbing.

                  Common formatting keyboard shortcuts:

                  • Control Shift B sets text to bold
                  • Control Shift I sets text to italic
                  • Control Shift U underlines text
                  • Control Shift L adds an HTML link
                  ",STR_TITLE:"Rich Text Area.",STR_IMAGE_HERE:"Image URL Here",STR_LINK_URL:"Link URL",STOP_EXEC_COMMAND:false,STOP_NODE_CHANGE:false,CLASS_NOEDIT:"yui-noedit",CLASS_CONTAINER:"yui-editor-container",CLASS_EDITABLE:"yui-editor-editable",CLASS_EDITABLE_CONT:"yui-editor-editable-container",CLASS_PREFIX:"yui-editor",browser:function(){var E=YAHOO.env.ua;if(E.webkit>=420){E.webkit3=E.webkit;}else{E.webkit3=0;}E.mac=false;if(navigator.userAgent.indexOf("Macintosh")!==-1){E.mac=true;}return E;}(),init:function(F,E){if(!this._defaultToolbar){this._defaultToolbar={collapse:true,titlebar:"Text Editing Tools",draggable:false,buttons:[{group:"fontstyle",label:"Font Name and Size",buttons:[{type:"select",label:"Arial",value:"fontname",disabled:true,menu:[{text:"Arial",checked:true},{text:"Arial Black"},{text:"Comic Sans MS"},{text:"Courier New"},{text:"Lucida Console"},{text:"Tahoma"},{text:"Times New Roman"},{text:"Trebuchet MS"},{text:"Verdana"}]},{type:"spin",label:"13",value:"fontsize",range:[9,75],disabled:true}]},{type:"separator"},{group:"textstyle",label:"Font Style",buttons:[{type:"push",label:"Bold CTRL + SHIFT + B",value:"bold"},{type:"push",label:"Italic CTRL + SHIFT + I",value:"italic"},{type:"push",label:"Underline CTRL + SHIFT + U",value:"underline"},{type:"push",label:"Strike Through",value:"strikethrough"},{type:"separator"},{type:"color",label:"Font Color",value:"forecolor",disabled:true},{type:"color",label:"Background Color",value:"backcolor",disabled:true}]},{type:"separator"},{group:"indentlist",label:"Lists",buttons:[{type:"push",label:"Create an Unordered List",value:"insertunorderedlist"},{type:"push",label:"Create an Ordered List",value:"insertorderedlist"}]},{type:"separator"},{group:"insertitem",label:"Insert Item",buttons:[{type:"push",label:"HTML Link CTRL + SHIFT + L",value:"createlink",disabled:true},{type:"push",label:"Insert Image",value:"insertimage"}]}]}; +}YAHOO.widget.SimpleEditor.superclass.init.call(this,F,E);YAHOO.widget.EditorInfo._instances[this.get("id")]=this;this.currentElement=[];this.on("contentReady",function(){this.DOMReady=true;this.fireQueue();},this,true);},initAttributes:function(E){YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this,E);var F=this;this.setAttributeConfig("nodeChangeDelay",{value:((E.nodeChangeDelay===false)?false:true)});this.setAttributeConfig("maxUndo",{writeOnce:true,value:E.maxUndo||30});this.setAttributeConfig("ptags",{writeOnce:true,value:E.ptags||false});this.setAttributeConfig("insert",{writeOnce:true,value:E.insert||false,method:function(K){if(K){var J={fontname:true,fontsize:true,forecolor:true,backcolor:true};var I=this._defaultToolbar.buttons;for(var H=0;H{TITLE}{CONTENT}',writeOnce:true});this.setAttributeConfig("extracss",{value:E.extracss||"",writeOnce:true});this.setAttributeConfig("handleSubmit",{value:E.handleSubmit||false,method:function(G){if(this.get("element").form){if(!this._formButtons){this._formButtons=[];}if(G){A.on(this.get("element").form,"submit",this._handleFormSubmit,this,true);var H=this.get("element").form.getElementsByTagName("input");for(var J=0;J=parseInt(this.get("height"),10))){C.setStyle(this.get("editor_wrapper"),"height",G+"px");if(this.browser.ie){this.get("iframe").setStyle("height","99%");this.get("iframe").setStyle("zoom","1");var H=this;window.setTimeout(function(){H.get("iframe").setStyle("height","100%");},1);}}},_formButtons:null,_formButtonClicked:null,_handleFormButtonClick:function(F){var E=A.getTarget(F);this._formButtonClicked=E;},_handleFormSubmit:function(H){this.saveHTML();var G=this.get("element").form,E=this._formButtonClicked||false;A.removeListener(G,"submit",this._handleFormSubmit);if(YAHOO.env.ua.ie){if(E&&!E.disabled){E.click();}}else{if(E&&!E.disabled){E.click();}var F=document.createEvent("HTMLEvents");F.initEvent("submit",true,true);G.dispatchEvent(F);if(YAHOO.env.ua.webkit){if(YAHOO.lang.isFunction(G.submit)){G.submit();}}}},_handleFontSize:function(G){var E=this.toolbar.getButtonById(G.button.id);var F=E.get("label")+"px";this.execCommand("fontsize",F);this.STOP_EXEC_COMMAND=true;},_handleColorPicker:function(G){var F=G.button;var E="#"+G.color;if((F=="forecolor")||(F=="backcolor")){this.execCommand(F,E);}},_handleAlign:function(H){var G=null;for(var E=0;E'+H+"";if(J.get("label")!=N){J.set("label",N);this._updateMenuChecked("fontname",H);}}if(K){M=parseInt(C.getStyle(L,"fontSize"),10);if((M===null)||isNaN(M)){M=K._configs.label._initialConfig.value;}K.set("label",""+M);}if(!this._isElement(L,"body")&&!this._isElement(L,"img")){this.toolbar.enableButton(J);this.toolbar.enableButton(K);this.toolbar.enableButton("forecolor");this.toolbar.enableButton("backcolor");}if(this._isElement(L,"img")){if(YAHOO.widget.Overlay){this.toolbar.enableButton("createlink");}}if(this._hasParent(L,"blockquote")){this.toolbar.selectButton("indent");this.toolbar.disableButton("indent");this.toolbar.enableButton("outdent");}if(this._hasParent(L,"ol")||this._hasParent(L,"ul")){this.toolbar.disableButton("indent");}this._lastButton=null;},_handleInsertImageClick:function(){if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("insertimage")){return false;}}this.toolbar.set("disabled",true);this.on("afterExecCommand",function(){var E=this.currentElement[0],G="http://";if(!E){E=this._getSelectedElement();}if(E){if(E.getAttribute("src")){G=E.getAttribute("src",2);if(G.indexOf(this.get("blankimage"))!=-1){G=this.STR_IMAGE_HERE;}}}var F=prompt(this.STR_LINK_URL+": ",G);if((F!=="")&&(F!==null)){E.setAttribute("src",F);}else{if(F===null){E.parentNode.removeChild(E);this.currentElement=[];this.nodeChange();}}this.closeWindow();this.toolbar.set("disabled",false);},this,true);},_handleInsertImageWindowClose:function(){this.nodeChange();},_isLocalFile:function(E){if((E)&&(E!=="")&&((E.indexOf("file:/")!=-1)||(E.indexOf(":\\")!=-1))){return true;}return false;},_handleCreateLinkClick:function(){if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue("createlink")){return false;}}this.toolbar.set("disabled",true);this.on("afterExecCommand",function(){var G=this.currentElement[0],F="";if(G){if(G.getAttribute("href",2)!==null){F=G.getAttribute("href",2);}}var I=prompt(this.STR_LINK_URL+": ",F);if((I!=="")&&(I!==null)){var H=I;if((H.indexOf(":/"+"/")==-1)&&(H.substring(0,1)!="/")&&(H.substring(0,6).toLowerCase()!="mailto")){if((H.indexOf("@")!=-1)&&(H.substring(0,6).toLowerCase()!="mailto")){H="mailto:"+H;}else{if(H.substring(0,1)!="#"){}}}G.setAttribute("href",H);}else{if(I!==null){var E=this._getDoc().createElement("span");E.innerHTML=G.innerHTML;C.addClass(E,"yui-non");G.parentNode.replaceChild(E,G);}}this.closeWindow();this.toolbar.set("disabled",false);},this);},_handleCreateLinkWindowClose:function(){this.nodeChange();this.currentElement=[]; +},render:function(){if(this._rendered){return false;}if(!this.DOMReady){this._queue[this._queue.length]=["render",arguments];return false;}if(this.get("element")){if(this.get("element").tagName){this._textarea=true;if(this.get("element").tagName.toLowerCase()!=="textarea"){this._textarea=false;}}else{return false;}}else{return false;}this._rendered=true;var E=this;window.setTimeout(function(){E._render.call(E);},4);},_render:function(){var E=this;this.set("textarea",this.get("element"));this.get("element_cont").setStyle("display","none");this.get("element_cont").addClass(this.CLASS_CONTAINER);this.set("iframe",this._createIframe());window.setTimeout(function(){E._setInitialContent.call(E);},10);this.get("editor_wrapper").appendChild(this.get("iframe").get("element"));if(this.get("disabled")){this._disableEditor(true);}var F=this.get("toolbar");if(F instanceof B){this.toolbar=F;this.toolbar.set("disabled",true);}else{F.disabled=true;this.toolbar=new B(this.get("toolbar_cont"),F);}this.fireEvent("toolbarLoaded",{type:"toolbarLoaded",target:this.toolbar});this.toolbar.on("toolbarCollapsed",function(){if(this.currentWindow){this.moveWindow();}},this,true);this.toolbar.on("toolbarExpanded",function(){if(this.currentWindow){this.moveWindow();}},this,true);this.toolbar.on("fontsizeClick",this._handleFontSize,this,true);this.toolbar.on("colorPickerClicked",function(G){this._handleColorPicker(G);return false;},this,true);this.toolbar.on("alignClick",this._handleAlign,this,true);this.on("afterNodeChange",this._handleAfterNodeChange,this,true);this.toolbar.on("insertimageClick",this._handleInsertImageClick,this,true);this.on("windowinsertimageClose",this._handleInsertImageWindowClose,this,true);this.toolbar.on("createlinkClick",this._handleCreateLinkClick,this,true);this.on("windowcreatelinkClose",this._handleCreateLinkWindowClose,this,true);this.get("parentNode").replaceChild(this.get("element_cont").get("element"),this.get("element"));this.setStyle("visibility","hidden");this.setStyle("position","absolute");this.setStyle("top","-9999px");this.setStyle("left","-9999px");this.get("element_cont").appendChild(this.get("element"));this.get("element_cont").setStyle("display","block");C.addClass(this.get("iframe").get("parentNode"),this.CLASS_EDITABLE_CONT);this.get("iframe").addClass(this.CLASS_EDITABLE);this.get("element_cont").setStyle("width",this.get("width"));C.setStyle(this.get("iframe").get("parentNode"),"height",this.get("height"));this.get("iframe").setStyle("width","100%");this.get("iframe").setStyle("height","100%");this._setupDD();window.setTimeout(function(){E._setupAfterElement.call(E);},0);this.fireEvent("afterRender",{type:"afterRender",target:this});},execCommand:function(G,F){var J=this.fireEvent("beforeExecCommand",{type:"beforeExecCommand",target:this,args:arguments});if((J===false)||(this.STOP_EXEC_COMMAND)){this.STOP_EXEC_COMMAND=false;return false;}this._lastCommand=G;this._setMarkupType(G);if(this.browser.ie){this._getWindow().focus();}var E=true;if(this.get("limitCommands")){if(!this.toolbar.getButtonByValue(G)){E=false;}}this.editorDirty=true;if((typeof this["cmd_"+G.toLowerCase()]=="function")&&E){var I=this["cmd_"+G.toLowerCase()](F);E=I[0];if(I[1]){G=I[1];}if(I[2]){F=I[2];}}if(E){try{this._getDoc().execCommand(G,false,F);}catch(H){}}else{}this.on("afterExecCommand",function(){this.unsubscribeAll("afterExecCommand");this.nodeChange();},this,true);this.fireEvent("afterExecCommand",{type:"afterExecCommand",target:this});},cmd_underline:function(F){if(!this.browser.webkit){var E=this._getSelectedElement();if(E&&this._isElement(E,"span")){if(E.style.textDecoration=="underline"){E.style.textDecoration="none";}else{E.style.textDecoration="underline";}return[false];}}return[true];},cmd_backcolor:function(H){var E=true,F=this._getSelectedElement(),G="backcolor";if(this.browser.gecko||this.browser.opera){this._setEditorStyle(true);G="hilitecolor";}if(!this._isElement(F,"body")&&!this._hasSelection()){C.setStyle(F,"background-color",H);this._selectNode(F);E=false;}else{if(!this._isElement(F,"body")&&this._hasSelection()){C.setStyle(F,"background-color",H);this._selectNode(F);E=false;}else{if(this.get("insert")){F=this._createInsertElement({backgroundColor:H});}else{this._createCurrentElement("span",{backgroundColor:H});this._selectNode(this.currentElement[0]);}E=false;}}return[E,G];},cmd_forecolor:function(G){var E=true,F=this._getSelectedElement();if(!this._isElement(F,"body")&&!this._hasSelection()){C.setStyle(F,"color",G);this._selectNode(F);E=false;}else{if(!this._isElement(F,"body")&&this._hasSelection()){C.setStyle(F,"color",G);this._selectNode(F);E=false;}else{if(this.get("insert")){F=this._createInsertElement({color:G});}else{this._createCurrentElement("span",{color:G});this._selectNode(this.currentElement[0]);}E=false;}}return[E];},cmd_unlink:function(E){this._swapEl(this.currentElement[0],"span",function(F){F.className="yui-non";});return[false];},cmd_createlink:function(G){var F=this._getSelectedElement(),E=null;if(this._hasParent(F,"a")){this.currentElement[0]=this._hasParent(F,"a");}else{if(!this._isElement(F,"a")){this._createCurrentElement("a");E=this._swapEl(this.currentElement[0],"a");this.currentElement[0]=E;}else{this.currentElement[0]=F;}}return[false];},cmd_insertimage:function(J){var E=true,F=null,I="insertimage",H=this._getSelectedElement();if(J===""){J=this.get("blankimage");}if(this._isElement(H,"img")){this.currentElement[0]=H;E=false;}else{if(this._getDoc().queryCommandEnabled(I)){this._getDoc().execCommand("insertimage",false,J);var K=this._getDoc().getElementsByTagName("img");for(var G=0;G"+F[M].innerHTML+"
                  ";}V.innerHTML=R;this.currentElement[0]=G;this.currentElement[0].parentNode.replaceChild(V,this.currentElement[0]);}else{this._createCurrentElement(Y.toLowerCase());V=this._getDoc().createElement(Y);for(M=0;M 
                   ';V.appendChild(J);if(M>0){this.currentElement[M].parentNode.removeChild(this.currentElement[M]);}}this.currentElement[0].parentNode.replaceChild(V,this.currentElement[0]);this.currentElement[0]=V;var H=this.currentElement[0].firstChild;H=C.getElementsByClassName("yui-non","span",H)[0];this._getSelection().setBaseAndExtent(H,1,H,H.innerText.length);}S=false;}else{G=this._getSelectedElement();if(this._isElement(G,"li")&&this._isElement(G.parentNode,Y)||(this.browser.ie&&this._isElement(this._getRange().parentElement,"li"))||(this.browser.ie&&this._isElement(G,"ul"))||(this.browser.ie&&this._isElement(G,"ol"))){if(this.browser.ie){if((this.browser.ie&&this._isElement(G,"ul"))||(this.browser.ie&&this._isElement(G,"ol"))){G=G.getElementsByTagName("li")[0];}R="";var I=G.parentNode.getElementsByTagName("li");for(var U=0;U";}var X=this._getDoc().createElement("span");X.innerHTML=R;G.parentNode.parentNode.replaceChild(X,G.parentNode);}else{this.nodeChange();this._getDoc().execCommand(T,"",G.parentNode);this.nodeChange();}S=false;}if(this.browser.opera){var Q=this;window.setTimeout(function(){var Z=Q._getDoc().getElementsByTagName("li");for(var a=0;a"){Z[a].parentNode.parentNode.removeChild(Z[a].parentNode);}}},30);}if(this.browser.ie&&S){var K="";if(this._getRange().html){K="
                • "+this._getRange().html+"
                • ";}else{var L=this._getRange().text.split("\n");if(L.length>1){K="";for(var P=0;P"+L[P]+"";}}else{var O=this._getRange().text;if(O===""){K='
                • '+O+"
                • ";}else{K="
                • "+O+"
                • ";}}}this._getRange().pasteHTML("<"+Y+">"+K+"");var E=this._getDoc().getElementById("new_list_item");if(E){var N=this._getDoc().body.createTextRange();N.moveToElementText(E);N.collapse(false);N.select();E.id="";}S=false;}}return S;},cmd_insertorderedlist:function(E){return[this.cmd_list("ol")];},cmd_insertunorderedlist:function(E){return[this.cmd_list("ul")];},cmd_fontname:function(H){var E=true,G=this._getSelectedElement();this.currentFont=H;if(G&&G.tagName&&!this._hasSelection()&&!this._isElement(G,"body")&&!this.get("insert")){YAHOO.util.Dom.setStyle(G,"font-family",H);E=false;}else{if(this.get("insert")&&!this._hasSelection()){var F=this._createInsertElement({fontFamily:H});E=false;}}return[E];},cmd_fontsize:function(G){var E=null;if(this.currentElement&&(this.currentElement.length>0)&&(!this._hasSelection())&&(!this.get("insert"))){YAHOO.util.Dom.setStyle(this.currentElement,"fontSize",G);}else{if(!this._isElement(this._getSelectedElement(),"body")){E=this._getSelectedElement();YAHOO.util.Dom.setStyle(E,"fontSize",G);if(this.get("insert")&&this.browser.ie){var F=this._getRange();F.collapse(false);F.select();}else{this._selectNode(E);}}else{if(this.get("insert")&&!this._hasSelection()){E=this._createInsertElement({fontSize:G});this.currentElement[0]=E;this._selectNode(this.currentElement[0]);}else{this._createCurrentElement("span",{"fontSize":G});this._selectNode(this.currentElement[0]);}}}return[false];},_swapEl:function(F,E,H){var G=this._getDoc().createElement(E);if(F){G.innerHTML=F.innerHTML;}if(typeof H=="function"){H.call(this,G);}if(F){F.parentNode.replaceChild(G,F);}return G;},_createInsertElement:function(E){this._createCurrentElement("span",E);var F=this.currentElement[0];if(this.browser.webkit){F.innerHTML=' ';F=F.firstChild;this._getSelection().setBaseAndExtent(F,1,F,F.innerText.length);}else{if(this.browser.ie||this.browser.opera){F.innerHTML=" ";}}this._focusWindow();this._selectNode(F,true);return F;},_createCurrentElement:function(G,J){G=((G)?G:"a");var R=null,F=[],H=this._getDoc();if(this.currentFont){if(!J){J={};}J.fontFamily=this.currentFont;this.currentFont=null;}this.currentElement=[];var M=function(X,Z){var Y=null;X=((X)?X:"span");X=X.toLowerCase();switch(X){case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":Y=H.createElement(X);break;default:Y=H.createElement(X);if(X==="span"){YAHOO.util.Dom.addClass(Y,"yui-tag-"+X);YAHOO.util.Dom.addClass(Y,"yui-tag");Y.setAttribute("tag",X);}for(var W in Z){if(YAHOO.lang.hasOwnProperty(Z,W)){Y.style[W]=Z[W];}}break;}return Y;};if(!this._hasSelection()){if(this._getDoc().queryCommandEnabled("insertimage")){this._getDoc().execCommand("insertimage",false,"yui-tmp-img");var L=this._getDoc().getElementsByTagName("img");for(var Q=0;Q]*)>/gi,"");E=E.replace(/<\/strong>/gi,"
                  ");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/embed>/gi,"");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/em>/gi,"
                  ");E=E.replace(/]*)>/gi,"");E=E.replace(/<\/YUI_EMBED>/gi,"");if(this.get("plainText")){E=E.replace(/\n/g,"
                  ").replace(/\r/g,"
                  ");E=E.replace(/ /gi,"  ");E=E.replace(/\t/gi,"    ");}E=E.replace(/]*)>/gi,"");E=E.replace(/<\/script([^>]*)>/gi,"");E=E.replace(/<script([^>]*)>/gi,"");E=E.replace(/<\/script([^>]*)>/gi,"");E=E.replace(/\n/g,"").replace(/\r/g,"");E=E.replace(new RegExp("]*)>(.*?)","gi"),"");E=E.replace(//g,"\n");return E;},cleanHTML:function(G){if(!G){G=this.getEditorHTML();}var F=this.get("markup");G=this.pre_filter_linebreaks(G,F);G=G.replace(/]*)\/>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/]*)\/>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/ul>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/blockquote>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/embed>/gi,"");if((F=="semantic")||(F=="xhtml")){G=G.replace(/]*)?>/gi,"");G=G.replace(/<\/i>/gi,"");G=G.replace(/]*)?>/gi,"");G=G.replace(/<\/b>/gi,"");}G=G.replace(//gi,"");G=G.replace(//gi,"");if((F=="semantic")||(F=="xhtml")||(F=="css")){G=G.replace(new RegExp(']*)face="([^>]*)">(.*?)',"gi"),'$3');G=G.replace(/([^>]*)',"gi"),"$1");G=G.replace(new RegExp('([^>]*)',"gi"),"$1");}G=G.replace(/\/u>/gi,"/span>");if(F=="css"){G=G.replace(/]*)>/gi,"");G=G.replace(/<\/em>/gi,"");G=G.replace(/]*)>/gi,"");G=G.replace(/<\/strong>/gi,"");G=G.replace(//gi,"/span>");G=G.replace(//gi,"/span>");}G=G.replace(/ /gi," ");}else{G=G.replace(//gi,"/u>");}G=G.replace(/]*)>/gi,"");G=G.replace(/\/ol>/gi,"/ol>");G=G.replace(/
                • /gi,"/li>");G=this.filter_safari(G);G=this.filter_internals(G);G=this.filter_all_rgb(G);G=this.post_filter_linebreaks(G,F);if(F=="xhtml"){G=G.replace(/]*)>/g,"");G=G.replace(/]*)>/g,"");}else{G=G.replace(/]*)>/g,"");G=G.replace(/]*)>/g,"");}G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_UL>/g,"
                ");G=this.filter_invalid_lists(G);G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_BQ>/g,"");G=G.replace(/]*)>/g,"");G=G.replace(/<\/YUI_EMBED>/g,"");G=G.replace(" & ","YUI_AMP");G=G.replace("&","&");G=G.replace("YUI_AMP","&");G=YAHOO.lang.trim(G);if(this.get("removeLineBreaks")){G=G.replace(/\n/g,"").replace(/\r/g,"");G=G.replace(/ /gi," ");}if(G.substring(0,6).toLowerCase()==""){G=G.substring(6);if(G.substring(G.length-7,G.length).toLowerCase()==""){G=G.substring(0,G.length-7);}}for(var E in this.invalidHTML){if(YAHOO.lang.hasOwnProperty(this.invalidHTML,E)){if(D.isObject(E)&&E.keepContents){G=G.replace(new RegExp("<"+E+"([^>]*)>(.*?)","gi"),"$1");}else{G=G.replace(new RegExp("<"+E+"([^>]*)>(.*?)","gi"),"");}}}this.fireEvent("cleanHTML",{type:"cleanHTML",target:this,html:G});return G;},filter_invalid_lists:function(E){E=E.replace(/<\/li>\n/gi,"");E=E.replace(/<\/li>
                  /gi,"
                  1. ");E=E.replace(/<\/ol>/gi,"
                1. ");E=E.replace(/<\/ol><\/li>\n/gi,"
                \n");E=E.replace(/<\/li>
                  /gi,"
                  • ");E=E.replace(/<\/ul>/gi,"
                • ");E=E.replace(/<\/ul><\/li>\n?/gi,"
                \n");E=E.replace(/<\/li>/gi,"\n");E=E.replace(/<\/ol>/gi,"
            \n");E=E.replace(/
              /gi,"
                \n");E=E.replace(/
                  /gi,"
                    \n");return E;},filter_safari:function(E){if(this.browser.webkit){E=E.replace(/([^>])<\/span>/gi,"    ");E=E.replace(/Apple-style-span/gi,"");E=E.replace(/style="line-height: normal;"/gi,"");E=E.replace(/
                  • <\/li>/gi,"");E=E.replace(/
                  • <\/li>/gi,"");E=E.replace(/
                  • <\/li>/gi,"");if(this.get("ptags")){E=E.replace(/]*)>/g,"");E=E.replace(/<\/div>/gi,"

                    ");}else{E=E.replace(/
                    /gi,"");E=E.replace(/<\/div>/gi,"
                    ");}}return E;},filter_internals:function(E){E=E.replace(/\r/g,"");E=E.replace(/<\/?(body|head|html)[^>]*>/gi,"");E=E.replace(/<\/li>/gi,"
                  • ");E=E.replace(/yui-tag-span/gi,"");E=E.replace(/yui-tag/gi,"");E=E.replace(/yui-non/gi,"");E=E.replace(/yui-img/gi,"");E=E.replace(/ tag="span"/gi,"");E=E.replace(/ class=""/gi,"");E=E.replace(/ style=""/gi,"");E=E.replace(/ class=" "/gi,"");E=E.replace(/ class=" "/gi,"");E=E.replace(/ target=""/gi,"");E=E.replace(/ title=""/gi,"");if(this.browser.ie){E=E.replace(/ class= /gi,"");E=E.replace(/ class= >/gi,"");E=E.replace(/_height="([^>])"/gi,"");E=E.replace(/_width="([^>])"/gi,"");}return E;},filter_all_rgb:function(I){var H=new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)","gi");var E=I.match(H);if(D.isArray(E)){for(var G=0;G/gi,"");F=F.replace(/
                    /gi,"");}F=F.replace(/
                    /gi,"");F=F.replace(/
                    /gi,"");F=F.replace(//gi,"");F=F.replace(/
                    /gi,"");F=F.replace(/
                    <\/div>/gi,"");F=F.replace(/

                    ( | )<\/p>/g,"");F=F.replace(/


                     <\/p>/gi,"");F=F.replace(/

                     <\/p>/gi,"");F=F.replace(/$/,"");F=F.replace(/<\/p>/g,"

                    ");if(this.browser.ie){F=F.replace(/    /g,"\t");}return F;},post_filter_linebreaks:function(F,E){if(E=="xhtml"){F=F.replace(//g,"
                    ");}else{F=F.replace(//g,"
                    ");}return F;},clearEditorDoc:function(){this._getDoc().body.innerHTML=" ";},openWindow:function(E){},moveWindow:function(){},_closeWindow:function(){},closeWindow:function(){this.toolbar.resetAllButtons();this._focusWindow();},destroy:function(){if(this.resize){this.resize.destroy();}if(this.dd){this.dd.unreg();}if(this.get("panel")){this.get("panel").destroy();}this.saveHTML();this.toolbar.destroy();this.setStyle("visibility","visible");this.setStyle("position","static");this.setStyle("top","");this.setStyle("left","");var E=this.get("element");this.get("element_cont").get("parentNode").replaceChild(E,this.get("element_cont").get("element"));this.get("element_cont").get("element").innerHTML="";this.set("handleSubmit",false);return true;},toString:function(){var E="SimpleEditor";if(this.get&&this.get("element_cont")){E="SimpleEditor (#"+this.get("element_cont").get("id")+")"+((this.get("disabled")?" Disabled":""));}return E;}});YAHOO.widget.EditorInfo={_instances:{},blankImage:"",window:{},panel:null,getEditorById:function(E){if(!YAHOO.lang.isString(E)){E=E.id;}if(this._instances[E]){return this._instances[E];}return false;},toString:function(){var E=0;for(var F in this._instances){if(D.hasOwnProperty(this._instances,F)){E++;}}return"Editor Info ("+E+" registered intance"+((E>1)?"s":"")+")"; +}};})();YAHOO.register("simpleeditor",YAHOO.widget.SimpleEditor,{version:"2.6.0",build:"1321"}); \ No newline at end of file diff --git a/lib/yui/editor/simpleeditor.js b/lib/yui/editor/simpleeditor.js new file mode 100644 index 00000000000..07e83c6cb7e --- /dev/null +++ b/lib/yui/editor/simpleeditor.js @@ -0,0 +1,6890 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +(function() { + /** + * @private + **/ +var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang; + /** + * @description

                    Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

                    + * @class ToolbarButtonAdvanced + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event, container_core, menu, button + * @beta + * + * Provides a toolbar button based on the button and menu widgets. + * @constructor + * @param {String/HTMLElement} el The element to turn into a button. + * @param {Object} attrs Object liternal containing configuration parameters. + */ + if (YAHOO.widget.Button) { + YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button; + /** + * @property buttonType + * @private + * @description Tells if the Button is a Rich Button or a Simple Button + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich'; + /** + * @method checkValue + * @param {String} value The value of the option that we want to mark as selected + * @description Select an option by value + */ + YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) { + var _menuItems = this.getMenu().getItems(); + if (_menuItems.length === 0) { + this.getMenu()._onBeforeShow(); + _menuItems = this.getMenu().getItems(); + } + for (var i = 0; i < _menuItems.length; i++) { + _menuItems[i].cfg.setProperty('checked', false); + if (_menuItems[i].value == value) { + _menuItems[i].cfg.setProperty('checked', true); + } + } + }; + } else { + YAHOO.widget.ToolbarButtonAdvanced = function() {}; + } + + + /** + * @description

                    Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar

                    + * @class ToolbarButton + * @namespace YAHOO.widget + * @requires yahoo, dom, element, event + * @Extends YAHOO.util.Element + * @beta + * + * Provides a toolbar button based on the button and menu widgets, '); + } else { + html = html.replace(/]*)>/g, ''); + html = html.replace(/]*)>/g, ''); + } + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_UL>/g, '<\/ul>'); + + html = this.filter_invalid_lists(html); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>'); + + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>'); + + //This should fix &s in URL's + html = html.replace(' & ', 'YUI_AMP'); + html = html.replace('&', '&'); + html = html.replace('YUI_AMP', '&'); + + //Trim the output, removing whitespace from the beginning and end + html = YAHOO.lang.trim(html); + + if (this.get('removeLineBreaks')) { + html = html.replace(/\n/g, '').replace(/\r/g, ''); + html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single + } + + //First empty span + if (html.substring(0, 6).toLowerCase() == '') { + html = html.substring(6); + //Last empty span + if (html.substring(html.length - 7, html.length).toLowerCase() == '') { + html = html.substring(0, html.length - 7); + } + } + + for (var v in this.invalidHTML) { + if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) { + if (Lang.isObject(v) && v.keepContents) { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1'); + } else { + html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), ''); + } + } + } + + this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html }); + + return html; + }, + /** + * @method filter_invalid_lists + * @param String html The HTML string to filter + * @description Filters invalid ol and ul list markup, converts this:
                    1. ..
                    to this:
                    1. ..
                  • + */ + filter_invalid_lists: function(html) { + html = html.replace(/<\/li>\n/gi, ''); + + html = html.replace(/<\/li>
                      /gi, '
                      1. '); + html = html.replace(/<\/ol>/gi, '
                    1. '); + html = html.replace(/<\/ol><\/li>\n/gi, "
                    \n"); + + html = html.replace(/<\/li>
                      /gi, '
                      • '); + html = html.replace(/<\/ul>/gi, '
                    • '); + html = html.replace(/<\/ul><\/li>\n?/gi, "
                    \n"); + + html = html.replace(/<\/li>/gi, "\n"); + html = html.replace(/<\/ol>/gi, "
              \n"); + html = html.replace(/
                /gi, "
                  \n"); + html = html.replace(/
                    /gi, "
                      \n"); + return html; + }, + /** + * @method filter_safari + * @param String html The HTML string to filter + * @description Filters strings specific to Safari + * @return String + */ + filter_safari: function(html) { + if (this.browser.webkit) { + // + html = html.replace(/([^>])<\/span>/gi, '    '); + html = html.replace(/Apple-style-span/gi, ''); + html = html.replace(/style="line-height: normal;"/gi, ''); + //Remove bogus LI's + html = html.replace(/
                    • <\/li>/gi, ''); + html = html.replace(/
                    • <\/li>/gi, ''); + html = html.replace(/
                    • <\/li>/gi, ''); + //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break + if (this.get('ptags')) { + html = html.replace(/]*)>/g, ''); + html = html.replace(/<\/div>/gi, '

                      '); + } else { + html = html.replace(/
                      /gi, ''); + html = html.replace(/<\/div>/gi, '
                      '); + } + } + return html; + }, + /** + * @method filter_internals + * @param String html The HTML string to filter + * @description Filters internal RTE strings and bogus attrs we don't want + * @return String + */ + filter_internals: function(html) { + html = html.replace(/\r/g, ''); + //Fix stuff we don't want + html = html.replace(/<\/?(body|head|html)[^>]*>/gi, ''); + //Fix last BR in LI + html = html.replace(/<\/li>/gi, '
                    • '); + + html = html.replace(/yui-tag-span/gi, ''); + html = html.replace(/yui-tag/gi, ''); + html = html.replace(/yui-non/gi, ''); + html = html.replace(/yui-img/gi, ''); + html = html.replace(/ tag="span"/gi, ''); + html = html.replace(/ class=""/gi, ''); + html = html.replace(/ style=""/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ class=" "/gi, ''); + html = html.replace(/ target=""/gi, ''); + html = html.replace(/ title=""/gi, ''); + + if (this.browser.ie) { + html = html.replace(/ class= /gi, ''); + html = html.replace(/ class= >/gi, ''); + html = html.replace(/_height="([^>])"/gi, ''); + html = html.replace(/_width="([^>])"/gi, ''); + } + + return html; + }, + /** + * @method filter_all_rgb + * @param String str The HTML string to filter + * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00" + * @return String + */ + filter_all_rgb: function(str) { + var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi"); + var arr = str.match(exp); + if (Lang.isArray(arr)) { + for (var i = 0; i < arr.length; i++) { + var color = this.filter_rgb(arr[i]); + str = str.replace(arr[i].toString(), color); + } + } + + return str; + }, + /** + * @method filter_rgb + * @param String css The CSS string containing rgb(#,#,#); + * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00 + * @return String + */ + filter_rgb: function(css) { + if (css.toLowerCase().indexOf('rgb') != -1) { + var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi"); + var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(','); + + if (rgb.length == 5) { + var r = parseInt(rgb[1], 10).toString(16); + var g = parseInt(rgb[2], 10).toString(16); + var b = parseInt(rgb[3], 10).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + css = "#" + r + g + b; + } + } + return css; + }, + /** + * @method pre_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + pre_filter_linebreaks: function(html, markup) { + if (this.browser.webkit) { + html = html.replace(/
                      /gi, ''); + html = html.replace(/
                      /gi, ''); + } + html = html.replace(/
                      /gi, ''); + html = html.replace(/
                      /gi, ''); + html = html.replace(//gi, ''); + html = html.replace(/
                      /gi, ''); + html = html.replace(/
                      <\/div>/gi, ''); + html = html.replace(/

                      ( | )<\/p>/g, ''); + html = html.replace(/


                       <\/p>/gi, ''); + html = html.replace(/

                       <\/p>/gi, ''); + //Fix last BR + html = html.replace(/$/, ''); + //Fix last BR in P + html = html.replace(/<\/p>/g, '

                      '); + if (this.browser.ie) { + html = html.replace(/    /g, '\t'); + } + return html; + }, + /** + * @method post_filter_linebreaks + * @param String html The HTML to filter + * @param String markup The markup type to filter to + * @description HTML Pre Filter + * @return String + */ + post_filter_linebreaks: function(html, markup) { + if (markup == 'xhtml') { + html = html.replace(//g, '
                      '); + } else { + html = html.replace(//g, '
                      '); + } + return html; + }, + /** + * @method clearEditorDoc + * @description Clear the doc of the Editor + */ + clearEditorDoc: function() { + this._getDoc().body.innerHTML = ' '; + }, + /** + * @method openWindow + * @description Override Method for Advanced Editor + */ + openWindow: function(win) { + }, + /** + * @method moveWindow + * @description Override Method for Advanced Editor + */ + moveWindow: function() { + }, + /** + * @private + * @method _closeWindow + * @description Override Method for Advanced Editor + */ + _closeWindow: function() { + }, + /** + * @method closeWindow + * @description Override Method for Advanced Editor + */ + closeWindow: function() { + //this.unsubscribeAll('afterExecCommand'); + this.toolbar.resetAllButtons(); + this._focusWindow(); + }, + /** + * @method destroy + * @description Destroys the editor, all of it's elements and objects. + * @return {Boolean} + */ + destroy: function() { + if (this.resize) { + this.resize.destroy(); + } + if (this.dd) { + this.dd.unreg(); + } + if (this.get('panel')) { + this.get('panel').destroy(); + } + this.saveHTML(); + this.toolbar.destroy(); + this.setStyle('visibility', 'visible'); + this.setStyle('position', 'static'); + this.setStyle('top', ''); + this.setStyle('left', ''); + var textArea = this.get('element'); + this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element')); + this.get('element_cont').get('element').innerHTML = ''; + this.set('handleSubmit', false); //Remove the submit handler + return true; + }, + /** + * @method toString + * @description Returns a string representing the editor. + * @return {String} + */ + toString: function() { + var str = 'SimpleEditor'; + if (this.get && this.get('element_cont')) { + str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : '')); + } + return str; + } + }); + +/** +* @event toolbarLoaded +* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event cleanHTML +* @description Event is fired after the cleanHTML method is called. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterRender +* @description Event is fired after the render process finishes. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorContentLoaded +* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeNodeChange +* @description Event fires at the beginning of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterNodeChange +* @description Event fires at the end of the nodeChange process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeExecCommand +* @description Event fires at the beginning of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event afterExecCommand +* @description Event fires at the end of the execCommand process. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorClick +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event editorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Passed through HTML Event. See Element.addListener for more information on listening for this event. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorMouseDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorDoubleClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorClick +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyUp +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyPress +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ +/** +* @event beforeEditorKeyDown +* @param {Event} ev The DOM Event that occured +* @description Fires before editor event, returning false will stop the internal processing. +* @type YAHOO.util.CustomEvent +*/ + + + /** + * @description Singleton object used to track the open window objects and panels across the various open editors + * @class EditorInfo + * @static + */ + YAHOO.widget.EditorInfo = { + /** + * @private + * @property _instances + * @description A reference to all editors on the page. + * @type Object + */ + _instances: {}, + /** + * @private + * @property blankImage + * @description A reference to the blankImage url + * @type String + */ + blankImage: '', + /** + * @private + * @property window + * @description A reference to the currently open window object in any editor on the page. + * @type Object YAHOO.widget.EditorWindow + */ + window: {}, + /** + * @private + * @property panel + * @description A reference to the currently open panel in any editor on the page. + * @type Object YAHOO.widget.Overlay + */ + panel: null, + /** + * @method getEditorById + * @description Returns a reference to the Editor object associated with the given textarea + * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of + * @return Object YAHOO.widget.Editor + */ + getEditorById: function(id) { + if (!YAHOO.lang.isString(id)) { + //Not a string, assume a node Reference + id = id.id; + } + if (this._instances[id]) { + return this._instances[id]; + } + return false; + }, + /** + * @method toString + * @description Returns a string representing the EditorInfo. + * @return {String} + */ + toString: function() { + var len = 0; + for (var i in this._instances) { + if (Lang.hasOwnProperty(this._instances, i)) { + len++; + } + } + return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')'; + } + }; + + + + +})(); +YAHOO.register("simpleeditor", YAHOO.widget.SimpleEditor, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/profiler/profiler-debug.js b/lib/yui/profiler/profiler-debug.js new file mode 100644 index 00000000000..3dadf136e20 --- /dev/null +++ b/lib/yui/profiler/profiler-debug.js @@ -0,0 +1,380 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +YAHOO.namespace("tool"); + +/** + * The YUI JavaScript profiler. + * @module profiler + * @namespace YAHOO.tool + * @requires yahoo + */ + +/** + * Profiles functions in JavaScript. + * @namespace YAHOO.tool + * @class Profiler + * @static + */ +YAHOO.tool.Profiler = { + + //------------------------------------------------------------------------- + // Private Properties + //------------------------------------------------------------------------- + + /** + * Container object on which to put the original unprofiled methods. + * @type Object + * @private + * @static + * @property _container + */ + _container : new Object(), + + /** + * Call information for functions. + * @type Object + * @private + * @static + * @property _report + */ + _report : new Object(), + + //------------------------------------------------------------------------- + // Private Methods + //------------------------------------------------------------------------- + + /** + * Called when a method ends execution. Marks the start and end time of the + * method so it can calculate how long the function took to execute. Also + * updates min/max/avg calculations for the function. + * @param {String} name The name of the function to mark as stopped. + * @param {int} duration The number of milliseconds it took the function to + * execute. + * @return {Void} + * @private + * @static + */ + _saveData : function (name /*:String*/, duration /*:int*/){ + + //get the function data + var functionData /*:Object*/ = this._report[name]; + + //increment the calls + functionData.calls++; + functionData.points.push(duration); + + //if it's already been called at least once, do more complex calculations + if (functionData.calls > 1) { + functionData.avg = ((functionData.avg*(functionData.calls-1))+duration)/functionData.calls; + functionData.min = Math.min(functionData.min, duration); + functionData.max = Math.max(functionData.max, duration); + } else { + functionData.avg = duration; + functionData.min = duration; + functionData.max = duration; + } + + }, + + //------------------------------------------------------------------------- + // Reporting Methods + //------------------------------------------------------------------------- + + /** + * Returns the average amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The average time it takes the function to execute. + * @static + */ + getAverage : function (name /*:String*/) /*:float*/ { + return this._report[name].avg; + }, + + /** + * Returns the number of times that the given function has been called. + * @param {String} name The name of the function whose data should be returned. + * @return {int} The number of times the function was called. + * @static + */ + getCallCount : function (name /*:String*/) /*:int*/ { + return this._report[name].calls; + }, + + /** + * Returns the maximum amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The maximum time it takes the function to execute. + */ + getMax : function (name /*:String*/) /*:int*/ { + return this._report[name].max; + }, + + /** + * Returns the minimum amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The minimum time it takes the function to execute. + */ + getMin : function (name /*:String*/) /*:int*/ { + return this._report[name].min; + }, + + /** + * Returns an object containing profiling data for a single function. + * The object has an entry for min, max, avg, calls, and points). + * @return {Object} An object containing profile data for a given function. + * @static + */ + getFunctionReport : function (name /*:String*/) /*:Object*/ { + return this._report[name]; + }, + + /** + * Returns an object containing profiling data for all of the functions + * that were profiled. The object has an entry for each function and + * returns all information (min, max, average, calls, etc.) for each + * function. + * @return {Object} An object containing all profile data. + * @static + */ + getFullReport : function (filter /*:Function*/) /*:Object*/ { + filter = filter || function(){return true;}; + + if (YAHOO.lang.isFunction(filter)) { + var report = {}; + + for (var name in this._report){ + if (filter(this._report[name])){ + report[name] = this._report[name]; + } + } + + return report; + } + }, + + //------------------------------------------------------------------------- + // Profiling Methods + //------------------------------------------------------------------------- + + /** + * Sets up a constructor for profiling, including all properties and methods on the prototype. + * @param {string} name The fully-qualified name of the function including namespace information. + * @param {Object} owner (Optional) The object that owns the function (namespace or containing object). + * @return {Void} + * @static + */ + registerConstructor : function (name /*:String*/, owner /*:Object*/) /*:Void*/ { + this.registerFunction(name, owner, true); + }, + + /** + * Sets up a function for profiling. It essentially overwrites the function with one + * that has instrumentation data. This method also creates an entry for the function + * in the profile report. The original function is stored on the _container object. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @param {Object} owner (Optional) The object that owns the function. If the function + * isn't global then this argument is required. This could be the namespace that + * the function belongs to, such as YAHOO.util.Dom, or the object on which it's + * a method. + * @return {Void} + * @method registerFunction + */ + registerFunction : function(name /*:String*/, owner /*:Object*/, registerPrototype /*:Boolean*/) /*:Void*/{ + + //figure out the function name without namespacing + var funcName /*:String*/ = (name.indexOf(".") > -1 ? name.substring(name.lastIndexOf(".")+1) : name); + if (!YAHOO.lang.isObject(owner)){ + owner = eval(name.substring(0, name.lastIndexOf("."))); + } + + //get the method and prototype + var method /*:Function*/ = owner[funcName]; + var prototype /*:Object*/ = method.prototype; + + //see if the method has already been registered + if (YAHOO.lang.isFunction(method) && !method.__yuiProfiled){ + + //create a new slot for the original method + this._container[name] = method; + + //replace the function with the profiling one + owner[funcName] = function () { + + var start = new Date(); + var retval = method.apply(this, arguments); + var stop = new Date(); + + YAHOO.tool.Profiler._saveData(name, stop-start); + + return retval; + + }; + + //copy the function properties over + YAHOO.lang.augmentObject(owner[funcName], method); + owner[funcName].__yuiProfiled = true; + owner[funcName].prototype = prototype; + this._container[name].__yuiOwner = owner; + this._container[name].__yuiFuncName = funcName; + + //register prototype if necessary + if (registerPrototype) { + this.registerObject(name + ".prototype", prototype); + } + + //store function information + this._report[name] = { + calls: 0, + max: 0, + min: 0, + avg: 0, + points: [] + }; + } + + return method; + + }, + + + /** + * Sets up an object for profiling. It takes the object and looks for functions. + * When a function is found, registerMethod() is called on it. If set to recrusive + * mode, it will also setup objects found inside of this object for profiling, + * using the same methodology. + * @param {String} name The name of the object to profile (shows up in report). + * @param {Object} owner (Optional) The object represented by the name. + * @param {Boolean} recurse (Optional) Determines if subobject methods are also profiled. + * @return {Void} + * @static + */ + registerObject : function (name /*:String*/, object /*:Object*/, recurse /*:Boolean*/) /*:Void*/{ + + //get the object + object = (YAHOO.lang.isObject(object) ? object : eval(name)); + + //save the object + this._container[name] = object; + + for (var prop in object) { + if (typeof object[prop] == "function"){ + if (prop != "constructor" && prop != "superclass"){ //don't do constructor or superclass, it's recursive + this.registerFunction(name + "." + prop, object); + } + } else if (typeof object[prop] == "object" && recurse){ + this.registerObject(name + "." + prop, object[prop], recurse); + } + } + + }, + + /** + * Removes a constructor function from profiling. Reverses the registerConstructor() method. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @return {Void} + * @method unregisterFunction + */ + unregisterConstructor : function(name /*:String*/) /*:Void*/{ + + //see if the method has been registered + if (YAHOO.lang.isFunction(this._container[name])){ + + //get original data + //var owner /*:Object*/ = this._container[name].__yuiOwner; + //var funcName /*:String*/ = this._container[name].__yuiFuncName; + //delete this._container[name].__yuiOwner; + //delete this._container[name].__yuiFuncName; + + //replace instrumented function + //owner[funcName] = this._container[name]; + //delete this._container[name]; + this.unregisterFunction(name, true); + + } + + + }, + + /** + * Removes function from profiling. Reverses the registerFunction() method. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @return {Void} + * @method unregisterFunction + */ + unregisterFunction : function(name /*:String*/, unregisterPrototype /*:Boolean*/) /*:Void*/{ + + //see if the method has been registered + if (YAHOO.lang.isFunction(this._container[name])){ + + //check to see if you should unregister the prototype + if (unregisterPrototype){ + this.unregisterObject(name + ".prototype", this._container[name].prototype); + } + + //get original data + var owner /*:Object*/ = this._container[name].__yuiOwner; + var funcName /*:String*/ = this._container[name].__yuiFuncName; + delete this._container[name].__yuiOwner; + delete this._container[name].__yuiFuncName; + + //replace instrumented function + owner[funcName] = this._container[name]; + + //delete supporting information + delete this._container[name]; + delete this._report[name]; + + } + + + }, + + /** + * Unregisters an object for profiling. It takes the object and looks for functions. + * When a function is found, unregisterMethod() is called on it. If set to recrusive + * mode, it will also unregister objects found inside of this object, + * using the same methodology. + * @param {String} name The name of the object to unregister. + * @param {Boolean} recurse (Optional) Determines if subobject methods should also be + * unregistered. + * @return {Void} + * @static + */ + unregisterObject : function (name /*:String*/, recurse /*:Boolean*/) /*:Void*/{ + + //get the object + if (YAHOO.lang.isObject(this._container[name])){ + var object = this._container[name]; + + for (var prop in object) { + if (typeof object[prop] == "function"){ + this.unregisterFunction(name + "." + prop); + } else if (typeof object[prop] == "object" && recurse){ + this.unregisterObject(name + "." + prop, recurse); + } + } + + delete this._container[name]; + } + + } + + +}; +YAHOO.register("profiler", YAHOO.tool.Profiler, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/profiler/profiler-min.js b/lib/yui/profiler/profiler-min.js new file mode 100644 index 00000000000..fd7eeba5cbe --- /dev/null +++ b/lib/yui/profiler/profiler-min.js @@ -0,0 +1,7 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +YAHOO.namespace("tool");YAHOO.tool.Profiler={_container:new Object(),_report:new Object(),_saveData:function(B,C){var A=this._report[B];A.calls++;A.points.push(C);if(A.calls>1){A.avg=((A.avg*(A.calls-1))+C)/A.calls;A.min=Math.min(A.min,C);A.max=Math.max(A.max,C);}else{A.avg=C;A.min=C;A.max=C;}},getAverage:function(A){return this._report[A].avg;},getCallCount:function(A){return this._report[A].calls;},getMax:function(A){return this._report[A].max;},getMin:function(A){return this._report[A].min;},getFunctionReport:function(A){return this._report[A];},getFullReport:function(C){C=C||function(){return true;};if(YAHOO.lang.isFunction(C)){var A={};for(var B in this._report){if(C(this._report[B])){A[B]=this._report[B];}}return A;}},registerConstructor:function(B,A){this.registerFunction(B,A,true);},registerFunction:function(name,owner,registerPrototype){var funcName=(name.indexOf(".")>-1?name.substring(name.lastIndexOf(".")+1):name);if(!YAHOO.lang.isObject(owner)){owner=eval(name.substring(0,name.lastIndexOf(".")));}var method=owner[funcName];var prototype=method.prototype;if(YAHOO.lang.isFunction(method)&&!method.__yuiProfiled){this._container[name]=method;owner[funcName]=function(){var start=new Date();var retval=method.apply(this,arguments);var stop=new Date();YAHOO.tool.Profiler._saveData(name,stop-start);return retval;};YAHOO.lang.augmentObject(owner[funcName],method);owner[funcName].__yuiProfiled=true;owner[funcName].prototype=prototype;this._container[name].__yuiOwner=owner;this._container[name].__yuiFuncName=funcName;if(registerPrototype){this.registerObject(name+".prototype",prototype);}this._report[name]={calls:0,max:0,min:0,avg:0,points:[]};}return method;},registerObject:function(name,object,recurse){object=(YAHOO.lang.isObject(object)?object:eval(name));this._container[name]=object;for(var prop in object){if(typeof object[prop]=="function"){if(prop!="constructor"&&prop!="superclass"){this.registerFunction(name+"."+prop,object);}}else{if(typeof object[prop]=="object"&&recurse){this.registerObject(name+"."+prop,object[prop],recurse);}}}},unregisterConstructor:function(A){if(YAHOO.lang.isFunction(this._container[A])){this.unregisterFunction(A,true);}},unregisterFunction:function(B,C){if(YAHOO.lang.isFunction(this._container[B])){if(C){this.unregisterObject(B+".prototype",this._container[B].prototype);}var A=this._container[B].__yuiOwner;var D=this._container[B].__yuiFuncName;delete this._container[B].__yuiOwner;delete this._container[B].__yuiFuncName;A[D]=this._container[B];delete this._container[B];delete this._report[B];}},unregisterObject:function(B,C){if(YAHOO.lang.isObject(this._container[B])){var A=this._container[B];for(var D in A){if(typeof A[D]=="function"){this.unregisterFunction(B+"."+D);}else{if(typeof A[D]=="object"&&C){this.unregisterObject(B+"."+D,C);}}}delete this._container[B];}}};YAHOO.register("profiler",YAHOO.tool.Profiler,{version:"2.6.0",build:"1321"}); \ No newline at end of file diff --git a/lib/yui/profiler/profiler.js b/lib/yui/profiler/profiler.js new file mode 100644 index 00000000000..3dadf136e20 --- /dev/null +++ b/lib/yui/profiler/profiler.js @@ -0,0 +1,380 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +YAHOO.namespace("tool"); + +/** + * The YUI JavaScript profiler. + * @module profiler + * @namespace YAHOO.tool + * @requires yahoo + */ + +/** + * Profiles functions in JavaScript. + * @namespace YAHOO.tool + * @class Profiler + * @static + */ +YAHOO.tool.Profiler = { + + //------------------------------------------------------------------------- + // Private Properties + //------------------------------------------------------------------------- + + /** + * Container object on which to put the original unprofiled methods. + * @type Object + * @private + * @static + * @property _container + */ + _container : new Object(), + + /** + * Call information for functions. + * @type Object + * @private + * @static + * @property _report + */ + _report : new Object(), + + //------------------------------------------------------------------------- + // Private Methods + //------------------------------------------------------------------------- + + /** + * Called when a method ends execution. Marks the start and end time of the + * method so it can calculate how long the function took to execute. Also + * updates min/max/avg calculations for the function. + * @param {String} name The name of the function to mark as stopped. + * @param {int} duration The number of milliseconds it took the function to + * execute. + * @return {Void} + * @private + * @static + */ + _saveData : function (name /*:String*/, duration /*:int*/){ + + //get the function data + var functionData /*:Object*/ = this._report[name]; + + //increment the calls + functionData.calls++; + functionData.points.push(duration); + + //if it's already been called at least once, do more complex calculations + if (functionData.calls > 1) { + functionData.avg = ((functionData.avg*(functionData.calls-1))+duration)/functionData.calls; + functionData.min = Math.min(functionData.min, duration); + functionData.max = Math.max(functionData.max, duration); + } else { + functionData.avg = duration; + functionData.min = duration; + functionData.max = duration; + } + + }, + + //------------------------------------------------------------------------- + // Reporting Methods + //------------------------------------------------------------------------- + + /** + * Returns the average amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The average time it takes the function to execute. + * @static + */ + getAverage : function (name /*:String*/) /*:float*/ { + return this._report[name].avg; + }, + + /** + * Returns the number of times that the given function has been called. + * @param {String} name The name of the function whose data should be returned. + * @return {int} The number of times the function was called. + * @static + */ + getCallCount : function (name /*:String*/) /*:int*/ { + return this._report[name].calls; + }, + + /** + * Returns the maximum amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The maximum time it takes the function to execute. + */ + getMax : function (name /*:String*/) /*:int*/ { + return this._report[name].max; + }, + + /** + * Returns the minimum amount of time (in milliseconds) that the function + * with the given name takes to execute. + * @param {String} name The name of the function whose data should be returned. + * If an object type method, it should be 'constructor.prototype.methodName'; + * a normal object method would just be 'object.methodName'. + * @return {float} The minimum time it takes the function to execute. + */ + getMin : function (name /*:String*/) /*:int*/ { + return this._report[name].min; + }, + + /** + * Returns an object containing profiling data for a single function. + * The object has an entry for min, max, avg, calls, and points). + * @return {Object} An object containing profile data for a given function. + * @static + */ + getFunctionReport : function (name /*:String*/) /*:Object*/ { + return this._report[name]; + }, + + /** + * Returns an object containing profiling data for all of the functions + * that were profiled. The object has an entry for each function and + * returns all information (min, max, average, calls, etc.) for each + * function. + * @return {Object} An object containing all profile data. + * @static + */ + getFullReport : function (filter /*:Function*/) /*:Object*/ { + filter = filter || function(){return true;}; + + if (YAHOO.lang.isFunction(filter)) { + var report = {}; + + for (var name in this._report){ + if (filter(this._report[name])){ + report[name] = this._report[name]; + } + } + + return report; + } + }, + + //------------------------------------------------------------------------- + // Profiling Methods + //------------------------------------------------------------------------- + + /** + * Sets up a constructor for profiling, including all properties and methods on the prototype. + * @param {string} name The fully-qualified name of the function including namespace information. + * @param {Object} owner (Optional) The object that owns the function (namespace or containing object). + * @return {Void} + * @static + */ + registerConstructor : function (name /*:String*/, owner /*:Object*/) /*:Void*/ { + this.registerFunction(name, owner, true); + }, + + /** + * Sets up a function for profiling. It essentially overwrites the function with one + * that has instrumentation data. This method also creates an entry for the function + * in the profile report. The original function is stored on the _container object. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @param {Object} owner (Optional) The object that owns the function. If the function + * isn't global then this argument is required. This could be the namespace that + * the function belongs to, such as YAHOO.util.Dom, or the object on which it's + * a method. + * @return {Void} + * @method registerFunction + */ + registerFunction : function(name /*:String*/, owner /*:Object*/, registerPrototype /*:Boolean*/) /*:Void*/{ + + //figure out the function name without namespacing + var funcName /*:String*/ = (name.indexOf(".") > -1 ? name.substring(name.lastIndexOf(".")+1) : name); + if (!YAHOO.lang.isObject(owner)){ + owner = eval(name.substring(0, name.lastIndexOf("."))); + } + + //get the method and prototype + var method /*:Function*/ = owner[funcName]; + var prototype /*:Object*/ = method.prototype; + + //see if the method has already been registered + if (YAHOO.lang.isFunction(method) && !method.__yuiProfiled){ + + //create a new slot for the original method + this._container[name] = method; + + //replace the function with the profiling one + owner[funcName] = function () { + + var start = new Date(); + var retval = method.apply(this, arguments); + var stop = new Date(); + + YAHOO.tool.Profiler._saveData(name, stop-start); + + return retval; + + }; + + //copy the function properties over + YAHOO.lang.augmentObject(owner[funcName], method); + owner[funcName].__yuiProfiled = true; + owner[funcName].prototype = prototype; + this._container[name].__yuiOwner = owner; + this._container[name].__yuiFuncName = funcName; + + //register prototype if necessary + if (registerPrototype) { + this.registerObject(name + ".prototype", prototype); + } + + //store function information + this._report[name] = { + calls: 0, + max: 0, + min: 0, + avg: 0, + points: [] + }; + } + + return method; + + }, + + + /** + * Sets up an object for profiling. It takes the object and looks for functions. + * When a function is found, registerMethod() is called on it. If set to recrusive + * mode, it will also setup objects found inside of this object for profiling, + * using the same methodology. + * @param {String} name The name of the object to profile (shows up in report). + * @param {Object} owner (Optional) The object represented by the name. + * @param {Boolean} recurse (Optional) Determines if subobject methods are also profiled. + * @return {Void} + * @static + */ + registerObject : function (name /*:String*/, object /*:Object*/, recurse /*:Boolean*/) /*:Void*/{ + + //get the object + object = (YAHOO.lang.isObject(object) ? object : eval(name)); + + //save the object + this._container[name] = object; + + for (var prop in object) { + if (typeof object[prop] == "function"){ + if (prop != "constructor" && prop != "superclass"){ //don't do constructor or superclass, it's recursive + this.registerFunction(name + "." + prop, object); + } + } else if (typeof object[prop] == "object" && recurse){ + this.registerObject(name + "." + prop, object[prop], recurse); + } + } + + }, + + /** + * Removes a constructor function from profiling. Reverses the registerConstructor() method. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @return {Void} + * @method unregisterFunction + */ + unregisterConstructor : function(name /*:String*/) /*:Void*/{ + + //see if the method has been registered + if (YAHOO.lang.isFunction(this._container[name])){ + + //get original data + //var owner /*:Object*/ = this._container[name].__yuiOwner; + //var funcName /*:String*/ = this._container[name].__yuiFuncName; + //delete this._container[name].__yuiOwner; + //delete this._container[name].__yuiFuncName; + + //replace instrumented function + //owner[funcName] = this._container[name]; + //delete this._container[name]; + this.unregisterFunction(name, true); + + } + + + }, + + /** + * Removes function from profiling. Reverses the registerFunction() method. + * @param {String} name The full name of the function including namespacing. This + * is the name of the function that is stored in the report. + * @return {Void} + * @method unregisterFunction + */ + unregisterFunction : function(name /*:String*/, unregisterPrototype /*:Boolean*/) /*:Void*/{ + + //see if the method has been registered + if (YAHOO.lang.isFunction(this._container[name])){ + + //check to see if you should unregister the prototype + if (unregisterPrototype){ + this.unregisterObject(name + ".prototype", this._container[name].prototype); + } + + //get original data + var owner /*:Object*/ = this._container[name].__yuiOwner; + var funcName /*:String*/ = this._container[name].__yuiFuncName; + delete this._container[name].__yuiOwner; + delete this._container[name].__yuiFuncName; + + //replace instrumented function + owner[funcName] = this._container[name]; + + //delete supporting information + delete this._container[name]; + delete this._report[name]; + + } + + + }, + + /** + * Unregisters an object for profiling. It takes the object and looks for functions. + * When a function is found, unregisterMethod() is called on it. If set to recrusive + * mode, it will also unregister objects found inside of this object, + * using the same methodology. + * @param {String} name The name of the object to unregister. + * @param {Boolean} recurse (Optional) Determines if subobject methods should also be + * unregistered. + * @return {Void} + * @static + */ + unregisterObject : function (name /*:String*/, recurse /*:Boolean*/) /*:Void*/{ + + //get the object + if (YAHOO.lang.isObject(this._container[name])){ + var object = this._container[name]; + + for (var prop in object) { + if (typeof object[prop] == "function"){ + this.unregisterFunction(name + "." + prop); + } else if (typeof object[prop] == "object" && recurse){ + this.unregisterObject(name + "." + prop, recurse); + } + } + + delete this._container[name]; + } + + } + + +}; +YAHOO.register("profiler", YAHOO.tool.Profiler, {version: "2.6.0", build: "1321"}); diff --git a/lib/yui/yuiloader/yuiloader-debug.js b/lib/yui/yuiloader/yuiloader-debug.js new file mode 100644 index 00000000000..7a5d243e290 --- /dev/null +++ b/lib/yui/yuiloader/yuiloader-debug.js @@ -0,0 +1,3677 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.6.0 +*/ +/** + * The YAHOO object is the single global object used by YUI Library. It + * contains utility function for setting up namespaces, inheritance, and + * logging. YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces + * created automatically for and used by the library. + * @module yahoo + * @title YAHOO Global + */ + +/** + * YAHOO_config is not included as part of the library. Instead it is an + * object that can be defined by the implementer immediately before + * including the YUI library. The properties included in this object + * will be used to configure global properties needed as soon as the + * library begins to load. + * @class YAHOO_config + * @static + */ + +/** + * A reference to a function that will be executed every time a YAHOO module + * is loaded. As parameter, this function will receive the version + * information for the module. See + * YAHOO.env.getVersion for the description of the version data structure. + * @property listener + * @type Function + * @static + * @default undefined + */ + +/** + * Set to true if the library will be dynamically loaded after window.onload. + * Defaults to false + * @property injecting + * @type boolean + * @static + * @default undefined + */ + +/** + * Instructs the yuiloader component to dynamically load yui components and + * their dependencies. See the yuiloader documentation for more information + * about dynamic loading + * @property load + * @static + * @default undefined + * @see yuiloader + */ + +/** + * Forces the use of the supplied locale where applicable in the library + * @property locale + * @type string + * @static + * @default undefined + */ + +if (typeof YAHOO == "undefined" || !YAHOO) { + /** + * The YAHOO global namespace object. If YAHOO is already defined, the + * existing YAHOO object will not be overwritten so that defined + * namespaces are preserved. + * @class YAHOO + * @static + */ + var YAHOO = {}; +} + +/** + * Returns the namespace specified and creates it if it doesn't exist + *
                      + * YAHOO.namespace("property.package");
                      + * YAHOO.namespace("YAHOO.property.package");
                      + * 
                      + * Either of the above would create YAHOO.property, then + * YAHOO.property.package + * + * Be careful when naming packages. Reserved words may work in some browsers + * and not others. For instance, the following will fail in Safari: + *
                      + * YAHOO.namespace("really.long.nested.namespace");
                      + * 
                      + * This fails because "long" is a future reserved word in ECMAScript + * + * @method namespace + * @static + * @param {String*} arguments 1-n namespaces to create + * @return {Object} A reference to the last namespace object created + */ +YAHOO.namespace = function() { + var a=arguments, o=null, i, j, d; + for (i=0; i + *
                      name:
                      The name of the module
                      + *
                      version:
                      The version in use
                      + *
                      build:
                      The build number in use
                      + *
                      versions:
                      All versions that were registered
                      + *
                      builds:
                      All builds that were registered.
                      + *
                      mainClass:
                      An object that was was stamped with the + * current version and build. If + * mainClass.VERSION != version or mainClass.BUILD != build, + * multiple versions of pieces of the library have been + * loaded, potentially causing issues.
                      + * + * + * @method getVersion + * @static + * @param {String} name the name of the module (event, slider, etc) + * @return {Object} The version info + */ +YAHOO.env.getVersion = function(name) { + return YAHOO.env.modules[name] || null; +}; + +/** + * Do not fork for a browser if it can be avoided. Use feature detection when + * you can. Use the user agent as a last resort. YAHOO.env.ua stores a version + * number for the browser engine, 0 otherwise. This value may or may not map + * to the version number of the browser using the engine. The value is + * presented as a float so that it can easily be used for boolean evaluation + * as well as for looking for a particular range of versions. Because of this, + * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 + * reports 1.8). + * @class YAHOO.env.ua + * @static + */ +YAHOO.env.ua = function() { + var o={ + + /** + * Internet Explorer version number or 0. Example: 6 + * @property ie + * @type float + */ + ie:0, + + /** + * Opera version number or 0. Example: 9.2 + * @property opera + * @type float + */ + opera:0, + + /** + * Gecko engine revision number. Will evaluate to 1 if Gecko + * is detected but the revision could not be found. Other browsers + * will be 0. Example: 1.8 + *
                      +         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
                      +         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
                      +         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
                      +         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
                      +         * 
                      + * @property gecko + * @type float + */ + gecko:0, + + /** + * AppleWebKit version. KHTML browsers that are not WebKit browsers + * will evaluate to 1, other browsers 0. Example: 418.9.1 + *
                      +         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
                      +         *                                   latest available for Mac OSX 10.3.
                      +         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
                      +         * Safari 2.0.4:         418     <-- preventDefault fixed
                      +         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
                      +         *                                   different versions of webkit
                      +         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
                      +         *                                   updated, but not updated
                      +         *                                   to the latest patch.
                      +         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
                      +         *                                   and many major issues fixed).  
                      +         * 3.x yahoo.com, flickr:422     <-- Safari 3.x hacks the user agent
                      +         *                                   string when hitting yahoo.com and 
                      +         *                                   flickr.com.
                      +         * Safari 3.0.4 (523.12):523.12  <-- First Tiger release - automatic update
                      +         *                                   from 2.x via the 10.4.11 OS patch
                      +         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
                      +         *                                   yahoo.com user agent hack removed.
                      +         *                                   
                      +         * 
                      + * http://developer.apple.com/internet/safari/uamatrix.html + * @property webkit + * @type float + */ + webkit: 0, + + /** + * The mobile property will be set to a string containing any relevant + * user agent information when a modern mobile browser is detected. + * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series + * devices with the WebKit-based browser, and Opera Mini. + * @property mobile + * @type string + */ + mobile: null, + + /** + * Adobe AIR version number or 0. Only populated if webkit is detected. + * Example: 1.0 + * @property air + * @type float + */ + air: 0 + + }; + + var ua=navigator.userAgent, m; + + // Modern KHTML browsers should qualify as Safari X-Grade + if ((/KHTML/).test(ua)) { + o.webkit=1; + } + // Modern WebKit browsers are at least X-Grade + m=ua.match(/AppleWebKit\/([^\s]*)/); + if (m&&m[1]) { + o.webkit=parseFloat(m[1]); + + // Mobile browser check + if (/ Mobile\//.test(ua)) { + o.mobile = "Apple"; // iPhone or iPod Touch + } else { + m=ua.match(/NokiaN[^\/]*/); + if (m) { + o.mobile = m[0]; // Nokia N-series, ex: NokiaN95 + } + } + + m=ua.match(/AdobeAIR\/([^\s]*)/); + if (m) { + o.air = m[0]; // Adobe AIR 1.0 or better + } + + } + + if (!o.webkit) { // not webkit + // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) + m=ua.match(/Opera[\s\/]([^\s]*)/); + if (m&&m[1]) { + o.opera=parseFloat(m[1]); + m=ua.match(/Opera Mini[^;]*/); + if (m) { + o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 + } + } else { // not opera or webkit + m=ua.match(/MSIE\s([^;]*)/); + if (m&&m[1]) { + o.ie=parseFloat(m[1]); + } else { // not opera, webkit, or ie + m=ua.match(/Gecko\/([^\s]*)/); + if (m) { + o.gecko=1; // Gecko detected, look for revision + m=ua.match(/rv:([^\s\)]*)/); + if (m&&m[1]) { + o.gecko=parseFloat(m[1]); + } + } + } + } + } + + return o; +}(); + +/* + * Initializes the global by creating the default namespaces and applying + * any new configuration information that is detected. This is the setup + * for env. + * @method init + * @static + * @private + */ +(function() { + YAHOO.namespace("util", "widget", "example"); + if ("undefined" !== typeof YAHOO_config) { + var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i; + if (l) { + // if YAHOO is loaded multiple times we need to check to see if + // this is a new config object. If it is, add the new component + // load listener to the stack + for (i=0;i 0) ? L.dump(o[i], d-1) : OBJ); + } else { + s.push(o[i]); + } + s.push(COMMA); + } + if (s.length > 1) { + s.pop(); + } + s.push("]"); + // objects {k1 => v1, k2 => v2} + } else { + s.push("{"); + for (i in o) { + if (L.hasOwnProperty(o, i)) { + s.push(i + ARROW); + if (L.isObject(o[i])) { + s.push((d > 0) ? L.dump(o[i], d-1) : OBJ); + } else { + s.push(o[i]); + } + s.push(COMMA); + } + } + if (s.length > 1) { + s.pop(); + } + s.push("}"); + } + + return s.join(""); + }, + + /** + * Does variable substitution on a string. It scans through the string + * looking for expressions enclosed in { } braces. If an expression + * is found, it is used a key on the object. If there is a space in + * the key, the first word is used for the key and the rest is provided + * to an optional function to be used to programatically determine the + * value (the extra information might be used for this decision). If + * the value for the key in the object, or what is returned from the + * function has a string value, number value, or object value, it is + * substituted for the bracket expression and it repeats. If this + * value is an object, it uses the Object's toString() if this has + * been overridden, otherwise it does a shallow dump of the key/value + * pairs. + * @method substitute + * @since 2.3.0 + * @param s {String} The string that will be modified. + * @param o {Object} An object containing the replacement values + * @param f {Function} An optional function that can be used to + * process each match. It receives the key, + * value, and any extra metadata included with + * the key inside of the braces. + * @return {String} the substituted string + */ + substitute: function (s, o, f) { + var i, j, k, key, v, meta, saved=[], token, + DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}'; + + + for (;;) { + i = s.lastIndexOf(LBRACE); + if (i < 0) { + break; + } + j = s.indexOf(RBRACE, i); + if (i + 1 >= j) { + break; + } + + //Extract key and meta info + token = s.substring(i + 1, j); + key = token; + meta = null; + k = key.indexOf(SPACE); + if (k > -1) { + meta = key.substring(k + 1); + key = key.substring(0, k); + } + + // lookup the value + v = o[key]; + + // if a substitution function was provided, execute it + if (f) { + v = f(key, v, meta); + } + + if (L.isObject(v)) { + if (L.isArray(v)) { + v = L.dump(v, parseInt(meta, 10)); + } else { + meta = meta || ""; + + // look for the keyword 'dump', if found force obj dump + var dump = meta.indexOf(DUMP); + if (dump > -1) { + meta = meta.substring(4); + } + + // use the toString if it is not the Object toString + // and the 'dump' meta info was not found + if (v.toString===Object.prototype.toString||dump>-1) { + v = L.dump(v, parseInt(meta, 10)); + } else { + v = v.toString(); + } + } + } else if (!L.isString(v) && !L.isNumber(v)) { + // This {block} has no replace string. Save it for later. + v = "~-" + saved.length + "-~"; + saved[saved.length] = token; + + // break; + } + + s = s.substring(0, i) + v + s.substring(j + 1); + + + } + + // restore saved {block}s + for (i=saved.length-1; i>=0; i=i-1) { + s = s.replace(new RegExp("~-" + i + "-~"), "{" + saved[i] + "}", "g"); + } + + return s; + }, + + + /** + * Returns a string without any leading or trailing whitespace. If + * the input is not a string, the input will be returned untouched. + * @method trim + * @since 2.3.0 + * @param s {string} the string to trim + * @return {string} the trimmed string + */ + trim: function(s){ + try { + return s.replace(/^\s+|\s+$/g, ""); + } catch(e) { + return s; + } + }, + + /** + * Returns a new object containing all of the properties of + * all the supplied objects. The properties from later objects + * will overwrite those in earlier objects. + * @method merge + * @since 2.3.0 + * @param arguments {Object*} the objects to merge + * @return the new merged object + */ + merge: function() { + var o={}, a=arguments; + for (var i=0, l=a.length; i + * var A = function() {}; + * A.prototype.foo = 'foo'; + * var a = new A(); + * a.foo = 'foo'; + * alert(a.hasOwnProperty('foo')); // true + * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback + * + * @method hasOwnProperty + * @param {any} o The object being testing + * @param prop {string} the name of the property to test + * @return {boolean} the result + */ +L.hasOwnProperty = (Object.prototype.hasOwnProperty) ? + function(o, prop) { + return o && o.hasOwnProperty(prop); + } : function(o, prop) { + return !L.isUndefined(o[prop]) && + o.constructor.prototype[prop] !== o[prop]; + }; + +// new lang wins +OB.augmentObject(L, OB, true); + +/* + * An alias for YAHOO.lang + * @class YAHOO.util.Lang + */ +YAHOO.util.Lang = L; + +/** + * Same as YAHOO.lang.augmentObject, except it only applies prototype + * properties. This is an alias for augmentProto. + * @see YAHOO.lang.augmentObject + * @method augment + * @static + * @param {Function} r the object to receive the augmentation + * @param {Function} s the object that supplies the properties to augment + * @param {String*|boolean} arguments zero or more properties methods to + * augment the receiver with. If none specified, everything + * in the supplier will be used unless it would + * overwrite an existing property in the receiver. if true + * is specified as the third parameter, all properties will + * be applied and will overwrite an existing property in + * the receiver + */ +L.augment = L.augmentProto; + +/** + * An alias for YAHOO.lang.augment + * @for YAHOO + * @method augment + * @static + * @param {Function} r the object to receive the augmentation + * @param {Function} s the object that supplies the properties to augment + * @param {String*} arguments zero or more properties methods to + * augment the receiver with. If none specified, everything + * in the supplier will be used unless it would + * overwrite an existing property in the receiver + */ +YAHOO.augment = L.augmentProto; + +/** + * An alias for YAHOO.lang.extend + * @method extend + * @static + * @param {Function} subc the object to modify + * @param {Function} superc the object to inherit + * @param {Object} overrides additional properties/methods to add to the + * subclass prototype. These will override the + * matching items obtained from the superclass if present. + */ +YAHOO.extend = L.extend; + +})(); +YAHOO.register("yahoo", YAHOO, {version: "2.6.0", build: "1321"}); +/** + * Provides a mechanism to fetch remote resources and + * insert them into a document + * @module get + * @requires yahoo + */ + +/** + * Fetches and inserts one or more script or link nodes into the document + * @namespace YAHOO.util + * @class YAHOO.util.Get + */ +YAHOO.util.Get = function() { + + /** + * hash of queues to manage multiple requests + * @property queues + * @private + */ + var queues={}, + + /** + * queue index used to generate transaction ids + * @property qidx + * @type int + * @private + */ + qidx=0, + + /** + * node index used to generate unique node ids + * @property nidx + * @type int + * @private + */ + nidx=0, + + // ridx=0, + + // sandboxFrame=null, + + /** + * interal property used to prevent multiple simultaneous purge + * processes + * @property purging + * @type boolean + * @private + */ + purging=false, + + ua=YAHOO.env.ua, + + lang=YAHOO.lang; + + /** + * Generates an HTML element, this is not appended to a document + * @method _node + * @param type {string} the type of element + * @param attr {string} the attributes + * @param win {Window} optional window to create the element in + * @return {HTMLElement} the generated node + * @private + */ + var _node = function(type, attr, win) { + var w = win || window, d=w.document, n=d.createElement(type); + + for (var i in attr) { + if (attr[i] && YAHOO.lang.hasOwnProperty(attr, i)) { + n.setAttribute(i, attr[i]); + } + } + + return n; + }; + + /** + * Generates a link node + * @method _linkNode + * @param url {string} the url for the css file + * @param win {Window} optional window to create the node in + * @return {HTMLElement} the generated node + * @private + */ + var _linkNode = function(url, win, charset) { + var c = charset || "utf-8"; + return _node("link", { + "id": "yui__dyn_" + (nidx++), + "type": "text/css", + "charset": c, + "rel": "stylesheet", + "href": url + }, win); + }; + + /** + * Generates a script node + * @method _scriptNode + * @param url {string} the url for the script file + * @param win {Window} optional window to create the node in + * @return {HTMLElement} the generated node + * @private + */ + var _scriptNode = function(url, win, charset) { + var c = charset || "utf-8"; + return _node("script", { + "id": "yui__dyn_" + (nidx++), + "type": "text/javascript", + "charset": c, + "src": url + }, win); + }; + + /** + * Returns the data payload for callback functions + * @method _returnData + * @private + */ + var _returnData = function(q, msg) { + return { + tId: q.tId, + win: q.win, + data: q.data, + nodes: q.nodes, + msg: msg, + purge: function() { + _purge(this.tId); + } + }; + }; + + var _get = function(nId, tId) { + var q = queues[tId], + n = (lang.isString(nId)) ? q.win.document.getElementById(nId) : nId; + if (!n) { + _fail(tId, "target node not found: " + nId); + } + + return n; + }; + + /* + * The request failed, execute fail handler with whatever + * was accomplished. There isn't a failure case at the + * moment unless you count aborted transactions + * @method _fail + * @param id {string} the id of the request + * @private + */ + var _fail = function(id, msg) { + var q = queues[id]; + // execute failure callback + if (q.onFailure) { + var sc=q.scope || q.win; + q.onFailure.call(sc, _returnData(q, msg)); + } + }; + + /** + * The request is complete, so executing the requester's callback + * @method _finish + * @param id {string} the id of the request + * @private + */ + var _finish = function(id) { + var q = queues[id]; + q.finished = true; + + if (q.aborted) { + var msg = "transaction " + id + " was aborted"; + _fail(id, msg); + return; + } + + // execute success callback + if (q.onSuccess) { + var sc=q.scope || q.win; + q.onSuccess.call(sc, _returnData(q)); + } + }; + + /** + * Timeout detected + * @method _timeout + * @param id {string} the id of the request + * @private + */ + var _timeout = function(id) { + var q = queues[id]; + if (q.onTimeout) { + var sc=q.context || q; + q.onTimeout.call(sc, _returnData(q)); + } + }; + + /** + * Loads the next item for a given request + * @method _next + * @param id {string} the id of the request + * @param loaded {string} the url that was just loaded, if any + * @private + */ + var _next = function(id, loaded) { + var q = queues[id]; + + if (q.timer) { + // Y.log('cancel timer'); + q.timer.cancel(); + } + + if (q.aborted) { + var msg = "transaction " + id + " was aborted"; + _fail(id, msg); + return; + } + + if (loaded) { + q.url.shift(); + if (q.varName) { + q.varName.shift(); + } + } else { + // This is the first pass: make sure the url is an array + q.url = (lang.isString(q.url)) ? [q.url] : q.url; + if (q.varName) { + q.varName = (lang.isString(q.varName)) ? [q.varName] : q.varName; + } + } + + var w=q.win, d=w.document, h=d.getElementsByTagName("head")[0], n; + + if (q.url.length === 0) { + // Safari 2.x workaround - There is no way to know when + // a script is ready in versions of Safari prior to 3.x. + // Adding an extra node reduces the problem, but doesn't + // eliminate it completely because the browser executes + // them asynchronously. + if (q.type === "script" && ua.webkit && ua.webkit < 420 && + !q.finalpass && !q.varName) { + // Add another script node. This does not guarantee that the + // scripts will execute in order, but it does appear to fix the + // problem on fast connections more effectively than using an + // arbitrary timeout. It is possible that the browser does + // block subsequent script execution in this case for a limited + // time. + var extra = _scriptNode(null, q.win, q.charset); + extra.innerHTML='YAHOO.util.Get._finalize("' + id + '");'; + q.nodes.push(extra); h.appendChild(extra); + + } else { + _finish(id); + } + + return; + } + + + var url = q.url[0]; + + // if the url is undefined, this is probably a trailing comma problem in IE + if (!url) { + q.url.shift(); + return _next(id); + } + + + if (q.timeout) { + // Y.log('create timer'); + q.timer = lang.later(q.timeout, q, _timeout, id); + } + + if (q.type === "script") { + n = _scriptNode(url, w, q.charset); + } else { + n = _linkNode(url, w, q.charset); + } + + // track this node's load progress + _track(q.type, n, id, url, w, q.url.length); + + // add the node to the queue so we can return it to the user supplied callback + q.nodes.push(n); + + // add it to the head or insert it before 'insertBefore' + if (q.insertBefore) { + var s = _get(q.insertBefore, id); + if (s) { + s.parentNode.insertBefore(n, s); + } + } else { + h.appendChild(n); + } + + + // FireFox does not support the onload event for link nodes, so there is + // no way to make the css requests synchronous. This means that the css + // rules in multiple files could be applied out of order in this browser + // if a later request returns before an earlier one. Safari too. + if ((ua.webkit || ua.gecko) && q.type === "css") { + _next(id, url); + } + }; + + /** + * Removes processed queues and corresponding nodes + * @method _autoPurge + * @private + */ + var _autoPurge = function() { + + if (purging) { + return; + } + + purging = true; + for (var i in queues) { + var q = queues[i]; + if (q.autopurge && q.finished) { + _purge(q.tId); + delete queues[i]; + } + } + + purging = false; + }; + + /** + * Removes the nodes for the specified queue + * @method _purge + * @private + */ + var _purge = function(tId) { + var q=queues[tId]; + if (q) { + var n=q.nodes, l=n.length, d=q.win.document, + h=d.getElementsByTagName("head")[0]; + + if (q.insertBefore) { + var s = _get(q.insertBefore, tId); + if (s) { + h = s.parentNode; + } + } + + for (var i=0; i= 420) { + + n.addEventListener("load", function() { + f(id, url); + }); + + // Nothing can be done with Safari < 3.x except to pause and hope + // for the best, particularly after last script is inserted. The + // scripts will always execute in the order they arrive, not + // necessarily the order in which they were inserted. To support + // script nodes with complete reliability in these browsers, script + // nodes either need to invoke a function in the window once they + // are loaded or the implementer needs to provide a well-known + // property that the utility can poll for. + } else { + // Poll for the existence of the named variable, if it + // was supplied. + var q = queues[id]; + if (q.varName) { + var freq=YAHOO.util.Get.POLL_FREQ; + q.maxattempts = YAHOO.util.Get.TIMEOUT/freq; + q.attempts = 0; + q._cache = q.varName[0].split("."); + q.timer = lang.later(freq, q, function(o) { + var a=this._cache, l=a.length, w=this.win, i; + for (i=0; i this.maxattempts) { + var msg = "Over retry limit, giving up"; + q.timer.cancel(); + _fail(id, msg); + } else { + } + return; + } + } + + + q.timer.cancel(); + f(id, url); + + }, null, true); + } else { + lang.later(YAHOO.util.Get.POLL_FREQ, null, f, [id, url]); + } + } + } + + // FireFox and Opera support onload (but not DOM2 in FF) handlers for + // script nodes. Opera, but not FF, supports the onload event for link + // nodes. + } else { + n.onload = function() { + f(id, url); + }; + } + }; + + return { + + /** + * The default poll freqency in ms, when needed + * @property POLL_FREQ + * @static + * @type int + * @default 10 + */ + POLL_FREQ: 10, + + /** + * The number of request required before an automatic purge. + * property PURGE_THRESH + * @static + * @type int + * @default 20 + */ + PURGE_THRESH: 20, + + /** + * The length time to poll for varName when loading a script in + * Safari 2.x before the transaction fails. + * property TIMEOUT + * @static + * @type int + * @default 2000 + */ + TIMEOUT: 2000, + + /** + * Called by the the helper for detecting script load in Safari + * @method _finalize + * @param id {string} the transaction id + * @private + */ + _finalize: function(id) { + lang.later(0, null, _finish, id); + }, + + /** + * Abort a transaction + * @method abort + * @param {string|object} either the tId or the object returned from + * script() or css() + */ + abort: function(o) { + var id = (lang.isString(o)) ? o : o.tId; + var q = queues[id]; + if (q) { + q.aborted = true; + } + }, + + /** + * Fetches and inserts one or more script nodes into the head + * of the current document or the document in a specified window. + * + * @method script + * @static + * @param url {string|string[]} the url or urls to the script(s) + * @param opts {object} Options: + *
                      + *
                      onSuccess
                      + *
                      + * callback to execute when the script(s) are finished loading + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      onFailure
                      + *
                      + * callback to execute when the script load operation fails + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted successfully
                      + *
                      purge
                      + *
                      A function that, when executed, will remove any nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      onTimeout
                      + *
                      + * callback to execute when a timeout occurs. + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      scope
                      + *
                      the execution context for the callbacks
                      + *
                      win
                      + *
                      a window other than the one the utility occupies
                      + *
                      autopurge
                      + *
                      + * setting to true will let the utilities cleanup routine purge + * the script once loaded + *
                      + *
                      data
                      + *
                      + * data that is supplied to the callback when the script(s) are + * loaded. + *
                      + *
                      varName
                      + *
                      + * variable that should be available when a script is finished + * loading. Used to help Safari 2.x and below with script load + * detection. The type of this property should match what was + * passed into the url parameter: if loading a single url, a + * string can be supplied. If loading multiple scripts, you + * must supply an array that contains the variable name for + * each script. + *
                      + *
                      insertBefore
                      + *
                      node or node id that will become the new node's nextSibling
                      + *
                      + *
                      charset
                      + *
                      Node charset, default utf-8
                      + *
                      timeout
                      + *
                      Number of milliseconds to wait before aborting and firing the timeout event
                      + *
                      +         * // assumes yahoo, dom, and event are already on the page
                      +         *   YAHOO.util.Get.script(
                      +         *   ["http://yui.yahooapis.com/2.3.1/build/dragdrop/dragdrop-min.js",
                      +         *    "http://yui.yahooapis.com/2.3.1/build/animation/animation-min.js"], {
                      +         *     onSuccess: function(o) {
                      +         *       new YAHOO.util.DDProxy("dd1"); // also new o.reference("dd1"); would work
                      +         *       this.log("won't cause error because YAHOO is the scope");
                      +         *       this.log(o.nodes.length === 2) // true
                      +         *       // o.purge(); // optionally remove the script nodes immediately
                      +         *     },
                      +         *     onFailure: function(o) {
                      +         *     },
                      +         *     data: "foo",
                      +         *     timeout: 10000, // 10 second timeout
                      +         *     scope: YAHOO,
                      +         *     // win: otherframe // target another window/frame
                      +         *     autopurge: true // allow the utility to choose when to remove the nodes
                      +         *   });
                      +         * 
                      + * @return {tId: string} an object containing info about the transaction + */ + script: function(url, opts) { return _queue("script", url, opts); }, + + /** + * Fetches and inserts one or more css link nodes into the + * head of the current document or the document in a specified + * window. + * @method css + * @static + * @param url {string} the url or urls to the css file(s) + * @param opts Options: + *
                      + *
                      onSuccess
                      + *
                      + * callback to execute when the css file(s) are finished loading + * The callback receives an object back with the following + * data: + *
                      win
                      + *
                      the window the link nodes(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + * + *
                      scope
                      + *
                      the execution context for the callbacks
                      + *
                      win
                      + *
                      a window other than the one the utility occupies
                      + *
                      data
                      + *
                      + * data that is supplied to the callbacks when the nodes(s) are + * loaded. + *
                      + *
                      insertBefore
                      + *
                      node or node id that will become the new node's nextSibling
                      + *
                      charset
                      + *
                      Node charset, default utf-8
                      + * + *
                      +         *      YAHOO.util.Get.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css");
                      +         * 
                      + *
                      +         *      YAHOO.util.Get.css(["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css",
                      +         * 
                      + * @return {tId: string} an object containing info about the transaction + */ + css: function(url, opts) { + return _queue("css", url, opts); + } + }; +}(); + +YAHOO.register("get", YAHOO.util.Get, {version: "2.6.0", build: "1321"}); +/** + * Provides dynamic loading for the YUI library. It includes the dependency + * info for the library, and will automatically pull in dependencies for + * the modules requested. It supports rollup files (such as utilities.js + * and yahoo-dom-event.js), and will automatically use these when + * appropriate in order to minimize the number of http connections + * required to load all of the dependencies. + * + * @module yuiloader + * @namespace YAHOO.util + */ + +/** + * YUILoader provides dynamic loading for YUI. + * @class YAHOO.util.YUILoader + * @todo + * version management, automatic sandboxing + */ +(function() { + + var Y=YAHOO, util=Y.util, lang=Y.lang, env=Y.env, + PROV = "_provides", SUPER = "_supersedes", + REQ = "expanded", AFTER = "_after"; + + var YUI = { + + dupsAllowed: {'yahoo': true, 'get': true}, + + /* + * The library metadata for the current release The is the default + * value for YAHOO.util.YUILoader.moduleInfo + * @property YUIInfo + * @static + */ + info: { + + // 'root': '2.5.2/build/', + // 'base': 'http://yui.yahooapis.com/2.5.2/build/', + + 'root': '2.6.0/build/', + 'base': 'http://yui.yahooapis.com/2.6.0/build/', + + 'comboBase': 'http://yui.yahooapis.com/combo?', + + 'skin': { + 'defaultSkin': 'sam', + 'base': 'assets/skins/', + 'path': 'skin.css', + 'after': ['reset', 'fonts', 'grids', 'base'], + 'rollup': 3 + }, + + dupsAllowed: ['yahoo', 'get'], + + 'moduleInfo': { + + 'animation': { + 'type': 'js', + 'path': 'animation/animation-min.js', + 'requires': ['dom', 'event'] + }, + + 'autocomplete': { + 'type': 'js', + 'path': 'autocomplete/autocomplete-min.js', + 'requires': ['dom', 'event', 'datasource'], + 'optional': ['connection', 'animation'], + 'skinnable': true + }, + + 'base': { + 'type': 'css', + 'path': 'base/base-min.css', + 'after': ['reset', 'fonts', 'grids'] + }, + + 'button': { + 'type': 'js', + 'path': 'button/button-min.js', + 'requires': ['element'], + 'optional': ['menu'], + 'skinnable': true + }, + + 'calendar': { + 'type': 'js', + 'path': 'calendar/calendar-min.js', + 'requires': ['event', 'dom'], + 'skinnable': true + }, + + 'carousel': { + 'type': 'js', + 'path': 'carousel/carousel-beta-min.js', + 'requires': ['element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'charts': { + 'type': 'js', + 'path': 'charts/charts-experimental-min.js', + 'requires': ['element', 'json', 'datasource'] + }, + + 'colorpicker': { + 'type': 'js', + 'path': 'colorpicker/colorpicker-min.js', + 'requires': ['slider', 'element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'connection': { + 'type': 'js', + 'path': 'connection/connection-min.js', + 'requires': ['event'] + }, + + 'container': { + 'type': 'js', + 'path': 'container/container-min.js', + 'requires': ['dom', 'event'], + // button is also optional, but this creates a circular + // dependency when loadOptional is specified. button + // optionally includes menu, menu requires container. + 'optional': ['dragdrop', 'animation', 'connection'], + 'supersedes': ['containercore'], + 'skinnable': true + }, + + 'containercore': { + 'type': 'js', + 'path': 'container/container_core-min.js', + 'requires': ['dom', 'event'], + 'pkg': 'container' + }, + + 'cookie': { + 'type': 'js', + 'path': 'cookie/cookie-min.js', + 'requires': ['yahoo'] + }, + + 'datasource': { + 'type': 'js', + 'path': 'datasource/datasource-min.js', + 'requires': ['event'], + 'optional': ['connection'] + }, + + 'datatable': { + 'type': 'js', + 'path': 'datatable/datatable-min.js', + 'requires': ['element', 'datasource'], + 'optional': ['calendar', 'dragdrop', 'paginator'], + 'skinnable': true + }, + + 'dom': { + 'type': 'js', + 'path': 'dom/dom-min.js', + 'requires': ['yahoo'] + }, + + 'dragdrop': { + 'type': 'js', + 'path': 'dragdrop/dragdrop-min.js', + 'requires': ['dom', 'event'] + }, + + 'editor': { + 'type': 'js', + 'path': 'editor/editor-min.js', + 'requires': ['menu', 'element', 'button'], + 'optional': ['animation', 'dragdrop'], + 'supersedes': ['simpleeditor'], + 'skinnable': true + }, + + 'element': { + 'type': 'js', + 'path': 'element/element-beta-min.js', + 'requires': ['dom', 'event'] + }, + + 'event': { + 'type': 'js', + 'path': 'event/event-min.js', + 'requires': ['yahoo'] + }, + + 'fonts': { + 'type': 'css', + 'path': 'fonts/fonts-min.css' + }, + + 'get': { + 'type': 'js', + 'path': 'get/get-min.js', + 'requires': ['yahoo'] + }, + + 'grids': { + 'type': 'css', + 'path': 'grids/grids-min.css', + 'requires': ['fonts'], + 'optional': ['reset'] + }, + + 'history': { + 'type': 'js', + 'path': 'history/history-min.js', + 'requires': ['event'] + }, + + 'imagecropper': { + 'type': 'js', + 'path': 'imagecropper/imagecropper-beta-min.js', + 'requires': ['dom', 'event', 'dragdrop', 'element', 'resize'], + 'skinnable': true + }, + + 'imageloader': { + 'type': 'js', + 'path': 'imageloader/imageloader-min.js', + 'requires': ['event', 'dom'] + }, + + 'json': { + 'type': 'js', + 'path': 'json/json-min.js', + 'requires': ['yahoo'] + }, + + 'layout': { + 'type': 'js', + 'path': 'layout/layout-min.js', + 'requires': ['dom', 'event', 'element'], + 'optional': ['animation', 'dragdrop', 'resize', 'selector'], + 'skinnable': true + }, + + 'logger': { + 'type': 'js', + 'path': 'logger/logger-min.js', + 'requires': ['event', 'dom'], + 'optional': ['dragdrop'], + 'skinnable': true + }, + + 'menu': { + 'type': 'js', + 'path': 'menu/menu-min.js', + 'requires': ['containercore'], + 'skinnable': true + }, + + 'paginator': { + 'type': 'js', + 'path': 'paginator/paginator-min.js', + 'requires': ['element'], + 'skinnable': true + }, + + 'profiler': { + 'type': 'js', + 'path': 'profiler/profiler-min.js', + 'requires': ['yahoo'] + }, + + + 'profilerviewer': { + 'type': 'js', + 'path': 'profilerviewer/profilerviewer-beta-min.js', + 'requires': ['profiler', 'yuiloader', 'element'], + 'skinnable': true + }, + + 'reset': { + 'type': 'css', + 'path': 'reset/reset-min.css' + }, + + 'reset-fonts-grids': { + 'type': 'css', + 'path': 'reset-fonts-grids/reset-fonts-grids.css', + 'supersedes': ['reset', 'fonts', 'grids', 'reset-fonts'], + 'rollup': 4 + }, + + 'reset-fonts': { + 'type': 'css', + 'path': 'reset-fonts/reset-fonts.css', + 'supersedes': ['reset', 'fonts'], + 'rollup': 2 + }, + + 'resize': { + 'type': 'js', + 'path': 'resize/resize-min.js', + 'requires': ['dom', 'event', 'dragdrop', 'element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'selector': { + 'type': 'js', + 'path': 'selector/selector-beta-min.js', + 'requires': ['yahoo', 'dom'] + }, + + 'simpleeditor': { + 'type': 'js', + 'path': 'editor/simpleeditor-min.js', + 'requires': ['element'], + 'optional': ['containercore', 'menu', 'button', 'animation', 'dragdrop'], + 'skinnable': true, + 'pkg': 'editor' + }, + + 'slider': { + 'type': 'js', + 'path': 'slider/slider-min.js', + 'requires': ['dragdrop'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'tabview': { + 'type': 'js', + 'path': 'tabview/tabview-min.js', + 'requires': ['element'], + 'optional': ['connection'], + 'skinnable': true + }, + + 'treeview': { + 'type': 'js', + 'path': 'treeview/treeview-min.js', + 'requires': ['event', 'dom'], + 'skinnable': true + }, + + 'uploader': { + 'type': 'js', + 'path': 'uploader/uploader-experimental.js', + 'requires': ['element'] + }, + + 'utilities': { + 'type': 'js', + 'path': 'utilities/utilities.js', + 'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event', 'get', 'yuiloader', 'yuiloader-dom-event'], + 'rollup': 8 + }, + + 'yahoo': { + 'type': 'js', + 'path': 'yahoo/yahoo-min.js' + }, + + 'yahoo-dom-event': { + 'type': 'js', + 'path': 'yahoo-dom-event/yahoo-dom-event.js', + 'supersedes': ['yahoo', 'event', 'dom'], + 'rollup': 3 + }, + + 'yuiloader': { + 'type': 'js', + 'path': 'yuiloader/yuiloader-min.js', + 'supersedes': ['yahoo', 'get'] + }, + + 'yuiloader-dom-event': { + 'type': 'js', + 'path': 'yuiloader-dom-event/yuiloader-dom-event.js', + 'supersedes': ['yahoo', 'dom', 'event', 'get', 'yuiloader', 'yahoo-dom-event'], + 'rollup': 5 + }, + + 'yuitest': { + 'type': 'js', + 'path': 'yuitest/yuitest-min.js', + 'requires': ['logger'], + 'skinnable': true + } + } +} + , + + ObjectUtil: { + appendArray: function(o, a) { + if (a) { + for (var i=0; i + *
                      DEBUG
                      + *
                      Selects the debug versions of the library (e.g., event-debug.js). + * This option will automatically include the logger widget
                      + *
                      RAW
                      + *
                      Selects the non-minified version of the library (e.g., event.js). + * + * You can also define a custom filter, which must be an object literal + * containing a search expression and a replace string: + *
                      +         *  myFilter: { 
                      +         *      'searchExp': "-min\\.js", 
                      +         *      'replaceStr': "-debug.js"
                      +         *  }
                      +         * 
                      + * @property filter + * @type string|{searchExp: string, replaceStr: string} + */ + this.filter = null; + + /** + * The list of requested modules + * @property required + * @type {string: boolean} + */ + this.required = {}; + + /** + * The library metadata + * @property moduleInfo + */ + this.moduleInfo = lang.merge(YUI.info.moduleInfo); + + /** + * List of rollup files found in the library metadata + * @property rollups + */ + this.rollups = null; + + /** + * Whether or not to load optional dependencies for + * the requested modules + * @property loadOptional + * @type boolean + * @default false + */ + this.loadOptional = false; + + /** + * All of the derived dependencies in sorted order, which + * will be populated when either calculate() or insert() + * is called + * @property sorted + * @type string[] + */ + this.sorted = []; + + /** + * Set when beginning to compute the dependency tree. + * Composed of what YAHOO reports to be loaded combined + * with what has been loaded by the tool + * @propery loaded + * @type {string: boolean} + */ + this.loaded = {}; + + /** + * Flag to indicate the dependency tree needs to be recomputed + * if insert is called again. + * @property dirty + * @type boolean + * @default true + */ + this.dirty = true; + + /** + * List of modules inserted by the utility + * @property inserted + * @type {string: boolean} + */ + this.inserted = {}; + + /** + * Provides the information used to skin the skinnable components. + * The following skin definition would result in 'skin1' and 'skin2' + * being loaded for calendar (if calendar was requested), and + * 'sam' for all other skinnable components: + * + * + * skin: { + * + * // The default skin, which is automatically applied if not + * // overriden by a component-specific skin definition. + * // Change this in to apply a different skin globally + * defaultSkin: 'sam', + * + * // This is combined with the loader base property to get + * // the default root directory for a skin. ex: + * // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/ + * base: 'assets/skins/', + * + * // The name of the rollup css file for the skin + * path: 'skin.css', + * + * // The number of skinnable components requested that are + * // required before using the rollup file rather than the + * // individual component css files + * rollup: 3, + * + * // Any component-specific overrides can be specified here, + * // making it possible to load different skins for different + * // components. It is possible to load more than one skin + * // for a given component as well. + * overrides: { + * calendar: ['skin1', 'skin2'] + * } + * } + * + * @property skin + */ + + var self = this; + + env.listeners.push(function(m) { + if (self._useYahooListener) { + //Y.log("YAHOO listener: " + m.name); + self.loadNext(m.name); + } + }); + + this.skin = lang.merge(YUI.info.skin); + + this._config(o); + + }; + + Y.util.YUILoader.prototype = { + + FILTERS: { + RAW: { + 'searchExp': "-min\\.js", + 'replaceStr': ".js" + }, + DEBUG: { + 'searchExp': "-min\\.js", + 'replaceStr': "-debug.js" + } + }, + + SKIN_PREFIX: "skin-", + + _config: function(o) { + + // apply config values + if (o) { + for (var i in o) { + if (lang.hasOwnProperty(o, i)) { + if (i == "require") { + this.require(o[i]); + } else { + this[i] = o[i]; + } + } + } + } + + // fix filter + var f = this.filter; + + if (lang.isString(f)) { + f = f.toUpperCase(); + + // the logger must be available in order to use the debug + // versions of the library + if (f === "DEBUG") { + this.require("logger"); + } + + // hack to handle a a bug where LogWriter is being instantiated + // at load time, and the loader has no way to sort above it + // at the moment. + if (!Y.widget.LogWriter) { + Y.widget.LogWriter = function() { + return Y; + }; + } + + this.filter = this.FILTERS[f]; + } + + }, + + /** Add a new module to the component metadata. + *
                      + *
                      name:
                      required, the component name
                      + *
                      type:
                      required, the component type (js or css)
                      + *
                      path:
                      required, the path to the script from "base"
                      + *
                      requires:
                      array of modules required by this component
                      + *
                      optional:
                      array of optional modules for this component
                      + *
                      supersedes:
                      array of the modules this component replaces
                      + *
                      after:
                      array of modules the components which, if present, should be sorted above this one
                      + *
                      rollup:
                      the number of superseded modules required for automatic rollup
                      + *
                      fullpath:
                      If fullpath is specified, this is used instead of the configured base + path
                      + *
                      skinnable:
                      flag to determine if skin assets should automatically be pulled in
                      + *
                      + * @method addModule + * @param o An object containing the module data + * @return {boolean} true if the module was added, false if + * the object passed in did not provide all required attributes + */ + addModule: function(o) { + + if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) { + return false; + } + + o.ext = ('ext' in o) ? o.ext : true; + o.requires = o.requires || []; + + this.moduleInfo[o.name] = o; + this.dirty = true; + + return true; + }, + + /** + * Add a requirement for one or more module + * @method require + * @param what {string[] | string*} the modules to load + */ + require: function(what) { + var a = (typeof what === "string") ? arguments : what; + this.dirty = true; + YUI.ObjectUtil.appendArray(this.required, a); + }, + + /** + * Adds the skin def to the module info + * @method _addSkin + * @param skin {string} the name of the skin + * @param mod {string} the name of the module + * @return {string} the module name for the skin + * @private + */ + _addSkin: function(skin, mod) { + + // Add a module definition for the skin rollup css + var name = this.formatSkin(skin), info = this.moduleInfo, + sinf = this.skin, ext = info[mod] && info[mod].ext; + + // Y.log('ext? ' + mod + ": " + ext); + if (!info[name]) { + // Y.log('adding skin ' + name); + this.addModule({ + 'name': name, + 'type': 'css', + 'path': sinf.base + skin + '/' + sinf.path, + //'supersedes': '*', + 'after': sinf.after, + 'rollup': sinf.rollup, + 'ext': ext + }); + } + + // Add a module definition for the module-specific skin css + if (mod) { + name = this.formatSkin(skin, mod); + if (!info[name]) { + var mdef = info[mod], pkg = mdef.pkg || mod; + // Y.log('adding skin ' + name); + this.addModule({ + 'name': name, + 'type': 'css', + 'after': sinf.after, + 'path': pkg + '/' + sinf.base + skin + '/' + mod + '.css', + 'ext': ext + }); + } + } + + return name; + }, + + /** + * Returns an object containing properties for all modules required + * in order to load the requested module + * @method getRequires + * @param mod The module definition from moduleInfo + */ + getRequires: function(mod) { + if (!mod) { + return []; + } + + if (!this.dirty && mod.expanded) { + return mod.expanded; + } + + mod.requires=mod.requires || []; + var i, d=[], r=mod.requires, o=mod.optional, info=this.moduleInfo, m; + for (i=0; i -1) { + // // YAHOO.log('adding ' + r[j]); + // d.push(req[j]); + // } + // } + // } + } + + if (o && this.loadOptional) { + for (i=0; iformatSkin, providing the skin name and + * module name if the string matches the pattern for skins. + * @method parseSkin + * @param mod {string} the module name to parse + * @return {skin: string, module: string} the parsed skin name + * and module name, or null if the supplied string does not match + * the skin pattern + */ + parseSkin: function(mod) { + + if (mod.indexOf(this.SKIN_PREFIX) === 0) { + var a = mod.split("-"); + return {skin: a[1], module: a[2]}; + } + + return null; + }, + + /** + * Look for rollup packages to determine if all of the modules a + * rollup supersedes are required. If so, include the rollup to + * help reduce the total number of connections required. Called + * by calculate() + * @method _rollup + * @private + */ + _rollup: function() { + var i, j, m, s, rollups={}, r=this.required, roll, + info = this.moduleInfo; + + // find and cache rollup modules + if (this.dirty || !this.rollups) { + for (i in info) { + if (lang.hasOwnProperty(info, i)) { + m = info[i]; + //if (m && m.rollup && m.supersedes) { + if (m && m.rollup) { + rollups[i] = m; + } + } + } + + this.rollups = rollups; + } + + // make as many passes as needed to pick up rollup rollups + for (;;) { + var rolled = false; + + // go through the rollup candidates + for (i in rollups) { + + // there can be only one + if (!r[i] && !this.loaded[i]) { + m =info[i]; s = m.supersedes; roll=false; + + if (!m.rollup) { + continue; + } + + var skin = (m.ext) ? false : this.parseSkin(i), c = 0; + + // Y.log('skin? ' + i + ": " + skin); + if (skin) { + for (j in r) { + if (lang.hasOwnProperty(r, j)) { + if (i !== j && this.parseSkin(j)) { + c++; + roll = (c >= m.rollup); + if (roll) { + // Y.log("skin rollup " + lang.dump(r)); + break; + } + } + } + } + + } else { + + // check the threshold + for (j=0;j= m.rollup); + if (roll) { + // Y.log("over thresh " + c + ", " + lang.dump(r)); + break; + } + } + } + } + + if (roll) { + // Y.log("rollup: " + i + ", " + lang.dump(this, 1)); + // add the rollup + r[i] = true; + rolled = true; + + // expand the rollup's dependencies + this.getRequires(m); + } + } + } + + // if we made it here w/o rolling up something, we are done + if (!rolled) { + break; + } + } + }, + + /** + * Remove superceded modules and loaded modules. Called by + * calculate() after we have the mega list of all dependencies + * @method _reduce + * @private + */ + _reduce: function() { + + var i, j, s, m, r=this.required; + for (i in r) { + + // remove if already loaded + if (i in this.loaded) { + delete r[i]; + + // remove anything this module supersedes + } else { + + var skinDef = this.parseSkin(i); + + if (skinDef) { + //YAHOO.log("skin found in reduce: " + skinDef.skin + ", " + skinDef.module); + // the skin rollup will not have a module name + if (!skinDef.module) { + var skin_pre = this.SKIN_PREFIX + skinDef.skin; + //YAHOO.log("skin_pre: " + skin_pre); + for (j in r) { + + if (lang.hasOwnProperty(r, j)) { + m = this.moduleInfo[j]; + var ext = m && m.ext; + if (!ext && j !== i && j.indexOf(skin_pre) > -1) { + // Y.log ("removing component skin: " + j); + delete r[j]; + } + } + } + } + } else { + + m = this.moduleInfo[i]; + s = m && m.supersedes; + if (s) { + for (j=0; j -1) { + return true; + } + + // check if this module should be sorted after the other + if (after && YUI.ArrayUtil.indexOf(after, bb) > -1) { + return true; + } + + // if loadOptional is not specified, optional dependencies still + // must be sorted correctly when present. + if (checkOptional && optional && YUI.ArrayUtil.indexOf(optional, bb) > -1) { + return true; + } + + // check if this module requires one the other supersedes + var ss=info[bb] && info[bb].supersedes; + if (ss) { + for (ii=0; ii startLen) { + YAHOO.util.Get.script(self._filter(js), { + data: self._loading, + onSuccess: callback, + onFailure: self._onFailure, + onTimeout: self._onTimeout, + insertBefore: self.insertBefore, + charset: self.charset, + timeout: self.timeout, + scope: self + }); + } + }; + + // load the css first + // YAHOO.log('combining css: ' + css); + if (css.length > startLen) { + YAHOO.util.Get.css(this._filter(css), { + data: this._loading, + onSuccess: loadScript, + onFailure: this._onFailure, + onTimeout: this._onTimeout, + insertBefore: this.insertBefore, + charset: this.charset, + timeout: this.timeout, + scope: self + }); + } else { + loadScript(); + } + + return; + + } else { + // this._combineComplete = true; + this.loadNext(this._loading); + } + }, + + /** + * inserts the requested modules and their dependencies. + * type can be "js" or "css". Both script and + * css are inserted if type is not provided. + * @method insert + * @param o optional options object + * @param type {string} the type of dependency to insert + */ + insert: function(o, type) { + // if (o) { + // Y.log("insert: " + lang.dump(o, 1) + ", " + type); + // } else { + // Y.log("insert: " + this.toString() + ", " + type); + // } + + // build the dependency list + this.calculate(o); + + + // set a flag to indicate the load has started + this._loading = true; + + // flag to indicate we are done with the combo service + // and any additional files will need to be loaded + // individually + // this._combineComplete = false; + + // keep the loadType (js, css or undefined) cached + this.loadType = type; + + if (this.combine) { + return this._combine(); + } + + if (!type) { + // Y.log("trying to load css first"); + var self = this; + this._internalCallback = function() { + self._internalCallback = null; + self.insert(null, "js"); + }; + this.insert(null, "css"); + return; + } + + + // start the load + this.loadNext(); + + }, + + /** + * Interns the script for the requested modules. The callback is + * provided a reference to the sandboxed YAHOO object. This only + * applies to the script: css can not be sandboxed; css will be + * loaded into the page normally if specified. + * @method sandbox + * @param callback {Function} the callback to exectued when the load is + * complete. + */ + sandbox: function(o, type) { + // if (o) { + // YAHOO.log("sandbox: " + lang.dump(o, 1) + ", " + type); + // } else { + // YAHOO.log("sandbox: " + this.toString() + ", " + type); + // } + + this._config(o); + + if (!this.onSuccess) { +throw new Error("You must supply an onSuccess handler for your sandbox"); + } + + this._sandbox = true; + + var self = this; + + // take care of any css first (this can't be sandboxed) + if (!type || type !== "js") { + this._internalCallback = function() { + self._internalCallback = null; + self.sandbox(null, "js"); + }; + this.insert(null, "css"); + return; + } + + // get the connection manager if not on the page + if (!util.Connect) { + // get a new loader instance to load connection. + var ld = new YAHOO.util.YUILoader(); + ld.insert({ + base: this.base, + filter: this.filter, + require: "connection", + insertBefore: this.insertBefore, + charset: this.charset, + onSuccess: function() { + this.sandbox(null, "js"); + }, + scope: this + }, "js"); + return; + } + + this._scriptText = []; + this._loadCount = 0; + this._stopCount = this.sorted.length; + this._xhr = []; + + this.calculate(); + + var s=this.sorted, l=s.length, i, m, url; + + for (i=0; i= this._stopCount) { + + // the variable to find + var v = this.varName || "YAHOO"; + + // wrap the contents of the requested modules in an anonymous function + var t = "(function() {\n"; + + // return the locally scoped reference. + var b = "\nreturn " + v + ";\n})();"; + + var ref = eval(t + this._scriptText.join("\n") + b); + + this._pushEvents(ref); + + if (ref) { + this.onSuccess.call(this.scope, { + reference: ref, + data: this.data + }); + } else { + this._onFailure.call(this.varName + " reference failure"); + } + } + }, + + failure: function(o) { + this.onFailure.call(this.scope, { + msg: "XHR failure", + xhrResponse: o, + data: this.data + }); + }, + + scope: this, + + // module index, module name, sandbox name + argument: [i, url, s[i]] + + }; + + this._xhr.push(util.Connect.asyncRequest('GET', url, xhrData)); + } + }, + + /** + * Executed every time a module is loaded, and if we are in a load + * cycle, we attempt to load the next script. Public so that it + * is possible to call this if using a method other than + * YAHOO.register to determine when scripts are fully loaded + * @method loadNext + * @param mname {string} optional the name of the module that has + * been loaded (which is usually why it is time to load the next + * one) + */ + loadNext: function(mname) { + + // It is possible that this function is executed due to something + // else one the page loading a YUI module. Only react when we + // are actively loading something + if (!this._loading) { + return; + } + + + if (mname) { + + // if the module that was just loaded isn't what we were expecting, + // continue to wait + if (mname !== this._loading) { + return; + } + + // YAHOO.log("loadNext executing, just loaded " + mname); + + // The global handler that is called when each module is loaded + // will pass that module name to this function. Storing this + // data to avoid loading the same module multiple times + this.inserted[mname] = true; + + if (this.onProgress) { + this.onProgress.call(this.scope, { + name: mname, + data: this.data + }); + } + //var o = this.getProvides(mname); + //this.inserted = lang.merge(this.inserted, o); + } + + var s=this.sorted, len=s.length, i, m; + + for (i=0; i0)?A.dump(D[F],I-1):L);}else{K.push(D[F]);}K.push(J);}if(K.length>1){K.pop();}K.push("]");}else{K.push("{");for(F in D){if(A.hasOwnProperty(D,F)){K.push(F+G);if(A.isObject(D[F])){K.push((I>0)?A.dump(D[F],I-1):L);}else{K.push(D[F]);}K.push(J);}}if(K.length>1){K.pop();}K.push("}");}return K.join("");},substitute:function(S,E,L){var I,H,G,O,P,R,N=[],F,J="dump",M=" ",D="{",Q="}";for(;;){I=S.lastIndexOf(D);if(I<0){break;}H=S.indexOf(Q,I);if(I+1>=H){break;}F=S.substring(I+1,H);O=F;R=null;G=O.indexOf(M);if(G>-1){R=O.substring(G+1);O=O.substring(0,G);}P=E[O];if(L){P=L(O,P,R);}if(A.isObject(P)){if(A.isArray(P)){P=A.dump(P,parseInt(R,10));}else{R=R||"";var K=R.indexOf(J);if(K>-1){R=R.substring(4);}if(P.toString===Object.prototype.toString||K>-1){P=A.dump(P,parseInt(R,10));}else{P=P.toString();}}}else{if(!A.isString(P)&&!A.isNumber(P)){P="~-"+N.length+"-~";N[N.length]=F;}}S=S.substring(0,I)+P+S.substring(H+1);}for(I=N.length-1;I>=0;I=I-1){S=S.replace(new RegExp("~-"+I+"-~"),"{"+N[I]+"}","g");}return S;},trim:function(D){try{return D.replace(/^\s+|\s+$/g,"");}catch(E){return D;}},merge:function(){var G={},E=arguments;for(var F=0,D=E.length;F=420){X.addEventListener("load",function(){a(W,U);});}else{var T=M[W];if(T.varName){var V=YAHOO.util.Get.POLL_FREQ;T.maxattempts=YAHOO.util.Get.TIMEOUT/V;T.attempts=0;T._cache=T.varName[0].split(".");T.timer=S.later(V,T,function(j){var f=this._cache,e=f.length,d=this.win,g;for(g=0;gthis.maxattempts){var h="Over retry limit, giving up";T.timer.cancel();Q(W,h);}else{}return ;}}T.timer.cancel();a(W,U);},null,true);}else{S.later(YAHOO.util.Get.POLL_FREQ,null,a,[W,U]);}}}}else{X.onload=function(){a(W,U);};}}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(T){S.later(0,null,C,T);},abort:function(U){var V=(S.isString(U))?U:U.tId;var T=M[V];if(T){T.aborted=true;}},script:function(T,U){return H("script",T,U);},css:function(T,U){return H("css",T,U);}};}();YAHOO.register("get",YAHOO.util.Get,{version:"2.6.0",build:"1321"});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV="_provides",SUPER="_supersedes",REQ="expanded",AFTER="_after";var YUI={dupsAllowed:{"yahoo":true,"get":true},info:{"root":"2.6.0/build/","base":"http://yui.yahooapis.com/2.6.0/build/","comboBase":"http://yui.yahooapis.com/combo?","skin":{"defaultSkin":"sam","base":"assets/skins/","path":"skin.css","after":["reset","fonts","grids","base"],"rollup":3},dupsAllowed:["yahoo","get"],"moduleInfo":{"animation":{"type":"js","path":"animation/animation-min.js","requires":["dom","event"]},"autocomplete":{"type":"js","path":"autocomplete/autocomplete-min.js","requires":["dom","event","datasource"],"optional":["connection","animation"],"skinnable":true},"base":{"type":"css","path":"base/base-min.css","after":["reset","fonts","grids"]},"button":{"type":"js","path":"button/button-min.js","requires":["element"],"optional":["menu"],"skinnable":true},"calendar":{"type":"js","path":"calendar/calendar-min.js","requires":["event","dom"],"skinnable":true},"carousel":{"type":"js","path":"carousel/carousel-beta-min.js","requires":["element"],"optional":["animation"],"skinnable":true},"charts":{"type":"js","path":"charts/charts-experimental-min.js","requires":["element","json","datasource"]},"colorpicker":{"type":"js","path":"colorpicker/colorpicker-min.js","requires":["slider","element"],"optional":["animation"],"skinnable":true},"connection":{"type":"js","path":"connection/connection-min.js","requires":["event"]},"container":{"type":"js","path":"container/container-min.js","requires":["dom","event"],"optional":["dragdrop","animation","connection"],"supersedes":["containercore"],"skinnable":true},"containercore":{"type":"js","path":"container/container_core-min.js","requires":["dom","event"],"pkg":"container"},"cookie":{"type":"js","path":"cookie/cookie-min.js","requires":["yahoo"]},"datasource":{"type":"js","path":"datasource/datasource-min.js","requires":["event"],"optional":["connection"]},"datatable":{"type":"js","path":"datatable/datatable-min.js","requires":["element","datasource"],"optional":["calendar","dragdrop","paginator"],"skinnable":true},"dom":{"type":"js","path":"dom/dom-min.js","requires":["yahoo"]},"dragdrop":{"type":"js","path":"dragdrop/dragdrop-min.js","requires":["dom","event"]},"editor":{"type":"js","path":"editor/editor-min.js","requires":["menu","element","button"],"optional":["animation","dragdrop"],"supersedes":["simpleeditor"],"skinnable":true},"element":{"type":"js","path":"element/element-beta-min.js","requires":["dom","event"]},"event":{"type":"js","path":"event/event-min.js","requires":["yahoo"]},"fonts":{"type":"css","path":"fonts/fonts-min.css"},"get":{"type":"js","path":"get/get-min.js","requires":["yahoo"]},"grids":{"type":"css","path":"grids/grids-min.css","requires":["fonts"],"optional":["reset"]},"history":{"type":"js","path":"history/history-min.js","requires":["event"]},"imagecropper":{"type":"js","path":"imagecropper/imagecropper-beta-min.js","requires":["dom","event","dragdrop","element","resize"],"skinnable":true},"imageloader":{"type":"js","path":"imageloader/imageloader-min.js","requires":["event","dom"]},"json":{"type":"js","path":"json/json-min.js","requires":["yahoo"]},"layout":{"type":"js","path":"layout/layout-min.js","requires":["dom","event","element"],"optional":["animation","dragdrop","resize","selector"],"skinnable":true},"logger":{"type":"js","path":"logger/logger-min.js","requires":["event","dom"],"optional":["dragdrop"],"skinnable":true},"menu":{"type":"js","path":"menu/menu-min.js","requires":["containercore"],"skinnable":true},"paginator":{"type":"js","path":"paginator/paginator-min.js","requires":["element"],"skinnable":true},"profiler":{"type":"js","path":"profiler/profiler-min.js","requires":["yahoo"]},"profilerviewer":{"type":"js","path":"profilerviewer/profilerviewer-beta-min.js","requires":["profiler","yuiloader","element"],"skinnable":true},"reset":{"type":"css","path":"reset/reset-min.css"},"reset-fonts-grids":{"type":"css","path":"reset-fonts-grids/reset-fonts-grids.css","supersedes":["reset","fonts","grids","reset-fonts"],"rollup":4},"reset-fonts":{"type":"css","path":"reset-fonts/reset-fonts.css","supersedes":["reset","fonts"],"rollup":2},"resize":{"type":"js","path":"resize/resize-min.js","requires":["dom","event","dragdrop","element"],"optional":["animation"],"skinnable":true},"selector":{"type":"js","path":"selector/selector-beta-min.js","requires":["yahoo","dom"]},"simpleeditor":{"type":"js","path":"editor/simpleeditor-min.js","requires":["element"],"optional":["containercore","menu","button","animation","dragdrop"],"skinnable":true,"pkg":"editor"},"slider":{"type":"js","path":"slider/slider-min.js","requires":["dragdrop"],"optional":["animation"],"skinnable":true},"tabview":{"type":"js","path":"tabview/tabview-min.js","requires":["element"],"optional":["connection"],"skinnable":true},"treeview":{"type":"js","path":"treeview/treeview-min.js","requires":["event","dom"],"skinnable":true},"uploader":{"type":"js","path":"uploader/uploader-experimental.js","requires":["element"]},"utilities":{"type":"js","path":"utilities/utilities.js","supersedes":["yahoo","event","dragdrop","animation","dom","connection","element","yahoo-dom-event","get","yuiloader","yuiloader-dom-event"],"rollup":8},"yahoo":{"type":"js","path":"yahoo/yahoo-min.js"},"yahoo-dom-event":{"type":"js","path":"yahoo-dom-event/yahoo-dom-event.js","supersedes":["yahoo","event","dom"],"rollup":3},"yuiloader":{"type":"js","path":"yuiloader/yuiloader-min.js","supersedes":["yahoo","get"]},"yuiloader-dom-event":{"type":"js","path":"yuiloader-dom-event/yuiloader-dom-event.js","supersedes":["yahoo","dom","event","get","yuiloader","yahoo-dom-event"],"rollup":5},"yuitest":{"type":"js","path":"yuitest/yuitest-min.js","requires":["logger"],"skinnable":true}}},ObjectUtil:{appendArray:function(o,a){if(a){for(var i=0; +i=m.rollup);if(roll){break;}}}}}else{for(j=0;j=m.rollup);if(roll){break;}}}}}if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}if(!rolled){break;}}},_reduce:function(){var i,j,s,m,r=this.required;for(i in r){if(i in this.loaded){delete r[i];}else{var skinDef=this.parseSkin(i);if(skinDef){if(!skinDef.module){var skin_pre=this.SKIN_PREFIX+skinDef.skin;for(j in r){if(lang.hasOwnProperty(r,j)){m=this.moduleInfo[j];var ext=m&&m.ext;if(!ext&&j!==i&&j.indexOf(skin_pre)>-1){delete r[j];}}}}}else{m=this.moduleInfo[i];s=m&&m.supersedes;if(s){for(j=0;j-1){return true;}if(after&&YUI.ArrayUtil.indexOf(after,bb)>-1){return true;}if(checkOptional&&optional&&YUI.ArrayUtil.indexOf(optional,bb)>-1){return true;}var ss=info[bb]&&info[bb].supersedes;if(ss){for(ii=0;iistartLen){YAHOO.util.Get.script(self._filter(js),{data:self._loading,onSuccess:callback,onFailure:self._onFailure,onTimeout:self._onTimeout,insertBefore:self.insertBefore,charset:self.charset,timeout:self.timeout,scope:self});}};if(css.length>startLen){YAHOO.util.Get.css(this._filter(css),{data:this._loading,onSuccess:loadScript,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,scope:self});}else{loadScript();}return ;}else{this.loadNext(this._loading);}},insert:function(o,type){this.calculate(o);this._loading=true;this.loadType=type;if(this.combine){return this._combine();}if(!type){var self=this;this._internalCallback=function(){self._internalCallback=null;self.insert(null,"js");};this.insert(null,"css");return ;}this.loadNext();},sandbox:function(o,type){this._config(o);if(!this.onSuccess){throw new Error("You must supply an onSuccess handler for your sandbox");}this._sandbox=true;var self=this;if(!type||type!=="js"){this._internalCallback=function(){self._internalCallback=null;self.sandbox(null,"js");};this.insert(null,"css");return ;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:this.base,filter:this.filter,require:"connection",insertBefore:this.insertBefore,charset:this.charset,onSuccess:function(){this.sandbox(null,"js");},scope:this},"js");return ;}this._scriptText=[];this._loadCount=0;this._stopCount=this.sorted.length;this._xhr=[];this.calculate();var s=this.sorted,l=s.length,i,m,url;for(i=0;i=this._stopCount){var v=this.varName||"YAHOO";var t="(function() {\n";var b="\nreturn "+v+";\n})();";var ref=eval(t+this._scriptText.join("\n")+b);this._pushEvents(ref);if(ref){this.onSuccess.call(this.scope,{reference:ref,data:this.data});}else{this._onFailure.call(this.varName+" reference failure");}}},failure:function(o){this.onFailure.call(this.scope,{msg:"XHR failure",xhrResponse:o,data:this.data});},scope:this,argument:[i,url,s[i]]};this._xhr.push(util.Connect.asyncRequest("GET",url,xhrData));}},loadNext:function(mname){if(!this._loading){return ;}if(mname){if(mname!==this._loading){return ;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}var s=this.sorted,len=s.length,i,m;for(i=0;i + * YAHOO.env.getVersion for the description of the version data structure. + * @property listener + * @type Function + * @static + * @default undefined + */ + +/** + * Set to true if the library will be dynamically loaded after window.onload. + * Defaults to false + * @property injecting + * @type boolean + * @static + * @default undefined + */ + +/** + * Instructs the yuiloader component to dynamically load yui components and + * their dependencies. See the yuiloader documentation for more information + * about dynamic loading + * @property load + * @static + * @default undefined + * @see yuiloader + */ + +/** + * Forces the use of the supplied locale where applicable in the library + * @property locale + * @type string + * @static + * @default undefined + */ + +if (typeof YAHOO == "undefined" || !YAHOO) { + /** + * The YAHOO global namespace object. If YAHOO is already defined, the + * existing YAHOO object will not be overwritten so that defined + * namespaces are preserved. + * @class YAHOO + * @static + */ + var YAHOO = {}; +} + +/** + * Returns the namespace specified and creates it if it doesn't exist + *
                      + * YAHOO.namespace("property.package");
                      + * YAHOO.namespace("YAHOO.property.package");
                      + * 
                      + * Either of the above would create YAHOO.property, then + * YAHOO.property.package + * + * Be careful when naming packages. Reserved words may work in some browsers + * and not others. For instance, the following will fail in Safari: + *
                      + * YAHOO.namespace("really.long.nested.namespace");
                      + * 
                      + * This fails because "long" is a future reserved word in ECMAScript + * + * @method namespace + * @static + * @param {String*} arguments 1-n namespaces to create + * @return {Object} A reference to the last namespace object created + */ +YAHOO.namespace = function() { + var a=arguments, o=null, i, j, d; + for (i=0; i + *
                      name:
                      The name of the module
                      + *
                      version:
                      The version in use
                      + *
                      build:
                      The build number in use
                      + *
                      versions:
                      All versions that were registered
                      + *
                      builds:
                      All builds that were registered.
                      + *
                      mainClass:
                      An object that was was stamped with the + * current version and build. If + * mainClass.VERSION != version or mainClass.BUILD != build, + * multiple versions of pieces of the library have been + * loaded, potentially causing issues.
                      + * + * + * @method getVersion + * @static + * @param {String} name the name of the module (event, slider, etc) + * @return {Object} The version info + */ +YAHOO.env.getVersion = function(name) { + return YAHOO.env.modules[name] || null; +}; + +/** + * Do not fork for a browser if it can be avoided. Use feature detection when + * you can. Use the user agent as a last resort. YAHOO.env.ua stores a version + * number for the browser engine, 0 otherwise. This value may or may not map + * to the version number of the browser using the engine. The value is + * presented as a float so that it can easily be used for boolean evaluation + * as well as for looking for a particular range of versions. Because of this, + * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 + * reports 1.8). + * @class YAHOO.env.ua + * @static + */ +YAHOO.env.ua = function() { + var o={ + + /** + * Internet Explorer version number or 0. Example: 6 + * @property ie + * @type float + */ + ie:0, + + /** + * Opera version number or 0. Example: 9.2 + * @property opera + * @type float + */ + opera:0, + + /** + * Gecko engine revision number. Will evaluate to 1 if Gecko + * is detected but the revision could not be found. Other browsers + * will be 0. Example: 1.8 + *
                      +         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
                      +         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
                      +         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
                      +         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
                      +         * 
                      + * @property gecko + * @type float + */ + gecko:0, + + /** + * AppleWebKit version. KHTML browsers that are not WebKit browsers + * will evaluate to 1, other browsers 0. Example: 418.9.1 + *
                      +         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
                      +         *                                   latest available for Mac OSX 10.3.
                      +         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
                      +         * Safari 2.0.4:         418     <-- preventDefault fixed
                      +         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
                      +         *                                   different versions of webkit
                      +         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
                      +         *                                   updated, but not updated
                      +         *                                   to the latest patch.
                      +         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
                      +         *                                   and many major issues fixed).  
                      +         * 3.x yahoo.com, flickr:422     <-- Safari 3.x hacks the user agent
                      +         *                                   string when hitting yahoo.com and 
                      +         *                                   flickr.com.
                      +         * Safari 3.0.4 (523.12):523.12  <-- First Tiger release - automatic update
                      +         *                                   from 2.x via the 10.4.11 OS patch
                      +         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
                      +         *                                   yahoo.com user agent hack removed.
                      +         *                                   
                      +         * 
                      + * http://developer.apple.com/internet/safari/uamatrix.html + * @property webkit + * @type float + */ + webkit: 0, + + /** + * The mobile property will be set to a string containing any relevant + * user agent information when a modern mobile browser is detected. + * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series + * devices with the WebKit-based browser, and Opera Mini. + * @property mobile + * @type string + */ + mobile: null, + + /** + * Adobe AIR version number or 0. Only populated if webkit is detected. + * Example: 1.0 + * @property air + * @type float + */ + air: 0 + + }; + + var ua=navigator.userAgent, m; + + // Modern KHTML browsers should qualify as Safari X-Grade + if ((/KHTML/).test(ua)) { + o.webkit=1; + } + // Modern WebKit browsers are at least X-Grade + m=ua.match(/AppleWebKit\/([^\s]*)/); + if (m&&m[1]) { + o.webkit=parseFloat(m[1]); + + // Mobile browser check + if (/ Mobile\//.test(ua)) { + o.mobile = "Apple"; // iPhone or iPod Touch + } else { + m=ua.match(/NokiaN[^\/]*/); + if (m) { + o.mobile = m[0]; // Nokia N-series, ex: NokiaN95 + } + } + + m=ua.match(/AdobeAIR\/([^\s]*)/); + if (m) { + o.air = m[0]; // Adobe AIR 1.0 or better + } + + } + + if (!o.webkit) { // not webkit + // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) + m=ua.match(/Opera[\s\/]([^\s]*)/); + if (m&&m[1]) { + o.opera=parseFloat(m[1]); + m=ua.match(/Opera Mini[^;]*/); + if (m) { + o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 + } + } else { // not opera or webkit + m=ua.match(/MSIE\s([^;]*)/); + if (m&&m[1]) { + o.ie=parseFloat(m[1]); + } else { // not opera, webkit, or ie + m=ua.match(/Gecko\/([^\s]*)/); + if (m) { + o.gecko=1; // Gecko detected, look for revision + m=ua.match(/rv:([^\s\)]*)/); + if (m&&m[1]) { + o.gecko=parseFloat(m[1]); + } + } + } + } + } + + return o; +}(); + +/* + * Initializes the global by creating the default namespaces and applying + * any new configuration information that is detected. This is the setup + * for env. + * @method init + * @static + * @private + */ +(function() { + YAHOO.namespace("util", "widget", "example"); + if ("undefined" !== typeof YAHOO_config) { + var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i; + if (l) { + // if YAHOO is loaded multiple times we need to check to see if + // this is a new config object. If it is, add the new component + // load listener to the stack + for (i=0;i 0) ? L.dump(o[i], d-1) : OBJ); + } else { + s.push(o[i]); + } + s.push(COMMA); + } + if (s.length > 1) { + s.pop(); + } + s.push("]"); + // objects {k1 => v1, k2 => v2} + } else { + s.push("{"); + for (i in o) { + if (L.hasOwnProperty(o, i)) { + s.push(i + ARROW); + if (L.isObject(o[i])) { + s.push((d > 0) ? L.dump(o[i], d-1) : OBJ); + } else { + s.push(o[i]); + } + s.push(COMMA); + } + } + if (s.length > 1) { + s.pop(); + } + s.push("}"); + } + + return s.join(""); + }, + + /** + * Does variable substitution on a string. It scans through the string + * looking for expressions enclosed in { } braces. If an expression + * is found, it is used a key on the object. If there is a space in + * the key, the first word is used for the key and the rest is provided + * to an optional function to be used to programatically determine the + * value (the extra information might be used for this decision). If + * the value for the key in the object, or what is returned from the + * function has a string value, number value, or object value, it is + * substituted for the bracket expression and it repeats. If this + * value is an object, it uses the Object's toString() if this has + * been overridden, otherwise it does a shallow dump of the key/value + * pairs. + * @method substitute + * @since 2.3.0 + * @param s {String} The string that will be modified. + * @param o {Object} An object containing the replacement values + * @param f {Function} An optional function that can be used to + * process each match. It receives the key, + * value, and any extra metadata included with + * the key inside of the braces. + * @return {String} the substituted string + */ + substitute: function (s, o, f) { + var i, j, k, key, v, meta, saved=[], token, + DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}'; + + + for (;;) { + i = s.lastIndexOf(LBRACE); + if (i < 0) { + break; + } + j = s.indexOf(RBRACE, i); + if (i + 1 >= j) { + break; + } + + //Extract key and meta info + token = s.substring(i + 1, j); + key = token; + meta = null; + k = key.indexOf(SPACE); + if (k > -1) { + meta = key.substring(k + 1); + key = key.substring(0, k); + } + + // lookup the value + v = o[key]; + + // if a substitution function was provided, execute it + if (f) { + v = f(key, v, meta); + } + + if (L.isObject(v)) { + if (L.isArray(v)) { + v = L.dump(v, parseInt(meta, 10)); + } else { + meta = meta || ""; + + // look for the keyword 'dump', if found force obj dump + var dump = meta.indexOf(DUMP); + if (dump > -1) { + meta = meta.substring(4); + } + + // use the toString if it is not the Object toString + // and the 'dump' meta info was not found + if (v.toString===Object.prototype.toString||dump>-1) { + v = L.dump(v, parseInt(meta, 10)); + } else { + v = v.toString(); + } + } + } else if (!L.isString(v) && !L.isNumber(v)) { + // This {block} has no replace string. Save it for later. + v = "~-" + saved.length + "-~"; + saved[saved.length] = token; + + // break; + } + + s = s.substring(0, i) + v + s.substring(j + 1); + + + } + + // restore saved {block}s + for (i=saved.length-1; i>=0; i=i-1) { + s = s.replace(new RegExp("~-" + i + "-~"), "{" + saved[i] + "}", "g"); + } + + return s; + }, + + + /** + * Returns a string without any leading or trailing whitespace. If + * the input is not a string, the input will be returned untouched. + * @method trim + * @since 2.3.0 + * @param s {string} the string to trim + * @return {string} the trimmed string + */ + trim: function(s){ + try { + return s.replace(/^\s+|\s+$/g, ""); + } catch(e) { + return s; + } + }, + + /** + * Returns a new object containing all of the properties of + * all the supplied objects. The properties from later objects + * will overwrite those in earlier objects. + * @method merge + * @since 2.3.0 + * @param arguments {Object*} the objects to merge + * @return the new merged object + */ + merge: function() { + var o={}, a=arguments; + for (var i=0, l=a.length; i + * var A = function() {}; + * A.prototype.foo = 'foo'; + * var a = new A(); + * a.foo = 'foo'; + * alert(a.hasOwnProperty('foo')); // true + * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback + * + * @method hasOwnProperty + * @param {any} o The object being testing + * @param prop {string} the name of the property to test + * @return {boolean} the result + */ +L.hasOwnProperty = (Object.prototype.hasOwnProperty) ? + function(o, prop) { + return o && o.hasOwnProperty(prop); + } : function(o, prop) { + return !L.isUndefined(o[prop]) && + o.constructor.prototype[prop] !== o[prop]; + }; + +// new lang wins +OB.augmentObject(L, OB, true); + +/* + * An alias for YAHOO.lang + * @class YAHOO.util.Lang + */ +YAHOO.util.Lang = L; + +/** + * Same as YAHOO.lang.augmentObject, except it only applies prototype + * properties. This is an alias for augmentProto. + * @see YAHOO.lang.augmentObject + * @method augment + * @static + * @param {Function} r the object to receive the augmentation + * @param {Function} s the object that supplies the properties to augment + * @param {String*|boolean} arguments zero or more properties methods to + * augment the receiver with. If none specified, everything + * in the supplier will be used unless it would + * overwrite an existing property in the receiver. if true + * is specified as the third parameter, all properties will + * be applied and will overwrite an existing property in + * the receiver + */ +L.augment = L.augmentProto; + +/** + * An alias for YAHOO.lang.augment + * @for YAHOO + * @method augment + * @static + * @param {Function} r the object to receive the augmentation + * @param {Function} s the object that supplies the properties to augment + * @param {String*} arguments zero or more properties methods to + * augment the receiver with. If none specified, everything + * in the supplier will be used unless it would + * overwrite an existing property in the receiver + */ +YAHOO.augment = L.augmentProto; + +/** + * An alias for YAHOO.lang.extend + * @method extend + * @static + * @param {Function} subc the object to modify + * @param {Function} superc the object to inherit + * @param {Object} overrides additional properties/methods to add to the + * subclass prototype. These will override the + * matching items obtained from the superclass if present. + */ +YAHOO.extend = L.extend; + +})(); +YAHOO.register("yahoo", YAHOO, {version: "2.6.0", build: "1321"}); +/** + * Provides a mechanism to fetch remote resources and + * insert them into a document + * @module get + * @requires yahoo + */ + +/** + * Fetches and inserts one or more script or link nodes into the document + * @namespace YAHOO.util + * @class YAHOO.util.Get + */ +YAHOO.util.Get = function() { + + /** + * hash of queues to manage multiple requests + * @property queues + * @private + */ + var queues={}, + + /** + * queue index used to generate transaction ids + * @property qidx + * @type int + * @private + */ + qidx=0, + + /** + * node index used to generate unique node ids + * @property nidx + * @type int + * @private + */ + nidx=0, + + // ridx=0, + + // sandboxFrame=null, + + /** + * interal property used to prevent multiple simultaneous purge + * processes + * @property purging + * @type boolean + * @private + */ + purging=false, + + ua=YAHOO.env.ua, + + lang=YAHOO.lang; + + /** + * Generates an HTML element, this is not appended to a document + * @method _node + * @param type {string} the type of element + * @param attr {string} the attributes + * @param win {Window} optional window to create the element in + * @return {HTMLElement} the generated node + * @private + */ + var _node = function(type, attr, win) { + var w = win || window, d=w.document, n=d.createElement(type); + + for (var i in attr) { + if (attr[i] && YAHOO.lang.hasOwnProperty(attr, i)) { + n.setAttribute(i, attr[i]); + } + } + + return n; + }; + + /** + * Generates a link node + * @method _linkNode + * @param url {string} the url for the css file + * @param win {Window} optional window to create the node in + * @return {HTMLElement} the generated node + * @private + */ + var _linkNode = function(url, win, charset) { + var c = charset || "utf-8"; + return _node("link", { + "id": "yui__dyn_" + (nidx++), + "type": "text/css", + "charset": c, + "rel": "stylesheet", + "href": url + }, win); + }; + + /** + * Generates a script node + * @method _scriptNode + * @param url {string} the url for the script file + * @param win {Window} optional window to create the node in + * @return {HTMLElement} the generated node + * @private + */ + var _scriptNode = function(url, win, charset) { + var c = charset || "utf-8"; + return _node("script", { + "id": "yui__dyn_" + (nidx++), + "type": "text/javascript", + "charset": c, + "src": url + }, win); + }; + + /** + * Returns the data payload for callback functions + * @method _returnData + * @private + */ + var _returnData = function(q, msg) { + return { + tId: q.tId, + win: q.win, + data: q.data, + nodes: q.nodes, + msg: msg, + purge: function() { + _purge(this.tId); + } + }; + }; + + var _get = function(nId, tId) { + var q = queues[tId], + n = (lang.isString(nId)) ? q.win.document.getElementById(nId) : nId; + if (!n) { + _fail(tId, "target node not found: " + nId); + } + + return n; + }; + + /* + * The request failed, execute fail handler with whatever + * was accomplished. There isn't a failure case at the + * moment unless you count aborted transactions + * @method _fail + * @param id {string} the id of the request + * @private + */ + var _fail = function(id, msg) { + var q = queues[id]; + // execute failure callback + if (q.onFailure) { + var sc=q.scope || q.win; + q.onFailure.call(sc, _returnData(q, msg)); + } + }; + + /** + * The request is complete, so executing the requester's callback + * @method _finish + * @param id {string} the id of the request + * @private + */ + var _finish = function(id) { + var q = queues[id]; + q.finished = true; + + if (q.aborted) { + var msg = "transaction " + id + " was aborted"; + _fail(id, msg); + return; + } + + // execute success callback + if (q.onSuccess) { + var sc=q.scope || q.win; + q.onSuccess.call(sc, _returnData(q)); + } + }; + + /** + * Timeout detected + * @method _timeout + * @param id {string} the id of the request + * @private + */ + var _timeout = function(id) { + var q = queues[id]; + if (q.onTimeout) { + var sc=q.context || q; + q.onTimeout.call(sc, _returnData(q)); + } + }; + + /** + * Loads the next item for a given request + * @method _next + * @param id {string} the id of the request + * @param loaded {string} the url that was just loaded, if any + * @private + */ + var _next = function(id, loaded) { + var q = queues[id]; + + if (q.timer) { + // Y.log('cancel timer'); + q.timer.cancel(); + } + + if (q.aborted) { + var msg = "transaction " + id + " was aborted"; + _fail(id, msg); + return; + } + + if (loaded) { + q.url.shift(); + if (q.varName) { + q.varName.shift(); + } + } else { + // This is the first pass: make sure the url is an array + q.url = (lang.isString(q.url)) ? [q.url] : q.url; + if (q.varName) { + q.varName = (lang.isString(q.varName)) ? [q.varName] : q.varName; + } + } + + var w=q.win, d=w.document, h=d.getElementsByTagName("head")[0], n; + + if (q.url.length === 0) { + // Safari 2.x workaround - There is no way to know when + // a script is ready in versions of Safari prior to 3.x. + // Adding an extra node reduces the problem, but doesn't + // eliminate it completely because the browser executes + // them asynchronously. + if (q.type === "script" && ua.webkit && ua.webkit < 420 && + !q.finalpass && !q.varName) { + // Add another script node. This does not guarantee that the + // scripts will execute in order, but it does appear to fix the + // problem on fast connections more effectively than using an + // arbitrary timeout. It is possible that the browser does + // block subsequent script execution in this case for a limited + // time. + var extra = _scriptNode(null, q.win, q.charset); + extra.innerHTML='YAHOO.util.Get._finalize("' + id + '");'; + q.nodes.push(extra); h.appendChild(extra); + + } else { + _finish(id); + } + + return; + } + + + var url = q.url[0]; + + // if the url is undefined, this is probably a trailing comma problem in IE + if (!url) { + q.url.shift(); + return _next(id); + } + + + if (q.timeout) { + // Y.log('create timer'); + q.timer = lang.later(q.timeout, q, _timeout, id); + } + + if (q.type === "script") { + n = _scriptNode(url, w, q.charset); + } else { + n = _linkNode(url, w, q.charset); + } + + // track this node's load progress + _track(q.type, n, id, url, w, q.url.length); + + // add the node to the queue so we can return it to the user supplied callback + q.nodes.push(n); + + // add it to the head or insert it before 'insertBefore' + if (q.insertBefore) { + var s = _get(q.insertBefore, id); + if (s) { + s.parentNode.insertBefore(n, s); + } + } else { + h.appendChild(n); + } + + + // FireFox does not support the onload event for link nodes, so there is + // no way to make the css requests synchronous. This means that the css + // rules in multiple files could be applied out of order in this browser + // if a later request returns before an earlier one. Safari too. + if ((ua.webkit || ua.gecko) && q.type === "css") { + _next(id, url); + } + }; + + /** + * Removes processed queues and corresponding nodes + * @method _autoPurge + * @private + */ + var _autoPurge = function() { + + if (purging) { + return; + } + + purging = true; + for (var i in queues) { + var q = queues[i]; + if (q.autopurge && q.finished) { + _purge(q.tId); + delete queues[i]; + } + } + + purging = false; + }; + + /** + * Removes the nodes for the specified queue + * @method _purge + * @private + */ + var _purge = function(tId) { + var q=queues[tId]; + if (q) { + var n=q.nodes, l=n.length, d=q.win.document, + h=d.getElementsByTagName("head")[0]; + + if (q.insertBefore) { + var s = _get(q.insertBefore, tId); + if (s) { + h = s.parentNode; + } + } + + for (var i=0; i= 420) { + + n.addEventListener("load", function() { + f(id, url); + }); + + // Nothing can be done with Safari < 3.x except to pause and hope + // for the best, particularly after last script is inserted. The + // scripts will always execute in the order they arrive, not + // necessarily the order in which they were inserted. To support + // script nodes with complete reliability in these browsers, script + // nodes either need to invoke a function in the window once they + // are loaded or the implementer needs to provide a well-known + // property that the utility can poll for. + } else { + // Poll for the existence of the named variable, if it + // was supplied. + var q = queues[id]; + if (q.varName) { + var freq=YAHOO.util.Get.POLL_FREQ; + q.maxattempts = YAHOO.util.Get.TIMEOUT/freq; + q.attempts = 0; + q._cache = q.varName[0].split("."); + q.timer = lang.later(freq, q, function(o) { + var a=this._cache, l=a.length, w=this.win, i; + for (i=0; i this.maxattempts) { + var msg = "Over retry limit, giving up"; + q.timer.cancel(); + _fail(id, msg); + } else { + } + return; + } + } + + + q.timer.cancel(); + f(id, url); + + }, null, true); + } else { + lang.later(YAHOO.util.Get.POLL_FREQ, null, f, [id, url]); + } + } + } + + // FireFox and Opera support onload (but not DOM2 in FF) handlers for + // script nodes. Opera, but not FF, supports the onload event for link + // nodes. + } else { + n.onload = function() { + f(id, url); + }; + } + }; + + return { + + /** + * The default poll freqency in ms, when needed + * @property POLL_FREQ + * @static + * @type int + * @default 10 + */ + POLL_FREQ: 10, + + /** + * The number of request required before an automatic purge. + * property PURGE_THRESH + * @static + * @type int + * @default 20 + */ + PURGE_THRESH: 20, + + /** + * The length time to poll for varName when loading a script in + * Safari 2.x before the transaction fails. + * property TIMEOUT + * @static + * @type int + * @default 2000 + */ + TIMEOUT: 2000, + + /** + * Called by the the helper for detecting script load in Safari + * @method _finalize + * @param id {string} the transaction id + * @private + */ + _finalize: function(id) { + lang.later(0, null, _finish, id); + }, + + /** + * Abort a transaction + * @method abort + * @param {string|object} either the tId or the object returned from + * script() or css() + */ + abort: function(o) { + var id = (lang.isString(o)) ? o : o.tId; + var q = queues[id]; + if (q) { + q.aborted = true; + } + }, + + /** + * Fetches and inserts one or more script nodes into the head + * of the current document or the document in a specified window. + * + * @method script + * @static + * @param url {string|string[]} the url or urls to the script(s) + * @param opts {object} Options: + *
                      + *
                      onSuccess
                      + *
                      + * callback to execute when the script(s) are finished loading + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      onFailure
                      + *
                      + * callback to execute when the script load operation fails + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted successfully
                      + *
                      purge
                      + *
                      A function that, when executed, will remove any nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      onTimeout
                      + *
                      + * callback to execute when a timeout occurs. + * The callback receives an object back with the following + * data: + *
                      + *
                      win
                      + *
                      the window the script(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + *
                      + *
                      scope
                      + *
                      the execution context for the callbacks
                      + *
                      win
                      + *
                      a window other than the one the utility occupies
                      + *
                      autopurge
                      + *
                      + * setting to true will let the utilities cleanup routine purge + * the script once loaded + *
                      + *
                      data
                      + *
                      + * data that is supplied to the callback when the script(s) are + * loaded. + *
                      + *
                      varName
                      + *
                      + * variable that should be available when a script is finished + * loading. Used to help Safari 2.x and below with script load + * detection. The type of this property should match what was + * passed into the url parameter: if loading a single url, a + * string can be supplied. If loading multiple scripts, you + * must supply an array that contains the variable name for + * each script. + *
                      + *
                      insertBefore
                      + *
                      node or node id that will become the new node's nextSibling
                      + *
                      + *
                      charset
                      + *
                      Node charset, default utf-8
                      + *
                      timeout
                      + *
                      Number of milliseconds to wait before aborting and firing the timeout event
                      + *
                      +         * // assumes yahoo, dom, and event are already on the page
                      +         *   YAHOO.util.Get.script(
                      +         *   ["http://yui.yahooapis.com/2.3.1/build/dragdrop/dragdrop-min.js",
                      +         *    "http://yui.yahooapis.com/2.3.1/build/animation/animation-min.js"], {
                      +         *     onSuccess: function(o) {
                      +         *       new YAHOO.util.DDProxy("dd1"); // also new o.reference("dd1"); would work
                      +         *       this.log("won't cause error because YAHOO is the scope");
                      +         *       this.log(o.nodes.length === 2) // true
                      +         *       // o.purge(); // optionally remove the script nodes immediately
                      +         *     },
                      +         *     onFailure: function(o) {
                      +         *     },
                      +         *     data: "foo",
                      +         *     timeout: 10000, // 10 second timeout
                      +         *     scope: YAHOO,
                      +         *     // win: otherframe // target another window/frame
                      +         *     autopurge: true // allow the utility to choose when to remove the nodes
                      +         *   });
                      +         * 
                      + * @return {tId: string} an object containing info about the transaction + */ + script: function(url, opts) { return _queue("script", url, opts); }, + + /** + * Fetches and inserts one or more css link nodes into the + * head of the current document or the document in a specified + * window. + * @method css + * @static + * @param url {string} the url or urls to the css file(s) + * @param opts Options: + *
                      + *
                      onSuccess
                      + *
                      + * callback to execute when the css file(s) are finished loading + * The callback receives an object back with the following + * data: + *
                      win
                      + *
                      the window the link nodes(s) were inserted into
                      + *
                      data
                      + *
                      the data object passed in when the request was made
                      + *
                      nodes
                      + *
                      An array containing references to the nodes that were + * inserted
                      + *
                      purge
                      + *
                      A function that, when executed, will remove the nodes + * that were inserted
                      + *
                      + *
                      + * + *
                      scope
                      + *
                      the execution context for the callbacks
                      + *
                      win
                      + *
                      a window other than the one the utility occupies
                      + *
                      data
                      + *
                      + * data that is supplied to the callbacks when the nodes(s) are + * loaded. + *
                      + *
                      insertBefore
                      + *
                      node or node id that will become the new node's nextSibling
                      + *
                      charset
                      + *
                      Node charset, default utf-8
                      + * + *
                      +         *      YAHOO.util.Get.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css");
                      +         * 
                      + *
                      +         *      YAHOO.util.Get.css(["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css",
                      +         * 
                      + * @return {tId: string} an object containing info about the transaction + */ + css: function(url, opts) { + return _queue("css", url, opts); + } + }; +}(); + +YAHOO.register("get", YAHOO.util.Get, {version: "2.6.0", build: "1321"}); +/** + * Provides dynamic loading for the YUI library. It includes the dependency + * info for the library, and will automatically pull in dependencies for + * the modules requested. It supports rollup files (such as utilities.js + * and yahoo-dom-event.js), and will automatically use these when + * appropriate in order to minimize the number of http connections + * required to load all of the dependencies. + * + * @module yuiloader + * @namespace YAHOO.util + */ + +/** + * YUILoader provides dynamic loading for YUI. + * @class YAHOO.util.YUILoader + * @todo + * version management, automatic sandboxing + */ +(function() { + + var Y=YAHOO, util=Y.util, lang=Y.lang, env=Y.env, + PROV = "_provides", SUPER = "_supersedes", + REQ = "expanded", AFTER = "_after"; + + var YUI = { + + dupsAllowed: {'yahoo': true, 'get': true}, + + /* + * The library metadata for the current release The is the default + * value for YAHOO.util.YUILoader.moduleInfo + * @property YUIInfo + * @static + */ + info: { + + // 'root': '2.5.2/build/', + // 'base': 'http://yui.yahooapis.com/2.5.2/build/', + + 'root': '2.6.0/build/', + 'base': 'http://yui.yahooapis.com/2.6.0/build/', + + 'comboBase': 'http://yui.yahooapis.com/combo?', + + 'skin': { + 'defaultSkin': 'sam', + 'base': 'assets/skins/', + 'path': 'skin.css', + 'after': ['reset', 'fonts', 'grids', 'base'], + 'rollup': 3 + }, + + dupsAllowed: ['yahoo', 'get'], + + 'moduleInfo': { + + 'animation': { + 'type': 'js', + 'path': 'animation/animation-min.js', + 'requires': ['dom', 'event'] + }, + + 'autocomplete': { + 'type': 'js', + 'path': 'autocomplete/autocomplete-min.js', + 'requires': ['dom', 'event', 'datasource'], + 'optional': ['connection', 'animation'], + 'skinnable': true + }, + + 'base': { + 'type': 'css', + 'path': 'base/base-min.css', + 'after': ['reset', 'fonts', 'grids'] + }, + + 'button': { + 'type': 'js', + 'path': 'button/button-min.js', + 'requires': ['element'], + 'optional': ['menu'], + 'skinnable': true + }, + + 'calendar': { + 'type': 'js', + 'path': 'calendar/calendar-min.js', + 'requires': ['event', 'dom'], + 'skinnable': true + }, + + 'carousel': { + 'type': 'js', + 'path': 'carousel/carousel-beta-min.js', + 'requires': ['element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'charts': { + 'type': 'js', + 'path': 'charts/charts-experimental-min.js', + 'requires': ['element', 'json', 'datasource'] + }, + + 'colorpicker': { + 'type': 'js', + 'path': 'colorpicker/colorpicker-min.js', + 'requires': ['slider', 'element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'connection': { + 'type': 'js', + 'path': 'connection/connection-min.js', + 'requires': ['event'] + }, + + 'container': { + 'type': 'js', + 'path': 'container/container-min.js', + 'requires': ['dom', 'event'], + // button is also optional, but this creates a circular + // dependency when loadOptional is specified. button + // optionally includes menu, menu requires container. + 'optional': ['dragdrop', 'animation', 'connection'], + 'supersedes': ['containercore'], + 'skinnable': true + }, + + 'containercore': { + 'type': 'js', + 'path': 'container/container_core-min.js', + 'requires': ['dom', 'event'], + 'pkg': 'container' + }, + + 'cookie': { + 'type': 'js', + 'path': 'cookie/cookie-min.js', + 'requires': ['yahoo'] + }, + + 'datasource': { + 'type': 'js', + 'path': 'datasource/datasource-min.js', + 'requires': ['event'], + 'optional': ['connection'] + }, + + 'datatable': { + 'type': 'js', + 'path': 'datatable/datatable-min.js', + 'requires': ['element', 'datasource'], + 'optional': ['calendar', 'dragdrop', 'paginator'], + 'skinnable': true + }, + + 'dom': { + 'type': 'js', + 'path': 'dom/dom-min.js', + 'requires': ['yahoo'] + }, + + 'dragdrop': { + 'type': 'js', + 'path': 'dragdrop/dragdrop-min.js', + 'requires': ['dom', 'event'] + }, + + 'editor': { + 'type': 'js', + 'path': 'editor/editor-min.js', + 'requires': ['menu', 'element', 'button'], + 'optional': ['animation', 'dragdrop'], + 'supersedes': ['simpleeditor'], + 'skinnable': true + }, + + 'element': { + 'type': 'js', + 'path': 'element/element-beta-min.js', + 'requires': ['dom', 'event'] + }, + + 'event': { + 'type': 'js', + 'path': 'event/event-min.js', + 'requires': ['yahoo'] + }, + + 'fonts': { + 'type': 'css', + 'path': 'fonts/fonts-min.css' + }, + + 'get': { + 'type': 'js', + 'path': 'get/get-min.js', + 'requires': ['yahoo'] + }, + + 'grids': { + 'type': 'css', + 'path': 'grids/grids-min.css', + 'requires': ['fonts'], + 'optional': ['reset'] + }, + + 'history': { + 'type': 'js', + 'path': 'history/history-min.js', + 'requires': ['event'] + }, + + 'imagecropper': { + 'type': 'js', + 'path': 'imagecropper/imagecropper-beta-min.js', + 'requires': ['dom', 'event', 'dragdrop', 'element', 'resize'], + 'skinnable': true + }, + + 'imageloader': { + 'type': 'js', + 'path': 'imageloader/imageloader-min.js', + 'requires': ['event', 'dom'] + }, + + 'json': { + 'type': 'js', + 'path': 'json/json-min.js', + 'requires': ['yahoo'] + }, + + 'layout': { + 'type': 'js', + 'path': 'layout/layout-min.js', + 'requires': ['dom', 'event', 'element'], + 'optional': ['animation', 'dragdrop', 'resize', 'selector'], + 'skinnable': true + }, + + 'logger': { + 'type': 'js', + 'path': 'logger/logger-min.js', + 'requires': ['event', 'dom'], + 'optional': ['dragdrop'], + 'skinnable': true + }, + + 'menu': { + 'type': 'js', + 'path': 'menu/menu-min.js', + 'requires': ['containercore'], + 'skinnable': true + }, + + 'paginator': { + 'type': 'js', + 'path': 'paginator/paginator-min.js', + 'requires': ['element'], + 'skinnable': true + }, + + 'profiler': { + 'type': 'js', + 'path': 'profiler/profiler-min.js', + 'requires': ['yahoo'] + }, + + + 'profilerviewer': { + 'type': 'js', + 'path': 'profilerviewer/profilerviewer-beta-min.js', + 'requires': ['profiler', 'yuiloader', 'element'], + 'skinnable': true + }, + + 'reset': { + 'type': 'css', + 'path': 'reset/reset-min.css' + }, + + 'reset-fonts-grids': { + 'type': 'css', + 'path': 'reset-fonts-grids/reset-fonts-grids.css', + 'supersedes': ['reset', 'fonts', 'grids', 'reset-fonts'], + 'rollup': 4 + }, + + 'reset-fonts': { + 'type': 'css', + 'path': 'reset-fonts/reset-fonts.css', + 'supersedes': ['reset', 'fonts'], + 'rollup': 2 + }, + + 'resize': { + 'type': 'js', + 'path': 'resize/resize-min.js', + 'requires': ['dom', 'event', 'dragdrop', 'element'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'selector': { + 'type': 'js', + 'path': 'selector/selector-beta-min.js', + 'requires': ['yahoo', 'dom'] + }, + + 'simpleeditor': { + 'type': 'js', + 'path': 'editor/simpleeditor-min.js', + 'requires': ['element'], + 'optional': ['containercore', 'menu', 'button', 'animation', 'dragdrop'], + 'skinnable': true, + 'pkg': 'editor' + }, + + 'slider': { + 'type': 'js', + 'path': 'slider/slider-min.js', + 'requires': ['dragdrop'], + 'optional': ['animation'], + 'skinnable': true + }, + + 'tabview': { + 'type': 'js', + 'path': 'tabview/tabview-min.js', + 'requires': ['element'], + 'optional': ['connection'], + 'skinnable': true + }, + + 'treeview': { + 'type': 'js', + 'path': 'treeview/treeview-min.js', + 'requires': ['event', 'dom'], + 'skinnable': true + }, + + 'uploader': { + 'type': 'js', + 'path': 'uploader/uploader-experimental.js', + 'requires': ['element'] + }, + + 'utilities': { + 'type': 'js', + 'path': 'utilities/utilities.js', + 'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event', 'get', 'yuiloader', 'yuiloader-dom-event'], + 'rollup': 8 + }, + + 'yahoo': { + 'type': 'js', + 'path': 'yahoo/yahoo-min.js' + }, + + 'yahoo-dom-event': { + 'type': 'js', + 'path': 'yahoo-dom-event/yahoo-dom-event.js', + 'supersedes': ['yahoo', 'event', 'dom'], + 'rollup': 3 + }, + + 'yuiloader': { + 'type': 'js', + 'path': 'yuiloader/yuiloader-min.js', + 'supersedes': ['yahoo', 'get'] + }, + + 'yuiloader-dom-event': { + 'type': 'js', + 'path': 'yuiloader-dom-event/yuiloader-dom-event.js', + 'supersedes': ['yahoo', 'dom', 'event', 'get', 'yuiloader', 'yahoo-dom-event'], + 'rollup': 5 + }, + + 'yuitest': { + 'type': 'js', + 'path': 'yuitest/yuitest-min.js', + 'requires': ['logger'], + 'skinnable': true + } + } +} + , + + ObjectUtil: { + appendArray: function(o, a) { + if (a) { + for (var i=0; i + *
                      DEBUG
                      + *
                      Selects the debug versions of the library (e.g., event-debug.js). + * This option will automatically include the logger widget
                      + *
                      RAW
                      + *
                      Selects the non-minified version of the library (e.g., event.js). + * + * You can also define a custom filter, which must be an object literal + * containing a search expression and a replace string: + *
                      +         *  myFilter: { 
                      +         *      'searchExp': "-min\\.js", 
                      +         *      'replaceStr': "-debug.js"
                      +         *  }
                      +         * 
                      + * @property filter + * @type string|{searchExp: string, replaceStr: string} + */ + this.filter = null; + + /** + * The list of requested modules + * @property required + * @type {string: boolean} + */ + this.required = {}; + + /** + * The library metadata + * @property moduleInfo + */ + this.moduleInfo = lang.merge(YUI.info.moduleInfo); + + /** + * List of rollup files found in the library metadata + * @property rollups + */ + this.rollups = null; + + /** + * Whether or not to load optional dependencies for + * the requested modules + * @property loadOptional + * @type boolean + * @default false + */ + this.loadOptional = false; + + /** + * All of the derived dependencies in sorted order, which + * will be populated when either calculate() or insert() + * is called + * @property sorted + * @type string[] + */ + this.sorted = []; + + /** + * Set when beginning to compute the dependency tree. + * Composed of what YAHOO reports to be loaded combined + * with what has been loaded by the tool + * @propery loaded + * @type {string: boolean} + */ + this.loaded = {}; + + /** + * Flag to indicate the dependency tree needs to be recomputed + * if insert is called again. + * @property dirty + * @type boolean + * @default true + */ + this.dirty = true; + + /** + * List of modules inserted by the utility + * @property inserted + * @type {string: boolean} + */ + this.inserted = {}; + + /** + * Provides the information used to skin the skinnable components. + * The following skin definition would result in 'skin1' and 'skin2' + * being loaded for calendar (if calendar was requested), and + * 'sam' for all other skinnable components: + * + * + * skin: { + * + * // The default skin, which is automatically applied if not + * // overriden by a component-specific skin definition. + * // Change this in to apply a different skin globally + * defaultSkin: 'sam', + * + * // This is combined with the loader base property to get + * // the default root directory for a skin. ex: + * // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/ + * base: 'assets/skins/', + * + * // The name of the rollup css file for the skin + * path: 'skin.css', + * + * // The number of skinnable components requested that are + * // required before using the rollup file rather than the + * // individual component css files + * rollup: 3, + * + * // Any component-specific overrides can be specified here, + * // making it possible to load different skins for different + * // components. It is possible to load more than one skin + * // for a given component as well. + * overrides: { + * calendar: ['skin1', 'skin2'] + * } + * } + * + * @property skin + */ + + var self = this; + + env.listeners.push(function(m) { + if (self._useYahooListener) { + //Y.log("YAHOO listener: " + m.name); + self.loadNext(m.name); + } + }); + + this.skin = lang.merge(YUI.info.skin); + + this._config(o); + + }; + + Y.util.YUILoader.prototype = { + + FILTERS: { + RAW: { + 'searchExp': "-min\\.js", + 'replaceStr': ".js" + }, + DEBUG: { + 'searchExp': "-min\\.js", + 'replaceStr': "-debug.js" + } + }, + + SKIN_PREFIX: "skin-", + + _config: function(o) { + + // apply config values + if (o) { + for (var i in o) { + if (lang.hasOwnProperty(o, i)) { + if (i == "require") { + this.require(o[i]); + } else { + this[i] = o[i]; + } + } + } + } + + // fix filter + var f = this.filter; + + if (lang.isString(f)) { + f = f.toUpperCase(); + + // the logger must be available in order to use the debug + // versions of the library + if (f === "DEBUG") { + this.require("logger"); + } + + // hack to handle a a bug where LogWriter is being instantiated + // at load time, and the loader has no way to sort above it + // at the moment. + if (!Y.widget.LogWriter) { + Y.widget.LogWriter = function() { + return Y; + }; + } + + this.filter = this.FILTERS[f]; + } + + }, + + /** Add a new module to the component metadata. + *
                      + *
                      name:
                      required, the component name
                      + *
                      type:
                      required, the component type (js or css)
                      + *
                      path:
                      required, the path to the script from "base"
                      + *
                      requires:
                      array of modules required by this component
                      + *
                      optional:
                      array of optional modules for this component
                      + *
                      supersedes:
                      array of the modules this component replaces
                      + *
                      after:
                      array of modules the components which, if present, should be sorted above this one
                      + *
                      rollup:
                      the number of superseded modules required for automatic rollup
                      + *
                      fullpath:
                      If fullpath is specified, this is used instead of the configured base + path
                      + *
                      skinnable:
                      flag to determine if skin assets should automatically be pulled in
                      + *
                      + * @method addModule + * @param o An object containing the module data + * @return {boolean} true if the module was added, false if + * the object passed in did not provide all required attributes + */ + addModule: function(o) { + + if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) { + return false; + } + + o.ext = ('ext' in o) ? o.ext : true; + o.requires = o.requires || []; + + this.moduleInfo[o.name] = o; + this.dirty = true; + + return true; + }, + + /** + * Add a requirement for one or more module + * @method require + * @param what {string[] | string*} the modules to load + */ + require: function(what) { + var a = (typeof what === "string") ? arguments : what; + this.dirty = true; + YUI.ObjectUtil.appendArray(this.required, a); + }, + + /** + * Adds the skin def to the module info + * @method _addSkin + * @param skin {string} the name of the skin + * @param mod {string} the name of the module + * @return {string} the module name for the skin + * @private + */ + _addSkin: function(skin, mod) { + + // Add a module definition for the skin rollup css + var name = this.formatSkin(skin), info = this.moduleInfo, + sinf = this.skin, ext = info[mod] && info[mod].ext; + + // Y.log('ext? ' + mod + ": " + ext); + if (!info[name]) { + // Y.log('adding skin ' + name); + this.addModule({ + 'name': name, + 'type': 'css', + 'path': sinf.base + skin + '/' + sinf.path, + //'supersedes': '*', + 'after': sinf.after, + 'rollup': sinf.rollup, + 'ext': ext + }); + } + + // Add a module definition for the module-specific skin css + if (mod) { + name = this.formatSkin(skin, mod); + if (!info[name]) { + var mdef = info[mod], pkg = mdef.pkg || mod; + // Y.log('adding skin ' + name); + this.addModule({ + 'name': name, + 'type': 'css', + 'after': sinf.after, + 'path': pkg + '/' + sinf.base + skin + '/' + mod + '.css', + 'ext': ext + }); + } + } + + return name; + }, + + /** + * Returns an object containing properties for all modules required + * in order to load the requested module + * @method getRequires + * @param mod The module definition from moduleInfo + */ + getRequires: function(mod) { + if (!mod) { + return []; + } + + if (!this.dirty && mod.expanded) { + return mod.expanded; + } + + mod.requires=mod.requires || []; + var i, d=[], r=mod.requires, o=mod.optional, info=this.moduleInfo, m; + for (i=0; i -1) { + // // YAHOO.log('adding ' + r[j]); + // d.push(req[j]); + // } + // } + // } + } + + if (o && this.loadOptional) { + for (i=0; iformatSkin, providing the skin name and + * module name if the string matches the pattern for skins. + * @method parseSkin + * @param mod {string} the module name to parse + * @return {skin: string, module: string} the parsed skin name + * and module name, or null if the supplied string does not match + * the skin pattern + */ + parseSkin: function(mod) { + + if (mod.indexOf(this.SKIN_PREFIX) === 0) { + var a = mod.split("-"); + return {skin: a[1], module: a[2]}; + } + + return null; + }, + + /** + * Look for rollup packages to determine if all of the modules a + * rollup supersedes are required. If so, include the rollup to + * help reduce the total number of connections required. Called + * by calculate() + * @method _rollup + * @private + */ + _rollup: function() { + var i, j, m, s, rollups={}, r=this.required, roll, + info = this.moduleInfo; + + // find and cache rollup modules + if (this.dirty || !this.rollups) { + for (i in info) { + if (lang.hasOwnProperty(info, i)) { + m = info[i]; + //if (m && m.rollup && m.supersedes) { + if (m && m.rollup) { + rollups[i] = m; + } + } + } + + this.rollups = rollups; + } + + // make as many passes as needed to pick up rollup rollups + for (;;) { + var rolled = false; + + // go through the rollup candidates + for (i in rollups) { + + // there can be only one + if (!r[i] && !this.loaded[i]) { + m =info[i]; s = m.supersedes; roll=false; + + if (!m.rollup) { + continue; + } + + var skin = (m.ext) ? false : this.parseSkin(i), c = 0; + + // Y.log('skin? ' + i + ": " + skin); + if (skin) { + for (j in r) { + if (lang.hasOwnProperty(r, j)) { + if (i !== j && this.parseSkin(j)) { + c++; + roll = (c >= m.rollup); + if (roll) { + // Y.log("skin rollup " + lang.dump(r)); + break; + } + } + } + } + + } else { + + // check the threshold + for (j=0;j= m.rollup); + if (roll) { + // Y.log("over thresh " + c + ", " + lang.dump(r)); + break; + } + } + } + } + + if (roll) { + // Y.log("rollup: " + i + ", " + lang.dump(this, 1)); + // add the rollup + r[i] = true; + rolled = true; + + // expand the rollup's dependencies + this.getRequires(m); + } + } + } + + // if we made it here w/o rolling up something, we are done + if (!rolled) { + break; + } + } + }, + + /** + * Remove superceded modules and loaded modules. Called by + * calculate() after we have the mega list of all dependencies + * @method _reduce + * @private + */ + _reduce: function() { + + var i, j, s, m, r=this.required; + for (i in r) { + + // remove if already loaded + if (i in this.loaded) { + delete r[i]; + + // remove anything this module supersedes + } else { + + var skinDef = this.parseSkin(i); + + if (skinDef) { + //YAHOO.log("skin found in reduce: " + skinDef.skin + ", " + skinDef.module); + // the skin rollup will not have a module name + if (!skinDef.module) { + var skin_pre = this.SKIN_PREFIX + skinDef.skin; + //YAHOO.log("skin_pre: " + skin_pre); + for (j in r) { + + if (lang.hasOwnProperty(r, j)) { + m = this.moduleInfo[j]; + var ext = m && m.ext; + if (!ext && j !== i && j.indexOf(skin_pre) > -1) { + // Y.log ("removing component skin: " + j); + delete r[j]; + } + } + } + } + } else { + + m = this.moduleInfo[i]; + s = m && m.supersedes; + if (s) { + for (j=0; j -1) { + return true; + } + + // check if this module should be sorted after the other + if (after && YUI.ArrayUtil.indexOf(after, bb) > -1) { + return true; + } + + // if loadOptional is not specified, optional dependencies still + // must be sorted correctly when present. + if (checkOptional && optional && YUI.ArrayUtil.indexOf(optional, bb) > -1) { + return true; + } + + // check if this module requires one the other supersedes + var ss=info[bb] && info[bb].supersedes; + if (ss) { + for (ii=0; ii startLen) { + YAHOO.util.Get.script(self._filter(js), { + data: self._loading, + onSuccess: callback, + onFailure: self._onFailure, + onTimeout: self._onTimeout, + insertBefore: self.insertBefore, + charset: self.charset, + timeout: self.timeout, + scope: self + }); + } + }; + + // load the css first + // YAHOO.log('combining css: ' + css); + if (css.length > startLen) { + YAHOO.util.Get.css(this._filter(css), { + data: this._loading, + onSuccess: loadScript, + onFailure: this._onFailure, + onTimeout: this._onTimeout, + insertBefore: this.insertBefore, + charset: this.charset, + timeout: this.timeout, + scope: self + }); + } else { + loadScript(); + } + + return; + + } else { + // this._combineComplete = true; + this.loadNext(this._loading); + } + }, + + /** + * inserts the requested modules and their dependencies. + * type can be "js" or "css". Both script and + * css are inserted if type is not provided. + * @method insert + * @param o optional options object + * @param type {string} the type of dependency to insert + */ + insert: function(o, type) { + // if (o) { + // Y.log("insert: " + lang.dump(o, 1) + ", " + type); + // } else { + // Y.log("insert: " + this.toString() + ", " + type); + // } + + // build the dependency list + this.calculate(o); + + + // set a flag to indicate the load has started + this._loading = true; + + // flag to indicate we are done with the combo service + // and any additional files will need to be loaded + // individually + // this._combineComplete = false; + + // keep the loadType (js, css or undefined) cached + this.loadType = type; + + if (this.combine) { + return this._combine(); + } + + if (!type) { + // Y.log("trying to load css first"); + var self = this; + this._internalCallback = function() { + self._internalCallback = null; + self.insert(null, "js"); + }; + this.insert(null, "css"); + return; + } + + + // start the load + this.loadNext(); + + }, + + /** + * Interns the script for the requested modules. The callback is + * provided a reference to the sandboxed YAHOO object. This only + * applies to the script: css can not be sandboxed; css will be + * loaded into the page normally if specified. + * @method sandbox + * @param callback {Function} the callback to exectued when the load is + * complete. + */ + sandbox: function(o, type) { + // if (o) { + // YAHOO.log("sandbox: " + lang.dump(o, 1) + ", " + type); + // } else { + // YAHOO.log("sandbox: " + this.toString() + ", " + type); + // } + + this._config(o); + + if (!this.onSuccess) { +throw new Error("You must supply an onSuccess handler for your sandbox"); + } + + this._sandbox = true; + + var self = this; + + // take care of any css first (this can't be sandboxed) + if (!type || type !== "js") { + this._internalCallback = function() { + self._internalCallback = null; + self.sandbox(null, "js"); + }; + this.insert(null, "css"); + return; + } + + // get the connection manager if not on the page + if (!util.Connect) { + // get a new loader instance to load connection. + var ld = new YAHOO.util.YUILoader(); + ld.insert({ + base: this.base, + filter: this.filter, + require: "connection", + insertBefore: this.insertBefore, + charset: this.charset, + onSuccess: function() { + this.sandbox(null, "js"); + }, + scope: this + }, "js"); + return; + } + + this._scriptText = []; + this._loadCount = 0; + this._stopCount = this.sorted.length; + this._xhr = []; + + this.calculate(); + + var s=this.sorted, l=s.length, i, m, url; + + for (i=0; i= this._stopCount) { + + // the variable to find + var v = this.varName || "YAHOO"; + + // wrap the contents of the requested modules in an anonymous function + var t = "(function() {\n"; + + // return the locally scoped reference. + var b = "\nreturn " + v + ";\n})();"; + + var ref = eval(t + this._scriptText.join("\n") + b); + + this._pushEvents(ref); + + if (ref) { + this.onSuccess.call(this.scope, { + reference: ref, + data: this.data + }); + } else { + this._onFailure.call(this.varName + " reference failure"); + } + } + }, + + failure: function(o) { + this.onFailure.call(this.scope, { + msg: "XHR failure", + xhrResponse: o, + data: this.data + }); + }, + + scope: this, + + // module index, module name, sandbox name + argument: [i, url, s[i]] + + }; + + this._xhr.push(util.Connect.asyncRequest('GET', url, xhrData)); + } + }, + + /** + * Executed every time a module is loaded, and if we are in a load + * cycle, we attempt to load the next script. Public so that it + * is possible to call this if using a method other than + * YAHOO.register to determine when scripts are fully loaded + * @method loadNext + * @param mname {string} optional the name of the module that has + * been loaded (which is usually why it is time to load the next + * one) + */ + loadNext: function(mname) { + + // It is possible that this function is executed due to something + // else one the page loading a YUI module. Only react when we + // are actively loading something + if (!this._loading) { + return; + } + + + if (mname) { + + // if the module that was just loaded isn't what we were expecting, + // continue to wait + if (mname !== this._loading) { + return; + } + + // YAHOO.log("loadNext executing, just loaded " + mname); + + // The global handler that is called when each module is loaded + // will pass that module name to this function. Storing this + // data to avoid loading the same module multiple times + this.inserted[mname] = true; + + if (this.onProgress) { + this.onProgress.call(this.scope, { + name: mname, + data: this.data + }); + } + //var o = this.getProvides(mname); + //this.inserted = lang.merge(this.inserted, o); + } + + var s=this.sorted, len=s.length, i, m; + + for (i=0; i