[ 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('exec-command', function (Y, NAME) { 9 10 11 /** 12 * Plugin for the frame module to handle execCommands for Editor 13 * @class Plugin.ExecCommand 14 * @extends Base 15 * @constructor 16 * @module editor 17 * @submodule exec-command 18 */ 19 var ExecCommand = function() { 20 ExecCommand.superclass.constructor.apply(this, arguments); 21 }, 22 /** 23 * This method is meant to normalize IE's in ability to exec the proper command on elements with CSS styling. 24 * @method fixIETags 25 * @protected 26 * @param {String} cmd The command to execute 27 * @param {String} tag The tag to create 28 * @param {String} rule The rule that we are looking for. 29 */ 30 fixIETags = function(cmd, tag, rule) { 31 var inst = this.getInstance(), 32 doc = inst.config.doc, 33 sel = doc.selection.createRange(), 34 o = doc.queryCommandValue(cmd), 35 html, reg, m, p, d, s, c; 36 37 if (o) { 38 html = sel.htmlText; 39 reg = new RegExp(rule, 'g'); 40 m = html.match(reg); 41 42 if (m) { 43 html = html.replace(rule + ';', '').replace(rule, ''); 44 45 sel.pasteHTML('<var id="yui-ie-bs">'); 46 47 p = doc.getElementById('yui-ie-bs'); 48 d = doc.createElement('div'); 49 s = doc.createElement(tag); 50 51 d.innerHTML = html; 52 if (p.parentNode !== inst.config.doc.body) { 53 p = p.parentNode; 54 } 55 56 c = d.childNodes; 57 58 p.parentNode.replaceChild(s, p); 59 60 Y.each(c, function(f) { 61 s.appendChild(f); 62 }); 63 sel.collapse(); 64 if (sel.moveToElementText) { 65 sel.moveToElementText(s); 66 } 67 sel.select(); 68 } 69 } 70 this._command(cmd); 71 }; 72 73 Y.extend(ExecCommand, Y.Base, { 74 /** 75 * An internal reference to the keyCode of the last key that was pressed. 76 * @private 77 * @property _lastKey 78 */ 79 _lastKey: null, 80 /** 81 * An internal reference to the instance of the frame plugged into. 82 * @private 83 * @property _inst 84 */ 85 _inst: null, 86 /** 87 * Execute a command on the frame's document. 88 * @method command 89 * @param {String} action The action to perform (bold, italic, fontname) 90 * @param {String} value The optional value (helvetica) 91 * @return {Node/NodeList} Should return the Node/Nodelist affected 92 */ 93 command: function(action, value) { 94 var fn = ExecCommand.COMMANDS[action]; 95 96 if (fn) { 97 return fn.call(this, action, value); 98 } else { 99 return this._command(action, value); 100 } 101 }, 102 /** 103 * The private version of execCommand that doesn't filter for overrides. 104 * @private 105 * @method _command 106 * @param {String} action The action to perform (bold, italic, fontname) 107 * @param {String} value The optional value (helvetica) 108 */ 109 _command: function(action, value) { 110 var inst = this.getInstance(); 111 try { 112 try { 113 inst.config.doc.execCommand('styleWithCSS', null, 1); 114 } catch (e1) { 115 try { 116 inst.config.doc.execCommand('useCSS', null, 0); 117 } catch (e2) { 118 } 119 } 120 inst.config.doc.execCommand(action, null, value); 121 } catch (e) { 122 } 123 }, 124 /** 125 * Get's the instance of YUI bound to the parent frame 126 * @method getInstance 127 * @return {YUI} The YUI instance bound to the parent frame 128 */ 129 getInstance: function() { 130 if (!this._inst) { 131 this._inst = this.get('host').getInstance(); 132 } 133 return this._inst; 134 }, 135 initializer: function() { 136 Y.mix(this.get('host'), { 137 execCommand: function(action, value) { 138 return this.exec.command(action, value); 139 }, 140 _execCommand: function(action, value) { 141 return this.exec._command(action, value); 142 } 143 }); 144 145 this.get('host').on('dom:keypress', Y.bind(function(e) { 146 this._lastKey = e.keyCode; 147 }, this)); 148 }, 149 _wrapContent: function(str, override) { 150 var useP = (this.getInstance().host.editorPara && !override ? true : false); 151 152 if (useP) { 153 str = '<p>' + str + '</p>'; 154 } else { 155 str = str + '<br>'; 156 } 157 return str; 158 } 159 }, { 160 /** 161 * execCommand 162 * @property NAME 163 * @static 164 */ 165 NAME: 'execCommand', 166 /** 167 * exec 168 * @property NS 169 * @static 170 */ 171 NS: 'exec', 172 ATTRS: { 173 host: { 174 value: false 175 } 176 }, 177 /** 178 * Static object literal of execCommand overrides 179 * @class Plugin.ExecCommand.COMMANDS 180 * @static 181 */ 182 COMMANDS: { 183 /** 184 * Wraps the content with a new element of type (tag) 185 * @method wrap 186 * @static 187 * @param {String} cmd The command executed: wrap 188 * @param {String} tag The tag to wrap the selection with 189 * @return {NodeList} NodeList of the items touched by this command. 190 */ 191 wrap: function(cmd, tag) { 192 var inst = this.getInstance(); 193 return (new inst.EditorSelection()).wrapContent(tag); 194 }, 195 /** 196 * Inserts the provided HTML at the cursor, should be a single element. 197 * @method inserthtml 198 * @static 199 * @param {String} cmd The command executed: inserthtml 200 * @param {String} html The html to insert 201 * @return {Node} Node instance of the item touched by this command. 202 */ 203 inserthtml: function(cmd, html) { 204 var inst = this.getInstance(); 205 if (inst.EditorSelection.hasCursor() || Y.UA.ie) { 206 return (new inst.EditorSelection()).insertContent(html); 207 } else { 208 this._command('inserthtml', html); 209 } 210 }, 211 /** 212 * Inserts the provided HTML at the cursor, and focuses the cursor afterwards. 213 * @method insertandfocus 214 * @static 215 * @param {String} cmd The command executed: insertandfocus 216 * @param {String} html The html to insert 217 * @return {Node} Node instance of the item touched by this command. 218 */ 219 insertandfocus: function(cmd, html) { 220 var inst = this.getInstance(), out, sel; 221 if (inst.EditorSelection.hasCursor()) { 222 html += inst.EditorSelection.CURSOR; 223 out = this.command('inserthtml', html); 224 sel = new inst.EditorSelection(); 225 sel.focusCursor(true, true); 226 } else { 227 this.command('inserthtml', html); 228 } 229 return out; 230 }, 231 /** 232 * Inserts a BR at the current cursor position 233 * @method insertbr 234 * @static 235 * @param {String} cmd The command executed: insertbr 236 */ 237 insertbr: function() { 238 var inst = this.getInstance(), 239 sel = new inst.EditorSelection(), 240 html = '<var>|</var>', last = null, 241 root = inst.EditorSelection.ROOT, 242 q = (Y.UA.webkit) ? 'span.Apple-style-span,var' : 'var', 243 insert = function(n) { 244 var c = inst.Node.create('<br>'); 245 n.insert(c, 'before'); 246 return c; 247 }; 248 249 if (sel._selection.pasteHTML) { 250 sel._selection.pasteHTML(html); 251 } else { 252 this._command('inserthtml', html); 253 } 254 255 256 root.all(q).each(function(n) { 257 var g = true, s; 258 if (Y.UA.webkit) { 259 g = false; 260 if (n.get('innerHTML') === '|') { 261 g = true; 262 } 263 } 264 if (g) { 265 last = insert(n); 266 if ((!last.previous() || !last.previous().test('br')) && Y.UA.gecko) { 267 s = last.cloneNode(); 268 last.insert(s, 'after'); 269 last = s; 270 } 271 n.remove(); 272 } 273 }); 274 if (Y.UA.webkit && last) { 275 insert(last); 276 sel.selectNode(last); 277 } 278 }, 279 /** 280 * Inserts an image at the cursor position 281 * @method insertimage 282 * @static 283 * @param {String} cmd The command executed: insertimage 284 * @param {String} img The url of the image to be inserted 285 * @return {Node} Node instance of the item touched by this command. 286 */ 287 insertimage: function(cmd, img) { 288 return this.command('inserthtml', '<img src="' + img + '">'); 289 }, 290 /** 291 * Add a class to all of the elements in the selection 292 * @method addclass 293 * @static 294 * @param {String} cmd The command executed: addclass 295 * @param {String} cls The className to add 296 * @return {NodeList} NodeList of the items touched by this command. 297 */ 298 addclass: function(cmd, cls) { 299 var inst = this.getInstance(); 300 return (new inst.EditorSelection()).getSelected().addClass(cls); 301 }, 302 /** 303 * Remove a class from all of the elements in the selection 304 * @method removeclass 305 * @static 306 * @param {String} cmd The command executed: removeclass 307 * @param {String} cls The className to remove 308 * @return {NodeList} NodeList of the items touched by this command. 309 */ 310 removeclass: function(cmd, cls) { 311 var inst = this.getInstance(); 312 return (new inst.EditorSelection()).getSelected().removeClass(cls); 313 }, 314 /** 315 * Adds a forecolor to the current selection, or creates a new element and applies it 316 * @method forecolor 317 * @static 318 * @param {String} cmd The command executed: forecolor 319 * @param {String} val The color value to apply 320 * @return {NodeList} NodeList of the items touched by this command. 321 */ 322 forecolor: function(cmd, val) { 323 var inst = this.getInstance(), 324 sel = new inst.EditorSelection(), n; 325 326 if (!Y.UA.ie) { 327 this._command('useCSS', false); 328 } 329 if (inst.EditorSelection.hasCursor()) { 330 if (sel.isCollapsed) { 331 if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === ' ')) { 332 sel.anchorNode.setStyle('color', val); 333 n = sel.anchorNode; 334 } else { 335 n = this.command('inserthtml', '<span style="color: ' + val + '">' + inst.EditorSelection.CURSOR + '</span>'); 336 sel.focusCursor(true, true); 337 } 338 return n; 339 } else { 340 return this._command(cmd, val); 341 } 342 } else { 343 this._command(cmd, val); 344 } 345 }, 346 /** 347 * Adds a background color to the current selection, or creates a new element and applies it 348 * @method backcolor 349 * @static 350 * @param {String} cmd The command executed: backcolor 351 * @param {String} val The color value to apply 352 * @return {NodeList} NodeList of the items touched by this command. 353 */ 354 backcolor: function(cmd, val) { 355 var inst = this.getInstance(), 356 sel = new inst.EditorSelection(), n; 357 358 if (Y.UA.gecko || Y.UA.opera) { 359 cmd = 'hilitecolor'; 360 } 361 if (!Y.UA.ie) { 362 this._command('useCSS', false); 363 } 364 if (inst.EditorSelection.hasCursor()) { 365 if (sel.isCollapsed) { 366 if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === ' ')) { 367 sel.anchorNode.setStyle('backgroundColor', val); 368 n = sel.anchorNode; 369 } else { 370 n = this.command('inserthtml', 371 '<span style="background-color: ' + val + '">' + inst.EditorSelection.CURSOR + '</span>'); 372 sel.focusCursor(true, true); 373 } 374 return n; 375 } else { 376 return this._command(cmd, val); 377 } 378 } else { 379 this._command(cmd, val); 380 } 381 }, 382 /** 383 * Sugar method, calles backcolor 384 * @method hilitecolor 385 * @static 386 * @param {String} cmd The command executed: backcolor 387 * @param {String} val The color value to apply 388 * @return {NodeList} NodeList of the items touched by this command. 389 */ 390 hilitecolor: function() { 391 return ExecCommand.COMMANDS.backcolor.apply(this, arguments); 392 }, 393 /** 394 * Adds a font name to the current selection, or creates a new element and applies it 395 * @method fontname2 396 * @deprecated 397 * @static 398 * @param {String} cmd The command executed: fontname 399 * @param {String} val The font name to apply 400 * @return {NodeList} NodeList of the items touched by this command. 401 */ 402 fontname2: function(cmd, val) { 403 this._command('fontname', val); 404 var inst = this.getInstance(), 405 sel = new inst.EditorSelection(); 406 407 if (sel.isCollapsed && (this._lastKey !== 32)) { 408 if (sel.anchorNode.test('font')) { 409 sel.anchorNode.set('face', val); 410 } 411 } 412 }, 413 /** 414 * Adds a fontsize to the current selection, or creates a new element and applies it 415 * @method fontsize2 416 * @deprecated 417 * @static 418 * @param {String} cmd The command executed: fontsize 419 * @param {String} val The font size to apply 420 * @return {NodeList} NodeList of the items touched by this command. 421 */ 422 fontsize2: function(cmd, val) { 423 this._command('fontsize', val); 424 425 var inst = this.getInstance(), 426 sel = new inst.EditorSelection(), p; 427 428 if (sel.isCollapsed && sel.anchorNode && (this._lastKey !== 32)) { 429 if (Y.UA.webkit) { 430 if (sel.anchorNode.getStyle('lineHeight')) { 431 sel.anchorNode.setStyle('lineHeight', ''); 432 } 433 } 434 if (sel.anchorNode.test('font')) { 435 sel.anchorNode.set('size', val); 436 } else if (Y.UA.gecko) { 437 p = sel.anchorNode.ancestor(inst.EditorSelection.DEFAULT_BLOCK_TAG); 438 if (p) { 439 p.setStyle('fontSize', ''); 440 } 441 } 442 } 443 }, 444 /** 445 * Overload for list 446 * @method insertorderedlist 447 * @static 448 * @param {String} cmd The command executed: list, ul 449 */ 450 insertunorderedlist: function() { 451 this.command('list', 'ul'); 452 }, 453 /** 454 * Overload for list 455 * @method insertunorderedlist 456 * @static 457 * @param {String} cmd The command executed: list, ol 458 */ 459 insertorderedlist: function() { 460 this.command('list', 'ol'); 461 }, 462 /** 463 * Noramlizes lists creation/destruction for IE. All others pass through to native calls 464 * @method list 465 * @static 466 * @param {String} cmd The command executed: list (not used) 467 * @param {String} tag The tag to deal with 468 */ 469 list: function(cmd, tag) { 470 var inst = this.getInstance(), html, self = this, 471 /* 472 The yui3- class name below is not a skinnable class, 473 it's a utility class used internally by editor and 474 stripped when completed, calling getClassName on this 475 is a waste of resources. 476 */ 477 DIR = 'dir', cls = 'yui3-touched', 478 dir, range, div, elm, n, str, s, par, list, lis, 479 useP = (inst.host.editorPara ? true : false), tmp, 480 sdir, hasPParent, fc, 481 root = inst.EditorSelection.ROOT, 482 sel = new inst.EditorSelection(); 483 484 cmd = 'insert' + ((tag === 'ul') ? 'un' : '') + 'orderedlist'; 485 486 if (Y.UA.ie && Y.UA.ie < 11 && !sel.isCollapsed) { 487 range = sel._selection; 488 html = range.htmlText; 489 div = inst.Node.create(html) || root; 490 491 if (div.test('li') || div.one('li')) { 492 this._command(cmd, null); 493 return; 494 } 495 if (div.test(tag)) { 496 elm = range.item ? range.item(0) : range.parentElement(); 497 n = inst.one(elm); 498 lis = n.all('li'); 499 500 str = '<div>'; 501 lis.each(function(l) { 502 str = self._wrapContent(l.get('innerHTML')); 503 }); 504 str += '</div>'; 505 s = inst.Node.create(str); 506 if (n.get('parentNode').test('div')) { 507 n = n.get('parentNode'); 508 } 509 if (n && n.hasAttribute(DIR)) { 510 if (useP) { 511 s.all('p').setAttribute(DIR, n.getAttribute(DIR)); 512 } else { 513 s.setAttribute(DIR, n.getAttribute(DIR)); 514 } 515 } 516 if (useP) { 517 n.replace(s.get('innerHTML')); 518 } else { 519 n.replace(s); 520 } 521 if (range.moveToElementText) { 522 range.moveToElementText(s._node); 523 } 524 range.select(); 525 } else { 526 par = Y.one(range.parentElement()); 527 if (!par.test(inst.EditorSelection.BLOCKS)) { 528 par = par.ancestor(inst.EditorSelection.BLOCKS); 529 } 530 if (par) { 531 if (par.hasAttribute(DIR)) { 532 dir = par.getAttribute(DIR); 533 } 534 } 535 if (html.indexOf('<br>') > -1) { 536 html = html.split(/<br>/i); 537 } else { 538 tmp = inst.Node.create(html); 539 ps = tmp ? tmp.all('p') : null; 540 541 if (ps && ps.size()) { 542 html = []; 543 ps.each(function(n) { 544 html.push(n.get('innerHTML')); 545 }); 546 } else { 547 html = [html]; 548 } 549 } 550 list = '<' + tag + ' id="ie-list">'; 551 Y.each(html, function(v) { 552 var a = inst.Node.create(v); 553 if (a && a.test('p')) { 554 if (a.hasAttribute(DIR)) { 555 dir = a.getAttribute(DIR); 556 } 557 v = a.get('innerHTML'); 558 } 559 list += '<li>' + v + '</li>'; 560 }); 561 list += '</' + tag + '>'; 562 range.pasteHTML(list); 563 elm = inst.config.doc.getElementById('ie-list'); 564 elm.id = ''; 565 if (dir) { 566 elm.setAttribute(DIR, dir); 567 } 568 if (range.moveToElementText) { 569 range.moveToElementText(elm); 570 } 571 range.select(); 572 } 573 } else if (Y.UA.ie && Y.UA.ie < 11) { 574 par = inst.one(sel._selection.parentElement()); 575 if (par.test('p')) { 576 if (par && par.hasAttribute(DIR)) { 577 dir = par.getAttribute(DIR); 578 } 579 html = Y.EditorSelection.getText(par); 580 if (html === '') { 581 sdir = ''; 582 if (dir) { 583 sdir = ' dir="' + dir + '"'; 584 } 585 list = inst.Node.create(Y.Lang.sub('<{tag}{dir}><li></li></{tag}>', { tag: tag, dir: sdir })); 586 par.replace(list); 587 sel.selectNode(list.one('li')); 588 } else { 589 this._command(cmd, null); 590 } 591 } else { 592 this._command(cmd, null); 593 } 594 } else { 595 root.all(tag).addClass(cls); 596 if (sel.anchorNode.test(inst.EditorSelection.BLOCKS)) { 597 par = sel.anchorNode; 598 } else { 599 par = sel.anchorNode.ancestor(inst.EditorSelection.BLOCKS); 600 } 601 if (!par) { //No parent, find the first block under the anchorNode 602 par = sel.anchorNode.one(inst.EditorSelection.BLOCKS); 603 } 604 605 if (par && par.hasAttribute(DIR)) { 606 dir = par.getAttribute(DIR); 607 } 608 if (par && par.test(tag)) { 609 hasPParent = par.ancestor('p'); 610 html = inst.Node.create('<div/>'); 611 elm = par.all('li'); 612 elm.each(function(h) { 613 html.append(self._wrapContent(h.get('innerHTML'), hasPParent)); 614 }); 615 if (dir) { 616 if (useP) { 617 html.all('p').setAttribute(DIR, dir); 618 } else { 619 html.setAttribute(DIR, dir); 620 } 621 } 622 if (useP) { 623 html = inst.Node.create(html.get('innerHTML')); 624 } 625 fc = html.get('firstChild'); 626 par.replace(html); 627 sel.selectNode(fc); 628 } else { 629 this._command(cmd, null); 630 } 631 list = root.all(tag); 632 if (dir) { 633 if (list.size()) { 634 //Changed to a List 635 list.each(function(n) { 636 if (!n.hasClass(cls)) { 637 n.setAttribute(DIR, dir); 638 } 639 }); 640 } 641 } 642 643 list.removeClass(cls); 644 } 645 }, 646 /** 647 * Noramlizes alignment for Webkit Browsers 648 * @method justify 649 * @static 650 * @param {String} cmd The command executed: justify (not used) 651 * @param {String} val The actual command from the justify{center,all,left,right} stubs 652 */ 653 justify: function(cmd, val) { 654 if (Y.UA.webkit) { 655 var inst = this.getInstance(), 656 sel = new inst.EditorSelection(), 657 aNode = sel.anchorNode, html, 658 bgColor = aNode.getStyle('backgroundColor'); 659 660 this._command(val); 661 sel = new inst.EditorSelection(); 662 if (sel.anchorNode.test('div')) { 663 html = '<span>' + sel.anchorNode.get('innerHTML') + '</span>'; 664 sel.anchorNode.set('innerHTML', html); 665 sel.anchorNode.one('span').setStyle('backgroundColor', bgColor); 666 sel.selectNode(sel.anchorNode.one('span')); 667 } 668 } else { 669 this._command(val); 670 } 671 }, 672 /** 673 * Override method for justify 674 * @method justifycenter 675 * @static 676 */ 677 justifycenter: function() { 678 this.command('justify', 'justifycenter'); 679 }, 680 /** 681 * Override method for justify 682 * @method justifyleft 683 * @static 684 */ 685 justifyleft: function() { 686 this.command('justify', 'justifyleft'); 687 }, 688 /** 689 * Override method for justify 690 * @method justifyright 691 * @static 692 */ 693 justifyright: function() { 694 this.command('justify', 'justifyright'); 695 }, 696 /** 697 * Override method for justify 698 * @method justifyfull 699 * @static 700 */ 701 justifyfull: function() { 702 this.command('justify', 'justifyfull'); 703 } 704 } 705 }); 706 707 if (Y.UA.ie && Y.UA.ie < 11) { 708 ExecCommand.COMMANDS.bold = function() { 709 fixIETags.call(this, 'bold', 'b', 'FONT-WEIGHT: bold'); 710 }; 711 ExecCommand.COMMANDS.italic = function() { 712 fixIETags.call(this, 'italic', 'i', 'FONT-STYLE: italic'); 713 }; 714 ExecCommand.COMMANDS.underline = function() { 715 fixIETags.call(this, 'underline', 'u', 'TEXT-DECORATION: underline'); 716 }; 717 } 718 719 Y.namespace('Plugin'); 720 Y.Plugin.ExecCommand = ExecCommand; 721 722 723 724 }, '3.17.2', {"requires": ["frame"]});
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 |