PageRenderTime 101ms CodeModel.GetById 10ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 0ms

/static/scripts/jquery.wymeditor.js

https://bitbucket.org/cistrome/cistrome-harvard/
JavaScript | 2092 lines | 1431 code | 272 blank | 389 comment | 156 complexity | e0b3fb4aa4dd7c540f46f4b312cca967 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * @version 0.5-rc1
   3 *
   4 * WYMeditor : what you see is What You Mean web-based editor
   5 * Copyright (c) 2005 - 2009 Jean-Francois Hovinne, http://www.wymeditor.org/
   6 * Dual licensed under the MIT (MIT-license.txt)
   7 * and GPL (GPL-license.txt) licenses.
   8 *
   9 * For further information visit:
  10 *        http://www.wymeditor.org/
  11 *
  12 * File: jquery.wymeditor.js
  13 *
  14 *        Main JS file with core classes and functions.
  15 *        See the documentation for more info.
  16 *
  17 * About: authors
  18 *
  19 *        Jean-Francois Hovinne (jf.hovinne a-t wymeditor dotorg)
  20 *        Volker Mische (vmx a-t gmx dotde)
  21 *        Scott Lewis (lewiscot a-t gmail dotcom)
  22 *        Bermi Ferrer (wymeditor a-t bermi dotorg)
  23 *        Daniel Reszka (d.reszka a-t wymeditor dotorg)
  24 *        Jonatan Lundin (jonatan.lundin _at_ gmail.com)
  25 */
  26
  27/*
  28   Namespace: WYMeditor
  29   Global WYMeditor namespace.
  30*/
  31if(!WYMeditor) var WYMeditor = {};
  32
  33//Wrap the Firebug console in WYMeditor.console
  34(function() {
  35    if ( !window.console || !console.firebug ) {
  36        var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
  37        "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
  38
  39        WYMeditor.console = {};
  40        for (var i = 0; i < names.length; ++i)
  41            WYMeditor.console[names[i]] = function() {}
  42
  43    } else WYMeditor.console = window.console;
  44})();
  45
  46jQuery.extend(WYMeditor, {
  47
  48/*
  49    Constants: Global WYMeditor constants.
  50
  51    VERSION             - Defines WYMeditor version.
  52    INSTANCES           - An array of loaded WYMeditor.editor instances.
  53    STRINGS             - An array of loaded WYMeditor language pairs/values.
  54    SKINS               - An array of loaded WYMeditor skins.
  55    NAME                - The "name" attribute.
  56    INDEX               - A string replaced by the instance index.
  57    WYM_INDEX           - A string used to get/set the instance index.
  58    BASE_PATH           - A string replaced by WYMeditor's base path.
  59    SKIN_PATH           - A string replaced by WYMeditor's skin path.
  60    WYM_PATH            - A string replaced by WYMeditor's main JS file path.
  61    SKINS_DEFAULT_PATH  - The skins default base path.
  62    SKINS_DEFAULT_CSS   - The skins default CSS file.
  63    LANG_DEFAULT_PATH   - The language files default path.
  64    IFRAME_BASE_PATH    - A string replaced by the designmode iframe's base path.
  65    IFRAME_DEFAULT      - The iframe's default base path.
  66    JQUERY_PATH         - A string replaced by the computed jQuery path.
  67    DIRECTION           - A string replaced by the text direction (rtl or ltr).
  68    LOGO                - A string replaced by WYMeditor logo.
  69    TOOLS               - A string replaced by the toolbar's HTML.
  70    TOOLS_ITEMS         - A string replaced by the toolbar items.
  71    TOOL_NAME           - A string replaced by a toolbar item's name.
  72    TOOL_TITLE          - A string replaced by a toolbar item's title.
  73    TOOL_CLASS          - A string replaced by a toolbar item's class.
  74    CLASSES             - A string replaced by the classes panel's HTML.
  75    CLASSES_ITEMS       - A string replaced by the classes items.
  76    CLASS_NAME          - A string replaced by a class item's name.
  77    CLASS_TITLE         - A string replaced by a class item's title.
  78    CONTAINERS          - A string replaced by the containers panel's HTML.
  79    CONTAINERS_ITEMS    - A string replaced by the containers items.
  80    CONTAINER_NAME      - A string replaced by a container item's name.
  81    CONTAINER_TITLE     - A string replaced by a container item's title.
  82    CONTAINER_CLASS     - A string replaced by a container item's class.
  83    HTML                - A string replaced by the HTML view panel's HTML.
  84    IFRAME              - A string replaced by the designmode iframe.
  85    STATUS              - A string replaced by the status panel's HTML.
  86    DIALOG_TITLE        - A string replaced by a dialog's title.
  87    DIALOG_BODY         - A string replaced by a dialog's HTML body.
  88    BODY                - The BODY element.
  89    STRING              - The "string" type.
  90    BODY,DIV,P,
  91    H1,H2,H3,H4,H5,H6,
  92    PRE,BLOCKQUOTE,
  93    A,BR,IMG,
  94    TABLE,TD,TH,
  95    UL,OL,LI            - HTML elements string representation.
  96    CLASS,HREF,SRC,
  97    TITLE,ALT           - HTML attributes string representation.
  98    DIALOG_LINK         - A link dialog type.
  99    DIALOG_IMAGE        - An image dialog type.
 100    DIALOG_TABLE        - A table dialog type.
 101    DIALOG_PASTE        - A 'Paste from Word' dialog type.
 102    BOLD                - Command: (un)set selection to <strong>.
 103    ITALIC              - Command: (un)set selection to <em>.
 104    CREATE_LINK         - Command: open the link dialog or (un)set link.
 105    INSERT_IMAGE        - Command: open the image dialog or insert an image.
 106    INSERT_TABLE        - Command: open the table dialog.
 107    PASTE               - Command: open the paste dialog.
 108    INDENT              - Command: nest a list item.
 109    OUTDENT             - Command: unnest a list item.
 110    TOGGLE_HTML         - Command: display/hide the HTML view.
 111    FORMAT_BLOCK        - Command: set a block element to another type.
 112    PREVIEW             - Command: open the preview dialog.
 113    UNLINK              - Command: unset a link.
 114    INSERT_UNORDEREDLIST- Command: insert an unordered list.
 115    INSERT_ORDEREDLIST  - Command: insert an ordered list.
 116    MAIN_CONTAINERS     - An array of the main HTML containers used in WYMeditor.
 117    BLOCKS              - An array of the HTML block elements.
 118    KEY                 - Standard key codes.
 119    NODE                - Node types.
 120
 121*/
 122
 123    VERSION             : "0.5-rc1",
 124    INSTANCES           : [],
 125    STRINGS             : [],
 126    SKINS               : [],
 127    NAME                : "name",
 128    INDEX               : "{Wym_Index}",
 129    WYM_INDEX           : "wym_index",
 130    BASE_PATH           : "{Wym_Base_Path}",
 131    CSS_PATH            : "{Wym_Css_Path}",
 132    WYM_PATH            : "{Wym_Wym_Path}",
 133    SKINS_DEFAULT_PATH  : "skins/",
 134    SKINS_DEFAULT_CSS   : "skin.css",
 135    SKINS_DEFAULT_JS    : "skin.js",
 136    LANG_DEFAULT_PATH   : "lang/",
 137    IFRAME_BASE_PATH    : "{Wym_Iframe_Base_Path}",
 138    IFRAME_DEFAULT      : "iframe/default/",
 139    JQUERY_PATH         : "{Wym_Jquery_Path}",
 140    DIRECTION           : "{Wym_Direction}",
 141    LOGO                : "{Wym_Logo}",
 142    TOOLS               : "{Wym_Tools}",
 143    TOOLS_ITEMS         : "{Wym_Tools_Items}",
 144    TOOL_NAME           : "{Wym_Tool_Name}",
 145    TOOL_TITLE          : "{Wym_Tool_Title}",
 146    TOOL_CLASS          : "{Wym_Tool_Class}",
 147    CLASSES             : "{Wym_Classes}",
 148    CLASSES_ITEMS       : "{Wym_Classes_Items}",
 149    CLASS_NAME          : "{Wym_Class_Name}",
 150    CLASS_TITLE         : "{Wym_Class_Title}",
 151    CONTAINERS          : "{Wym_Containers}",
 152    CONTAINERS_ITEMS    : "{Wym_Containers_Items}",
 153    CONTAINER_NAME      : "{Wym_Container_Name}",
 154    CONTAINER_TITLE     : "{Wym_Containers_Title}",
 155    CONTAINER_CLASS     : "{Wym_Container_Class}",
 156    HTML                : "{Wym_Html}",
 157    IFRAME              : "{Wym_Iframe}",
 158    STATUS              : "{Wym_Status}",
 159    DIALOG_TITLE        : "{Wym_Dialog_Title}",
 160    DIALOG_BODY         : "{Wym_Dialog_Body}",
 161    STRING              : "string",
 162    BODY                : "body",
 163    DIV                 : "div",
 164    P                   : "p",
 165    H1                  : "h1",
 166    H2                  : "h2",
 167    H3                  : "h3",
 168    H4                  : "h4",
 169    H5                  : "h5",
 170    H6                  : "h6",
 171    PRE                 : "pre",
 172    BLOCKQUOTE          : "blockquote",
 173    A                   : "a",
 174    BR                  : "br",
 175    IMG                 : "img",
 176    TABLE               : "table",
 177    TD                  : "td",
 178    TH                  : "th",
 179    UL                  : "ul",
 180    OL                  : "ol",
 181    LI                  : "li",
 182    CLASS               : "class",
 183    HREF                : "href",
 184    SRC                 : "src",
 185    TITLE               : "title",
 186    ALT                 : "alt",
 187    DIALOG_LINK         : "Link",
 188    DIALOG_IMAGE        : "Image",
 189    DIALOG_TABLE        : "Table",
 190    DIALOG_PASTE        : "Paste_From_Word",
 191    BOLD                : "Bold",
 192    ITALIC              : "Italic",
 193    CREATE_LINK         : "CreateLink",
 194    INSERT_IMAGE        : "InsertImage",
 195    INSERT_TABLE        : "InsertTable",
 196    INSERT_HTML         : "InsertHTML",
 197    PASTE               : "Paste",
 198    INDENT              : "Indent",
 199    OUTDENT             : "Outdent",
 200    TOGGLE_HTML         : "ToggleHtml",
 201    FORMAT_BLOCK        : "FormatBlock",
 202    PREVIEW             : "Preview",
 203    UNLINK			        : "Unlink",
 204    INSERT_UNORDEREDLIST: "InsertUnorderedList",
 205    INSERT_ORDEREDLIST	: "InsertOrderedList",
 206
 207    MAIN_CONTAINERS : new Array("p","h1","h2","h3","h4","h5","h6","pre","blockquote"),
 208
 209    BLOCKS : new Array("address", "blockquote", "div", "dl",
 210	   "fieldset", "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr",
 211	   "noscript", "ol", "p", "pre", "table", "ul", "dd", "dt",
 212	   "li", "tbody", "td", "tfoot", "th", "thead", "tr"),
 213
 214    KEY : {
 215      BACKSPACE: 8,
 216      ENTER: 13,
 217      END: 35,
 218      HOME: 36,
 219      LEFT: 37,
 220      UP: 38,
 221      RIGHT: 39,
 222      DOWN: 40,
 223      CURSOR: new Array(37, 38, 39, 40),
 224      DELETE: 46
 225    },
 226
 227    NODE : {
 228      ELEMENT: 1,
 229      ATTRIBUTE: 2,
 230      TEXT: 3
 231    },
 232	
 233    /*
 234        Class: WYMeditor.editor
 235        WYMeditor editor main class, instanciated for each editor occurrence.
 236    */
 237
 238	editor : function(elem, options) {
 239
 240        /*
 241            Constructor: WYMeditor.editor
 242
 243            Initializes main values (index, elements, paths, ...)
 244            and call WYMeditor.editor.init which initializes the editor.
 245
 246            Parameters:
 247
 248                elem - The HTML element to be replaced by the editor.
 249                options - The hash of options.
 250
 251            Returns:
 252
 253                Nothing.
 254
 255            See Also:
 256
 257                <WYMeditor.editor.init>
 258        */
 259
 260        //store the instance in the INSTANCES array and store the index
 261        this._index = WYMeditor.INSTANCES.push(this) - 1;
 262        //store the element replaced by the editor
 263        this._element = elem;
 264        //store the options
 265        this._options = options;
 266        //store the element's inner value
 267        this._html = jQuery(elem).val();
 268
 269        //store the HTML option, if any
 270        if(this._options.html) this._html = this._options.html;
 271        //get or compute the base path (where the main JS file is located)
 272        this._options.basePath = this._options.basePath
 273        || this.computeBasePath();
 274        //get or set the skin path (where the skin files are located)
 275        this._options.skinPath = this._options.skinPath
 276        || this._options.basePath + WYMeditor.SKINS_DEFAULT_PATH
 277           + this._options.skin + '/';
 278        //get or compute the main JS file location
 279        this._options.wymPath = this._options.wymPath
 280        || this.computeWymPath();
 281        //get or set the language files path
 282        this._options.langPath = this._options.langPath
 283        || this._options.basePath + WYMeditor.LANG_DEFAULT_PATH;
 284        //get or set the designmode iframe's base path
 285        this._options.iframeBasePath = this._options.iframeBasePath
 286        || this._options.basePath + WYMeditor.IFRAME_DEFAULT;
 287        //get or compute the jQuery JS file location
 288        this._options.jQueryPath = this._options.jQueryPath
 289        || this.computeJqueryPath();
 290
 291        //initialize the editor instance
 292        this.init();
 293	
 294	}
 295
 296});
 297
 298/********** JQUERY **********/
 299
 300/**
 301 * Replace an HTML element by WYMeditor
 302 *
 303 * @example jQuery(".wymeditor").wymeditor(
 304 *        {
 305 *
 306 *        }
 307 *      );
 308 * @desc Example description here
 309 * 
 310 * @name WYMeditor
 311 * @description WYMeditor is a web-based WYSIWYM XHTML editor
 312 * @param Hash hash A hash of parameters
 313 * @option Integer iExample Description here
 314 * @option String sExample Description here
 315 *
 316 * @type jQuery
 317 * @cat Plugins/WYMeditor
 318 * @author Jean-Francois Hovinne
 319 */
 320jQuery.fn.wymeditor = function(options) {
 321
 322  options = jQuery.extend({
 323
 324    html:       "",
 325    
 326    basePath:   false,
 327    
 328    skinPath:    false,
 329    
 330    wymPath:    false,
 331    
 332    iframeBasePath: false,
 333    
 334    jQueryPath: false,
 335    
 336    styles: false,
 337    
 338    stylesheet: false,
 339    
 340    skin:       "default",
 341    initSkin:   true,
 342    loadSkin:   true,
 343
 344    lang:       "en",
 345
 346    direction:  "ltr",
 347
 348    boxHtml:   "<div class='wym_box'>"
 349              + "<div class='wym_area_top'>" 
 350              + WYMeditor.TOOLS
 351              + "</div>"
 352              + "<div class='wym_area_left'></div>"
 353              + "<div class='wym_area_right'>"
 354              + WYMeditor.CONTAINERS
 355              + WYMeditor.CLASSES
 356              + "</div>"
 357              + "<div class='wym_area_main'>"
 358              + WYMeditor.HTML
 359              + WYMeditor.IFRAME
 360              + WYMeditor.STATUS
 361              + "</div>"
 362              + "<div class='wym_area_bottom'>"
 363              + WYMeditor.LOGO
 364              + "</div>"
 365              + "</div>",
 366
 367    logoHtml:  "<a class='wym_wymeditor_link' "
 368              + "href='http://www.wymeditor.org/'>WYMeditor</a>",
 369
 370    iframeHtml:"<div class='wym_iframe wym_section'>"
 371              + "<iframe "
 372              + "src='"
 373              + "/page/get_editor_iframe' "
 374              //+ WYMeditor.IFRAME_BASE_PATH
 375              //+ "wymiframe.html' "
 376              + "onload='this.contentWindow.parent.WYMeditor.INSTANCES["
 377              + WYMeditor.INDEX + "].initIframe(this)'"
 378              + "></iframe>"
 379              + "</div>",
 380              
 381    editorStyles: [],
 382
 383    toolsHtml: "<div class='wym_tools wym_section'>"
 384              + "<h2>{Tools}</h2>"
 385              + "<ul>"
 386              + WYMeditor.TOOLS_ITEMS
 387              + "</ul>"
 388              + "</div>",
 389              
 390    toolsItemHtml:   "<li class='"
 391                        + WYMeditor.TOOL_CLASS
 392                        + "'><a href='#' name='"
 393                        + WYMeditor.TOOL_NAME
 394                        + "' title='"
 395                        + WYMeditor.TOOL_TITLE
 396                        + "'>"
 397                        + WYMeditor.TOOL_TITLE
 398                        + "</a></li>",
 399
 400    toolsItems: [
 401        {'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'}, 
 402        {'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'},
 403        {'name': 'Superscript', 'title': 'Superscript',
 404            'css': 'wym_tools_superscript'},
 405        {'name': 'Subscript', 'title': 'Subscript',
 406            'css': 'wym_tools_subscript'},
 407        {'name': 'InsertOrderedList', 'title': 'Ordered_List',
 408            'css': 'wym_tools_ordered_list'},
 409        {'name': 'InsertUnorderedList', 'title': 'Unordered_List',
 410            'css': 'wym_tools_unordered_list'},
 411        {'name': 'Indent', 'title': 'Indent', 'css': 'wym_tools_indent'},
 412        {'name': 'Outdent', 'title': 'Outdent', 'css': 'wym_tools_outdent'},
 413        {'name': 'Undo', 'title': 'Undo', 'css': 'wym_tools_undo'},
 414        {'name': 'Redo', 'title': 'Redo', 'css': 'wym_tools_redo'},
 415        {'name': 'CreateLink', 'title': 'Link', 'css': 'wym_tools_link'},
 416        {'name': 'Unlink', 'title': 'Unlink', 'css': 'wym_tools_unlink'},
 417        {'name': 'InsertImage', 'title': 'Image', 'css': 'wym_tools_image'},
 418        {'name': 'InsertTable', 'title': 'Table', 'css': 'wym_tools_table'},
 419        {'name': 'Paste', 'title': 'Paste_From_Word',
 420            'css': 'wym_tools_paste'},
 421        {'name': 'ToggleHtml', 'title': 'HTML', 'css': 'wym_tools_html'},
 422        {'name': 'Preview', 'title': 'Preview', 'css': 'wym_tools_preview'}
 423    ],
 424
 425    containersHtml:    "<div class='wym_containers wym_section'>"
 426                        + "<h2>{Containers}</h2>"
 427                        + "<ul>"
 428                        + WYMeditor.CONTAINERS_ITEMS
 429                        + "</ul>"
 430                        + "</div>",
 431                        
 432    containersItemHtml:"<li class='"
 433                        + WYMeditor.CONTAINER_CLASS
 434                        + "'>"
 435                        + "<a href='#' name='"
 436                        + WYMeditor.CONTAINER_NAME
 437                        + "'>"
 438                        + WYMeditor.CONTAINER_TITLE
 439                        + "</a></li>",
 440                        
 441    containersItems: [
 442        {'name': 'P', 'title': 'Paragraph', 'css': 'wym_containers_p'},
 443        {'name': 'H1', 'title': 'Heading_1', 'css': 'wym_containers_h1'},
 444        {'name': 'H2', 'title': 'Heading_2', 'css': 'wym_containers_h2'},
 445        {'name': 'H3', 'title': 'Heading_3', 'css': 'wym_containers_h3'},
 446        {'name': 'H4', 'title': 'Heading_4', 'css': 'wym_containers_h4'},
 447        {'name': 'H5', 'title': 'Heading_5', 'css': 'wym_containers_h5'},
 448        {'name': 'H6', 'title': 'Heading_6', 'css': 'wym_containers_h6'},
 449        {'name': 'PRE', 'title': 'Preformatted', 'css': 'wym_containers_pre'},
 450        {'name': 'BLOCKQUOTE', 'title': 'Blockquote',
 451            'css': 'wym_containers_blockquote'},
 452        {'name': 'TH', 'title': 'Table_Header', 'css': 'wym_containers_th'}
 453    ],
 454
 455    classesHtml:       "<div class='wym_classes wym_section'>"
 456                        + "<h2>{Classes}</h2><ul>"
 457                        + WYMeditor.CLASSES_ITEMS
 458                        + "</ul></div>",
 459
 460    classesItemHtml:   "<li><a href='#' name='"
 461                        + WYMeditor.CLASS_NAME
 462                        + "'>"
 463                        + WYMeditor.CLASS_TITLE
 464                        + "</a></li>",
 465
 466    classesItems:      [],
 467
 468    statusHtml:        "<div class='wym_status wym_section'>"
 469                        + "<h2>{Status}</h2>"
 470                        + "</div>",
 471
 472    htmlHtml:          "<div class='wym_html wym_section'>"
 473                        + "<h2>{Source_Code}</h2>"
 474                        + "<textarea class='wym_html_val'></textarea>"
 475                        + "</div>",
 476
 477    boxSelector:       ".wym_box",
 478    toolsSelector:     ".wym_tools",
 479    toolsListSelector: " ul",
 480    containersSelector:".wym_containers",
 481    classesSelector:   ".wym_classes",
 482    htmlSelector:      ".wym_html",
 483    iframeSelector:    ".wym_iframe iframe",
 484    iframeBodySelector:".wym_iframe",
 485    statusSelector:    ".wym_status",
 486    toolSelector:      ".wym_tools a",
 487    containerSelector: ".wym_containers a",
 488    classSelector:     ".wym_classes a",
 489    htmlValSelector:   ".wym_html_val",
 490    
 491    hrefSelector:      ".wym_href",
 492    srcSelector:       ".wym_src",
 493    titleSelector:     ".wym_title",
 494    altSelector:       ".wym_alt",
 495    textSelector:      ".wym_text",
 496    
 497    rowsSelector:      ".wym_rows",
 498    colsSelector:      ".wym_cols",
 499    captionSelector:   ".wym_caption",
 500    summarySelector:   ".wym_summary",
 501    
 502    submitSelector:    ".wym_submit",
 503    cancelSelector:    ".wym_cancel",
 504    previewSelector:   "",
 505    
 506    dialogTypeSelector:    ".wym_dialog_type",
 507    dialogLinkSelector:    ".wym_dialog_link",
 508    dialogImageSelector:   ".wym_dialog_image",
 509    dialogTableSelector:   ".wym_dialog_table",
 510    dialogPasteSelector:   ".wym_dialog_paste",
 511    dialogPreviewSelector: ".wym_dialog_preview",
 512    
 513    updateSelector:    ".wymupdate",
 514    updateEvent:       "click",
 515    
 516    dialogFeatures:    "menubar=no,titlebar=no,toolbar=no,resizable=no"
 517                      + ",width=560,height=300,top=0,left=0",
 518    dialogFeaturesPreview: "menubar=no,titlebar=no,toolbar=no,resizable=no"
 519                      + ",scrollbars=yes,width=560,height=300,top=0,left=0",
 520
 521    dialogHtml:      "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'"
 522                      + " 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>"
 523                      + "<html dir='"
 524                      + WYMeditor.DIRECTION
 525                      + "'><head>"
 526                      + "<link rel='stylesheet' type='text/css' media='screen'"
 527                      + " href='"
 528                      + WYMeditor.CSS_PATH
 529                      + "' />"
 530                      + "<title>"
 531                      + WYMeditor.DIALOG_TITLE
 532                      + "</title>"
 533                      + "<script type='text/javascript'"
 534                      + " src='"
 535                      + WYMeditor.JQUERY_PATH
 536                      + "'></script>"
 537                      + "<script type='text/javascript'"
 538                      + " src='"
 539                      + WYMeditor.WYM_PATH
 540                      + "'></script>"
 541                      + "</head>"
 542                      + WYMeditor.DIALOG_BODY
 543                      + "</html>",
 544                      
 545    dialogLinkHtml:  "<body class='wym_dialog wym_dialog_link'"
 546               + " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
 547               + ">"
 548               + "<form>"
 549               + "<fieldset>"
 550               + "<input type='hidden' class='wym_dialog_type' value='"
 551               + WYMeditor.DIALOG_LINK
 552               + "' />"
 553               + "<legend>{Link}</legend>"
 554               + "<div class='row'>"
 555               + "<label>{URL}</label>"
 556               + "<input type='text' class='wym_href' value='' size='40' />"
 557               + "</div>"
 558               + "<div class='row'>"
 559               + "<label>{Title}</label>"
 560               + "<input type='text' class='wym_title' value='' size='40' />"
 561               + "</div>"
 562               + "<div class='row row-indent'>"
 563               + "<input class='wym_submit' type='button'"
 564               + " value='{Submit}' />"
 565               + "<input class='wym_cancel' type='button'"
 566               + "value='{Cancel}' />"
 567               + "</div>"
 568               + "</fieldset>"
 569               + "</form>"
 570               + "</body>",
 571    
 572    dialogImageHtml:  "<body class='wym_dialog wym_dialog_image'"
 573               + " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
 574               + ">"
 575               + "<form>"
 576               + "<fieldset>"
 577               + "<input type='hidden' class='wym_dialog_type' value='"
 578               + WYMeditor.DIALOG_IMAGE
 579               + "' />"
 580               + "<legend>{Image}</legend>"
 581               + "<div class='row'>"
 582               + "<label>{URL}</label>"
 583               + "<input type='text' class='wym_src' value='' size='40' />"
 584               + "</div>"
 585               + "<div class='row'>"
 586               + "<label>{Alternative_Text}</label>"
 587               + "<input type='text' class='wym_alt' value='' size='40' />"
 588               + "</div>"
 589               + "<div class='row'>"
 590               + "<label>{Title}</label>"
 591               + "<input type='text' class='wym_title' value='' size='40' />"
 592               + "</div>"
 593               + "<div class='row row-indent'>"
 594               + "<input class='wym_submit' type='button'"
 595               + " value='{Submit}' />"
 596               + "<input class='wym_cancel' type='button'"
 597               + "value='{Cancel}' />"
 598               + "</div>"
 599               + "</fieldset>"
 600               + "</form>"
 601               + "</body>",
 602    
 603    dialogTableHtml:  "<body class='wym_dialog wym_dialog_table'"
 604               + " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
 605               + ">"
 606               + "<form>"
 607               + "<fieldset>"
 608               + "<input type='hidden' class='wym_dialog_type' value='"
 609               + WYMeditor.DIALOG_TABLE
 610               + "' />"
 611               + "<legend>{Table}</legend>"
 612               + "<div class='row'>"
 613               + "<label>{Caption}</label>"
 614               + "<input type='text' class='wym_caption' value='' size='40' />"
 615               + "</div>"
 616               + "<div class='row'>"
 617               + "<label>{Summary}</label>"
 618               + "<input type='text' class='wym_summary' value='' size='40' />"
 619               + "</div>"
 620               + "<div class='row'>"
 621               + "<label>{Number_Of_Rows}</label>"
 622               + "<input type='text' class='wym_rows' value='3' size='3' />"
 623               + "</div>"
 624               + "<div class='row'>"
 625               + "<label>{Number_Of_Cols}</label>"
 626               + "<input type='text' class='wym_cols' value='2' size='3' />"
 627               + "</div>"
 628               + "<div class='row row-indent'>"
 629               + "<input class='wym_submit' type='button'"
 630               + " value='{Submit}' />"
 631               + "<input class='wym_cancel' type='button'"
 632               + "value='{Cancel}' />"
 633               + "</div>"
 634               + "</fieldset>"
 635               + "</form>"
 636               + "</body>",
 637
 638    dialogPasteHtml:  "<body class='wym_dialog wym_dialog_paste'"
 639               + " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
 640               + ">"
 641               + "<form>"
 642               + "<input type='hidden' class='wym_dialog_type' value='"
 643               + WYMeditor.DIALOG_PASTE
 644               + "' />"
 645               + "<fieldset>"
 646               + "<legend>{Paste_From_Word}</legend>"
 647               + "<div class='row'>"
 648               + "<textarea class='wym_text' rows='10' cols='50'></textarea>"
 649               + "</div>"
 650               + "<div class='row'>"
 651               + "<input class='wym_submit' type='button'"
 652               + " value='{Submit}' />"
 653               + "<input class='wym_cancel' type='button'"
 654               + "value='{Cancel}' />"
 655               + "</div>"
 656               + "</fieldset>"
 657               + "</form>"
 658               + "</body>",
 659
 660    dialogPreviewHtml: "<body class='wym_dialog wym_dialog_preview'"
 661                      + " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
 662                      + "></body>",
 663                      
 664    dialogStyles: [],
 665
 666    stringDelimiterLeft: "{",
 667    stringDelimiterRight:"}",
 668    
 669    preInit: null,
 670    preBind: null,
 671    postInit: null,
 672    
 673    preInitDialog: null,
 674    postInitDialog: null
 675
 676  }, options);
 677
 678  return this.each(function() {
 679
 680    new WYMeditor.editor(jQuery(this),options);
 681  });
 682};
 683
 684/* @name extend
 685 * @description Returns the WYMeditor instance based on its index
 686 */
 687jQuery.extend({
 688  wymeditors: function(i) {
 689    return (WYMeditor.INSTANCES[i]);
 690  }
 691});
 692
 693
 694/********** WYMeditor **********/
 695
 696/* @name Wymeditor
 697 * @description WYMeditor class
 698 */
 699
 700/* @name init
 701 * @description Initializes a WYMeditor instance
 702 */
 703WYMeditor.editor.prototype.init = function() {
 704
 705  //load subclass - browser specific
 706  //unsupported browsers: do nothing
 707  if (jQuery.browser.msie) {
 708    var WymClass = new WYMeditor.WymClassExplorer(this);
 709  }
 710  else if (jQuery.browser.mozilla) {
 711    var WymClass = new WYMeditor.WymClassMozilla(this);
 712  }
 713  else if (jQuery.browser.opera) {
 714    var WymClass = new WYMeditor.WymClassOpera(this);
 715  }
 716  else if (jQuery.browser.safari) {
 717    var WymClass = new WYMeditor.WymClassSafari(this);
 718  }
 719  
 720  if(WymClass) {
 721  
 722      if(jQuery.isFunction(this._options.preInit)) this._options.preInit(this);
 723
 724      var SaxListener = new WYMeditor.XhtmlSaxListener();
 725      jQuery.extend(SaxListener, WymClass);
 726      this.parser = new WYMeditor.XhtmlParser(SaxListener);
 727      
 728      if(this._options.styles || this._options.stylesheet){
 729        this.configureEditorUsingRawCss();
 730      }
 731      
 732      this.helper = new WYMeditor.XmlHelper();
 733      
 734      //extend the Wymeditor object
 735      //don't use jQuery.extend since 1.1.4
 736      //jQuery.extend(this, WymClass);
 737      for (var prop in WymClass) { this[prop] = WymClass[prop]; }
 738
 739      //load wymbox
 740      this._box = jQuery(this._element).hide().after(this._options.boxHtml).next().addClass('wym_box_' + this._index);
 741
 742      //store the instance index in wymbox and element replaced by editor instance
 743      //but keep it compatible with jQuery < 1.2.3, see #122
 744      if( jQuery.isFunction( jQuery.fn.data ) ) {
 745        jQuery.data(this._box.get(0), WYMeditor.WYM_INDEX, this._index);
 746        jQuery.data(this._element.get(0), WYMeditor.WYM_INDEX, this._index);
 747      }
 748      
 749      var h = WYMeditor.Helper;
 750
 751      //construct the iframe
 752      var iframeHtml = this._options.iframeHtml;
 753      iframeHtml = h.replaceAll(iframeHtml, WYMeditor.INDEX, this._index);
 754      iframeHtml = h.replaceAll(iframeHtml, WYMeditor.IFRAME_BASE_PATH, this._options.iframeBasePath);
 755      
 756      //construct wymbox
 757      var boxHtml = jQuery(this._box).html();
 758      
 759      boxHtml = h.replaceAll(boxHtml, WYMeditor.LOGO, this._options.logoHtml);
 760      boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS, this._options.toolsHtml);
 761      boxHtml = h.replaceAll(boxHtml, WYMeditor.CONTAINERS,this._options.containersHtml);
 762      boxHtml = h.replaceAll(boxHtml, WYMeditor.CLASSES, this._options.classesHtml);
 763      boxHtml = h.replaceAll(boxHtml, WYMeditor.HTML, this._options.htmlHtml);
 764      boxHtml = h.replaceAll(boxHtml, WYMeditor.IFRAME, iframeHtml);
 765      boxHtml = h.replaceAll(boxHtml, WYMeditor.STATUS, this._options.statusHtml);
 766      
 767      //construct tools list
 768      var aTools = eval(this._options.toolsItems);
 769      var sTools = "";
 770
 771      for(var i = 0; i < aTools.length; i++) {
 772        var oTool = aTools[i];
 773        if(oTool.name && oTool.title)
 774          var sTool = this._options.toolsItemHtml;
 775          var sTool = h.replaceAll(sTool, WYMeditor.TOOL_NAME, oTool.name);
 776          sTool = h.replaceAll(sTool, WYMeditor.TOOL_TITLE, this._options.stringDelimiterLeft
 777            + oTool.title
 778            + this._options.stringDelimiterRight);
 779          sTool = h.replaceAll(sTool, WYMeditor.TOOL_CLASS, oTool.css);
 780          sTools += sTool;
 781      }
 782
 783      boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS_ITEMS, sTools);
 784      
 785      //construct classes list
 786      var aClasses = eval(this._options.classesItems);
 787      var sClasses = "";
 788
 789      for(var i = 0; i < aClasses.length; i++) {
 790        var oClass = aClasses[i];
 791        if(oClass.name && oClass.title)
 792          var sClass = this._options.classesItemHtml;
 793          sClass = h.replaceAll(sClass, WYMeditor.CLASS_NAME, oClass.name);
 794          sClass = h.replaceAll(sClass, WYMeditor.CLASS_TITLE, oClass.title);
 795          sClasses += sClass;
 796      }
 797
 798      boxHtml = h.replaceAll(boxHtml, WYMeditor.CLASSES_ITEMS, sClasses);
 799      
 800      //construct containers list
 801      var aContainers = eval(this._options.containersItems);
 802      var sContainers = "";
 803
 804      for(var i = 0; i < aContainers.length; i++) {
 805        var oContainer = aContainers[i];
 806        if(oContainer.name && oContainer.title)
 807          var sContainer = this._options.containersItemHtml;
 808          sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_NAME, oContainer.name);
 809          sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_TITLE,
 810              this._options.stringDelimiterLeft
 811            + oContainer.title
 812            + this._options.stringDelimiterRight);
 813          sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_CLASS, oContainer.css);
 814          sContainers += sContainer;
 815      }
 816
 817      boxHtml = h.replaceAll(boxHtml, WYMeditor.CONTAINERS_ITEMS, sContainers);
 818
 819      //l10n
 820      boxHtml = this.replaceStrings(boxHtml);
 821      
 822      //load html in wymbox
 823      jQuery(this._box).html(boxHtml);
 824      
 825      //hide the html value
 826      jQuery(this._box).find(this._options.htmlSelector).hide();
 827      
 828      //enable the skin
 829      this.loadSkin();
 830      
 831    }
 832};
 833
 834WYMeditor.editor.prototype.bindEvents = function() {
 835
 836  //copy the instance
 837  var wym = this;
 838  
 839  //handle click event on tools buttons
 840  jQuery(this._box).find(this._options.toolSelector).click(function() {
 841    wym._iframe.contentWindow.focus(); //See #154
 842    wym.exec(jQuery(this).attr(WYMeditor.NAME));    
 843    return(false);
 844  });
 845  
 846  //handle click event on containers buttons
 847  jQuery(this._box).find(this._options.containerSelector).click(function() {
 848    wym.container(jQuery(this).attr(WYMeditor.NAME));
 849    return(false);
 850  });
 851  
 852  //handle keyup event on html value: set the editor value
 853  //handle focus/blur events to check if the element has focus, see #147
 854  jQuery(this._box).find(this._options.htmlValSelector)
 855    .keyup(function() { jQuery(wym._doc.body).html(jQuery(this).val());})
 856    .focus(function() { jQuery(this).toggleClass('hasfocus'); })
 857    .blur(function() { jQuery(this).toggleClass('hasfocus'); });
 858
 859  //handle click event on classes buttons
 860  jQuery(this._box).find(this._options.classSelector).click(function() {
 861  
 862    var aClasses = eval(wym._options.classesItems);
 863    var sName = jQuery(this).attr(WYMeditor.NAME);
 864    
 865    var oClass = WYMeditor.Helper.findByName(aClasses, sName);
 866    
 867    if(oClass) {
 868      var jqexpr = oClass.expr;
 869      wym.toggleClass(sName, jqexpr);
 870    }
 871    wym._iframe.contentWindow.focus(); //See #154
 872    return(false);
 873  });
 874  
 875  //handle event on update element
 876  jQuery(this._options.updateSelector)
 877    .bind(this._options.updateEvent, function() {
 878      wym.update();
 879  });
 880};
 881
 882WYMeditor.editor.prototype.ready = function() {
 883  return(this._doc != null);
 884};
 885
 886
 887/********** METHODS **********/
 888
 889/* @name box
 890 * @description Returns the WYMeditor container
 891 */
 892WYMeditor.editor.prototype.box = function() {
 893  return(this._box);
 894};
 895
 896/* @name html
 897 * @description Get/Set the html value
 898 */
 899WYMeditor.editor.prototype.html = function(html) {
 900
 901  if(typeof html === 'string') jQuery(this._doc.body).html(html);
 902  else return(jQuery(this._doc.body).html());
 903};
 904
 905/* @name xhtml
 906 * @description Cleans up the HTML
 907 */
 908WYMeditor.editor.prototype.xhtml = function() {
 909    return this.parser.parse(this.html());
 910};
 911
 912/* @name exec
 913 * @description Executes a button command
 914 */
 915WYMeditor.editor.prototype.exec = function(cmd) {
 916  
 917  //base function for execCommand
 918  //open a dialog or exec
 919  switch(cmd) {
 920    case WYMeditor.CREATE_LINK:
 921      var container = this.container();
 922      if(container || this._selected_image) this.dialog(WYMeditor.DIALOG_LINK);
 923    break;
 924    
 925    case WYMeditor.INSERT_IMAGE:
 926      this.dialog(WYMeditor.DIALOG_IMAGE);
 927    break;
 928    
 929    case WYMeditor.INSERT_TABLE:
 930      this.dialog(WYMeditor.DIALOG_TABLE);
 931    break;
 932    
 933    case WYMeditor.PASTE:
 934      this.dialog(WYMeditor.DIALOG_PASTE);
 935    break;
 936    
 937    case WYMeditor.TOGGLE_HTML:
 938      this.update();
 939      this.toggleHtml();
 940
 941      //partially fixes #121 when the user manually inserts an image
 942      if(!jQuery(this._box).find(this._options.htmlSelector).is(':visible'))
 943        this.listen();
 944    break;
 945    
 946    case WYMeditor.PREVIEW:
 947      this.dialog(WYMeditor.PREVIEW, this._options.dialogFeaturesPreview);
 948    break;
 949    
 950    default:
 951      this._exec(cmd);
 952    break;
 953  }
 954};
 955
 956/* @name container
 957 * @description Get/Set the selected container
 958 */
 959WYMeditor.editor.prototype.container = function(sType) {
 960
 961  if(sType) {
 962  
 963    var container = null;
 964    
 965    if(sType.toLowerCase() == WYMeditor.TH) {
 966    
 967      container = this.container();
 968      
 969      //find the TD or TH container
 970      switch(container.tagName.toLowerCase()) {
 971      
 972        case WYMeditor.TD: case WYMeditor.TH:
 973          break;
 974        default:
 975          var aTypes = new Array(WYMeditor.TD,WYMeditor.TH);
 976          container = this.findUp(this.container(), aTypes);
 977          break;
 978      }
 979      
 980      //if it exists, switch
 981      if(container!=null) {
 982      
 983        sType = (container.tagName.toLowerCase() == WYMeditor.TD)? WYMeditor.TH: WYMeditor.TD;
 984        this.switchTo(container,sType);
 985        this.update();
 986      }
 987    } else {
 988  
 989      //set the container type
 990      var aTypes=new Array(WYMeditor.P,WYMeditor.H1,WYMeditor.H2,WYMeditor.H3,WYMeditor.H4,WYMeditor.H5,
 991      WYMeditor.H6,WYMeditor.PRE,WYMeditor.BLOCKQUOTE);
 992      container = this.findUp(this.container(), aTypes);
 993      
 994      if(container) {
 995  
 996        var newNode = null;
 997  
 998        //blockquotes must contain a block level element
 999        if(sType.toLowerCase() == WYMeditor.BLOCKQUOTE) {
1000        
1001          var blockquote = this.findUp(this.container(), WYMeditor.BLOCKQUOTE);
1002          
1003          if(blockquote == null) {
1004          
1005            newNode = this._doc.createElement(sType);
1006            container.parentNode.insertBefore(newNode,container);
1007            newNode.appendChild(container);
1008            this.setFocusToNode(newNode.firstChild);
1009            
1010          } else {
1011          
1012            var nodes = blockquote.childNodes;
1013            var lgt = nodes.length;
1014            var firstNode = null;
1015            
1016            if(lgt > 0) firstNode = nodes.item(0);
1017            for(var x=0; x<lgt; x++) {
1018              blockquote.parentNode.insertBefore(nodes.item(0),blockquote);
1019            }
1020            blockquote.parentNode.removeChild(blockquote);
1021            if(firstNode) this.setFocusToNode(firstNode);
1022          }
1023        }
1024        
1025        else this.switchTo(container,sType);
1026      
1027        this.update();
1028      }
1029    }
1030  }
1031  else return(this.selected());
1032};
1033
1034/* @name toggleClass
1035 * @description Toggles class on selected element, or one of its parents
1036 */
1037WYMeditor.editor.prototype.toggleClass = function(sClass, jqexpr) {
1038
1039  var container = (this._selected_image
1040                    ? this._selected_image
1041                    : jQuery(this.selected()));
1042  container = jQuery(container).parentsOrSelf(jqexpr);
1043  jQuery(container).toggleClass(sClass);
1044
1045  if(!jQuery(container).attr(WYMeditor.CLASS)) jQuery(container).removeAttr(this._class);
1046
1047};
1048
1049/* @name findUp
1050 * @description Returns the first parent or self container, based on its type
1051 */
1052WYMeditor.editor.prototype.findUp = function(node, filter) {
1053
1054  //filter is a string or an array of strings
1055
1056  if(node) {
1057
1058      var tagname = node.tagName.toLowerCase();
1059      
1060      if(typeof(filter) == WYMeditor.STRING) {
1061    
1062        while(tagname != filter && tagname != WYMeditor.BODY) {
1063        
1064          node = node.parentNode;
1065          tagname = node.tagName.toLowerCase();
1066        }
1067      
1068      } else {
1069      
1070        var bFound = false;
1071        
1072        while(!bFound && tagname != WYMeditor.BODY) {
1073          for(var i = 0; i < filter.length; i++) {
1074            if(tagname == filter[i]) {
1075              bFound = true;
1076              break;
1077            }
1078          }
1079          if(!bFound) {
1080            node = node.parentNode;
1081            tagname = node.tagName.toLowerCase();
1082          }
1083        }
1084      }
1085      
1086      if(tagname != WYMeditor.BODY) return(node);
1087      else return(null);
1088      
1089  } else return(null);
1090};
1091
1092/* @name switchTo
1093 * @description Switch the node's type
1094 */
1095WYMeditor.editor.prototype.switchTo = function(node,sType) {
1096
1097  var newNode = this._doc.createElement(sType);
1098  var html = jQuery(node).html();
1099  node.parentNode.replaceChild(newNode,node);
1100  jQuery(newNode).html(html);
1101  this.setFocusToNode(newNode);
1102};
1103
1104WYMeditor.editor.prototype.replaceStrings = function(sVal) {
1105  //check if the language file has already been loaded
1106  //if not, get it via a synchronous ajax call
1107  if(!WYMeditor.STRINGS[this._options.lang]) {
1108    try {
1109      eval(jQuery.ajax({url:this._options.langPath
1110        + this._options.lang + '.js', async:false}).responseText);
1111    } catch(e) {
1112        WYMeditor.console.error("WYMeditor: error while parsing language file.");
1113        return sVal;
1114    }
1115  }
1116
1117  //replace all the strings in sVal and return it
1118  for (var key in WYMeditor.STRINGS[this._options.lang]) {
1119    sVal = WYMeditor.Helper.replaceAll(sVal, this._options.stringDelimiterLeft + key 
1120    + this._options.stringDelimiterRight,
1121    WYMeditor.STRINGS[this._options.lang][key]);
1122  };
1123  return(sVal);
1124};
1125
1126WYMeditor.editor.prototype.encloseString = function(sVal) {
1127
1128  return(this._options.stringDelimiterLeft
1129    + sVal
1130    + this._options.stringDelimiterRight);
1131};
1132
1133/* @name status
1134 * @description Prints a status message
1135 */
1136WYMeditor.editor.prototype.status = function(sMessage) {
1137
1138  //print status message
1139  jQuery(this._box).find(this._options.statusSelector).html(sMessage);
1140};
1141
1142/* @name update
1143 * @description Updates the element and textarea values
1144 */
1145WYMeditor.editor.prototype.update = function() {
1146
1147  var html = this.xhtml();
1148  jQuery(this._element).val(html);
1149  jQuery(this._box).find(this._options.htmlValSelector).not('.hasfocus').val(html); //#147
1150};
1151
1152/* @name dialog
1153 * @description Opens a dialog box
1154 */
1155WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHtml ) {
1156  var features = dialogFeatures || this._wym._options.dialogFeatures;
1157  var wDialog = window.open('', 'dialog', features);
1158
1159  if(wDialog) {
1160
1161    var sBodyHtml = "";
1162    
1163    switch( dialogType ) {
1164
1165      case(WYMeditor.DIALOG_LINK):
1166        sBodyHtml = this._options.dialogLinkHtml;
1167      break;
1168      case(WYMeditor.DIALOG_IMAGE):
1169        sBodyHtml = this._options.dialogImageHtml;
1170      break;
1171      case(WYMeditor.DIALOG_TABLE):
1172        sBodyHtml = this._options.dialogTableHtml;
1173      break;
1174      case(WYMeditor.DIALOG_PASTE):
1175        sBodyHtml = this._options.dialogPasteHtml;
1176      break;
1177      case(WYMeditor.PREVIEW):
1178        sBodyHtml = this._options.dialogPreviewHtml;
1179      break;
1180      default:
1181        sBodyHtml = bodyHtml;
1182    }
1183    var h = WYMeditor.Helper;
1184
1185    //construct the dialog
1186    var dialogHtml = this._options.dialogHtml;
1187    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.BASE_PATH, this._options.basePath);
1188    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.DIRECTION, this._options.direction);
1189    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.CSS_PATH, this._options.skinPath + WYMeditor.SKINS_DEFAULT_CSS);
1190    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.WYM_PATH, this._options.wymPath);
1191    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.JQUERY_PATH, this._options.jQueryPath);
1192    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.DIALOG_TITLE, this.encloseString( dialogType ));
1193    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.DIALOG_BODY, sBodyHtml);
1194    dialogHtml = h.replaceAll(dialogHtml, WYMeditor.INDEX, this._index);
1195      
1196    dialogHtml = this.replaceStrings(dialogHtml);
1197    var doc = wDialog.document;
1198    doc.write(dialogHtml);
1199    doc.close();
1200  }
1201};
1202
1203/* @name toggleHtml
1204 * @description Shows/Hides the HTML
1205 */
1206WYMeditor.editor.prototype.toggleHtml = function() {
1207  jQuery(this._box).find(this._options.htmlSelector).toggle();
1208};
1209
1210WYMeditor.editor.prototype.uniqueStamp = function() {
1211	var now = new Date();
1212	return("wym-" + now.getTime());
1213};
1214
1215WYMeditor.editor.prototype.paste = function(sData) {
1216
1217  var sTmp;
1218  var container = this.selected();
1219	
1220  //split the data, using double newlines as the separator
1221  var aP = sData.split(this._newLine + this._newLine);
1222  var rExp = new RegExp(this._newLine, "g");
1223
1224  //add a P for each item
1225  if(container && container.tagName.toLowerCase() != WYMeditor.BODY) {
1226    for(x = aP.length - 1; x >= 0; x--) {
1227        sTmp = aP[x];
1228        //simple newlines are replaced by a break
1229        sTmp = sTmp.replace(rExp, "<br />");
1230        jQuery(container).after("<p>" + sTmp + "</p>");
1231    }
1232  } else {
1233    for(x = 0; x < aP.length; x++) {
1234        sTmp = aP[x];
1235        //simple newlines are replaced by a break
1236        sTmp = sTmp.replace(rExp, "<br />");
1237        jQuery(this._doc.body).append("<p>" + sTmp + "</p>");
1238    }
1239  
1240  }
1241};
1242
1243WYMeditor.editor.prototype.insert = function(html) {
1244    // Do we have a selection?
1245    if (this._iframe.contentWindow.getSelection().focusNode != null) {
1246        // Overwrite selection with provided html
1247        this._exec( WYMeditor.INSERT_HTML, html);
1248    } else {
1249        // Fall back to the internal paste function if there's no selection
1250        this.paste(html)
1251    }
1252};
1253
1254WYMeditor.editor.prototype.wrap = function(left, right) {
1255    // Do we have a selection?
1256    if (this._iframe.contentWindow.getSelection().focusNode != null) {
1257        // Wrap selection with provided html
1258        this._exec( WYMeditor.INSERT_HTML, left + this._iframe.contentWindow.getSelection().toString() + right);
1259    }
1260};
1261
1262WYMeditor.editor.prototype.unwrap = function() {
1263    // Do we have a selection?
1264    if (this._iframe.contentWindow.getSelection().focusNode != null) {
1265        // Unwrap selection
1266        this._exec( WYMeditor.INSERT_HTML, this._iframe.contentWindow.getSelection().toString() );
1267    }
1268};
1269
1270WYMeditor.editor.prototype.addCssRules = function(doc, aCss) {
1271  var styles = doc.styleSheets[0];
1272  if(styles) {
1273    for(var i = 0; i < aCss.length; i++) {
1274      var oCss = aCss[i];
1275      if(oCss.name && oCss.css) this.addCssRule(styles, oCss);
1276    }
1277  }
1278};
1279
1280/********** CONFIGURATION **********/
1281
1282WYMeditor.editor.prototype.computeBasePath = function() {
1283  return jQuery(jQuery.grep(jQuery('script'), function(s){
1284    return (s.src && s.src.match(/jquery\.wymeditor(\.pack|\.min|\.packed)?\.js(\?.*)?$/ ))
1285  })).attr('src').replace(/jquery\.wymeditor(\.pack|\.min|\.packed)?\.js(\?.*)?$/, '');
1286};
1287
1288WYMeditor.editor.prototype.computeWymPath = function() {
1289  return jQuery(jQuery.grep(jQuery('script'), function(s){
1290    return (s.src && s.src.match(/jquery\.wymeditor(\.pack|\.min|\.packed)?\.js(\?.*)?$/ ))
1291  })).attr('src');
1292};
1293
1294WYMeditor.editor.prototype.computeJqueryPath = function() {
1295  return jQuery(jQuery.grep(jQuery('script'), function(s){
1296    return (s.src && s.src.match(/jquery(-(.*)){0,1}(\.pack|\.min|\.packed)?\.js(\?.*)?$/ ))
1297  })).attr('src');
1298};
1299
1300WYMeditor.editor.prototype.computeCssPath = function() {
1301  return jQuery(jQuery.grep(jQuery('link'), function(s){
1302   return (s.href && s.href.match(/wymeditor\/skins\/(.*)screen\.css(\?.*)?$/ ))
1303  })).attr('href');
1304};
1305
1306WYMeditor.editor.prototype.configureEditorUsingRawCss = function() {
1307
1308  var CssParser = new WYMeditor.WymCssParser();
1309  if(this._options.stylesheet){
1310    CssParser.parse(jQuery.ajax({url: this._options.stylesheet,async:false}).responseText);
1311  }else{
1312    CssParser.parse(this._options.styles, false);
1313  }
1314
1315  if(this._options.classesItems.length == 0) {
1316    this._options.classesItems = CssParser.css_settings.classesItems;
1317  }
1318  if(this._options.editorStyles.length == 0) {
1319    this._options.editorStyles = CssParser.css_settings.editorStyles;
1320  }
1321  if(this._options.dialogStyles.length == 0) {
1322    this._options.dialogStyles = CssParser.css_settings.dialogStyles;
1323  }
1324};
1325
1326/********** EVENTS **********/
1327
1328WYMeditor.editor.prototype.listen = function() {
1329
1330  //don't use jQuery.find() on the iframe body
1331  //because of MSIE + jQuery + expando issue (#JQ1143)
1332  //jQuery(this._doc.body).find("*").bind("mouseup", this.mouseup);
1333  
1334  jQuery(this._doc.body).bind("mousedown", this.mousedown);
1335  var images = this._doc.body.getElementsByTagName("img");
1336  for(var i=0; i < images.length; i++) {
1337    jQuery(images[i]).bind("mousedown", this.mousedown);
1338  }
1339};
1340
1341WYMeditor.editor.prototype.mousedown = function(evt) {
1342  
1343  var wym = WYMeditor.INSTANCES[this.ownerDocument.title];
1344  wym._selected_image = (this.tagName.toLowerCase() == WYMeditor.IMG) ? this : null;
1345  evt.stopPropagation();
1346};
1347
1348/********** SKINS **********/
1349
1350/*
1351 * Function: WYMeditor.loadCss
1352 *      Loads a stylesheet in the document.
1353 *
1354 * Parameters:
1355 *      href - The CSS path.
1356 */
1357WYMeditor.loadCss = function(href) {
1358    
1359    var link = document.createElement('link');
1360    link.rel = 'stylesheet';
1361    link.href = href;
1362
1363    var head = jQuery('head').get(0);
1364    head.appendChild(link);
1365};
1366
1367/*
1368 *  Function: WYMeditor.editor.loadSkin
1369 *      Loads the skin CSS and initialization script (if needed).
1370 */
1371WYMeditor.editor.prototype.loadSkin = function() {
1372
1373    //does the user want to automatically load the CSS (default: yes)?
1374    //we also test if it hasn't been already loaded by another instance
1375    //see below for a better (second) test
1376    if(this._options.loadSkin && !WYMeditor.SKINS[this._options.skin]) {
1377
1378        //check if it hasn't been already loaded
1379        //so we don't load it more than once
1380        //(we check the existing <link> elements)
1381
1382        var found = false;
1383        var rExp = new RegExp(this._options.skin
1384             + '\/' + WYMeditor.SKINS_DEFAULT_CSS + '$');
1385
1386        jQuery('link').each( function() {
1387            if(this.href.match(rExp)) found = true;
1388        });
1389
1390        //load it, using the skin path
1391        if(!found) WYMeditor.loadCss( this._options.skinPath
1392            + WYMeditor.SKINS_DEFAULT_CSS );
1393    }
1394
1395    //put the classname (ex. wym_skin_default) on wym_box
1396    jQuery(this._box).addClass( "wym_skin_" + this._options.skin );
1397
1398    //does the user want to use some JS to initialize the skin (default: yes)?
1399    //also check if it hasn't already been loaded by another instance
1400    if(this._options.initSkin && !WYMeditor.SKINS[this._options.skin]) {
1401
1402        eval(jQuery.ajax({url:this._options.skinPath
1403            + WYMeditor.SKINS_DEFAULT_JS, async:false}).responseText);
1404    }
1405
1406    //init the skin, if needed
1407    if(WYMeditor.SKINS[this._options.skin]
1408    && WYMeditor.SKINS[this._options.skin].init)
1409       WYMeditor.SKINS[this._options.skin].init(this);
1410
1411};
1412
1413
1414/********** DIALOGS **********/
1415
1416WYMeditor.INIT_DIALOG = function(index) {
1417
1418  var wym = window.opener.WYMeditor.INSTANCES[index];
1419  var doc = window.document;
1420  var selected = wym.selected();
1421  var dialogType = jQuery(wym._options.dialogTypeSelector).val();
1422  var sStamp = wym.uniqueStamp();
1423
1424  switch(dialogType) {
1425
1426  case WYMeditor.DIALOG_LINK:
1427    //ensure that we select the link to populate the fields
1428    if(selected && selected.tagName && selected.tagName.toLowerCase != WYMeditor.A)
1429      selected = jQuery(selected).parentsOrSelf(WYMeditor.A);
1430
1431    //fix MSIE selection if link image has been clicked
1432    if(!selected && wym._selected_image)
1433      selected = jQuery(wym._selected_image).parentsOrSelf(WYMeditor.A);
1434  break;
1435
1436  }
1437
1438  //pre-init functions
1439  if(jQuery.isFunction(wym._options.preInitDialog))
1440    wym._options.preInitDialog(wym,window);
1441
1442  //add css rules from options
1443  var styles = doc.styleSheets[0];
1444  var aCss = eval(wym._options.dialogStyles);
1445
1446  wym.addCssRules(doc, aCss);
1447
1448  //auto populate fields if selected container (e.g. A)
1449  if(selected) {
1450    jQuery(wym._options.hrefSelector).val(jQuery(selected).

Large files files are truncated, but you can click here to view the full file