[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('editor-base', function (Y, NAME) { 9 10 11 /** 12 * Base class for Editor. Handles the business logic of Editor, no GUI involved only utility methods and events. 13 * 14 * var editor = new Y.EditorBase({ 15 * content: 'Foo' 16 * }); 17 * editor.render('#demo'); 18 * 19 * @class EditorBase 20 * @extends Base 21 * @module editor 22 * @main editor 23 * @submodule editor-base 24 * @constructor 25 */ 26 27 var Lang = Y.Lang, 28 29 EditorBase = function() { 30 EditorBase.superclass.constructor.apply(this, arguments); 31 }, LAST_CHILD = ':last-child'; 32 33 Y.extend(EditorBase, Y.Base, { 34 /** 35 * Internal reference to the Y.ContentEditable instance 36 * @property frame 37 */ 38 frame: null, 39 40 initializer: function() { 41 this.publish('nodeChange', { 42 emitFacade: true, 43 bubbles: true, 44 defaultFn: this._defNodeChangeFn 45 }); 46 47 //this.plug(Y.Plugin.EditorPara); 48 }, 49 destructor: function() { 50 this.detachAll(); 51 }, 52 /** 53 * Copy certain styles from one node instance to another (used for new paragraph creation mainly) 54 * @method copyStyles 55 * @param {Node} from The Node instance to copy the styles from 56 * @param {Node} to The Node instance to copy the styles to 57 */ 58 copyStyles: function(from, to) { 59 if (from.test('a')) { 60 //Don't carry the A styles 61 return; 62 } 63 var styles = ['color', 'fontSize', 'fontFamily', 'backgroundColor', 'fontStyle' ], 64 newStyles = {}; 65 66 Y.each(styles, function(v) { 67 newStyles[v] = from.getStyle(v); 68 }); 69 if (from.ancestor('b,strong')) { 70 newStyles.fontWeight = 'bold'; 71 } 72 if (from.ancestor('u')) { 73 if (!newStyles.textDecoration) { 74 newStyles.textDecoration = 'underline'; 75 } 76 } 77 to.setStyles(newStyles); 78 }, 79 /** 80 * Holder for the selection bookmark in IE. 81 * @property _lastBookmark 82 * @private 83 */ 84 _lastBookmark: null, 85 /** 86 * Resolves the e.changedNode in the nodeChange event if it comes from the document. If 87 * the event came from the document, it will get the last child of the last child of the document 88 * and return that instead. 89 * @method _resolveChangedNode 90 * @param {Node} n The node to resolve 91 * @private 92 */ 93 _resolveChangedNode: function(n) { 94 var inst = this.getInstance(), lc, lc2, found, root = this._getRoot(), sel; 95 96 if (n && n.compareTo(root)) { 97 sel = new inst.EditorSelection(); 98 if (sel && sel.anchorNode) { 99 n = sel.anchorNode; 100 } 101 } 102 if (inst && n && n.test('html')) { 103 lc = root.one(LAST_CHILD); 104 while (!found) { 105 if (lc) { 106 lc2 = lc.one(LAST_CHILD); 107 if (lc2) { 108 lc = lc2; 109 } else { 110 found = true; 111 } 112 } else { 113 found = true; 114 } 115 } 116 if (lc) { 117 if (lc.test('br')) { 118 if (lc.previous()) { 119 lc = lc.previous(); 120 } else { 121 lc = lc.get('parentNode'); 122 } 123 } 124 if (lc) { 125 n = lc; 126 } 127 } 128 } 129 if (!n) { 130 //Fallback to make sure a node is attached to the event 131 n = root; 132 } 133 return n; 134 }, 135 /** 136 * Resolves the ROOT editor element. 137 * @method _getRoot 138 * @private 139 */ 140 _getRoot: function() { 141 return this.getInstance().EditorSelection.ROOT; 142 }, 143 /** 144 * The default handler for the nodeChange event. 145 * @method _defNodeChangeFn 146 * @param {Event} e The event 147 * @private 148 */ 149 _defNodeChangeFn: function(e) { 150 var startTime = (new Date()).getTime(), 151 inst = this.getInstance(), sel, 152 changed, endTime, 153 cmds = {}, family, fsize, classes = [], 154 fColor = '', bColor = '', bq, 155 normal = false, 156 root = this._getRoot(); 157 158 if (Y.UA.ie && Y.UA.ie < 11) { 159 try { 160 sel = inst.config.doc.selection.createRange(); 161 if (sel.getBookmark) { 162 this._lastBookmark = sel.getBookmark(); 163 } 164 } catch (ie) {} 165 } 166 167 e.changedNode = this._resolveChangedNode(e.changedNode); 168 169 170 /* 171 * @TODO 172 * This whole method needs to be fixed and made more dynamic. 173 * Maybe static functions for the e.changeType and an object bag 174 * to walk through and filter to pass off the event to before firing.. 175 */ 176 177 switch (e.changedType) { 178 case 'tab': 179 if (!e.changedNode.test('li, li *') && !e.changedEvent.shiftKey) { 180 e.changedEvent.frameEvent.preventDefault(); 181 if (Y.UA.webkit) { 182 this.execCommand('inserttext', '\t'); 183 } else if (Y.UA.gecko) { 184 this.frame.exec._command('inserthtml', EditorBase.TABKEY); 185 } else if (Y.UA.ie) { 186 this.execCommand('inserthtml', EditorBase.TABKEY); 187 } 188 } 189 break; 190 case 'backspace-up': 191 // Fixes #2531090 - Joins text node strings so they become one for bidi 192 if (Y.UA.webkit && e.changedNode) { 193 e.changedNode.set('innerHTML', e.changedNode.get('innerHTML')); 194 } 195 break; 196 } 197 if (Y.UA.webkit && e.commands && (e.commands.indent || e.commands.outdent)) { 198 /* 199 * When executing execCommand 'indent or 'outdent' Webkit applies 200 * a class to the BLOCKQUOTE that adds left/right margin to it 201 * This strips that style so it is just a normal BLOCKQUOTE 202 */ 203 bq = root.all('.webkit-indent-blockquote, blockquote'); 204 if (bq.size()) { 205 bq.setStyle('margin', ''); 206 } 207 } 208 209 changed = this.getDomPath(e.changedNode, false); 210 211 if (e.commands) { 212 cmds = e.commands; 213 } 214 215 216 Y.each(changed, function(el) { 217 var tag = el.tagName.toLowerCase(), 218 cmd = EditorBase.TAG2CMD[tag], s, 219 n, family2, cls, bColor2; 220 221 if (cmd) { 222 cmds[cmd] = 1; 223 } 224 225 //Bold and Italic styles 226 s = el.currentStyle || el.style; 227 228 if ((''+s.fontWeight) === 'normal') { 229 normal = true; 230 } 231 if ((''+s.fontWeight) === 'bold') { //Cast this to a string 232 cmds.bold = 1; 233 } 234 if (Y.UA.ie) { 235 if (s.fontWeight > 400) { 236 cmds.bold = 1; 237 } 238 } 239 if (s.fontStyle === 'italic') { 240 cmds.italic = 1; 241 } 242 243 if (s.textDecoration.indexOf('underline') > -1) { 244 cmds.underline = 1; 245 } 246 if (s.textDecoration.indexOf('line-through') > -1) { 247 cmds.strikethrough = 1; 248 } 249 250 n = inst.one(el); 251 if (n.getStyle('fontFamily')) { 252 family2 = n.getStyle('fontFamily').split(',')[0].toLowerCase(); 253 if (family2) { 254 family = family2; 255 } 256 if (family) { 257 family = family.replace(/'/g, '').replace(/"/g, ''); 258 } 259 } 260 261 fsize = EditorBase.NORMALIZE_FONTSIZE(n); 262 263 264 cls = el.className.split(' '); 265 Y.each(cls, function(v) { 266 if (v !== '' && (v.substr(0, 4) !== 'yui_')) { 267 classes.push(v); 268 } 269 }); 270 271 fColor = EditorBase.FILTER_RGB(n.getStyle('color')); 272 bColor2 = EditorBase.FILTER_RGB(s.backgroundColor); 273 if (bColor2 !== 'transparent') { 274 if (bColor2 !== '') { 275 bColor = bColor2; 276 } 277 } 278 279 }); 280 281 if (normal) { 282 delete cmds.bold; 283 delete cmds.italic; 284 } 285 286 e.dompath = inst.all(changed); 287 e.classNames = classes; 288 e.commands = cmds; 289 290 //TODO Dont' like this, not dynamic enough.. 291 if (!e.fontFamily) { 292 e.fontFamily = family; 293 } 294 if (!e.fontSize) { 295 e.fontSize = fsize; 296 } 297 if (!e.fontColor) { 298 e.fontColor = fColor; 299 } 300 if (!e.backgroundColor) { 301 e.backgroundColor = bColor; 302 } 303 304 endTime = (new Date()).getTime(); 305 }, 306 /** 307 * Walk the dom tree from this node up to body, returning a reversed array of parents. 308 * @method getDomPath 309 * @param {Node} node The Node to start from 310 */ 311 getDomPath: function(node, nodeList) { 312 var domPath = [], domNode, rootNode, 313 root = this._getRoot(), 314 inst = this.frame.getInstance(); 315 316 domNode = inst.Node.getDOMNode(node); 317 rootNode = inst.Node.getDOMNode(root); 318 //return inst.all(domNode); 319 320 while (domNode !== null) { 321 322 if ((domNode === inst.config.doc.documentElement) || (domNode === inst.config.doc) || !domNode.tagName) { 323 domNode = null; 324 break; 325 } 326 327 if (!inst.DOM.inDoc(domNode)) { 328 domNode = null; 329 break; 330 } 331 332 //Check to see if we get el.nodeName and nodeType 333 if (domNode.nodeName && domNode.nodeType && (domNode.nodeType === 1)) { 334 domPath.push(domNode); 335 } 336 337 if (domNode === rootNode) { 338 domNode = null; 339 break; 340 } 341 342 domNode = domNode.parentNode; 343 } 344 345 /*{{{ Using Node 346 while (node !== null) { 347 if (node.test('html') || node.test('doc') || !node.get('tagName')) { 348 node = null; 349 break; 350 } 351 if (!node.inDoc()) { 352 node = null; 353 break; 354 } 355 //Check to see if we get el.nodeName and nodeType 356 if (node.get('nodeName') && node.get('nodeType') && (node.get('nodeType') == 1)) { 357 domPath.push(inst.Node.getDOMNode(node)); 358 } 359 360 if (node.test('body')) { 361 node = null; 362 break; 363 } 364 365 node = node.get('parentNode'); 366 } 367 }}}*/ 368 369 if (domPath.length === 0) { 370 domPath[0] = inst.config.doc.body; 371 } 372 373 if (nodeList) { 374 return inst.all(domPath.reverse()); 375 } else { 376 return domPath.reverse(); 377 } 378 379 }, 380 /** 381 * After frame ready, bind mousedown & keyup listeners 382 * @method _afterFrameReady 383 * @private 384 */ 385 _afterFrameReady: function() { 386 var inst = this.frame.getInstance(); 387 388 this.frame.on('dom:mouseup', Y.bind(this._onFrameMouseUp, this)); 389 this.frame.on('dom:mousedown', Y.bind(this._onFrameMouseDown, this)); 390 this.frame.on('dom:keydown', Y.bind(this._onFrameKeyDown, this)); 391 392 if (Y.UA.ie && Y.UA.ie < 11) { 393 this.frame.on('dom:activate', Y.bind(this._onFrameActivate, this)); 394 this.frame.on('dom:beforedeactivate', Y.bind(this._beforeFrameDeactivate, this)); 395 } 396 this.frame.on('dom:keyup', Y.bind(this._onFrameKeyUp, this)); 397 this.frame.on('dom:keypress', Y.bind(this._onFrameKeyPress, this)); 398 this.frame.on('dom:paste', Y.bind(this._onPaste, this)); 399 400 inst.EditorSelection.filter(); 401 this.fire('ready'); 402 }, 403 /** 404 * Caches the current cursor position in IE. 405 * @method _beforeFrameDeactivate 406 * @private 407 */ 408 _beforeFrameDeactivate: function(e) { 409 if (e.frameTarget.test('html')) { //Means it came from a scrollbar 410 return; 411 } 412 var inst = this.getInstance(), 413 sel = inst.config.doc.selection.createRange(); 414 415 if (sel.compareEndPoints && !sel.compareEndPoints('StartToEnd', sel)) { 416 sel.pasteHTML('<var id="yui-ie-cursor">'); 417 } 418 }, 419 /** 420 * Moves the cached selection bookmark back so IE can place the cursor in the right place. 421 * @method _onFrameActivate 422 * @private 423 */ 424 _onFrameActivate: function(e) { 425 if (e.frameTarget.test('html')) { //Means it came from a scrollbar 426 return; 427 } 428 var inst = this.getInstance(), 429 sel = new inst.EditorSelection(), 430 range = sel.createRange(), 431 root = this._getRoot(), 432 cur = root.all('#yui-ie-cursor'); 433 434 if (cur.size()) { 435 cur.each(function(n) { 436 n.set('id', ''); 437 if (range.moveToElementText) { 438 try { 439 range.moveToElementText(n._node); 440 var moved = range.move('character', -1); 441 if (moved === -1) { //Only move up if we actually moved back. 442 range.move('character', 1); 443 } 444 range.select(); 445 range.text = ''; 446 } catch (e) {} 447 } 448 n.remove(); 449 }); 450 } 451 }, 452 /** 453 * Fires nodeChange event 454 * @method _onPaste 455 * @private 456 */ 457 _onPaste: function(e) { 458 this.fire('nodeChange', { changedNode: e.frameTarget, changedType: 'paste', changedEvent: e.frameEvent }); 459 }, 460 /** 461 * Fires nodeChange event 462 * @method _onFrameMouseUp 463 * @private 464 */ 465 _onFrameMouseUp: function(e) { 466 this.fire('nodeChange', { changedNode: e.frameTarget, changedType: 'mouseup', changedEvent: e.frameEvent }); 467 }, 468 /** 469 * Fires nodeChange event 470 * @method _onFrameMouseDown 471 * @private 472 */ 473 _onFrameMouseDown: function(e) { 474 this.fire('nodeChange', { changedNode: e.frameTarget, changedType: 'mousedown', changedEvent: e.frameEvent }); 475 }, 476 /** 477 * Caches a copy of the selection for key events. Only creating the selection on keydown 478 * @property _currentSelection 479 * @private 480 */ 481 _currentSelection: null, 482 /** 483 * Holds the timer for selection clearing 484 * @property _currentSelectionTimer 485 * @private 486 */ 487 _currentSelectionTimer: null, 488 /** 489 * Flag to determine if we can clear the selection or not. 490 * @property _currentSelectionClear 491 * @private 492 */ 493 _currentSelectionClear: null, 494 /** 495 * Fires nodeChange event 496 * @method _onFrameKeyDown 497 * @private 498 */ 499 _onFrameKeyDown: function(e) { 500 var inst, sel; 501 if (!this._currentSelection) { 502 if (this._currentSelectionTimer) { 503 this._currentSelectionTimer.cancel(); 504 } 505 this._currentSelectionTimer = Y.later(850, this, function() { 506 this._currentSelectionClear = true; 507 }); 508 509 inst = this.frame.getInstance(); 510 sel = new inst.EditorSelection(e); 511 512 this._currentSelection = sel; 513 } else { 514 sel = this._currentSelection; 515 } 516 517 inst = this.frame.getInstance(); 518 sel = new inst.EditorSelection(); 519 520 this._currentSelection = sel; 521 522 if (sel && sel.anchorNode) { 523 this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keydown', changedEvent: e.frameEvent }); 524 if (EditorBase.NC_KEYS[e.keyCode]) { 525 this.fire('nodeChange', { 526 changedNode: sel.anchorNode, 527 changedType: EditorBase.NC_KEYS[e.keyCode], 528 changedEvent: e.frameEvent 529 }); 530 this.fire('nodeChange', { 531 changedNode: sel.anchorNode, 532 changedType: EditorBase.NC_KEYS[e.keyCode] + '-down', 533 changedEvent: e.frameEvent 534 }); 535 } 536 } 537 }, 538 /** 539 * Fires nodeChange event 540 * @method _onFrameKeyPress 541 * @private 542 */ 543 _onFrameKeyPress: function(e) { 544 var sel = this._currentSelection; 545 546 if (sel && sel.anchorNode) { 547 this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keypress', changedEvent: e.frameEvent }); 548 if (EditorBase.NC_KEYS[e.keyCode]) { 549 this.fire('nodeChange', { 550 changedNode: sel.anchorNode, 551 changedType: EditorBase.NC_KEYS[e.keyCode] + '-press', 552 changedEvent: e.frameEvent 553 }); 554 } 555 } 556 }, 557 /** 558 * Fires nodeChange event for keyup on specific keys 559 * @method _onFrameKeyUp 560 * @private 561 */ 562 _onFrameKeyUp: function(e) { 563 var inst = this.frame.getInstance(), 564 sel = new inst.EditorSelection(e); 565 566 if (sel && sel.anchorNode) { 567 this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keyup', selection: sel, changedEvent: e.frameEvent }); 568 if (EditorBase.NC_KEYS[e.keyCode]) { 569 this.fire('nodeChange', { 570 changedNode: sel.anchorNode, 571 changedType: EditorBase.NC_KEYS[e.keyCode] + '-up', 572 selection: sel, 573 changedEvent: e.frameEvent 574 }); 575 } 576 } 577 if (this._currentSelectionClear) { 578 this._currentSelectionClear = this._currentSelection = null; 579 } 580 }, 581 /** 582 * Validates linkedcss property 583 * 584 * @method _validateLinkedCSS 585 * @private 586 */ 587 _validateLinkedCSS: function(value) { 588 return Lang.isString(value) || Lang.isArray(value); 589 }, 590 /** 591 * Pass through to the frame.execCommand method 592 * @method execCommand 593 * @param {String} cmd The command to pass: inserthtml, insertimage, bold 594 * @param {String} val The optional value of the command: Helvetica 595 * @return {Node/NodeList} The Node or Nodelist affected by the command. Only returns on override commands, not browser defined commands. 596 */ 597 execCommand: function(cmd, val) { 598 var ret = this.frame.execCommand(cmd, val), 599 inst = this.frame.getInstance(), 600 sel = new inst.EditorSelection(), cmds = {}, 601 e = { changedNode: sel.anchorNode, changedType: 'execcommand', nodes: ret }; 602 603 switch (cmd) { 604 case 'forecolor': 605 e.fontColor = val; 606 break; 607 case 'backcolor': 608 e.backgroundColor = val; 609 break; 610 case 'fontsize': 611 e.fontSize = val; 612 break; 613 case 'fontname': 614 e.fontFamily = val; 615 break; 616 } 617 618 cmds[cmd] = 1; 619 e.commands = cmds; 620 621 this.fire('nodeChange', e); 622 623 return ret; 624 }, 625 /** 626 * Get the YUI instance of the frame 627 * @method getInstance 628 * @return {YUI} The YUI instance bound to the frame. 629 */ 630 getInstance: function() { 631 return this.frame.getInstance(); 632 }, 633 /** 634 * Renders the Y.ContentEditable to the passed node. 635 * @method render 636 * @param {Selector/HTMLElement/Node} node The node to append the Editor to 637 * @return {EditorBase} 638 * @chainable 639 */ 640 render: function(node) { 641 var frame = this.frame; 642 643 if (!frame) { 644 this.plug(Y.Plugin.Frame, { 645 designMode: true, 646 title: EditorBase.STRINGS.title, 647 use: EditorBase.USE, 648 dir: this.get('dir'), 649 extracss: this.get('extracss'), 650 linkedcss: this.get('linkedcss'), 651 defaultblock: this.get('defaultblock') 652 }); 653 654 frame = this.frame; 655 } 656 657 if (!frame.hasPlugin('exec')) { 658 frame.plug(Y.Plugin.ExecCommand); 659 } 660 661 frame.after('ready', Y.bind(this._afterFrameReady, this)); 662 663 frame.addTarget(this); 664 665 frame.set('content', this.get('content')); 666 667 frame.render(node); 668 669 return this; 670 }, 671 /** 672 * Focus the contentWindow of the iframe 673 * @method focus 674 * @param {Function} fn Callback function to execute after focus happens 675 * @return {EditorBase} 676 * @chainable 677 */ 678 focus: function(fn) { 679 this.frame.focus(fn); 680 return this; 681 }, 682 /** 683 * Handles the showing of the Editor instance. Currently only handles the iframe 684 * @method show 685 * @return {EditorBase} 686 * @chainable 687 */ 688 show: function() { 689 this.frame.show(); 690 return this; 691 }, 692 /** 693 * Handles the hiding of the Editor instance. Currently only handles the iframe 694 * @method hide 695 * @return {EditorBase} 696 * @chainable 697 */ 698 hide: function() { 699 this.frame.hide(); 700 return this; 701 }, 702 /** 703 * (Un)Filters the content of the Editor, cleaning YUI related code. //TODO better filtering 704 * @method getContent 705 * @return {String} The filtered content of the Editor 706 */ 707 getContent: function() { 708 var html = '', inst = this.getInstance(); 709 if (inst && inst.EditorSelection) { 710 html = inst.EditorSelection.unfilter(); 711 } 712 //Removing the _yuid from the objects in IE 713 html = html.replace(/ _yuid="([^>]*)"/g, ''); 714 return html; 715 } 716 }, { 717 /** 718 * @static 719 * @method NORMALIZE_FONTSIZE 720 * @description Pulls the fontSize from a node, then checks for string values (x-large, x-small) 721 * and converts them to pixel sizes. If the parsed size is different from the original, it calls 722 * node.setStyle to update the node with a pixel size for normalization. 723 */ 724 NORMALIZE_FONTSIZE: function(n) { 725 var size = n.getStyle('fontSize'), oSize = size; 726 727 switch (size) { 728 case '-webkit-xxx-large': 729 size = '48px'; 730 break; 731 case 'xx-large': 732 size = '32px'; 733 break; 734 case 'x-large': 735 size = '24px'; 736 break; 737 case 'large': 738 size = '18px'; 739 break; 740 case 'medium': 741 size = '16px'; 742 break; 743 case 'small': 744 size = '13px'; 745 break; 746 case 'x-small': 747 size = '10px'; 748 break; 749 } 750 if (oSize !== size) { 751 n.setStyle('fontSize', size); 752 } 753 return size; 754 }, 755 /** 756 * @static 757 * @property TABKEY 758 * @description The HTML markup to use for the tabkey 759 */ 760 TABKEY: '<span class="tab"> </span>', 761 /** 762 * @static 763 * @method FILTER_RGB 764 * @param String css The CSS string containing rgb(#,#,#); 765 * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00 766 * @return String 767 */ 768 FILTER_RGB: function(css) { 769 if (css.toLowerCase().indexOf('rgb') !== -1) { 770 var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi"), 771 rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(','), 772 r, g, b; 773 774 if (rgb.length === 5) { 775 r = parseInt(rgb[1], 10).toString(16); 776 g = parseInt(rgb[2], 10).toString(16); 777 b = parseInt(rgb[3], 10).toString(16); 778 779 r = r.length === 1 ? '0' + r : r; 780 g = g.length === 1 ? '0' + g : g; 781 b = b.length === 1 ? '0' + b : b; 782 783 css = "#" + r + g + b; 784 } 785 } 786 return css; 787 }, 788 /** 789 * @static 790 * @property TAG2CMD 791 * @description A hash table of tags to their execcomand's 792 */ 793 TAG2CMD: { 794 'b': 'bold', 795 'strong': 'bold', 796 'i': 'italic', 797 'em': 'italic', 798 'u': 'underline', 799 'sup': 'superscript', 800 'sub': 'subscript', 801 'img': 'insertimage', 802 'a' : 'createlink', 803 'ul' : 'insertunorderedlist', 804 'ol' : 'insertorderedlist' 805 }, 806 /** 807 * Hash table of keys to fire a nodeChange event for. 808 * @static 809 * @property NC_KEYS 810 * @type Object 811 */ 812 NC_KEYS: { 813 8: 'backspace', 814 9: 'tab', 815 13: 'enter', 816 32: 'space', 817 33: 'pageup', 818 34: 'pagedown', 819 35: 'end', 820 36: 'home', 821 37: 'left', 822 38: 'up', 823 39: 'right', 824 40: 'down', 825 46: 'delete' 826 }, 827 /** 828 * The default modules to use inside the Frame 829 * @static 830 * @property USE 831 * @type Array 832 */ 833 USE: ['node', 'selector-css3', 'editor-selection', 'stylesheet'], 834 /** 835 * The Class Name: editorBase 836 * @static 837 * @property NAME 838 */ 839 NAME: 'editorBase', 840 /** 841 * Editor Strings. By default contains only the `title` property for the 842 * Title of frame document (default "Rich Text Editor"). 843 * 844 * @static 845 * @property STRINGS 846 */ 847 STRINGS: { 848 title: 'Rich Text Editor' 849 }, 850 ATTRS: { 851 /** 852 * The content to load into the Editor Frame 853 * @attribute content 854 */ 855 content: { 856 validator: Lang.isString, 857 value: '<br class="yui-cursor">', 858 setter: function(str) { 859 if (str.substr(0, 1) === "\n") { 860 str = str.substr(1); 861 } 862 if (str === '') { 863 str = '<br class="yui-cursor">'; 864 } 865 if (str === ' ') { 866 if (Y.UA.gecko) { 867 str = '<br class="yui-cursor">'; 868 } 869 } 870 return this.frame.set('content', str); 871 }, 872 getter: function() { 873 return this.frame.get('content'); 874 } 875 }, 876 /** 877 * The value of the dir attribute on the HTML element of the frame. Default: ltr 878 * @attribute dir 879 */ 880 dir: { 881 validator: Lang.isString, 882 writeOnce: true, 883 value: 'ltr' 884 }, 885 /** 886 * @attribute linkedcss 887 * @description An array of url's to external linked style sheets 888 * @type String|Array 889 */ 890 linkedcss: { 891 validator: '_validateLinkedCSS', 892 value: '', 893 setter: function(css) { 894 if (this.frame) { 895 this.frame.set('linkedcss', css); 896 } 897 return css; 898 } 899 }, 900 /** 901 * @attribute extracss 902 * @description A string of CSS to add to the Head of the Editor 903 * @type String 904 */ 905 extracss: { 906 validator: Lang.isString, 907 value: '', 908 setter: function(css) { 909 if (this.frame) { 910 this.frame.set('extracss', css); 911 } 912 return css; 913 } 914 }, 915 /** 916 * @attribute defaultblock 917 * @description The default tag to use for block level items, defaults to: p 918 * @type String 919 */ 920 defaultblock: { 921 validator: Lang.isString, 922 value: 'p' 923 } 924 } 925 }); 926 927 Y.EditorBase = EditorBase; 928 929 /** 930 * @event nodeChange 931 * @description Fired from several mouse/key/paste event points. 932 * @param {EventFacade} event An Event Facade object with the following specific properties added: 933 * <dl> 934 * <dt>changedEvent</dt><dd>The event that caused the nodeChange</dd> 935 * <dt>changedNode</dt><dd>The node that was interacted with</dd> 936 * <dt>changedType</dt><dd>The type of change: mousedown, mouseup, right, left, backspace, tab, enter, etc..</dd> 937 * <dt>commands</dt><dd>The list of execCommands that belong to this change and the dompath that's associated with the changedNode</dd> 938 * <dt>classNames</dt><dd>An array of classNames that are applied to the changedNode and all of it's parents</dd> 939 * <dt>dompath</dt><dd>A sorted array of node instances that make up the DOM path from the changedNode to body.</dd> 940 * <dt>backgroundColor</dt><dd>The cascaded backgroundColor of the changedNode</dd> 941 * <dt>fontColor</dt><dd>The cascaded fontColor of the changedNode</dd> 942 * <dt>fontFamily</dt><dd>The cascaded fontFamily of the changedNode</dd> 943 * <dt>fontSize</dt><dd>The cascaded fontSize of the changedNode</dd> 944 * </dl> 945 */ 946 947 /** 948 * @event ready 949 * @description Fired after the frame is ready. 950 * @param {EventFacade} event An Event Facade object. 951 */ 952 953 954 955 956 957 }, '3.17.2', {"requires": ["base", "frame", "node", "exec-command", "editor-selection"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |