Changeset 818
- Timestamp:
- 04/19/07 23:17:41 (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 2 removed
- 1 modified
-
XinhaConfig.js (deleted)
-
XinhaCore.js (modified) (165 diffs, 1 prop)
-
compression_readme.txt (added)
-
contrib/compression_readme.txt (deleted)
Legend:
- Unmodified
- Added
- Removed
-
trunk/XinhaCore.js
- Property svn:keywords changed from LastChangedDate LastChangedRevision LastChangedBy HeadURL Id to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Rev
r817 r818 103 103 _editor_skin = ""; 104 104 } 105 105 /** 106 * The list of Xinha editors on the page. May be multiple editors. 107 * You can access each editor object through this global variable. 108 * 109 * Example:<br /> 110 * <code> 111 * var html = __xinhas[0].getEditorContent(); // gives you the HTML of the first editor in the page 112 * </code> 113 */ 106 114 var __xinhas = []; 107 115 108 116 // browser identification 117 /** Cache the user agent for the following checks 118 * @private 119 */ 109 120 Xinha.agt = navigator.userAgent.toLowerCase(); 121 /** Browser is Microsoft Internet Explorer 122 @type string 123 */ 110 124 Xinha.is_ie = ((Xinha.agt.indexOf("msie") != -1) && (Xinha.agt.indexOf("opera") == -1)); 125 /** Version Number, if browser is Microsoft Internet Explorer 126 @type string 127 */ 111 128 Xinha.ie_version= parseFloat(Xinha.agt.substring(Xinha.agt.indexOf("msie")+5)); 129 /** Browser is Opera 130 @type string 131 */ 112 132 Xinha.is_opera = (Xinha.agt.indexOf("opera") != -1); 133 /** Version Number, if browser is Opera 134 @type string 135 */ 136 Xinha.opera_version = navigator.appVersion.substring(0, navigator.appVersion.indexOf(" "))*1; 137 /** Browserengine is KHTML (Konqueror, Safari) 138 @type string 139 */ 113 140 Xinha.is_khtml = (Xinha.agt.indexOf("khtml") != -1); 141 /** Browser is Safari 142 @type string 143 */ 114 144 Xinha.is_safari = (Xinha.agt.indexOf("safari") != -1); 115 Xinha.opera_version = navigator.appVersion.substring(0, navigator.appVersion.indexOf(" "))*1; 145 /** OS is MacOS 146 @type string 147 */ 116 148 Xinha.is_mac = (Xinha.agt.indexOf("mac") != -1); 149 /** Browser is Microsoft Internet Explorer Mac 150 @type string 151 */ 117 152 Xinha.is_mac_ie = (Xinha.is_ie && Xinha.is_mac); 153 /** Browser is Microsoft Internet Explorer Windows 154 @type string 155 */ 118 156 Xinha.is_win_ie = (Xinha.is_ie && !Xinha.is_mac); 157 /** Browserengine is Gecko (Mozilla) 158 @type string 159 */ 119 160 Xinha.is_gecko = (navigator.product == "Gecko" && !Xinha.is_safari); // Safari lies! 161 /** File is opened locally opened ("file://" protocol) 162 * @type string 163 * @private 164 */ 120 165 Xinha.isRunLocally = document.URL.toLowerCase().search(/^file:/) != -1; 166 /** Editing is enabled by document.designMode (Gecko, Opera), as opposed to contenteditable (IE) 167 * @type string 168 * @private 169 */ 121 170 Xinha.is_designMode = (typeof document.designMode != 'undefined' && !Xinha.is_ie); // IE has designMode, but we're not using it 171 172 /** Check if Xinha can run in the used browser, otherwise the textarea will be remain unchanged 173 * @type Boolean 174 * @private 175 */ 122 176 Xinha.checkSupportedBrowser = function() 123 177 { … … 140 194 return Xinha.is_gecko || (Xinha.is_opera && Xinha.opera_version >= 9.1) || Xinha.ie_version >= 5.5; 141 195 }; 142 196 /** Cache result of checking for browser support 197 * @type Boolean 198 * @private 199 */ 143 200 Xinha.isSupportedBrowser = Xinha.checkSupportedBrowser(); 144 201 … … 148 205 } 149 206 150 // Creates a new Xinha object. Tries to replace the textarea with the given 151 // ID with it. 207 /** Creates a new Xinha object 208 * @version $Rev 817$ $LastChangedDate$ 209 * @constructor 210 * @param {String|DomNode} textarea the textarea to replace; can be either only the id or the DOM object as returned by document.getElementById() 211 * @param {Xinha.Config} config optional if no Xinha.Config object is passed, the default config is used 212 */ 152 213 function Xinha(textarea, config) 153 214 { … … 161 222 if ( typeof config == "undefined" ) 162 223 { 224 /** The configuration used in the editor 225 * @type Xinha.Config 226 */ 163 227 this.config = new Xinha.Config(); 164 228 } … … 167 231 this.config = config; 168 232 } 169 this._htmlArea = null;170 233 171 234 if ( typeof textarea != 'object' ) … … 173 236 textarea = Xinha.getElementById('textarea', textarea); 174 237 } 238 /** This property references the original textarea, which is at the same time the editor in text mode 239 * @type DomNode textarea 240 */ 175 241 this._textArea = textarea; 176 242 this._textArea.spellcheck = false; 177 178 // Before we modify anything, get the initial textarea size 243 Xinha.freeLater(this, '_textArea'); 244 245 // 246 /** Before we modify anything, get the initial textarea size 247 * @private 248 * @type Object w,h 249 */ 179 250 this._initial_ta_size = 180 251 { … … 192 263 } 193 264 265 /** the current editing mode 266 * @private 267 * @type string "wysiwyg"|"text" 268 */ 194 269 this._editMode = "wysiwyg"; 270 /** this object holds the plugins used in the editor 271 * @private 272 * @type Object 273 */ 195 274 this.plugins = {}; 275 /** periodically updates the toolbar 276 * @private 277 * @type timeout 278 */ 196 279 this._timerToolbar = null; 280 /** periodically takes a snapshot of the current editor content 281 * @private 282 * @type timeout 283 */ 197 284 this._timerUndo = null; 285 /** holds the undo snapshots 286 * @private 287 * @type Array 288 */ 198 289 this._undoQueue = [this.config.undoSteps]; 290 /** the current position in the undo queue 291 * @private 292 * @type integer 293 */ 199 294 this._undoPos = -1; 295 /** use our own undo implementation (true) or the browser's (false) 296 * @private 297 * @type Boolean 298 */ 200 299 this._customUndo = true; 300 /** the document object of the page Xinha is embedded in 301 * @private 302 * @type document 303 */ 201 304 this._mdoc = document; // cache the document, we need it in plugins 305 /** doctype of the edited document (fullpage mode) 306 * @private 307 * @type string 308 */ 202 309 this.doctype = ''; 310 /** running number that identifies the current editor 311 * @public 312 * @type integer 313 */ 203 314 this.__htmlarea_id_num = __xinhas.length; 204 315 __xinhas[this.__htmlarea_id_num] = this; 205 316 317 /** holds the events for use with the notifyOn/notifyOf system 318 * @private 319 * @type Object 320 */ 206 321 this._notifyListeners = {}; 207 322 … … 243 358 Xinha.freeLater(panels[i], 'div'); 244 359 } 360 /** holds the panels 361 * @private 362 * @type Array 363 */ 245 364 // finally store the variable 246 365 this._panels = panels; 247 248 Xinha.freeLater(this, '_textArea'); 366 367 // Init some properties that are defined later 368 /** The statusbar container 369 * @type DomNode statusbar div 370 */ 371 this._statusBar = null; 372 /** The DOM path that is shown in the statusbar in wysiwyg mode 373 * @private 374 * @type DomNode 375 */ 376 this._statusBarTree = null; 377 /** The message that is shown in the statusbar in text mode 378 * @private 379 * @type DomNode 380 */ 381 this._statusBarTextMode = null; 382 /** Holds the items of the DOM path that is shown in the statusbar in wysiwyg mode 383 * @private 384 * @type Array tag names 385 */ 386 this._statusBarItems = []; 387 /** Holds the parts (table cells) of the UI (toolbar, panels, statusbar) 388 389 * @type Object framework parts 390 */ 391 this._framework = {}; 392 /** Them whole thing (table) 393 * @private 394 * @type DomNode 395 */ 396 this._htmlArea = null; 397 /** This is the actual editable area.<br /> 398 * Technically it's an iframe that's made editable using window.designMode = 'on', respectively document.body.contentEditable = true (IE).<br /> 399 * Use this property to get a grip on the iframe's window features<br /> 400 * 401 * @type window 402 */ 403 this._iframe = null; 404 /** The document object of the iframe.<br /> 405 * Use this property to perform DOM operations on the edited document 406 * @type document 407 */ 408 this._doc = null; 409 /** The toolbar 410 * @private 411 * @type DomNode 412 */ 413 this._toolBar = this._toolbar = null; //._toolbar is for legacy, ._toolBar is better thanks. 414 /** Holds the botton objects 415 * @private 416 * @type Object 417 */ 418 this._toolbarObjects = {}; 419 249 420 } 250 421 … … 253 424 254 425 // cache some regexps 426 /** Identifies HTML tag names 427 * @type RegExp 428 */ 255 429 Xinha.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig; 430 /** Exracts DOCTYPE string from HTML 431 * @type RegExp 432 */ 256 433 Xinha.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i; 434 /** Finds head section in HTML 435 * @type RegExp 436 */ 257 437 Xinha.RE_head = /<head>((.|\n)*?)<\/head>/i; 438 /** Finds body section in HTML 439 * @type RegExp 440 */ 258 441 Xinha.RE_body = /<body[^>]*>((.|\n|\r|\t)*?)<\/body>/i; 442 /** Special characters that need to be escaped when dynamically creating a RegExp from an arbtrary string 443 * @private 444 * @type RegExp 445 */ 259 446 Xinha.RE_Specials = /([\/\^$*+?.()|{}[\]])/g; 447 /** When dynamically creating a RegExp from an arbtrary string, some charactes that have special meanings in regular expressions have to be escaped. 448 * Run any string through this function to escape reserved characters. 449 * @param {string} string the string to be escaped 450 * @returns string 451 */ 452 Xinha.escapeStringForRegExp = function (string) 453 { 454 return string.replace(Xinha.RE_Specials, '\\$1'); 455 } 456 /** Identifies email addresses 457 * @type RegExp 458 */ 260 459 Xinha.RE_email = /[_a-z\d\-\.]{3,}@[_a-z\d\-]{2,}(\.[_a-z\d\-]{2,})+/i; 460 /** Identifies URLs 461 * @type RegExp 462 */ 261 463 Xinha.RE_url = /(https?:\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,}){2,}(:[0-9]+)?(\/\S+)*)/i; 262 464 465 466 467 /** 468 * This class creates an object that can be passed to the Xinha constructor as a parameter. 469 * Set the object's properties as you need to configure the editor (toolbar etc.) 470 * @version $Rev 817$ $LastChangedDate$ 471 * @constructor 472 */ 263 473 Xinha.Config = function() 264 474 { 265 475 var cfg = this; 266 476 this.version = Xinha.version.Revision; 267 268 // Width and Height 269 // you may set these as follows 270 // width = 'auto' -- the width of the original textarea will be used 271 // width = 'toolbar' -- the width of the toolbar will be used 272 // width = '<css measure>' -- use any css measurement, eg width = '75%' 273 // 274 // height = 'auto' -- the height of the original textarea 275 // height = '<css measure>' -- any css measurement, eg height = '480px' 477 478 /** This property controls the width of the editor.<br /> 479 * Allowed values are 'auto', 'toolbar' or a numeric value followed by "px".<br /> 480 * <code>auto</code>: let Xinha choose the width to use.<br /> 481 * <code>toolbar</code>: compute the width size from the toolbar width.<br /> 482 * <code>numeric value</code>: forced width in pixels ('600px').<br /> 483 * 484 * Default: <code>"auto"</code> 485 * @type String 486 */ 276 487 this.width = "auto"; 488 /** This property controls the height of the editor.<br /> 489 * Allowed values are 'auto' or a numeric value followed by px.<br /> 490 * <code>"auto"</code>: let Xinha choose the height to use.<br /> 491 * <code>numeric value</code>: forced height in pixels ('200px').<br /> 492 * Default: <code>"auto"</code> 493 * @type String 494 */ 277 495 this.height = "auto"; 278 496 279 // the next parameter specifies whether the toolbar should be included 280 // in the size above, or are extra to it. If false then it's recommended 281 // to have explicit pixel sizes above (or on your textarea and have auto above) 497 /** Specifies whether the toolbar should be included 498 * in the size, or are extra to it. If false then it's recommended 499 * to have the size set as explicit pixel sizes (either in Xinha.Config or on your textarea)<br /> 500 * 501 * Default: <code>true</code> 502 * 503 * @type Boolean 504 */ 282 505 this.sizeIncludesBars = true; 283 284 // the next parameter specifies whether the panels should be included 285 // in the size above, or are extra to it. If false then it's recommended 286 // to have explicit pixel sizes above (or on your textarea and have auto above) 506 /** 507 * Specifies whether the panels should be included 508 * in the size, or are extra to it. If false then it's recommended 509 * to have the size set as explicit pixel sizes (either in Xinha.Config or on your textarea)<br /> 510 * 511 * Default: <code>true</code> 512 * 513 * @type Boolean 514 */ 287 515 this.sizeIncludesPanels = true; 288 516 289 // each of the panels has a dimension, for the left/right it's the width 290 // for the top/bottom it's the height. 291 // 292 // WARNING: PANEL DIMENSIONS MUST BE SPECIFIED AS PIXEL WIDTHS 517 /** 518 * each of the panels has a dimension, for the left/right it's the width 519 * for the top/bottom it's the height. 520 * 521 * WARNING: PANEL DIMENSIONS MUST BE SPECIFIED AS PIXEL WIDTHS<br /> 522 *Default values: 523 *<pre> 524 * xinha_config.panel_dimensions = 525 * { 526 * left: '200px', // Width 527 * right: '200px', 528 * top: '100px', // Height 529 * bottom: '100px' 530 * } 531 *</pre> 532 * @type Object 533 */ 293 534 this.panel_dimensions = 294 535 { … … 299 540 }; 300 541 301 // to make the iframe width narrower than the toolbar width, e.g. to maintain 302 // the layout when editing a narrow column of text, set the next parameter (in pixels). 542 /** To make the iframe width narrower than the toolbar width, e.g. to maintain 543 * the layout when editing a narrow column of text, set the next parameter (in pixels).<br /> 544 * 545 * Default: <code>true</code> 546 * 547 * @type Integer|null 548 */ 303 549 this.iframeWidth = null; 304 305 // enable creation of a status bar? 550 551 /** Enable creation of the status bar?<br /> 552 * 553 * Default: <code>true</code> 554 * 555 * @type Boolean 556 */ 306 557 this.statusBar = true; 307 558 308 // intercept ^V and use the Xinha paste command 309 // If false, then passes ^V through to browser editor widget 559 /** Intercept ^V and use the Xinha paste command 560 * If false, then passes ^V through to browser editor widget, which is the only way it works without problems in Mozilla<br /> 561 * 562 * Default: <code>false</code> 563 * 564 * @type Boolean 565 */ 310 566 this.htmlareaPaste = false; 311 312 this.mozParaHandler = 'best'; // set to 'built-in', 'dirty' or 'best'313 // built-in: will (may) use 'br' instead of 'p' tags314 // dirty : will use p and work good enough for the majority of cases,315 // best : works the best, but it's about 12kb worth of javascript316 // and will probably be slower than 'dirty'. This is the "EnterParagraphs"317 // plugin from "hipikat", rolled in to be part of the core code318 319 567 320 // possible values 321 // 'DOMwalk' (the "original") 322 // 'TransformInnerHTML' (this used to be the GetHtml plugin) 568 /** <strong>Gecko only:</strong> Let the built-in routine for handling the <em>return</em> key decide if to enter <em>br</em> or <em>p</em> tags, 569 * or use a custom implementation.<br /> 570 * For information about the rules applied by Gecko, <a href="http://www.mozilla.org/editor/rules.html">see Mozilla website</a> <br /> 571 * Possible values are <em>built-in</em> or <em>best</em><br /> 572 * 573 * Default: <code>"best"</code> 574 * 575 * @type String 576 */ 577 this.mozParaHandler = 'best'; 578 579 /** This determines the method how the HTML output is generated. 580 * There are two choices: 581 * 582 *<table border="1"> 583 * <tr> 584 * <td><em>DOMwalk</em></td> 585 * <td>This is the classic and proven method. It recusively traverses the DOM tree 586 * and builds the HTML string "from scratch". Tends to be a bit slow, especially in IE.</td> 587 * </tr> 588 * <tr> 589 * <td><em>TransformInnerHTML</em></td> 590 * <td>This method uses the JavaScript innerHTML property and relies on Regular Expressions to produce 591 * clean XHTML output. This method is much faster than the other one.</td> 592 * </tr> 593 * </table> 594 * 595 * Default: <code>"DOMwalk"</code> 596 * 597 * @type String 598 */ 323 599 this.getHtmlMethod = 'DOMwalk'; 324 600 325 // maximum size of the undo queue 601 /** Maximum size of the undo queue<br /> 602 * Default: <code>20</code> 603 * @type Integer 604 */ 326 605 this.undoSteps = 20; 327 606 328 // the time interval at which undo samples are taken 329 this.undoTimeout = 500; // 1/2 sec. 330 331 // set this to true if you want to explicitly right-justify when 332 // setting the text direction to right-to-left 607 /** The time interval at which undo samples are taken<br /> 608 * Default: <code>500</code> (1/2 sec) 609 * @type Integer milliseconds 610 */ 611 this.undoTimeout = 500; 612 613 /** Set this to true if you want to explicitly right-justify when setting the text direction to right-to-left<br /> 614 * Default: <code>false</code> 615 * @type Boolean 616 */ 333 617 this.changeJustifyWithDirection = false; 334 618 335 // if true then Xinha will retrieve the full HTML, starting with the 336 // <HTML> tag. 619 /** If true then Xinha will retrieve the full HTML, starting with the <HTML> tag.<br /> 620 * Default: <code>false</code> 621 * @type Boolean 622 */ 337 623 this.fullPage = false; 338 624 339 // style included in the iframe document 625 /** Raw style definitions included in the edited document<br /> 626 * When a lot of inline style is used, perhaps it is wiser to use one or more external stylesheets.<br /> 627 * To set tags P in red, H1 in blue andn A not underlined, we may do the following 628 *<pre> 629 * xinha_config.pageStyle = 630 * 'p { color:red; }\n' + 631 * 'h1 { color:bleu; }\n' + 632 * 'a {text-decoration:none; }'; 633 *</pre> 634 * Default: <code>""</code> (empty) 635 * @type String 636 */ 340 637 this.pageStyle = ""; 341 638 342 // external stylesheets to load (REFERENCE THESE ABSOLUTELY) 639 /** Array of external stylesheets to load. (Reference these absolutely)<br /> 640 * Example<br /> 641 * <pre>xinha_config.pageStyleSheets = ["/css/myPagesStyleSheet.css","/css/anotherOne.css"];</pre> 642 * Default: <code>[]</code> (empty) 643 * @type Array 644 */ 343 645 this.pageStyleSheets = []; 344 646 345 647 // specify a base href for relative links 648 /** Specify a base href for relative links<br /> 649 * ATTENTION: this does not work as expected and needs t be changed, see Ticket #961 <br /> 650 * Default: <code>null</code> 651 * @type String|null 652 */ 346 653 this.baseHref = null; 347 654 348 // when the editor is in different directory depth as the edited page relative image sources 349 // will break the display of your images 350 // this fixes an issue where Mozilla converts the urls of images and links that are on the same server 351 // to relative ones (../) when dragging them around in the editor (Ticket #448) 655 /** If true, relative URLs (../) will be made absolute. 656 * When the editor is in different directory depth 657 * as the edited page relative image sources will break the display of your images. 658 * this fixes an issue where Mozilla converts the urls of images and links that are on the same server 659 * to relative ones (../) when dragging them around in the editor (Ticket #448)<br /> 660 * Default: <code>true</code> 661 * @type Boolean 662 */ 352 663 this.expandRelativeUrl = true; 353 664 354 // we can strip the base href out of relative links to leave them relative, reason for this 355 // especially if you don't specify a baseHref is that mozilla at least (& IE ?) will prefix 356 // the baseHref to any relative links to make them absolute, which isn't what you want most the time. 665 /** We can strip the server part out of URL to make/leave them semi-absolute, reason for this 666 * is that the browsers will prefix the server to any relative links to make them absolute, 667 * which isn't what you want most the time.<br /> 668 * Default: <code>true</code> 669 * @type Boolean 670 */ 357 671 this.stripBaseHref = true; 358 672 359 // and we can strip the url of the editor page from named links (eg <a href="#top">...</a>) 360 // reason for this is that mozilla at least (and IE ?) prefixes location.href to any 361 // that don't have a url prefixing them 673 /** We can strip the url of the editor page from named links (eg <a href="#top">...</a>) 674 * reason for this is that mozilla at least (and IE ?) prefixes location.href to any anchor 675 * that don't have a url prefixing them<br /> 676 * Default: <code>true</code> 677 * @type Boolean 678 */ 362 679 this.stripSelfNamedAnchors = true; 363 680 364 // sometimes high-ascii in links can cause problems for servers (basically they don't recognise them) 365 // so you can use this flag to ensure that all characters other than the normal ascii set (actually 366 // only ! through ~) are escaped in URLs to % codes 681 /** In URLs all characters above ASCII value 127 have to be encoded using % codes<br /> 682 * Default: <code>true</code> 683 * @type Boolean 684 */ 367 685 this.only7BitPrintablesInURLs = true; 368 686 369 // if you are putting the HTML written in Xinha into an email you might want it to be 7-bit 370 // characters only. This config option (off by default) will convert all characters consuming 371 // more than 7bits into UNICODE decimal entity references (actually it will convert anything 372 // below <space> (chr 20) except cr, lf and tab and above <tilde> (~, chr 7E)) 687 688 /** If you are putting the HTML written in Xinha into an email you might want it to be 7-bit 689 * characters only. This config option will convert all characters consuming 690 * more than 7bits into UNICODE decimal entity references (actually it will convert anything 691 * below <space> (chr 20) except cr, lf and tab and above <tilde> (~, chr 7E))<br /> 692 * Default: <code>false</code> 693 * @type Boolean 694 */ 373 695 this.sevenBitClean = false; 374 696 375 // sometimes we want to be able to replace some string in the html comng in and going out 376 // so that in the editor we use the "internal" string, and outside and in the source view 377 // we use the "external" string this is useful for say making special codes for 378 // your absolute links, your external string might be some special code, say "{server_url}" 379 // an you say that the internal represenattion of that should be http://your.server/ 697 698 /** Sometimes we want to be able to replace some string in the html comng in and going out 699 * so that in the editor we use the "internal" string, and outside and in the source view 700 * we use the "external" string this is useful for say making special codes for 701 * your absolute links, your external string might be some special code, say "{server_url}" 702 * an you say that the internal represenattion of that should be http://your.server/<br /> 703 * Example: <code>{'external_string' : 'internal_string'}</code><br /> 704 * Default: <code>{}</code> (empty) 705 * @type Object 706 */ 380 707 this.specialReplacements = {}; // { 'external_string' : 'internal_string' } 381 708 382 // set to true if you want Word code to be cleaned upon Paste 709 /** Set to true if you want Word code to be cleaned upon Paste. This only works if 710 * you use the toolbr button to paste, not ^V. This means that due to the restrictions 711 * regarding pasting, this actually has no real effect in Mozilla <br /> 712 * Default: <code>true</code> 713 * @type Boolean 714 */ 383 715 this.killWordOnPaste = true; 384 716 385 // enable the 'Target' field in the Make Link dialog 717 /** Enable the 'Target' field in the Make Link dialog. Note that the target attribute is invalid in (X)HTML strict<br /> 718 * Default: <code>true</code> 719 * @type Boolean 720 */ 386 721 this.makeLinkShowsTarget = true; 387 722 388 // CharSet of the iframe, default is the charset of the document 723 /** CharSet of the iframe, default is the charset of the document 724 * @type String 725 */ 389 726 this.charSet = (typeof document.characterSet != 'undefined') ? document.characterSet : document.charset; 390 727 391 // Whether the edited document should be rendered in Quirksmode or Standard Compliant (Strict) Mode 392 // This is commonly known as the "doctype switch" 393 // for details read here http://www.quirksmode.org/css/quirksmode.html 394 // 395 // Possible values: 396 // true : Quirksmode is used 397 // false : Strict mode is used 398 // leave empty : the mode of the document Xinha is in is used 399 this.browserQuirksMode = ''; 728 /** Whether the edited document should be rendered in Quirksmode or Standard Compliant (Strict) Mode.<br /> 729 * This is commonly known as the "doctype switch"<br /> 730 * for details read here http://www.quirksmode.org/css/quirksmode.html 731 * 732 * Possible values:<br /> 733 * true : Quirksmode is used<br /> 734 * false : Strict mode is used<br /> 735 * null (default): the mode of the document Xinha is in is used 736 * @type Boolean|null 737 */ 738 this.browserQuirksMode = null; 400 739 401 740 // URL-s … … 403 742 this.popupURL = "popups/"; 404 743 405 // remove tags (these have to be a regexp, or null if this functionality is not desired) 744 /** Remove given tags when rendering the HTML (these have to be a regexp, or null if this functionality is not desired)<br /> 745 * Default: <code>null</code> 746 * @type RegExp|null 747 */ 406 748 this.htmlRemoveTags = null; 407 749 408 // Turning this on will turn all "linebreak" and "separator" items in your toolbar into soft-breaks, 409 // this means that if the items between that item and the next linebreak/separator can 410 // fit on the same line as that which came before then they will, otherwise they will 411 // float down to the next line. 412 413 // If you put a linebreak and separator next to each other, only the separator will 414 // take effect, this allows you to have one toolbar that works for both flowToolbars = true and false 415 // infact the toolbar below has been designed in this way, if flowToolbars is false then it will 416 // create explictly two lines (plus any others made by plugins) breaking at justifyleft, however if 417 // flowToolbars is false and your window is narrow enough then it will create more than one line 418 // even neater, if you resize the window the toolbars will reflow. Niiiice. 419 750 /** Turning this on will turn all "linebreak" and "separator" items in your toolbar into soft-breaks, 751 * this means that if the items between that item and the next linebreak/separator can 752 * fit on the same line as that which came before then they will, otherwise they will 753 * float down to the next line. 754 755 * If you put a linebreak and separator next to each other, only the separator will 756 * take effect, this allows you to have one toolbar that works for both flowToolbars = true and false 757 * infact the toolbar below has been designed in this way, if flowToolbars is false then it will 758 * create explictly two lines (plus any others made by plugins) breaking at justifyleft, however if 759 * flowToolbars is false and your window is narrow enough then it will create more than one line 760 * even neater, if you resize the window the toolbars will reflow. <br /> 761 * Default: <code>true</code> 762 * @type Boolean 763 */ 420 764 this.flowToolbars = true; 421 765 422 // set to center or right to change button alignment in toolbar 766 /** Set to center or right to change button alignment in toolbar 767 * @type String 768 */ 423 769 this.toolbarAlign = "left"; 424 770 425 // set to true if you want the loading panel to show at startup 771 /** Set to true if you want the loading panel to show at startup<br /> 772 * Default: <code>false</code> 773 * @type Boolean 774 */ 426 775 this.showLoading = false; 427 428 // set to false if you want to allow JavaScript in the content, otherwise <script> tags are stripped out 776 777 /** Set to false if you want to allow JavaScript in the content, otherwise <script> tags are stripped out.<br /> 778 * This currently only affects the "DOMwalk" getHtmlMethod.<br /> 779 * Default: <code>true</code> 780 * @type Boolean 781 */ 429 782 this.stripScripts = true; 430 783 431 // see if the text just typed looks like a URL, or email address 432 // and link it appropriatly 433 // Note: Setting this option to false only affects Mozilla based browsers. 434 // In InternetExplorer this is native behaviour and cannot be turned off. 435 this.convertUrlsToLinks = true; 436 437 // size of color picker cells 784 /** See if the text just typed looks like a URL, or email address 785 * and link it appropriatly 786 * Note: Setting this option to false only affects Mozilla based browsers. 787 * In InternetExplorer this is native behaviour and cannot be turned off.<br /> 788 * Default: <code>true</code> 789 * @type Boolean 790 */ 791 this.convertUrlsToLinks = true; 792 793 794 /** Size of color picker cells<br /> 795 * Use number + "px"<br /> 796 * Default: <code>"6px"</code> 797 * @type String 798 */ 438 799 this.colorPickerCellSize = '6px'; 439 // granularity of color picker cells (number per column/row) 800 /** Granularity of color picker cells (number per column/row)<br /> 801 * Default: <code>18</code> 802 * @type Integer 803 */ 440 804 this.colorPickerGranularity = 18; 441 // position of color picker from toolbar button 805 /** Position of color picker from toolbar button<br /> 806 * Default: <code>"bottom,right"</code> 807 * @type String 808 */ 442 809 this.colorPickerPosition = 'bottom,right'; 443 // set to true to show websafe checkbox in picker 810 /** Set to true to show only websafe checkbox in picker<br /> 811 * Default: <code>false</code> 812 * @type Boolean 813 */ 444 814 this.colorPickerWebSafe = false; 445 // number of recent colors to remember 815 /** Number of recent colors to remember<br /> 816 * Default: <code>20</code> 817 * @type Integer 818 */ 446 819 this.colorPickerSaveColors = 20; 447 820 448 // start up the editor in fullscreen mode 821 /** Start up the editor in fullscreen mode<br /> 822 * Default: <code>false</code> 823 * @type Boolean 824 */ 449 825 this.fullScreen = false; 450 826 451 // you can tell the fullscreen mode to leave certain margins on each side 452 // the value is an array with the values for [top,right,bottom,left] in that order 827 /** You can tell the fullscreen mode to leave certain margins on each side.<br /> 828 * The value is an array with the values for <code>[top,right,bottom,left]</code> in that order<br /> 829 * Default: <code>[0,0,0,0]</code> 830 * @type Array 831 */ 453 832 this.fullScreenMargins = [0,0,0,0]; 454 833 455 /** CUSTOMIZING THE TOOLBAR 456 * ------------------------- 457 * 458 * It is recommended that you customize the toolbar contents in an 459 * external file (i.e. the one calling Xinha) and leave this one 460 * unchanged. That's because when we (InteractiveTools.com) release a 461 * new official version, it's less likely that you will have problems 462 * upgrading Xinha. 463 */ 834 /** This array orders all buttons except plugin buttons in the toolbar. Plugin buttons typically look for one 835 * a certain button in the toolbar and place themselves next to it. 836 * Default value: 837 *<pre> 838 *xinha_config.toolbar = 839 * [ 840 * ["popupeditor"], 841 * ["separator","formatblock","fontname","fontsize","bold","italic","underline","strikethrough"], 842 * ["separator","forecolor","hilitecolor","textindicator"], 843 * ["separator","subscript","superscript"], 844 * ["linebreak","separator","justifyleft","justifycenter","justifyright","justifyfull"], 845 * ["separator","insertorderedlist","insertunorderedlist","outdent","indent"], 846 * ["separator","inserthorizontalrule","createlink","insertimage","inserttable"], 847 * ["linebreak","separator","undo","redo","selectall","print"], (Xinha.is_gecko ? [] : ["cut","copy","paste","overwrite","saveas"]), 848 * ["separator","killword","clearfonts","removeformat","toggleborders","splitblock","lefttoright", "righttoleft"], 849 * ["separator","htmlmode","showhelp","about"] 850 * ]; 851 *</pre> 852 * @type Array 853 */ 464 854 this.toolbar = 465 855 [ … … 476 866 ]; 477 867 478 868 /** The fontnames listed in the fontname dropdown 869 * Default value: 870 *<pre> 871 *xinha_config.fontname = 872 *{ 873 * "— font —" : '', 874 * "Arial" : 'arial,helvetica,sans-serif', 875 * "Courier New" : 'courier new,courier,monospace', 876 * "Georgia" : 'georgia,times new roman,times,serif', 877 * "Tahoma" : 'tahoma,arial,helvetica,sans-serif', 878 * "Times New Roman" : 'times new roman,times,serif', 879 * "Verdana" : 'verdana,arial,helvetica,sans-serif', 880 * "impact" : 'impact', 881 * "WingDings" : 'wingdings' 882 *}; 883 *</pre> 884 * @type Object 885 */ 479 886 this.fontname = 480 887 { 481 888 "— font —": '', 482 "Arial" :'arial,helvetica,sans-serif',483 "Courier New" :'courier new,courier,monospace',484 "Georgia" :'georgia,times new roman,times,serif',485 "Tahoma" :'tahoma,arial,helvetica,sans-serif',486 "Times New Roman" : 'times new roman,times,serif',487 "Verdana" :'verdana,arial,helvetica,sans-serif',488 "impact" :'impact',489 "WingDings" : 'wingdings'889 "Arial" : 'arial,helvetica,sans-serif', 890 "Courier New" : 'courier new,courier,monospace', 891 "Georgia" : 'georgia,times new roman,times,serif', 892 "Tahoma" : 'tahoma,arial,helvetica,sans-serif', 893 "Times New Roman" : 'times new roman,times,serif', 894 "Verdana" : 'verdana,arial,helvetica,sans-serif', 895 "impact" : 'impact', 896 "WingDings" : 'wingdings' 490 897 }; 491 898 899 /** The fontsizes listed in the fontsize dropdown 900 * Default value: 901 *<pre> 902 *xinha_config.fontsize = 903 *{ 904 * "— size —": "", 905 * "1 (8 pt)" : "1", 906 * "2 (10 pt)": "2", 907 * "3 (12 pt)": "3", 908 * "4 (14 pt)": "4", 909 * "5 (18 pt)": "5", 910 * "6 (24 pt)": "6", 911 * "7 (36 pt)": "7" 912 *}; 913 *</pre> 914 * @type Object 915 */ 492 916 this.fontsize = 493 917 { … … 501 925 "7 (36 pt)": "7" 502 926 }; 503 927 /** The tags listed in the formatblock dropdown 928 * Default value: 929 *<pre> 930 *xinha_config.formatblock = 931 *{ 932 * "— size —": "", 933 * "1 (8 pt)" : "1", 934 * "2 (10 pt)": "2", 935 * "3 (12 pt)": "3", 936 * "4 (14 pt)": "4", 937 * "5 (18 pt)": "5", 938 * "6 (24 pt)": "6", 939 * "7 (36 pt)": "7" 940 *}; 941 *</pre> 942 * @type Object 943 */ 504 944 this.formatblock = 505 945 { … … 515 955 "Formatted": "pre" 516 956 }; 517 957 /** ?? 958 * Default: <code>{}</code> 959 * @type Object 960 */ 518 961 this.customSelects = {}; 519 962 520 function cut_copy_paste(e, cmd, obj) { e.execCommand(cmd); } 521 963 /** Switches on some debugging (only in execCommand() as far as I see at the moment)<br /> 964 * 965 * Default: <code>true</code> 966 * @type Boolean 967 */ 522 968 this.debug = true; 523 969 … … 534 980 535 981 536 // ADDING CUSTOM BUTTONS: please read below! 537 // format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]" 538 // - ID: unique ID for the button. If the button calls document.execCommand 539 // it's wise to give it the same name as the called command. 540 // - ACTION: function that gets called when the button is clicked. 541 // it has the following prototype: 542 // function(editor, buttonName) 543 // - editor is the Xinha object that triggered the call 544 // - buttonName is the ID of the clicked button 545 // These 2 parameters makes it possible for you to use the same 546 // handler for more Xinha objects or for more different buttons. 547 // - ToolTip: tooltip, will be translated below 548 // - Icon: path to an icon image file for the button 549 // OR; you can use an 18x18 block of a larger image by supllying an array 550 // that has three elemtents, the first is the larger image, the second is the column 551 // the third is the row. The ros and columns numbering starts at 0 but there is 552 // a header row and header column which have numbering to make life easier. 553 // See images/buttons_main.gif to see how it's done. 554 // - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time. 982 /** The button list conains the definitions of the toolbar button. Normally, there's nothing to change here :) 983 * <div style="white-space:pre">ADDING CUSTOM BUTTONS: please read below! 984 * format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]" 985 * - ID: unique ID for the button. If the button calls document.execCommand 986 * it's wise to give it the same name as the called command. 987 * - ACTION: function that gets called when the button is clicked. 988 * it has the following prototype: 989 * function(editor, buttonName) 990 * - editor is the Xinha object that triggered the call 991 * - buttonName is the ID of the clicked button 992 * These 2 parameters makes it possible for you to use the same 993 * handler for more Xinha objects or for more different buttons. 994 * - ToolTip: tooltip, will be translated below 995 * - Icon: path to an icon image file for the button 996 * OR; you can use an 18x18 block of a larger image by supllying an array 997 * that has three elemtents, the first is the larger image, the second is the column 998 * the third is the row. The ros and columns numbering starts at 0 but there is 999 * a header row and header column which have numbering to make life easier. 1000 * See images/buttons_main.gif to see how it's done. 1001 * - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time.</div> 1002 * @type Object 1003 */ 555 1004 this.btnList = 556 1005 { … … 579 1028 undo: [ "Undoes your last action", ["ed_buttons_main.gif",4,2], false, function(e) { e.execCommand("undo"); } ], 580 1029 redo: [ "Redoes your last action", ["ed_buttons_main.gif",5,2], false, function(e) { e.execCommand("redo"); } ], 581 cut: [ "Cut selection", ["ed_buttons_main.gif",5,0], false, cut_copy_paste],582 copy: [ "Copy selection", ["ed_buttons_main.gif",4,0], false, cut_copy_paste],583 paste: [ "Paste from clipboard", ["ed_buttons_main.gif",4,1], false, cut_copy_paste],1030 cut: [ "Cut selection", ["ed_buttons_main.gif",5,0], false, function (e, cmd) { e.execCommand(cmd); } ], 1031 copy: [ "Copy selection", ["ed_buttons_main.gif",4,0], false, function (e, cmd) { e.execCommand(cmd); } ], 1032 paste: [ "Paste from clipboard", ["ed_buttons_main.gif",4,1], false, function (e, cmd) { e.execCommand(cmd); } ], 584 1033 selectall: [ "Select all", "ed_selectall.gif", false, function(e) {e.execCommand("selectall");} ], 585 1034 … … 607 1056 }; 608 1057 609 /* ADDING CUSTOM BUTTONS 610 * --------------------- 611 * 612 * It is recommended that you add the custom buttons in an external 613 * file and leave this one unchanged. That's because when we 614 * (InteractiveTools.com) release a new official version, it's less 615 * likely that you will have problems upgrading Xinha. 616 * 617 * Example on how to add a custom button when you construct the Xinha: 618 * 619 * var editor = new Xinha("your_text_area_id"); 620 * var cfg = editor.config; // this is the default configuration 621 * cfg.btnList["my-hilite"] = 622 * [ function(editor) { editor.surroundHTML('<span style="background:yellow">', '</span>'); }, // action 623 * "Highlight selection", // tooltip 624 * "my_hilite.gif", // image 625 * false // disabled in text mode 626 * ]; 627 * cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar 628 * 629 * An alternate (also more convenient and recommended) way to 630 * accomplish this is to use the registerButton function below. 631 */ 1058 632 1059 // initialize tooltips from the I18N module and generate correct image path 633 1060 for ( var i in this.btnList ) … … 651 1078 652 1079 }; 653 1080 /** ADDING CUSTOM BUTTONS 1081 * --------------------- 1082 * 1083 * 1084 * Example on how to add a custom button when you construct the Xinha: 1085 * 1086 * var editor = new Xinha("your_text_area_id"); 1087 * var cfg = editor.config; // this is the default configuration 1088 * cfg.btnList["my-hilite"] = 1089 * [ function(editor) { editor.surroundHTML('<span style="background:yellow">', '</span>'); }, // action 1090 * "Highlight selection", // tooltip 1091 * "my_hilite.gif", // image 1092 * false // disabled in text mode 1093 * ]; 1094 * cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar 1095 * 1096 * An alternate (also more convenient and recommended) way to 1097 * accomplish this is to use the registerButton function below. 1098 */ 654 1099 /** Helper function: register a new button with the configuration. It can be 655 1100 * called with all 5 arguments, or with only one (first one). When called with 656 1101 * only one argument it must be an object with the following properties: id, 657 * tooltip, image, textMode, action. Examples: 658 * 659 * 1. config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...}); 660 * 2. config.registerButton({ 1102 * tooltip, image, textMode, action.<br /> 1103 * 1104 * Examples:<br /> 1105 *<pre> 1106 * config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...}); 1107 * config.registerButton({ 661 1108 * id : "my-hilite", // the ID of your button 662 1109 * tooltip : "Hilite text", // the tooltip … … 667 1114 * }, 668 1115 * context : "p" // will be disabled if outside a <p> element 669 * }); 1116 * });</pre> 670 1117 */ 671 1118 Xinha.Config.prototype.registerButton = function(id, tooltip, image, textMode, action, context) … … 936 1383 } 937 1384 }; 938 1385 /** Alias of Xinha.Config.prototype.hideSomeButtons() 1386 * @type Function 1387 */ 939 1388 Xinha.Config.prototype.removeToolbarElement = Xinha.Config.prototype.hideSomeButtons; 940 1389 941 /** Helper function: replace all TEXTAREA-s in the document with Xinha-s. */ 1390 /** Helper function: replace all TEXTAREA-s in the document with Xinha-s. 1391 * @param {Xinha.Config} optional config 1392 */ 942 1393 Xinha.replaceAll = function(config) 943 1394 { … … 950 1401 }; 951 1402 952 /** Helper function: replaces the TEXTAREA with the given ID with Xinha. */ 1403 /** Helper function: replaces the TEXTAREA with the given ID with Xinha. 1404 * @param {string} id id of the textarea to replace 1405 * @param {Xinha.Config} optional config 1406 */ 953 1407 Xinha.replace = function(id, config) 954 1408 { … … 956 1410 return ta ? (new Xinha(ta, config)).generate() : null; 957 1411 }; 958 959 // Creates the toolbar and appends it to the _htmlarea 1412 1413 /** Creates the toolbar and appends it to the _htmlarea 1414 * @private 1415 * @returns {DomNode} toolbar 1416 */ 960 1417 Xinha.prototype._createToolbar = function () 961 1418 { … … 968 1425 toolbar.className = "toolbar"; 969 1426 toolbar.unselectable = "1"; 970 toolbar.align = this.config.toolbarAlign;971 1427 972 1428 Xinha.freeLater(this, '_toolBar'); … … 983 1439 }; 984 1440 985 // FIXME : function never used, can probably be removed from source 1441 /** FIXME : function never used, can probably be removed from source 1442 * @private 1443 * @deprecated 1444 */ 986 1445 Xinha.prototype._setConfig = function(config) 987 1446 { 988 1447 this.config = config; 989 1448 }; 990 1449 /** FIXME: How can this be used?? 1450 * @private 1451 */ 991 1452 Xinha.prototype._addToolbar = function() 992 1453 { … … 997 1458 * Create a break element to add in the toolbar 998 1459 * 999 * @return { Object} HTML element to add1460 * @return {DomNode} HTML element to add 1000 1461 * @private 1001 1462 */ … … 1011 1472 }; 1012 1473 1013 // separate from previous createToolBar to allow dynamic change of toolbar 1474 1475 /** separate from previous createToolBar to allow dynamic change of toolbar 1476 * @private 1477 * @return {DomNode} toolbar 1478 */ 1014 1479 Xinha.prototype._createToolbar1 = function (editor, toolbar, tb_objects) 1015 1480 { … … 1408 1873 // Why the hell this is not in the config object ? 1409 1874 var use_clone_img = false; 1875 /** creates a button (i.e. container element + image) 1876 * @private 1877 * @return {DomNode} conteainer element 1878 */ 1410 1879 Xinha.makeBtnImg = function(imgDef, doc) 1411 1880 { … … 1481 1950 return i_contain; 1482 1951 }; 1483 1952 /** creates the status bar 1953 * @private 1954 * @return {DomNode} status bar 1955 */ 1484 1956 Xinha.prototype._createStatusBar = function() 1485 1957 { … … 1495 1967 div.className = "statusBarTree"; 1496 1968 div.innerHTML = Xinha._lc("Path") + ": "; 1969 1497 1970 this._statusBarTree = div; 1498 1971 Xinha.freeLater(this, '_statusBarTree'); … … 1502 1975 div.innerHTML = Xinha._lc("You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG."); 1503 1976 div.style.display = "none"; 1977 1504 1978 this._statusBarTextMode = div; 1505 1979 Xinha.freeLater(this, '_statusBarTextMode'); … … 1511 1985 statusbar.style.display = "none"; 1512 1986 } 1513 1514 this._statusBarItems = [];1515 1516 1987 return statusbar; 1517 1988 }; 1518 1989 1519 // Creates the Xinha object and replaces the textarea with it. 1990 /** Creates the Xinha object and replaces the textarea with it. Loads required files. 1991 * @returns {Boolean} 1992 */ 1520 1993 Xinha.prototype.generate = function () 1521 1994 { … … 1912 2385 * false = the tool & status bars will appear outside the width & height confines 1913 2386 * 2387 * @private 1914 2388 */ 1915 2389 … … 1960 2434 /** 1961 2435 * Size the editor to a specific size, or just refresh the size (when window resizes for example) 1962 * @param width optional width (CSS specification) 1963 * @param height optional height (CSS specification) 1964 * @param includingBars optional boolean to indicate if the size should include or exclude tool & status bars 2436 * @param {string} width optional width (CSS specification) 2437 * @param {string} height optional height (CSS specification) 2438 * @param {Boolean} includingBars optional to indicate if the size should include or exclude tool & status bars 2439 * @param {Boolean} includingPanels optional to indicate if the size should include or exclude panels 1965 2440 */ 1966 2441 Xinha.prototype.sizeEditor = function(width, height, includingBars, includingPanels) … … 2151 2626 edcellwidth -= parseInt(this.config.panel_dimensions.right, 10); 2152 2627 } 2153 var iframeWidth = (this.config.iframeWidth)? parseInt(this.config.iframeWidth,10): null; 2154 this._iframe.style.width = (iframeWidth && iframeWidth < edcellwidth)? iframeWidth + "px": edcellwidth + "px"; 2628 this._iframe.style.width = edcellwidth + 'px'; 2155 2629 2156 2630 this._textArea.style.height = this._iframe.style.height; … … 2160 2634 this._risizing = false; 2161 2635 }; 2162 2636 /** FIXME: Never used, what is this for? 2637 * @param {string} side 2638 * @param {Object} 2639 */ 2640 Xinha.prototype.registerPanel = function(side, object) 2641 { 2642 if ( !side ) 2643 { 2644 side = 'right'; 2645 } 2646 this.setLoadingMessage('Register ' + side + ' panel '); 2647 var panel = this.addPanel(side); 2648 if ( object ) 2649 { 2650 object.drawPanelIn(panel); 2651 } 2652 }; 2653 /** Creates a panel in the panel container on the specified side 2654 * @param {String} side the panel container to which the new panel will be added<br /> 2655 * Possible values are: "right","left","top","bottom" 2656 * @returns {DomNode} Panel div 2657 */ 2163 2658 Xinha.prototype.addPanel = function(side) 2164 2659 { … … 2178 2673 return div; 2179 2674 }; 2180 2181 2675 /** Removes a panel 2676 * @param {DomNode} panel object as returned by Xinha.prototype.addPanel() 2677 */ 2182 2678 Xinha.prototype.removePanel = function(panel) 2183 2679 { … … 2194 2690 this.notifyOf('panel_change', {'action':'remove','panel':panel}); 2195 2691 }; 2196 2692 /** Hides a panel 2693 * @param {DomNode} panel object as returned by Xinha.prototype.addPanel() 2694 */ 2197 2695 Xinha.prototype.hidePanel = function(panel) 2198 2696 { … … 2205 2703 } 2206 2704 }; 2207 2705 /** Shows a panel 2706 * @param {DomNode} panel object as returned by Xinha.prototype.addPanel() 2707 */ 2208 2708 Xinha.prototype.showPanel = function(panel) 2209 2709 { … … 2216 2716 } 2217 2717 }; 2218 2718 /** Hides the panel(s) on one or more sides 2719 * @param {Array} sides the sides on which the panels shall be hidden 2720 */ 2219 2721 Xinha.prototype.hidePanels = function(sides) 2220 2722 { … … 2235 2737 this.notifyOf('panel_change', {'action':'multi_hide','sides':sides}); 2236 2738 }; 2237 2739 /** Shows the panel(s) on one or more sides 2740 * @param {Array} sides the sides on which the panels shall be hidden 2741 */ 2238 2742 Xinha.prototype.showPanels = function(sides) 2239 2743 { … … 2254 2758 this.notifyOf('panel_change', {'action':'multi_show','sides':sides}); 2255 2759 }; 2256 2760 /** Returns an array containig all properties that are set in an object 2761 * @param {Object} obj 2762 * @returns {Array} 2763 */ 2257 2764 Xinha.objectProperties = function(obj) 2258 2765 { … … 2265 2772 }; 2266 2773 2267 /* 2268 * EDITOR ACTIVATION NOTES: 2774 /** Checks if editor is active 2775 *<br /> 2776 * EDITOR ACTIVATION NOTES:<br /> 2269 2777 * when a page has multiple Xinha editors, ONLY ONE should be activated at any time (this is mostly to 2270 2778 * work around a bug in Mozilla, but also makes some sense). No editor should be activated or focused 2271 2779 * automatically until at least one editor has been activated through user action (by mouse-clicking in 2272 2780 * the editor). 2781 * @private 2782 * @returns {Boolean} 2273 2783 */ 2274 2784 Xinha.prototype.editorIsActivated = function() … … 2283 2793 } 2284 2794 }; 2285 2795 /** We need to know that at least one editor on the page has been activated 2796 * this is because we will not focus any editor until an editor has been activated 2797 * @private 2798 * @type {Boolean} 2799 */ 2286 2800 Xinha._someEditorHasBeenActivated = false; 2287 Xinha._currentlyActiveEditor = false; 2801 /** Stores a reference to the currently active editor 2802 * @private 2803 * @type {Xinha} 2804 */ 2805 Xinha._currentlyActiveEditor = null; 2806 /** Enables one editor for editing, e.g. by a click in the editing area or after it has been 2807 * deactivated programmatically before 2808 * @private 2809 * @returns {Boolean} 2810 */ 2288 2811 Xinha.prototype.activateEditor = function() 2289 2812 { … … 2320 2843 } 2321 2844 2322 // We need to know that at least one editor on the page has been activated2323 // this is because we will not focus any editor until an editor has been activated2324 2845 Xinha._someEditorHasBeenActivated = true; 2325 2846 Xinha._currentlyActiveEditor = this; … … 2328 2849 this.enableToolbar(); 2329 2850 }; 2330 2851 /** Disables the editor 2852 * @private 2853 */ 2331 2854 Xinha.prototype.deactivateEditor = function() 2332 2855 { … … 2357 2880 Xinha._currentlyActiveEditor = false; 2358 2881 }; 2359 2882 /** Creates the iframe (editable area) 2883 * @private 2884 */ 2360 2885 Xinha.prototype.initIframe = function() 2361 2886 { … … 2470 2995 * Delay a function until the document is ready for operations. 2471 2996 * See ticket:547 2472 * @param {object} F (Function) The function to call once the document is ready2473 2997 * @public 2474 */ 2475 Xinha.prototype.whenDocReady = function(F) 2476 { 2477 var E = this; 2998 * @param {Function} f The function to call once the document is ready 2999 */ 3000 Xinha.prototype.whenDocReady = function(f) 3001 { 3002 var e = this; 2478 3003 if ( this._doc && this._doc.body ) 2479 3004 { 2480 F();3005 f(); 2481 3006 } 2482 3007 else 2483 3008 { 2484 setTimeout(function() { E.whenDocReady(F); }, 50); 2485 } 2486 }; 2487 2488 // Switches editor mode; parameter can be "textmode" or "wysiwyg". If no 2489 // parameter was passed this function toggles between modes. 3009 setTimeout(function() { e.whenDocReady(f); }, 50); 3010 } 3011 }; 3012 3013 3014 /** Switches editor mode between wysiwyg and text (HTML) 3015 * @param {String} mode optional "textmode" or "wysiwyg", if omitted, toggles between modes. 3016 */ 2490 3017 Xinha.prototype.setMode = function(mode) 2491 3018 { … … 2548 3075 } 2549 3076 }; 2550 3077 /** Sets the HTML in fullpage mode. Actually the whole iframe document is rewritten. 3078 * @private 3079 * @param {String} html 3080 */ 2551 3081 Xinha.prototype.setFullHTML = function(html) 2552 3082 { … … 2593 3123 } 2594 3124 }; 2595 3125 /** Initialize some event handlers 3126 * @private 3127 */ 2596 3128 Xinha.prototype.setEditorEvents = function() 2597 3129 { … … 2649 3181 ***************************************************/ 2650 3182 2651 // Create the specified plugin and register it with this Xinha 2652 // return the plugin created to allow refresh when necessary 3183 3184 /** Create the specified plugin and register it with this Xinha 3185 * return the plugin created to allow refresh when necessary.<br /> 3186 * <strong>This is only useful if Xinha is generated without using Xinha.makeEditors()</strong> 3187 */ 2653 3188 Xinha.prototype.registerPlugin = function() 2654 3189 { … … 2671 3206 return this.registerPlugin2(plugin, args); 2672 3207 }; 2673 2674 // this is the variant of the function above where the plugin arguments are 2675 // already packed in an array. Externally, it should be only used in the 2676 // full-screen editor code, in order to initialize plugins with the same 2677 // parameters as in the opener window. 3208 /** This is the variant of the function above where the plugin arguments are 3209 * already packed in an array. Externally, it should be only used in the 3210 * full-screen editor code, in order to initialize plugins with the same 3211 * parameters as in the opener window. 3212 * @private 3213 */ 2678 3214 Xinha.prototype.registerPlugin2 = function(plugin, args) 2679 3215 { … … 2708 3244 }; 2709 3245 2710 // static function that loads the required plugin and lang file, based on the 2711 // language loaded already for Xinha. You better make sure that the plugin 2712 // _has_ that language, otherwise shit might happen ;-) 3246 3247 /** Dynamically returns the directory from which the plugins are loaded<br /> 3248 * This could be overridden to change the dir<br /> 3249 * @TODO: Wouldn't this be better as a config option? 3250 * @private 3251 * @param {String} pluginName 3252 * @returns {String} path to plugin 3253 */ 2713 3254 Xinha.getPluginDir = function(pluginName) 2714 3255 { 2715 3256 return _editor_url + "plugins/" + pluginName; 2716 3257 }; 2717 3258 /** Static function that loads the given plugin 3259 * @param {String} pluginName 3260 * @param {Function} callback function to be called when file is loaded 3261 * @param {String} plugin_file URL of the file to load 3262 * @returns {Boolean} true if plugin loaded, false otherwise 3263 */ 2718 3264 Xinha.loadPlugin = function(pluginName, callback, plugin_file) 2719 3265 { … … 2744 3290 return false; 2745 3291 }; 2746 3292 /** Stores a status for each loading plugin that may be one of "loading","ready", or "failed" 3293 * @private 3294 * @type {Object} 3295 */ 2747 3296 Xinha._pluginLoadStatus = {}; 2748 3297 3298 /** Static function that loads the plugins (see xinha_plugins in NewbieGuide) 3299 * @param {Array} plugins 3300 * @param {Function} callbackIfNotReady function that is called repeatedly until all files are 3301 * @returns {Boolean} true if all plugins are loaded, false otherwise 3302 */ 2749 3303 Xinha.loadPlugins = function(plugins, callbackIfNotReady) 2750 3304 { … … 2819 3373 }; 2820 3374 2821 // refresh plugin by calling onGenerate or onGenerateOnce method. 3375 // 3376 /** Refresh plugin by calling onGenerate or onGenerateOnce method. 3377 * @private 3378 * @param {PluginInstance} plugin 3379 */ 2822 3380 Xinha.refreshPlugin = function(plugin) 2823 3381 { … … 2833 3391 }; 2834 3392 2835 /** Call a method of all plugins which define the method using the supplied arguments. 3393 /** Call a method of all plugins which define the method using the supplied arguments.<br /><br /> 2836 3394 * 2837 * Example: editor.firePluginEvent('onExecCommand', 'paste') 3395 * Example: <code>editor.firePluginEvent('onExecCommand', 'paste')</code><br /> 3396 * The plugin would then define a method<br /> 3397 * <code>PluginName.prototype.onExecCommand = function (cmdID, UI, param) {do something...}</code><br /><br /> 3398 * The following methodNames are currently available:<br /> 3399 * <table border="1"> 3400 * <tr> 3401 * <th>methodName</th><th>Parameters</th> 3402 * </tr> 3403 * <tr> 3404 * <td>onExecCommand</td><td> cmdID, UI, param</td> 3405 * </tr> 3406 * <tr> 3407 * <td>onKeyPress</td><td>ev</td> 3408 * </tr> 3409 * <tr> 3410 * <td>onMouseDown</td><td>ev</td> 3411 * </tr> 3412 * </table><br /><br /> 2838 3413 * 2839 3414 * The browser specific plugin (if any) is called last. The result of each call is … … 2841 3416 * will get the event, a false return means the event will continue to fire. 2842 3417 * 2843 * @param methodName 2844 * @param arguments to pass to the method, optional [2..n] 3418 * @param {String} methodName 3419 * @param {mixed} arguments to pass to the method, optional [2..n] 3420 * @returns {Boolean} 2845 3421 */ 2846 3422 … … 2882 3458 return false; 2883 3459 } 2884 3460 /** Adds a stylesheet to the document 3461 * @param {String} style name of the stylesheet file 3462 * @param {String} plugin optional name of a plugin; if passed this function looks for the stylesheet file in the plugin directory 3463 * @param {String} id optional a unique id for identifiing the created link element, e.g. for avoiding double loading 3464 * or later removing it again 3465 */ 2885 3466 Xinha.loadStyle = function(style, plugin, id) 2886 3467 { … … 2888 3469 if ( plugin ) 2889 3470 { 2890 url += "plugins/" + plugin+ "/";3471 url = Xinha.getPluginDir( plugin ) + "/"; 2891 3472 } 2892 3473 url += style; … … 2912 3493 * Category: EDITOR UTILITIES 2913 3494 ***************************************************/ 2914 3495 /** Utility function: Outputs the structure of the edited document */ 2915 3496 Xinha.prototype.debugTree = function() 2916 3497 { … … 2943 3524 document.body.appendChild(ta); 2944 3525 }; 3526 /** Extracts the textual content of a given node 3527 * @param {DomNode} el 3528 */ 2945 3529 2946 3530 Xinha.getInnerText = function(el) … … 2960 3544 return txt; 2961 3545 }; 2962 3546 /** Cleans dirty HTML from MS word; always cleans the whole editor content 3547 * @TODO: move this in a separate file 3548 * @TODO: turn this into a static function that cleans a given string 3549 */ 2963 3550 Xinha.prototype._wordClean = function() 2964 3551 { … … 3090 3677 }; 3091 3678 3679 /** Removes <font> tags; always cleans the whole editor content 3680 * @TODO: move this in a separate file 3681 * @TODO: turn this into a static function that cleans a given string 3682 */ 3092 3683 Xinha.prototype._clearFonts = function() 3093 3684 { … … 3123 3714 }; 3124 3715 3716 /** Sometimes the display has to be refreshed to make DOM changes visible (?) (Gecko bug?) */ 3125 3717 Xinha.prototype.forceRedraw = function() 3126 3718 { … … 3130 3722 }; 3131 3723 3132 // focuses the iframe window. returns a reference to the editor document. 3724 /** Focuses the iframe window. 3725 * @returns {document} a reference to the editor document 3726 */ 3133 3727 Xinha.prototype.focusEditor = function() 3134 3728 { … … 3161 3755 }; 3162 3756 3163 // takes a snapshot of the current text (for undo) 3757 /** Takes a snapshot of the current text (for undo) 3758 * @private 3759 */ 3164 3760 Xinha.prototype._undoTakeSnapshot = function() 3165 3761 { … … 3187 3783 } 3188 3784 }; 3189 3785 /** Custom implementation of undo functionality 3786 * @private 3787 */ 3190 3788 Xinha.prototype.undo = function() 3191 3789 { … … 3203 3801 } 3204 3802 }; 3205 3803 /** Custom implementation of redo functionality 3804 * @private 3805 */ 3206 3806 Xinha.prototype.redo = function() 3207 3807 { … … 3219 3819 } 3220 3820 }; 3221 3821 /** Disables (greys out) the buttons of the toolbar 3822 * @param {Array} except this array contains ids of toolbar objects that will not be disabled 3823 */ 3222 3824 Xinha.prototype.disableToolbar = function(except) 3223 3825 { … … 3250 3852 } 3251 3853 }; 3252 3854 /** Enables the toolbar again when disabled by disableToolbar() */ 3253 3855 Xinha.prototype.enableToolbar = function() 3254 3856 { … … 3256 3858 }; 3257 3859 3258 if ( !Array.prototype.contains ) 3259 { 3260 Array.prototype.contains = function(needle) 3261 { 3262 var haystack = this; 3263 for ( var i = 0; i < haystack.length; i++ ) 3264 { 3265 if ( needle == haystack[i] ) 3266 { 3267 return true; 3268 } 3269 } 3270 return false; 3271 }; 3272 } 3273 3274 if ( !Array.prototype.indexOf ) 3275 { 3276 Array.prototype.indexOf = function(needle) 3277 { 3278 var haystack = this; 3279 for ( var i = 0; i < haystack.length; i++ ) 3280 { 3281 if ( needle == haystack[i] ) 3282 { 3283 return i; 3284 } 3285 } 3286 return null; 3287 }; 3288 } 3289 3860 /** Updates enabled/disable/active state of the toolbar elements, the statusbar and other things 3861 * This function is called on every key stroke as well as by a timer on a regular basis.<br /> 3862 * Plugins have the opportunity to implement a prototype.onUpdateToolbar() method, which will also 3863 * be called by this function. 3864 * @param {Boolean} noStatus private use Exempt updating of statusbar 3865 */ 3290 3866 // FIXME : this function needs to be splitted in more functions. 3291 3867 // It is actually to heavy to be understable and very scary to manipulate 3292 // updates enabled/disable/active state of the toolbar elements3293 3868 Xinha.prototype.updateToolbar = function(noStatus) 3294 3869 { … … 3612 4187 }; 3613 4188 3614 3615 // moved Xinha.prototype.insertNodeAtSelection() to browser specific file 3616 // moved Xinha.prototype.getParentElement() to browser specific file 3617 3618 // Returns an array with all the ancestor nodes of the selection. 4189 /** Returns an array with all the ancestor nodes of the selection or current cursor position. 4190 * @returns {Array} 4191 */ 3619 4192 Xinha.prototype.getAllAncestors = function() 3620 4193 { … … 3630 4203 }; 3631 4204 3632 // Returns the deepest ancestor of the selection that is of the current type 4205 /** Traverses the DOM upwards and returns the first element that is of one of the specified types 4206 * @param {Selection} sel Selection object as returned by getSelection 4207 * @param {Array} types Array of HTML tag names (lower case) 4208 * @returns {DomNode|null} 4209 */ 3633 4210 Xinha.prototype._getFirstAncestor = function(sel, types) 3634 4211 { … … 3679 4256 }; 3680 4257 3681 // moved Xinha.prototype._activeElement() to browser specific file 3682 // moved Xinha.prototype._selectionEmpty() to browser specific file 3683 4258 /** Traverses the DOM upwards and returns the first element that is a block level element 4259 * @param {Selection} sel Selection object as returned by getSelection 4260 * @returns {DomNode|null} 4261 */ 3684 4262 Xinha.prototype._getAncestorBlock = function(sel) 3685 4263 { … … 3728 4306 }; 3729 4307 4308 /** What's this? does nothing, has to be removed 4309 * 4310 * @deprecated 4311 */ 3730 4312 Xinha.prototype._createImplicitBlock = function(type) 3731 4313 { … … 3750 4332 3751 4333 3752 // moved Xinha.prototype.selectNodeContents() to browser specific file3753 // moved Xinha.prototype.insertHTML() to browser specific file3754 4334 3755 4335 /** 3756 4336 * Call this function to surround the existing HTML code in the selection with 3757 * your tags. FIXME: buggy! This function will be deprecated "soon".4337 * your tags. FIXME: buggy! Don't use this 3758 4338 * @todo: when will it be deprecated ? Can it be removed already ? 4339 * @private (tagged private to not further promote use of this function) 4340 * @deprecated 3759 4341 */ 3760 4342 Xinha.prototype.surroundHTML = function(startTag, endTag) … … 3765 4347 }; 3766 4348 3767 / / moved Xinha.prototype.getSelectedHTML() to browser specific file3768 3769 /// Return true if we have some selection 4349 /** Return true if we have some selection 4350 * @returns {Boolean} 4351 */ 3770 4352 Xinha.prototype.hasSelectedText = function() 3771 4353 { … … 3773 4355 return this.getSelectedHTML() !== ''; 3774 4356 }; 3775 3776 // moved Xinha.prototype._createLink() to popups/link.js3777 // moved Xinha.prototype._insertImage() to popups/insert_image.js3778 3779 // Called when the user clicks the Insert Table button3780 3781 4357 3782 4358 /*************************************************** … … 3784 4360 ***************************************************/ 3785 4361 3786 // el is reference to the SELECT object 3787 // txt is the name of the select field, as in config.toolbar 4362 /** onChange handler for dropdowns in toolbar 4363 * @private 4364 * @param {DomNode} el Reference to the SELECT object 4365 * @param {String} txt The name of the select field, as in config.toolbar 4366 * @returns {DomNode|null} 4367 */ 3788 4368 Xinha.prototype._comboSelected = function(el, txt) 3789 4369 { … … 3824 4404 }; 3825 4405 3826 /** 3827 * Open a popup to select the hilitecolor or forecolor 3828 * 4406 /** Open a popup to select the hilitecolor or forecolor 4407 * @private 3829 4408 * @param {String} cmdID The commande ID (hilitecolor or forecolor) 3830 * @private3831 4409 */ 3832 4410 Xinha.prototype._colorSelector = function(cmdID) … … 3885 4463 }; 3886 4464 3887 // the execCommand function (intercepts some commands and replaces them with 3888 // our own implementation) 4465 /** This is a wrapper for the browser's execCommand function that handles things like 4466 * formatting, inserting elements, etc.<br /> 4467 * It intercepts some commands and replaces them with our own implementation.<br /> 4468 * It provides a hook for the "firePluginEvent" system ("onExecCommand").<br /><br /> 4469 * For reference see:<br /> 4470 * <a href="http://www.mozilla.org/editor/midas-spec.html">Mozilla implementation</a><br /> 4471 * <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/execcommand.asp">MS implementation</a> 4472 * 4473 * @see Xinha#firePluginEvent 4474 * @param {String} cmdID command to be executed as defined in the browsers implemantations or Xinha custom 4475 * @param {Boolean} UI for compatibility with the execCommand syntax; false in most (all) cases 4476 * @param {Mixed} param Some commands require parameters 4477 * @returns {Boolean} always false 4478 */ 3889 4479 Xinha.prototype.execCommand = function(cmdID, UI, param) 3890 4480 { … … 4016 4606 }; 4017 4607 4018 /** A generic event handler for things that happen in the IFRAME's document. 4019 * @todo: this function is *TOO* generic, it needs to be splitted in more specific handlers 4020 * This function also handles key bindings. */ 4608 /** A generic event handler for things that happen in the IFRAME's document.<br /> 4609 * It provides two hooks for the "firePluginEvent" system:<br /> 4610 * "onKeyPress"<br /> 4611 * "onMouseDown" 4612 * @see Xinha#firePluginEvent 4613 * @param {Event} ev 4614 */ 4021 4615 Xinha.prototype._editorEvent = function(ev) 4022 4616 { … … 4065 4659 }; 4066 4660 4067 // handles ctrl + key shortcuts 4661 /** Handles ctrl + key shortcuts 4662 * @TODO: make this mor flexible 4663 * @private 4664 * @param {Event} ev 4665 */ 4068 4666 Xinha.prototype._shortCuts = function (ev) 4069 4667 { … … 4111 4709 } 4112 4710 }; 4113 4711 /** Changes the type of a given node 4712 * @param {DomNode} el The element to convert 4713 * @param {String} newTagName The type the element will be converted to 4714 * @returns {DomNode} A reference to the new element 4715 */ 4114 4716 Xinha.prototype.convertNode = function(el, newTagName) 4115 4717 { … … 4122 4724 }; 4123 4725 4124 / / moved Xinha.prototype.checkBackspace() to browser specific file4125 // moved Xinha.prototype.dom_checkInsertP() to browser specific file 4126 4726 /** Scrolls the editor iframe to a given element or to the cursor 4727 * @param {DomNode} e optional The element to scroll to; if ommitted, element the element the cursor is in 4728 */ 4127 4729 Xinha.prototype.scrollToElement = function(e) 4128 4730 { … … 4141 4743 * 4142 4744 * @public 4143 * @returns { string} HTML content4745 * @returns {String} HTML content 4144 4746 */ 4145 4747 Xinha.prototype.getEditorContent = function() … … 4148 4750 } 4149 4751 4150 /** Completely change the HTML inside 4752 /** Completely change the HTML inside the editor 4151 4753 * 4152 4754 * @public 4153 * @param { string} html new content4755 * @param {String} html new content 4154 4756 */ 4155 4757 Xinha.prototype.setEditorContent = function(html) … … 4158 4760 } 4159 4761 4160 // retrieve the HTML 4762 /** Get the raw edited HTML, should not be used without Xinha.prototype.outwardHtml() 4763 * 4764 * @private 4765 * @returns {String} HTML content 4766 */ 4161 4767 Xinha.prototype.getHTML = function() 4162 4768 { … … 4184 4790 }; 4185 4791 4792 /** Performs various transformations of the HTML used internally, complement to Xinha.prototype.inwardHtml() 4793 * Plugins can provide their own, additional transformations by defining a plugin.prototype.outwardHtml() implematation, 4794 * which is called by this function 4795 * 4796 * @private 4797 * @see Xinha#inwardHtml 4798 * @param {String} html 4799 * @returns {String} HTML content 4800 */ 4186 4801 Xinha.prototype.outwardHtml = function(html) 4187 4802 { … … 4242 4857 }; 4243 4858 4859 /** Performs various transformations of the HTML to be edited 4860 * Plugins can provide their own, additional transformations by defining a plugin.prototype.inwardHtml() implematation, 4861 * which is called by this function 4862 * 4863 * @private 4864 * @see Xinha#outwardHtml 4865 * @param {String} html 4866 * @returns {String} transformed HTML 4867 */ 4244 4868 Xinha.prototype.inwardHtml = function(html) 4245 4869 { … … 4282 4906 return html; 4283 4907 }; 4284 4908 /** Apply the replacements defined in Xinha.Config.specialReplacements 4909 * 4910 * @private 4911 * @see Xinha#inwardSpecialReplacements 4912 * @param {String} html 4913 * @returns {String} transformed HTML 4914 */ 4285 4915 Xinha.prototype.outwardSpecialReplacements = function(html) 4286 4916 { … … 4295 4925 } 4296 4926 // alert('out : ' + from + '=>' + to); 4297 var reg = new RegExp( from.replace(Xinha.RE_Specials, '\\$1'), 'g');4927 var reg = new RegExp(Xinha.escapeStringForRegExp(from), 'g'); 4298 4928 html = html.replace(reg, to.replace(/\$/g, '$$$$')); 4299 4929 //html = html.replace(from, to); … … 4301 4931 return html; 4302 4932 }; 4303 4933 /** Apply the replacements defined in Xinha.Config.specialReplacements 4934 * 4935 * @private 4936 * @see Xinha#outwardSpecialReplacements 4937 * @param {String} html 4938 * @returns {String} transformed HTML 4939 */ 4304 4940 Xinha.prototype.inwardSpecialReplacements = function(html) 4305 4941 { … … 4318 4954 // html = html.replace(reg, to); 4319 4955 // html = html.replace(from, to); 4320 var reg = new RegExp( from.replace(Xinha.RE_Specials, '\\$1'), 'g');4956 var reg = new RegExp(Xinha.escapeStringForRegExp(from), 'g'); 4321 4957 html = html.replace(reg, to.replace(/\$/g, '$$$$')); // IE uses doubled dollar signs to escape backrefs, also beware that IE also implements $& $_ and $' like perl. 4322 4958 } 4323 4959 return html; 4324 4960 }; 4325 4961 /** Transforms the paths in src & href attributes 4962 * 4963 * @private 4964 * @see Xinha.Config#expandRelativeUrl 4965 * @see Xinha.Config#stripSelfNamedAnchors 4966 * @see Xinha.Config#stripBaseHref 4967 * @see Xinha.Config#baseHref 4968 * @param {String} html 4969 * @returns {String} transformed HTML 4970 */ 4326 4971 Xinha.prototype.fixRelativeLinks = function(html) 4327 4972 { … … 4341 4986 base_m = b.match( relPath ); 4342 4987 absPath = url[2].replace(/(\.\.\/)*/,base_m[1]); 4343 html = html.replace( new RegExp( url[2].replace( Xinha.RE_Specials, '\\$1' )),absPath );4988 html = html.replace( new RegExp(Xinha.escapeStringForRegExp(url[2])),absPath ); 4344 4989 } 4345 4990 } … … 4348 4993 if ( typeof this.config.stripSelfNamedAnchors != 'undefined' && this.config.stripSelfNamedAnchors ) 4349 4994 { 4350 var stripRe = new RegExp( document.location.href.replace(/&/g,'&').replace(Xinha.RE_Specials, '\\$1') + '(#[^\'" ]*)', 'g');4995 var stripRe = new RegExp(Xinha.escapeStringForRegExp(document.location.href.replace(/&/g,'&')) + '(#[^\'" ]*)', 'g'); 4351 4996 html = html.replace(stripRe, '$1'); 4352 4997 } … … 4357 5002 if ( typeof this.config.baseHref != 'undefined' && this.config.baseHref !== null ) 4358 5003 { 4359 baseRe = new RegExp( "((href|src|background)=\")(" + this.config.baseHref.replace( Xinha.RE_Specials, '\\$1') + ")", 'g' );5004 baseRe = new RegExp( "((href|src|background)=\")(" + Xinha.escapeStringForRegExp(this.config.baseHref) + ")", 'g' ); 4360 5005 } 4361 5006 else 4362 5007 { 4363 baseRe = new RegExp( "((href|src|background)=\")(" + document.location.href.replace( /^(https?:\/\/[^\/]*)(.*)/, '$1' ).replace( Xinha.RE_Specials, '\\$1') + ")", 'g' );5008 baseRe = new RegExp( "((href|src|background)=\")(" + Xinha.escapeStringForRegExp(document.location.href.replace( /^(https?:\/\/[^\/]*)(.*)/, '$1' )) + ")", 'g' ); 4364 5009 } 4365 5010 … … 4370 5015 }; 4371 5016 4372 // retrieve the HTML (fastest version, but uses innerHTML) 5017 /** retrieve the HTML (fastest version, but uses innerHTML) 5018 * 5019 * @private 5020 * @returns {String} HTML content 5021 */ 4373 5022 Xinha.prototype.getInnerHTML = function() 4374 5023 { … … 4402 5051 }; 4403 5052 4404 // completely change the HTML inside 5053 /** Completely change the HTML inside 5054 * 5055 * @private 5056 * @param {String} html new content, should have been run through inwardHtml() first 5057 */ 4405 5058 Xinha.prototype.setHTML = function(html) 4406 5059 { … … 4416 5069 }; 4417 5070 4418 // sets the given doctype (useful when config.fullPage is true) 5071 /** sets the given doctype (useful only when config.fullPage is true) 5072 * 5073 * @private 5074 * @param {String} doctype 5075 */ 4419 5076 Xinha.prototype.setDoctype = function(doctype) 4420 5077 { … … 4426 5083 ***************************************************/ 4427 5084 4428 // variable used to pass the object to the popup editor window. 5085 /** Variable used to pass the object to the popup editor window. 5086 * @FIXME: Is this in use? 5087 * @deprecated 5088 * @private 5089 * @type {Object} 5090 */ 4429 5091 Xinha._object = null; 4430 5092 4431 // function that returns a clone of the given object 5093 /** function that returns a clone of the given object 5094 * 5095 * @private 5096 * @param {Object} obj 5097 * @returns {Object} cloned object 5098 */ 4432 5099 Xinha.cloneObject = function(obj) 4433 5100 { … … 4468 5135 return newObj; 4469 5136 }; 4470 4471 // selection & ranges4472 4473 // moved Xinha.prototype._getSelection() to browser specific file4474 // moved Xinha.prototype._createRange() to browser specific file4475 4476 // event handling4477 5137 4478 5138 /** Event Flushing … … 4481 5141 * onunload, it will remove any event listeners (that were added 4482 5142 * through _addEvent(s)) and clear any DOM-0 events. 4483 */ 4484 Xinha._eventFlushers = []; 5143 * @private 5144 * 5145 */ 4485 5146 Xinha.flushEvents = function() 4486 5147 { … … 4532 5193 // alert('Flushed ' + x + ' events.'); 4533 5194 }; 5195 /** Holds the events to be flushed 5196 * @type Array 5197 */ 5198 Xinha._eventFlushers = []; 4534 5199 4535 5200 if ( document.addEventListener ) 4536 5201 { 5202 /** adds an event listener for the specified element and event type 5203 * 5204 * @public 5205 * @see Xinha#_addEvents 5206 * @see Xinha#addDom0Event 5207 * @see Xinha#prependDom0Event 5208 * @param {DomNode} el the DOM element the event should be attached to 5209 * @param {String} evname the name of the event to listen for (without leading "on") 5210 * @param {function} func the function to be called when the event is fired 5211 */ 4537 5212 Xinha._addEvent = function(el, evname, func) 4538 5213 { … … 4540 5215 Xinha._eventFlushers.push([el, evname, func]); 4541 5216 }; 5217 5218 /** removes an event listener previously added 5219 * 5220 * @public 5221 * @see Xinha#_removeEvents 5222 * @param {DomNode} el the DOM element the event should be removed from 5223 * @param {String} evname the name of the event the listener should be removed from (without leading "on") 5224 * @param {function} func the function to be removed 5225 */ 4542 5226 Xinha._removeEvent = function(el, evname, func) 4543 5227 { 4544 5228 el.removeEventListener(evname, func, true); 4545 5229 }; 5230 5231 /** stops bubbling of the event, if no further listeners should be triggered 5232 * 5233 * @public 5234 * @param {event} ev the event to be stopped 5235 */ 4546 5236 Xinha._stopEvent = function(ev) 4547 5237 { … … 4550 5240 }; 4551 5241 } 5242 /** same as above, for IE 5243 * 5244 */ 4552 5245 else if ( document.attachEvent ) 4553 5246 { … … 4591 5284 }; 4592 5285 } 4593 5286 /** add several events at once to one element 5287 * 5288 * @public 5289 * @see Xinha#_addEvent 5290 * @param {DomNode} el the DOM element the event should be attached to 5291 * @param {Array} evs the names of the event to listen for (without leading "on") 5292 * @param {function} func the function to be called when the event is fired 5293 */ 4594 5294 Xinha._addEvents = function(el, evs, func) 4595 5295 { … … 4599 5299 } 4600 5300 }; 4601 5301 /** remove several events at once to from element 5302 * 5303 * @public 5304 * @see Xinha#_removeEvent 5305 * @param {DomNode} el the DOM element the events should be remove from 5306 * @param {Array} evs the names of the events the listener should be removed from (without leading "on") 5307 * @param {function} func the function to be removed 5308 */ 4602 5309 Xinha._removeEvents = function(el, evs, func) 4603 5310 { … … 4621 5328 * whether subsequent handlers will be triggered (ie that the event will 4622 5329 * continue or be canceled). 4623 * 5330 * 5331 * @public 5332 * @see Xinha#_addEvent 5333 * @see Xinha#prependDom0Event 5334 * @param {DomNode} el the DOM element the event should be attached to 5335 * @param {String} ev the name of the event to listen for (without leading "on") 5336 * @param {function} fn the function to be called when the event is fired 4624 5337 */ 4625 5338 … … 4631 5344 4632 5345 4633 /** 4634 * See addDom0Event, the difference is that handlers registered using 4635 * prependDom0Event will be triggered before existing DOM-0 events of the 4636 * same name on the same element. 5346 /** See addDom0Event, the difference is that handlers registered using 5347 * prependDom0Event will be triggered before existing DOM-0 events of the 5348 * same name on the same element. 5349 * 5350 * @public 5351 * @see Xinha#_addEvent 5352 * @see Xinha#addDom0Event 5353 * @param {DomNode} the DOM element the event should be attached to 5354 * @param {String} the name of the event to listen for (without leading "on") 5355 * @param {function} the function to be called when the event is fired 4637 5356 */ 4638 5357 … … 4646 5365 * Prepares an element to receive more than one DOM-0 event handler 4647 5366 * when handlers are added via addDom0Event and prependDom0Event. 5367 * 5368 * @private 4648 5369 */ 4649 5370 Xinha._prepareForDom0Events = function(el, ev) … … 4713 5434 }; 4714 5435 4715 Xinha._removeClass = function(el, className) 4716 { 4717 if ( ! ( el && el.className ) ) 4718 { 4719 return; 4720 } 4721 var cls = el.className.split(" "); 4722 var ar = []; 4723 for ( var i = cls.length; i > 0; ) 4724 { 4725 if ( cls[--i] != className ) 4726 { 4727 ar[ar.length] = cls[i]; 4728 } 4729 } 4730 el.className = ar.join(" "); 4731 }; 4732 4733 Xinha._addClass = function(el, className) 4734 { 4735 // remove the class first, if already there 4736 Xinha._removeClass(el, className); 4737 el.className += " " + className; 4738 }; 4739 4740 Xinha._hasClass = function(el, className) 4741 { 4742 if ( ! ( el && el.className ) ) 4743 { 4744 return false; 4745 } 4746 var cls = el.className.split(" "); 4747 for ( var i = cls.length; i > 0; ) 4748 { 4749 if ( cls[--i] == className ) 4750 { 4751 return true; 4752 } 4753 } 4754 return false; 4755 }; 4756 5436 /** List of tag names that are defined as block level elements in HTML 5437 * 5438 * @private 5439 * @see Xinha#isBlockElement 5440 * @type {String} 5441 */ 4757 5442 Xinha._blockTags = " body form textarea fieldset ul ol dl li div " + 4758 5443 "p h1 h2 h3 h4 h5 h6 quote pre table thead " + 4759 5444 "tbody tfoot tr td th iframe address blockquote "; 5445 5446 /** Checks if one element is in the list of elements that are defined as block level elements in HTML 5447 * 5448 * @param {DomNode} el The DOM element to check 5449 * @returns {Boolean} 5450 */ 4760 5451 Xinha.isBlockElement = function(el) 4761 5452 { 4762 5453 return el && el.nodeType == 1 && (Xinha._blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); 4763 5454 }; 4764 5455 /** List of tag names that are allowed to contain a paragraph 5456 * 5457 * @private 5458 * @see Xinha#isParaContainer 5459 * @type {String} 5460 */ 4765 5461 Xinha._paraContainerTags = " body td th caption fieldset div"; 5462 /** Checks if one element is in the list of elements that are allowed to contain a paragraph in HTML 5463 * 5464 * @param {DomNode} el The DOM element to check 5465 * @returns {Boolean} 5466 */ 4766 5467 Xinha.isParaContainer = function(el) 4767 5468 { … … 4769 5470 }; 4770 5471 4771 // These are all the tags for which the end tag is not optional or 4772 // forbidden, taken from the list at: 4773 // http://www.w3.org/TR/REC-html40/index/elements.html 5472 5473 /* * These are all the tags for which the end tag is not optional or forbidden, taken from the list at: 5474 * http: www.w3.org/TR/REC-html40/index/elements.html 5475 * 5476 * @private 5477 * @see Xinha#needsClosingTag 5478 * @type {String} 5479 */ 4774 5480 Xinha._closingTags = " a abbr acronym address applet b bdo big blockquote button caption center cite code del dfn dir div dl em fieldset font form frameset h1 h2 h3 h4 h5 h6 i iframe ins kbd label legend map menu noframes noscript object ol optgroup pre q s samp script select small span strike strong style sub sup table textarea title tt u ul var "; 4775 5481 5482 /** Checks if one element is in the list of elements for which the end tag is not optional or forbidden in HTML 5483 * 5484 * @param {DomNode} el The DOM element to check 5485 * @returns {Boolean} 5486 */ 4776 5487 Xinha.needsClosingTag = function(el) 4777 5488 { … … 4779 5490 }; 4780 5491 4781 // performs HTML encoding of some given string 5492 /** Performs HTML encoding of some given string (converts HTML special characters to entities) 5493 * 5494 * @param {String} str The unencoded input 5495 * @returns {String} The encoded output 5496 */ 4782 5497 Xinha.htmlEncode = function(str) 4783 5498 { … … 4797 5512 }; 4798 5513 4799 // moved Xinha.getHTML() to getHTML.js 5514 /** Strips host-part of URL which is added by browsers to links relative to server root 5515 * 5516 * @param {String} string 5517 * @returns {String} 5518 */ 4800 5519 Xinha.prototype.stripBaseURL = function(string) 4801 5520 { … … 4804 5523 return string; 4805 5524 } 4806 // strip host-part of URL which is added by MSIE to links relative to server root4807 5525 var baseurl = this.config.baseHref.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1'); 4808 5526 var basere = new RegExp(baseurl); 4809 5527 return string.replace(basere, ""); 4810 5528 }; 4811 5529 /** Removes whitespace from beginning and end of a string 5530 * 5531 * @returns {String} 5532 */ 4812 5533 String.prototype.trim = function() 4813 5534 { … … 4815 5536 }; 4816 5537 4817 // creates a rgb-style color from a number 5538 /** Creates a rgb-style rgb(r,g,b) color from a (24bit) number 5539 * 5540 * @param {Integer} 5541 * @returns {String} rgb(r,g,b) color definition 5542 */ 4818 5543 Xinha._makeColor = function(v) 4819 5544 { … … 4830 5555 }; 4831 5556 4832 // returns hexadecimal color representation from a number or a rgb-style color. 5557 /** Returns hexadecimal color representation from a number or a rgb-style color. 5558 * 5559 * @param {String|Integer} v rgb(r,g,b) or 24bit color definition 5560 * @returns {String} #RRGGBB color definition 5561 */ 4833 5562 Xinha._colorToRgb = function(v) 4834 5563 { … … 4880 5609 }; 4881 5610 4882 // modal dialogs for Mozilla (for IE we're using the showModalDialog() call). 4883 4884 // receives an URL to the popup dialog and a function that receives one value; 4885 // this function will get called after the dialog is closed, with the return 4886 // value of the dialog. 5611 /** Modal popup dialogs 5612 * 5613 * @param {String} url URL to the popup dialog 5614 * @param {Function} action A function that receives one value; this function will get called 5615 * after the dialog is closed, with the return value of the dialog. 5616 * @param {Mixed} init A variable that is passed to the popup window to pass arbitrary data 5617 */ 4887 5618 Xinha.prototype._popupDialog = function(url, action, init) 4888 5619 { … … 4890 5621 }; 4891 5622 4892 // paths 4893 5623 /** Creates a path in the form _editor_url + "plugins/" + plugin + "/img/" + file 5624 * 5625 * @deprecated 5626 * @param {String} file Name of the image 5627 * @param {String} plugin optional If omitted, simply _editor_url + file is returned 5628 * @returns {String} 5629 */ 4894 5630 Xinha.prototype.imgURL = function(file, plugin) 4895 5631 { … … 4903 5639 } 4904 5640 }; 4905 5641 /** Creates a path 5642 * 5643 * @deprecated 5644 * @param {String} file Name of the popup 5645 * @returns {String} 5646 */ 4906 5647 Xinha.prototype.popupURL = function(file) 4907 5648 { … … 4928 5669 }; 4929 5670 4930 /** 4931 * FIX: Internet Explorer returns an item having the _name_ equal to the given 5671 /** FIX: Internet Explorer returns an item having the _name_ equal to the given 4932 5672 * id, even if it's not having any id. This way it can return a different form 4933 * field even if it's not a textarea. This workarounds the problem by5673 * field, even if it's not a textarea. This workarounds the problem by 4934 5674 * specifically looking to search only elements having a certain tag name. 5675 * @param {String} tag The tag name to limit the return to 5676 * @param {String} id 5677 * @returns {DomNode} 4935 5678 */ 4936 5679 Xinha.getElementById = function(tag, id) … … 4948 5691 4949 5692 4950 /** Use some CSS trickery to toggle borders on tables */ 5693 /** Use some CSS trickery to toggle borders on tables 5694 * @returns {Boolean} always true 5695 */ 4951 5696 4952 5697 Xinha.prototype._toggleBorders = function() … … 4978 5723 return true; 4979 5724 }; 4980 5725 /** Adds styles for internal use to the edited document 5726 * 5727 * @private 5728 * @see Xinha#stripCoreCSS 5729 * @param {String} html optional 5730 * @returns {String} html HTML with added styles or only styles if html omitted 5731 */ 4981 5732 Xinha.addCoreCSS = function(html) 4982 5733 { … … 5001 5752 } 5002 5753 } 5003 5754 /** Remove internal styles 5755 * 5756 * @private 5757 * @see Xinha#addCoreCSS 5758 * @param {String} html 5759 * @returns {String} 5760 */ 5004 5761 Xinha.stripCoreCSS = function(html) 5005 5762 { 5006 5763 return html.replace(/<style[^>]+title="Xinha Internal CSS"(.|\n)*?<\/style>/i, ''); 5007 5764 } 5008 5765 /** Removes one CSS class (that is one of possible more parts 5766 * separated by spaces) from a given element 5767 * 5768 * @see Xinha#_removeClasses 5769 * @param {DomNode} el The DOM element the class will be removed from 5770 * @param {String} className The class to be removed 5771 */ 5772 Xinha._removeClass = function(el, className) 5773 { 5774 if ( ! ( el && el.className ) ) 5775 { 5776 return; 5777 } 5778 var cls = el.className.split(" "); 5779 var ar = []; 5780 for ( var i = cls.length; i > 0; ) 5781 { 5782 if ( cls[--i] != className ) 5783 { 5784 ar[ar.length] = cls[i]; 5785 } 5786 } 5787 el.className = ar.join(" "); 5788 }; 5789 /** Adds one CSS class to a given element (that is, it expands its className property by the given string, 5790 * separated by a space) 5791 * 5792 * @see Xinha#addClasses 5793 * @param {DomNode} el The DOM element the class will be added to 5794 * @param {String} className The class to be added 5795 */ 5796 Xinha._addClass = function(el, className) 5797 { 5798 // remove the class first, if already there 5799 Xinha._removeClass(el, className); 5800 el.className += " " + className; 5801 }; 5802 5803 /** Adds CSS classes to a given element (that is, it expands its className property by the given string, 5804 * separated by a space, thereby checking that no class is doubly added) 5805 * 5806 * @see Xinha#addClass 5807 * @param {DomNode} el The DOM element the classes will be added to 5808 * @param {String} classes The classes to be added 5809 */ 5009 5810 Xinha.addClasses = function(el, classes) 5010 5811 { … … 5032 5833 }; 5033 5834 5835 /** Removes CSS classes (that is one or more of possibly several parts 5836 * separated by spaces) from a given element 5837 * 5838 * @see Xinha#_removeClasses 5839 * @param {DomNode} el The DOM element the class will be removed from 5840 * @param {String} className The class to be removed 5841 */ 5034 5842 Xinha.removeClasses = function(el, classes) 5035 5843 { … … 5056 5864 }; 5057 5865 5058 /** Alias these for convenience */ 5866 /** Alias of Xinha._addClass() 5867 * @see Xinha#_addClass 5868 */ 5059 5869 Xinha.addClass = Xinha._addClass; 5870 /** Alias of Xinha.Xinha._removeClass() 5871 * @see Xinha#_removeClass 5872 */ 5060 5873 Xinha.removeClass = Xinha._removeClass; 5874 /** Alias of Xinha.addClasses() 5875 * @see Xinha#addClasses 5876 */ 5061 5877 Xinha._addClasses = Xinha.addClasses; 5878 /** Alias of Xinha.removeClasses() 5879 * @see Xinha#removeClasses 5880 */ 5062 5881 Xinha._removeClasses = Xinha.removeClasses; 5063 5882 5064 /** Use XML HTTPRequest to post some data back to the server and do something 5065 * with the response (asyncronously!), this is used by such things as the tidy functions 5883 /** Checks if one element has set the given className 5884 * 5885 * @param {DomNode} el The DOM element to check 5886 * @param {String} className The class to be looked for 5887 * @returns {Boolean} 5888 */ 5889 Xinha._hasClass = function(el, className) 5890 { 5891 if ( ! ( el && el.className ) ) 5892 { 5893 return false; 5894 } 5895 var cls = el.className.split(" "); 5896 for ( var i = cls.length; i > 0; ) 5897 { 5898 if ( cls[--i] == className ) 5899 { 5900 return true; 5901 } 5902 } 5903 return false; 5904 }; 5905 5906 /** Use XMLHTTPRequest to post some data back to the server and do something 5907 * with the response (asyncronously!), this is used by such things as the tidy functions 5908 * @param {String} url The address for the HTTPRequest 5909 * @param {Object} data The data to be passed to the server like {name:"value"} 5910 * @param {Function} handler A function that is called when an answer is received from the server with the responseText 5911 * as argument 5066 5912 */ 5067 5913 Xinha._postback = function(url, data, handler) … … 5109 5955 }; 5110 5956 5957 /** Use XMLHTTPRequest to receive some data from the server and do something 5958 * with the it (asyncronously!) 5959 * @param {String} url The address for the HTTPRequest 5960 * @param {Function} handler A function that is called when an answer is received from the server with the responseText 5961 * as argument 5962 */ 5111 5963 Xinha._getback = function(url, handler) 5112 5964 { … … 5133 5985 req.send(null); 5134 5986 }; 5135 5987 /** Use XMLHTTPRequest to receive some data from the server syncronously 5988 * @param {String} url The address for the HTTPRequest 5989 */ 5136 5990 Xinha._geturlcontent = function(url) 5137 5991 { … … 5153 6007 }; 5154 6008 5155 /** 5156 * Unless somebody already has, make a little function to debug things 5157 */ 6009 // Unless somebody already has, make a little function to debug things 6010 5158 6011 if ( typeof dump == 'undefined' ) 5159 6012 { … … 5169 6022 } 5170 6023 } 5171 6024 if ( !Array.prototype.contains ) 6025 { 6026 /** Walks through an array and checks if the specified item exists in it 6027 * @param {String} needle The string to search for 6028 * @returns {Boolean} True if item found, false otherwise 6029 */ 6030 Array.prototype.contains = function(needle) 6031 { 6032 var haystack = this; 6033 for ( var i = 0; i < haystack.length; i++ ) 6034 { 6035 if ( needle == haystack[i] ) 6036 { 6037 return true; 6038 } 6039 } 6040 return false; 6041 }; 6042 } 6043 6044 if ( !Array.prototype.indexOf ) 6045 { 6046 /** Walks through an array and, if the specified item exists in it, returns the position 6047 * @param {String} needle The string to search for 6048 * @returns {Integer|null} Index position if item found, null otherwise 6049 */ 6050 Array.prototype.indexOf = function(needle) 6051 { 6052 var haystack = this; 6053 for ( var i = 0; i < haystack.length; i++ ) 6054 { 6055 if ( needle == haystack[i] ) 6056 { 6057 return i; 6058 } 6059 } 6060 return null; 6061 }; 6062 } 6063 if ( !Array.prototype.append ) 6064 { 6065 /** Adds an item to an array 6066 * @param {Mixed} a Item to add 6067 * @returns {Array} The array including the newly added item 6068 */ 6069 Array.prototype.append = function(a) 6070 { 6071 for ( var i = 0; i < a.length; i++ ) 6072 { 6073 this.push(a[i]); 6074 } 6075 return this; 6076 }; 6077 } 6078 /** Returns true if all elements of <em>a2</em> are also contained in <em>a1</em> (at least I think this is what it does) 6079 * @param {Array} a1 6080 * @param {Array} a2 6081 * @returns {Boolean} 6082 */ 5172 6083 Xinha.arrayContainsArray = function(a1, a2) 5173 6084 { … … 5192 6103 return all_found; 5193 6104 }; 5194 6105 /** Walks through an array and applies a filter function to each item 6106 * @param {Array} a1 The array to filter 6107 * @param {Function} filterfn If this function returns true, the item is added to the new array 6108 * @returns {Array} Filtered array 6109 */ 5195 6110 Xinha.arrayFilter = function(a1, filterfn) 5196 6111 { … … 5205 6120 return new_a; 5206 6121 }; 5207 6122 /** Converts a Collection object to an array 6123 * @param {Collection} collection The array to filter 6124 * @returns {Array} Array containing the item of collection 6125 */ 6126 Xinha.collectionToArray = function(collection) 6127 { 6128 var array = [ ]; 6129 for ( var i = 0; i < collection.length; i++ ) 6130 { 6131 array.push(collection.item(i)); 6132 } 6133 return array; 6134 }; 6135 6136 /** Index for Xinha.uniq function 6137 * @private 6138 */ 5208 6139 Xinha.uniq_count = 0; 6140 /** Returns a string that is unique on the page 6141 * @param {String} prefix This string is prefixed to a running number 6142 * @returns {String} 6143 */ 5209 6144 Xinha.uniq = function(prefix) 5210 6145 { … … 5212 6147 }; 5213 6148 5214 /** New language handling functions **/ 5215 6149 // New language handling functions 5216 6150 5217 6151 /** Load a language file. 5218 6152 * This function should not be used directly, Xinha._lc will use it when necessary. 5219 * @param context Case sensitive context name, eg 'Xinha', 'TableOperations', ... 6153 * @private 6154 * @param {String} context Case sensitive context name, eg 'Xinha', 'TableOperations', ... 6155 * @returns {Object} 5220 6156 */ 5221 6157 Xinha._loadlang = function(context,url) … … 5266 6202 5267 6203 /** Return a localised string. 5268 * @param stringEnglish language string. It can also contain variables in the form "Some text with $variable=replaced text$".6204 * @param {String} string English language string. It can also contain variables in the form "Some text with $variable=replaced text$". 5269 6205 * This replaces $variable in "Some text with $variable" with "replaced text" 5270 * @param context Case sensitive context name, eg 'Xinha' (default), 'TableOperations'...5271 * @param replace Replace $variables in String, eg {foo: 'replaceText'} ($foo in string will be replaced)6206 * @param {String} context Case sensitive context name, eg 'Xinha' (default), 'TableOperations'... 6207 * @param {Object} replace Replace $variables in String, eg {foo: 'replaceText'} ($foo in string will be replaced by replaceText) 5272 6208 */ 5273 6209 Xinha._lc = function(string, context, replace) … … 5374 6310 return ret; 5375 6311 }; 5376 6312 /** Walks through the children of a given element and checks if any of the are visible (= not display:none) 6313 * @param {DomNode} el 6314 * @returns {Boolean} 6315 */ 5377 6316 Xinha.hasDisplayedChildren = function(el) 5378 6317 { … … 5391 6330 }; 5392 6331 5393 /** 5394 * Load a javascript file by inserting it in the HEAD tag and eventually call a function when loaded 6332 /** Load a javascript file by inserting it in the HEAD tag and eventually call a function when loaded 5395 6333 * 5396 * Note that this method cannot be abstracted into browser specific files6334 * Note that this method cannot be abstracted into browser specific files 5397 6335 * because this method LOADS the browser specific files. Hopefully it should work for most 5398 6336 * browsers as it is. 5399 6337 * 5400 * @param {string} U (Url) Source url of the file to load 5401 * @param {object} C {Callback} Callback function to launch once ready (optional) 5402 * @param {object} O (scOpe) Application scope for the callback function (optional) 5403 * @param {object} B (Bonus} Arbitrary object send as a param to the callback function (optional) 5404 * @public 5405 * 5406 */ 5407 6338 * @param {String} url Source url of the file to load 6339 * @param {Object} callback optional Callback function to launch once ready 6340 * @param {Object} scope optional Application scope for the callback function 6341 * @param {Object} bonus optional Arbitrary object send as a param to the callback function 6342 */ 5408 6343 Xinha._loadback = function(url, callback, scope, bonus) 5409 6344 { … … 5434 6369 }; 5435 6370 5436 Xinha.collectionToArray = function(collection) 5437 { 5438 var array = [ ]; 5439 for ( var i = 0; i < collection.length; i++ ) 5440 { 5441 array.push(collection.item(i)); 5442 } 5443 return array; 5444 }; 5445 5446 if ( !Array.prototype.append ) 5447 { 5448 Array.prototype.append = function(a) 5449 { 5450 for ( var i = 0; i < a.length; i++ ) 5451 { 5452 this.push(a[i]); 5453 } 5454 return this; 5455 }; 5456 } 5457 6371 /** Xinha's main loading function (see NewbieGuide) 6372 * @param {Array} editor_names 6373 * @param {Xinha.Config} default_config 6374 * @param {Array} plugin_names 6375 * @returns {Object} An object that contains references to all created editors indexed by the IDs of the textareas 6376 */ 5458 6377 Xinha.makeEditors = function(editor_names, default_config, plugin_names) 5459 6378 { … … 5479 6398 return editors; 5480 6399 }; 5481 6400 /** Another main loading function (see NewbieGuide) 6401 * @param {Object} editors As returned by Xinha.makeEditors() 6402 */ 5482 6403 Xinha.startEditors = function(editors) 5483 6404 { … … 5492 6413 } 5493 6414 }; 5494 6415 /** Registers the loaded plugins with the editor 6416 * @private 6417 * @param {Array} plugin_names 6418 */ 5495 6419 Xinha.prototype.registerPlugins = function(plugin_names) 5496 6420 { … … 5507 6431 }; 5508 6432 5509 /** Utility function to base64_encode some arbitrary data, uses the builtin btoa() if it exists (Moz) */ 5510 6433 /** Utility function to base64_encode some arbitrary data, uses the builtin btoa() if it exists (Moz) 6434 * @param {String} input 6435 * @returns {String} 6436 */ 5511 6437 Xinha.base64_encode = function(input) 5512 6438 { … … 5543 6469 }; 5544 6470 5545 /** Utility function to base64_decode some arbitrary data, uses the builtin atob() if it exists (Moz) */ 5546 6471 /** Utility function to base64_decode some arbitrary data, uses the builtin atob() if it exists (Moz) 6472 * @param {String} input 6473 * @returns {String} 6474 */ 5547 6475 Xinha.base64_decode = function(input) 5548 6476 { … … 5581 6509 return output; 5582 6510 }; 5583 6511 /** Removes a node from the DOM 6512 * @param {DomNode} el The element to be removed 6513 * @returns {DomNode} The removed element 6514 */ 5584 6515 Xinha.removeFromParent = function(el) 5585 6516 { … … 5592 6523 return el; 5593 6524 }; 5594 6525 /** Checks if some element has a parent node 6526 * @param {DomNode} el 6527 * @returns {Boolean} 6528 */ 5595 6529 Xinha.hasParentNode = function(el) 5596 6530 { … … 5609 6543 }; 5610 6544 5611 / / moved Xinha.getOuterHTML() to browser specific file5612 5613 // detect the size of visible area 5614 // when calling from a popup window, call Xinha.viewportSize(window) to get the size of the popup 6545 /** Detect the size of visible area 6546 * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup 6547 * @returns {Object} Object with Integer properties x and y 6548 */ 5615 6549 Xinha.viewportSize = function(scope) 5616 6550 { … … 5635 6569 return {'x':x,'y':y}; 5636 6570 }; 5637 6571 /** Detect the size of the whole document 6572 * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup 6573 * @returns {Object} Object with Integer properties x and y 6574 */ 5638 6575 Xinha.pageSize = function(scope) 5639 6576 { … … 5656 6593 return {'x':x,'y':y}; 5657 6594 }; 5658 6595 /** Detect the current scroll position 6596 * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup 6597 * @returns {Object} Object with Integer properties x and y 6598 */ 5659 6599 Xinha.prototype.scrollPos = function(scope) 5660 6600 { … … 5680 6620 }; 5681 6621 5682 /** 5683 * Calculate the top and left pixel position of an element in the DOM. 5684 * 5685 * @param element HTML Element DOM Node 5686 * @returns Object with integer properties top and left 6622 /** Calculate the top and left pixel position of an element in the DOM. 6623 * @param {DomNode} element HTML Element 6624 * @returns {Object} Object with Integer properties top and left 5687 6625 */ 5688 6626 … … 5702 6640 return { top:curtop, left:curleft }; 5703 6641 } 5704 5705 // find X position of an element 6642 /** Find left pixel position of an element in the DOM. 6643 * @param {DomNode} element HTML Element 6644 * @returns {Integer} 6645 */ 5706 6646 Xinha.findPosX = function(obj) 5707 6647 { … … 5717 6657 return curleft; 5718 6658 }; 5719 5720 // find Y position of an element 6659 /** Find top pixel position of an element in the DOM. 6660 * @param {DomNode} element HTML Element 6661 * @returns {Integer} 6662 */ 5721 6663 Xinha.findPosY = function(obj) 5722 6664 { … … 5822 6764 }; 5823 6765 6766 /** List of objects that have to be trated on page unload in order to work around the broken 6767 * Garbage Collector in IE 6768 * @private 6769 * @see Xinha#freeLater 6770 * @see Xinha#free 6771 * @see Xinha#collectGarbageForIE 6772 */ 5824 6773 Xinha.toFree = []; 6774 /** Adds objects to Xinha.toFree 6775 * @param {Object} object The object to free memory 6776 * @param (String} prop optional The property to release 6777 * @private 6778 * @see Xinha#toFree 6779 * @see Xinha#free 6780 * @see Xinha#collectGarbageForIE 6781 */ 5825 6782 Xinha.freeLater = function(obj,prop) 5826 6783 { … … 5828 6785 }; 5829 6786 5830 /** 5831 * Release memory properties from object 5832 * @param {object} object The object to free memory 5833 * @param (string} prop The property to release (optional) 6787 /** Release memory properties from object 6788 * @param {Object} object The object to free memory 6789 * @param (String} prop optional The property to release 5834 6790 * @private 6791 * @see Xinha#collectGarbageForIE 6792 * @see Xinha#free 5835 6793 */ 5836 6794 Xinha.free = function(obj, prop) … … 5850 6808 5851 6809 /** IE's Garbage Collector is broken very badly. We will do our best to 5852 * do it's job for it, but we can't be perfect. 6810 * do it's job for it, but we can't be perfect. Takes all objects from Xinha.free and releases sets the null 6811 * @private 6812 * @see Xinha#toFree 6813 * @see Xinha#free 5853 6814 */ 5854 6815 … … 5869 6830 5870 6831 /** Insert a node at the current selection point. 5871 * @param toBeInserted DomNode6832 * @param {DomNode} toBeInserted 5872 6833 */ 5873 6834 … … 5875 6836 5876 6837 /** Get the parent element of the supplied or current selection. 5877 * @param sel optional selection as returned by getSelection5878 * @returns DomNode6838 * @param {Selection} sel optional selection as returned by getSelection 6839 * @returns {DomNode} 5879 6840 */ 5880 6841 … … 5886 6847 * at the bottom of the editor, or a "control" (eg image) 5887 6848 * 5888 * @returns null | DomNode6849 * @returns {DomNode|null} 5889 6850 */ 5890 6851 … … 5893 6854 /** 5894 6855 * Determines if the given selection is empty (collapsed). 5895 * @param selectionSelection object as returned by getSelection5896 * @returns true|false6856 * @param {Selection} sel Selection object as returned by getSelection 6857 * @returns {Boolean} 5897 6858 */ 5898 6859 5899 6860 Xinha.prototype.selectionEmpty = function(sel) { Xinha.notImplemented("selectionEmpty"); } 6861 /** 6862 * Returns a range object to be stored 6863 * and later restored with Xinha.prototype.restoreSelection() 6864 * @returns {Range} 6865 */ 6866 6867 Xinha.prototype.saveSelection = function() { Xinha.notImplemented("saveSelection"); } 6868 6869 /** Restores a selection previously stored 6870 * @param {Range} savedSelection Range object as returned by Xinha.prototype.restoreSelection() 6871 */ 6872 Xinha.prototype.restoreSelection = function(savedSelection) { Xinha.notImplemented("restoreSelection"); } 5900 6873 5901 6874 /** … … 5903 6876 * the node itself is selected for manipulation. 5904 6877 * 5905 * @param node DomNode 5906 * @param pos Set to a numeric position inside the node to collapse the cursor here if possible. 5907 */ 5908 6878 * @param {DomNode} node 6879 * @param {Integer} pos Set to a numeric position inside the node to collapse the cursor here if possible. 6880 */ 5909 6881 Xinha.prototype.selectNodeContents = function(node,pos) { Xinha.notImplemented("selectNodeContents"); } 5910 6882 5911 6883 /** Insert HTML at the current position, deleting the selection if any. 5912 6884 * 5913 * @param html string6885 * @param {String} html 5914 6886 */ 5915 6887 … … 5918 6890 /** Get the HTML of the current selection. HTML returned has not been passed through outwardHTML. 5919 6891 * 5920 * @returns string6892 * @returns {String} 5921 6893 */ 5922 6894 Xinha.prototype.getSelectedHTML = function() { Xinha.notImplemented("getSelectedHTML"); } … … 5924 6896 /** Get a Selection object of the current selection. Note that selection objects are browser specific. 5925 6897 * 5926 * @returns Selection6898 * @returns {Selection} 5927 6899 */ 5928 6900 … … 5930 6902 5931 6903 /** Create a Range object from the given selection. Note that range objects are browser specific. 5932 * 5933 * @param sel Selection object (see getSelection) 5934 * @returns Range 5935 */ 5936 6904 * @see Xinha#getSelection 6905 * @param {Selection} sel Selection object 6906 * @returns {Range} 6907 */ 5937 6908 Xinha.prototype.createRange = function(sel) { Xinha.notImplemented("createRange"); } 5938 6909 5939 6910 /** Determine if the given event object is a keydown/press event. 5940 6911 * 5941 * @param event Event5942 * @returns true|false6912 * @param {Event} event 6913 * @returns {Boolean} 5943 6914 */ 5944 6915 … … 5948 6919 * which for Xinha is a shortcut. Note that CTRL-ALT-<key> is not a shortcut. 5949 6920 * 5950 * @param keyEvent5951 * @returns true|false6921 * @param {Event} keyEvent 6922 * @returns {Boolean} 5952 6923 */ 5953 6924 … … 5965 6936 * this method will return 'a', press SHIFT-a and it will return 'A'. 5966 6937 * 5967 * @param keyEvent5968 * @returns string6938 * @param {Event} keyEvent 6939 * @returns {String} 5969 6940 */ 5970 6941 … … 5973 6944 /** Return the HTML string of the given Element, including the Element. 5974 6945 * 5975 * @param element HTML Element DomNode5976 * @returns string6946 * @param {DomNode} element HTML Element 6947 * @returns {String} 5977 6948 */ 5978 6949 … … 5981 6952 /** Get a new XMLHTTPRequest Object ready to be used. 5982 6953 * 5983 * @returns object XMLHTTPRequest6954 * @returns {XMLHTTPRequest} 5984 6955 */ 5985 6956 … … 6004 6975 6005 6976 // Compatability - all these names are deprecated and will be removed in a future version 6977 /** Alias of activeElement() 6978 * @see Xinha#activeElement 6979 * @deprecated 6980 * @returns {DomNode|null} 6981 */ 6006 6982 Xinha.prototype._activeElement = function(sel) { return this.activeElement(sel); } 6983 /** Alias of selectionEmpty() 6984 * @see Xinha#selectionEmpty 6985 * @deprecated 6986 * @param {Selection} sel Selection object as returned by getSelection 6987 * @returns {Boolean} 6988 */ 6007 6989 Xinha.prototype._selectionEmpty = function(sel) { return this.selectionEmpty(sel); } 6990 /** Alias of getSelection() 6991 * @see Xinha#getSelection 6992 * @deprecated 6993 * @returns {Selection} 6994 */ 6008 6995 Xinha.prototype._getSelection = function() { return this.getSelection(); } 6996 /** Alias of createRange() 6997 * @see Xinha#createRange 6998 * @deprecated 6999 * @param {Selection} sel Selection object 7000 * @returns {Range} 7001 */ 6009 7002 Xinha.prototype._createRange = function(sel) { return this.createRange(sel); } 6010 7003 HTMLArea = Xinha;
