1$(document).ready(function () { 2 3 /** 4 * WYSIWYG - jQuery plugin 0.97 5 * (0.97.2 - From infinity) 6 * 7 * Copyright (c) 2008-2009 Juan M Martinez, 2010-2011 Akzhan Abdulin and all contributors 8 * https://github.com/akzhan/jwysiwyg 9 * 10 * Dual licensed under the MIT and GPL licenses: 11 * http://www.opensource.org/licenses/mit-license.php 12 * http://www.gnu.org/licenses/gpl.html 13 * 14 */ 15 16 /*jslint browser: true, forin: true */ 17 18 (function ($) { 19 "use strict"; 20 /* Wysiwyg namespace: private properties and methods */ 21 22 var console = window.console ? window.console : { 23 log: $.noop, 24 error: function (msg) { 25 $.error(msg); 26 } 27 }; 28 var supportsProp = (('prop' in $.fn) && ('removeProp' in $.fn)); 29 30 function Wysiwyg() { 31 this.controls = { 32 bold: { 33 groupIndex: 0, 34 visible: false, 35 tags: ["b", "strong"], 36 css: { 37 fontWeight: "bold" 38 }, 39 tooltip: "Bold", 40 hotkey: {"ctrl": 1, "key": 66} 41 }, 42 43 copy: { 44 groupIndex: 8, 45 visible: false, 46 tooltip: "Copy" 47 }, 48 49 createLink: { 50 groupIndex: 6, 51 visible: false, 52 exec: function () { 53 var self = this; 54 if ($.wysiwyg.controls && $.wysiwyg.controls.link) { 55 $.wysiwyg.controls.link.init(this); 56 } else if ($.wysiwyg.autoload) { 57 $.wysiwyg.autoload.control("wysiwyg.link.js", function () { 58 self.controls.createLink.exec.apply(self); 59 }); 60 } else { 61 console.error("$.wysiwyg.controls.link not defined. You need to include wysiwyg.link.js file"); 62 } 63 }, 64 tags: ["a"], 65 tooltip: "Create link" 66 }, 67 68 cut: { 69 groupIndex: 8, 70 visible: false, 71 tooltip: "Cut" 72 }, 73 74 decreaseFontSize: { 75 groupIndex: 9, 76 visible: false, 77 tags: ["small"], 78 tooltip: "Decrease font size", 79 exec: function () { 80 this.decreaseFontSize(); 81 } 82 }, 83 84 h1: { 85 groupIndex: 7, 86 visible: false, 87 className: "h1", 88 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 89 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h1>" : "h1", 90 tags: ["h1"], 91 tooltip: "Header 1" 92 }, 93 94 h2: { 95 groupIndex: 7, 96 visible: false, 97 className: "h2", 98 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 99 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h2>" : "h2", 100 tags: ["h2"], 101 tooltip: "Header 2" 102 }, 103 104 h3: { 105 groupIndex: 7, 106 visible: false, 107 className: "h3", 108 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 109 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h3>" : "h3", 110 tags: ["h3"], 111 tooltip: "Header 3" 112 }, 113 h4: { 114 groupIndex: 7, 115 visible: false, 116 className: "h4", 117 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 118 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h4>" : "h4", 119 tags: ["h4"], 120 tooltip: "Header 4" 121 }, 122 123 h5: { 124 groupIndex: 7, 125 visible: false, 126 className: "h5", 127 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 128 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h5>" : "h5", 129 tags: ["h5"], 130 tooltip: "Header 5" 131 }, 132 133 h6: { 134 groupIndex: 7, 135 visible: false, 136 className: "h6", 137 command: ($.browser.msie || $.browser.safari || $.browser.opera) ? "FormatBlock" : "heading", 138 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<h6>" : "h6", 139 tags: ["h6"], 140 tooltip: "Header 6" 141 }, 142 143 highlight: { 144 tooltip: "Highlight", 145 className: "highlight", 146 groupIndex: 1, 147 visible: false, 148 css: { 149 backgroundColor: "rgb(255, 255, 102)" 150 }, 151 exec: function () { 152 var command, node, selection, args; 153 154 if ($.browser.msie || $.browser.safari) { 155 command = "backcolor"; 156 } else { 157 command = "hilitecolor"; 158 } 159 160 if ($.browser.msie) { 161 node = this.getInternalRange().parentElement(); 162 } else { 163 selection = this.getInternalSelection(); 164 node = selection.extentNode || selection.focusNode; 165 166 while (node.style === undefined) { 167 node = node.parentNode; 168 if (node.tagName && node.tagName.toLowerCase() === "body") { 169 return; 170 } 171 } 172 } 173 174 if (node.style.backgroundColor === "rgb(255, 255, 102)" || 175 node.style.backgroundColor === "#ffff66") { 176 args = "#ffffff"; 177 } else { 178 args = "#ffff66"; 179 } 180 181 this.editorDoc.execCommand(command, false, args); 182 } 183 }, 184 185 html: { 186 groupIndex: 10, 187 visible: false, 188 exec: function () { 189 var elementHeight; 190 191 if (this.options.resizeOptions && $.fn.resizable) { 192 elementHeight = this.element.height(); 193 } 194 195 if (this.viewHTML) { 196 this.setContent(this.original.value); 197 198 $(this.original).hide(); 199 this.editor.show(); 200 201 if (this.options.resizeOptions && $.fn.resizable) { 202 // if element.height still the same after frame was shown 203 if (elementHeight === this.element.height()) { 204 this.element.height(elementHeight + this.editor.height()); 205 } 206 207 this.element.resizable($.extend(true, { 208 alsoResize: this.editor
209 }, this.options.resizeOptions)); 210 } 211 212 this.ui.toolbar.find("li").each(function () { 213 var li = $(this); 214 215 if (li.hasClass("html")) { 216 li.removeClass("active"); 217 } else { 218 li.removeClass('disabled'); 219 } 220 }); 221 } else { 222 this.saveContent(); 223 224 $(this.original).css({ 225 width: this.element.outerWidth() - 6, 226 height: this.element.height() - this.ui.toolbar.height() - 6, 227 resize: "none" 228 }).show(); 229 this.editor.hide(); 230 231 if (this.options.resizeOptions && $.fn.resizable) { 232 // if element.height still the same after frame was hidden 233 if (elementHeight === this.element.height()) { 234 this.element.height(this.ui.toolbar.height()); 235 } 236 237 this.element.resizable("destroy"); 238 } 239 240 this.ui.toolbar.find("li").each(function () { 241 var li = $(this); 242 243 if (li.hasClass("html")) { 244 li.addClass("active"); 245 } else { 246 if (false === li.hasClass("fullscreen")) { 247 li.removeClass("active").addClass('disabled'); 248 } 249 } 250 }); 251 } 252 253 this.viewHTML = !(this.viewHTML); 254 }, 255 tooltip: "View source code" 256 }, 257 258 increaseFontSize: { 259 groupIndex: 9, 260 visible: false, 261 tags: ["big"], 262 tooltip: "Increase font size", 263 exec: function () { 264 this.increaseFontSize(); 265 } 266 }, 267 268 insertImage: { 269 groupIndex: 6, 270 visible: false, 271 exec: function () { 272 var self = this; 273 274 if ($.wysiwyg.controls && $.wysiwyg.controls.image) { 275 $.wysiwyg.controls.image.init(this); 276 } else if ($.wysiwyg.autoload) { 277 $.wysiwyg.autoload.control("wysiwyg.image.js", function () { 278 self.controls.insertImage.exec.apply(self); 279 }); 280 } else { 281 console.error("$.wysiwyg.controls.image not defined. You need to include wysiwyg.image.js file"); 282 } 283 }, 284 tags: ["img"], 285 tooltip: "Insert image" 286 }, 287 288 insertOrderedList: { 289 groupIndex: 5, 290 visible: false, 291 tags: ["ol"], 292 tooltip: "Insert Ordered List" 293 }, 294 295 insertTable: { 296 groupIndex: 6, 297 visible: false, 298 exec: function () { 299 var self = this; 300 301 if ($.wysiwyg.controls && $.wysiwyg.controls.table) { 302 $.wysiwyg.controls.table(this); 303 } else if ($.wysiwyg.autoload) { 304 $.wysiwyg.autoload.control("wysiwyg.table.js", function () { 305 self.controls.insertTable.exec.apply(self); 306 }); 307 } else { 308 console.error("$.wysiwyg.controls.table not defined. You need to include wysiwyg.table.js file"); 309 } 310 }, 311 tags: ["table"], 312 tooltip: "Insert table" 313 }, 314 315 insertUnorderedList: { 316 groupIndex: 5, 317 visible: false, 318 tags: ["ul"], 319 tooltip: "Insert Unordered List" 320 }, 321 322 italic: { 323 groupIndex: 0, 324 visible: false, 325 tags: ["i", "em"], 326 css: { 327 fontStyle: "italic" 328 }, 329 tooltip: "Italic", 330 hotkey: {"ctrl": 1, "key": 73} 331 }, 332 333 justifyLeft: { 334 visible: false, 335 groupIndex: 1, 336 css: { 337 textAlign: "left" 338 }, 339 tooltip: "Justify Left" 340 }, 341 342 justifyCenter: { 343 groupIndex: 1, 344 visible: false, 345 tags: ["center"], 346 css: { 347 textAlign: "center" 348 }, 349 tooltip: "Justify Center" 350 }, 351 352 justifyRight: { 353 groupIndex: 1, 354 visible: false, 355 css: { 356 textAlign: "right" 357 }, 358 tooltip: "Justify Right" 359 }, 360 361 justifyFull: { 362 groupIndex: 1, 363 visible: false, 364 css: { 365 textAlign: "justify" 366 }, 367 tooltip: "Justify Full" 368 }, 369 370 ltr: { 371 groupIndex: 9, 372 visible: false, 373 exec: function () { 374 var p = this.dom.getElement("p"); 375 376 if (!p) { 377 return false; 378 } 379 380 $(p).attr("dir", "ltr"); 381 return true; 382 }, 383 tooltip : "Left to Right" 384 }, 385 386 rtl: { 387 groupIndex: 9, 388 visible: false, 389 exec: function () { 390 var p = this.dom.getElement("p"); 391 392 if (!p) { 393 return false; 394 } 395 396 $(p).attr("dir", "rtl"); 397 return true; 398 }, 399 tooltip : "Right to Left" 400 }, 401 402 indent: { 403 groupIndex: 2, 404 visible: false, 405 tooltip: "Indent" 406 }, 407
408 outdent: { 409 groupIndex: 2, 410 visible: false, 411 tooltip: "Outdent" 412 }, 413 414 insertHorizontalRule: { 415 groupIndex: 5, 416 visible: false, 417 tags: ["hr"], 418 tooltip: "Insert Horizontal Rule" 419 }, 420 421 paragraph: { 422 groupIndex: 7, 423 visible: false, 424 className: "paragraph", 425 command: "FormatBlock", 426 "arguments": ($.browser.msie || $.browser.safari || $.browser.opera) ? "<p>" : "p", 427 tags: ["p"], 428 tooltip: "Paragraph" 429 }, 430 431 paste: { 432 groupIndex: 8, 433 visible: false, 434 tooltip: "Paste" 435 }, 436 437 undo: { 438 groupIndex: 4, 439 visible: false, 440 tooltip: "Undo" 441 }, 442 443 redo: { 444 groupIndex: 4, 445 visible: false, 446 tooltip: "Redo" 447 }, 448 449 removeFormat: { 450 groupIndex: 10, 451 visible: false, 452 exec: function () { 453 this.removeFormat(); 454 }, 455 tooltip: "Remove formatting" 456 }, 457 458 459 underline: { 460 groupIndex: 0, 461 visible: false, 462 tags: ["u"], 463 css: { 464 textDecoration: "underline" 465 }, 466 tooltip: "Underline", 467 hotkey: {"ctrl": 1, "key": 85} 468 }, 469 470 strikeThrough: { 471 groupIndex: 0, 472 visible: false, 473 tags: ["s", "strike"], 474 css: { 475 textDecoration: "line-through" 476 }, 477 tooltip: "Strike-through" 478 }, 479 480 subscript: { 481 groupIndex: 3, 482 visible: false, 483 tags: ["sub"], 484 tooltip: "Subscript" 485 }, 486 487 superscript: { 488 groupIndex: 3, 489 visible: false, 490 tags: ["sup"], 491 tooltip: "Superscript" 492 }, 493 494 code: { 495 visible : false, 496 groupIndex: 6, 497 tooltip: "Code snippet", 498 exec: function () { 499 var range = this.getInternalRange(), 500 common = $(range.commonAncestorContainer), 501 $nodeName = range.commonAncestorContainer.nodeName.toLowerCase(); 502 if (common.parent("code").length) { 503 common.unwrap(); 504 } else { 505 if ($nodeName !== "body") { 506 common.wrap("<code/>"); 507 } 508 } 509 } 510 }, 511 512 cssWrap: { 513 visible : false, 514 groupIndex: 6, 515 tooltip: "CSS Wrapper", 516 exec: function () { 517 $.wysiwyg.controls.cssWrap.init(this); 518 } 519 } 520 521 }; 522 523 this.defaults = { 524 html: '<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>INITIAL_CONTENT</body></html>', 525 debug: false, 526 controls: {}, 527 css: {}, 528 events: {}, 529 autoGrow: false, 530 autoSave: true, 531 brIE: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=15 532 formHeight: 270, 533 formWidth: 440, 534 iFrameClass: null, 535 initialContent: "<p>Initial content</p>", 536 maxHeight: 10000, // see autoGrow 537 maxLength: 0, 538 messages: { 539 nonSelection: "Select the text you wish to link" 540 }, 541 toolbarHtml: '<ul role="menu" class="toolbar"></ul>', 542 removeHeadings: false, 543 replaceDivWithP: false, 544 resizeOptions: false, 545 rmUnusedControls: false, // https://github.com/akzhan/jwysiwyg/issues/52 546 rmUnwantedBr: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=11 547 tableFiller: "Lorem ipsum", 548 initialMinHeight: null, 549 550 controlImage: { 551 forceRelativeUrls: false 552 }, 553 554 controlLink: { 555 forceRelativeUrls: false 556 }, 557 558 plugins: { // placeholder for plugins settings 559 autoload: false, 560 i18n: false, 561 rmFormat: { 562 rmMsWordMarkup: false 563 } 564 } 565 }; 566 567 this.availableControlProperties = [ 568 "arguments", 569 "callback", 570 "className", 571 "command", 572 "css", 573 "custom", 574 "exec", 575 "groupIndex", 576 "hotkey", 577 "icon", 578 "tags", 579 "tooltip", 580 "visible" 581 ]; 582 583 this.editor = null; 584 this.editorDoc = null; 585 this.element = null; 586 this.options = {}; 587 this.original = null; 588 this.savedRange = null; 589 this.timers = []; 590 this.validKeyCodes = [8, 9, 13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46]; 591 592 this.isDestroyed = false; 593 594 this.dom = { // DOM related properties and methods 595 ie: { 596 parent: null // link to dom 597 }, 598 w3c: { 599 parent: null // link to dom 600 } 601 }; 602 this.dom.parent = this; 603 this.dom.ie.parent = this.dom; 604 this.dom.w3c.parent = this.dom; 605 606 this.ui = {}; // UI related properties and methods 607 this.ui.self = this; 608 this.ui.toolbar = null; 609 this.ui.initialHeight = null; // ui.grow 610 611 this.dom.getAncestor = function (element, filterTagName) { 612 filterTagName = filterTagName.toLowerCase(); 613 614 while (element && "body" !== element.tagName.toLowerCase()) { 615 if (filterTagName === element.tagName.toLowerCase()) { 616 return element; 617 } 618 619 element = element.parentNode; 620 } 621 622 return null; 623 }; 624 625 this.dom.getElement = function (filterTagName) { 626 var dom = this; 627 628 if (window.getSelection) { 629 return dom.w3c.getElement(filterTagName); 630 } else { 631 return dom.ie.getElement(filterTagName); 632 } 633 }; 634 635 this.dom.ie.getElement = function (filterTagName) { 636 var dom = this.parent, 637 selection = dom.parent.getInternalSelection(), 638 range = selection.createRange(), 639 element; 640 641 if ("Control" === selection.type) { 642 // control selection 643 if (1 === range.length) { 644 element = range.item(0); 645 } else { 646 // multiple control selection 647 return null; 648 } 649 } else { 650 element = range.parentElement(); 651 } 652 653 return dom.getAncestor(element, filterTagName); 654 }; 655 656 this.dom.w3c.getElement = function (filterTagName) { 657 var dom = this.parent, 658 range = dom.parent.getInternalRange(), 659 element; 660 661 if (!range) { 662 return null; 663 } 664 665 element = range.commonAncestorContainer; 666 667 if (3 === element.nodeType) { 668 element = element.parentNode; 669 } 670 671 // if startContainer not Text, Comment, or CDATASection element then 672 // startOffset is the number of child nodes between the start of the 673 // startContainer and the boundary point of the Range 674 if (element === range.startContainer) { 675 element = element.childNodes[range.startOffset]; 676 } 677 678 return dom.getAncestor(element, filterTagName); 679 }; 680 681 this.ui.addHoverClass = function () { 682 $(this).addClass("wysiwyg-button-hover"); 683 }; 684
685 this.ui.appendControls = function () { 686 var ui = this, 687 self = this.self, 688 controls = self.parseControls(), 689 hasVisibleControls = true, // to prevent separator before first item 690 groups = [], 691 controlsByGroup = {}, 692 i, 693 currentGroupIndex, // jslint wants all vars at top of function 694 iterateGroup = function (controlName, control) { 695 if (control.groupIndex && currentGroupIndex !== control.groupIndex) { 696 currentGroupIndex = control.groupIndex; 697 hasVisibleControls = false; 698 } 699 700 if (!control.visible) { 701 return; 702 } 703 704 if (!hasVisibleControls) { 705 ui.appendItemSeparator(); 706 hasVisibleControls = true; 707 } 708 709 if (control.custom) { 710 ui.appendItemCustom(controlName, control); 711 } else { 712 ui.appendItem(controlName, control); 713 } 714 }; 715 716 $.each(controls, function (name, c) { 717 var index = "empty"; 718 719 if (undefined !== c.groupIndex) { 720 if ("" === c.groupIndex) { 721 index = "empty"; 722 } else { 723 index = c.groupIndex; 724 } 725 } 726 727 if (undefined === controlsByGroup[index]) { 728 groups.push(index); 729 controlsByGroup[index] = {}; 730 } 731 controlsByGroup[index][name] = c; 732 }); 733 734 groups.sort(function (a, b) { 735 if ("number" === typeof (a) && typeof (a) === typeof (b)) { 736 return (a - b); 737 } else { 738 a = a.toString(); 739 b = b.toString(); 740 741 if (a > b) { 742 return 1; 743 } 744 745 if (a === b) { 746 return 0; 747 } 748 749 return -1; 750 } 751 }); 752 753 if (0 < groups.length) { 754 // set to first index in groups to proper placement of separator 755 currentGroupIndex = groups[0]; 756 } 757 758 for (i = 0; i < groups.length; i += 1) { 759 $.each(controlsByGroup[groups[i]], iterateGroup); 760 } 761 }; 762 763 this.ui.appendItem = function (name, control) { 764 var self = this.self, 765 className = control.className || control.command || name || "empty", 766 tooltip = control.tooltip || control.command || name || ""; 767 768 return $('<li role="menuitem" unselectable="on">' + (className) + "</li>") 769 .addClass(className) 770 .attr("title", tooltip) 771 .hover(this.addHoverClass, this.removeHoverClass) 772 .click(function () { 773 if ($(this).hasClass("disabled")) { 774 return false; 775 } 776 777 self.triggerControl.apply(self, [name, control]); 778 779 this.blur(); 780 self.ui.returnRange(); 781 self.ui.focus(); 782 return true; 783 }) 784 .appendTo(self.ui.toolbar); 785 }; 786 787 this.ui.appendItemCustom = function (name, control) { 788 var self = this.self, 789 tooltip = control.tooltip || control.command || name || ""; 790 791 if (control.callback) { 792 $(window).bind("trigger-" + name + ".wysiwyg", control.callback); 793 } 794 795 return $('<li role="menuitem" unselectable="on" style="background: url(\'' + control.icon + '\') no-repeat;"></li>') 796 .addClass("custom-command-" + name) 797 .addClass("wysiwyg-custom-command") 798 .addClass(name) 799 .attr("title", tooltip) 800 .hover(this.addHoverClass, this.removeHoverClass) 801 .click(function () { 802 if ($(this).hasClass("disabled")) { 803 return false; 804 } 805 806 self.triggerControl.apply(self, [name, control]); 807 808 this.blur(); 809 self.ui.returnRange(); 810 self.ui.focus(); 811 812 self.triggerControlCallback(name); 813 return true; 814 }) 815 .appendTo(self.ui.toolbar); 816 }; 817 818 this.ui.appendItemSeparator = function () { 819 var self = this.self; 820 return $('<li role="separator" class="separator"></li>').appendTo(self.ui.toolbar); 821 }; 822 823 this.autoSaveFunction = function () { 824 this.saveContent(); 825 }; 826 827 this.ui.checkTargets = function (element) { 828 var self = this.self; 829 830 $.each(self.options.controls, function (name, control) { 831 var className = control.className || control.command || name || "empty", 832 tags, 833 elm, 834 css, 835 el, 836 checkActiveStatus = function (cssProperty, cssValue) { 837 var handler; 838 839 if ("function" === typeof (cssValue)) { 840 handler = cssValue; 841 if (handler(el.css(cssProperty).toString().toLowerCase(), self)) { 842 self.ui.toolbar.find("." + className).addClass("active"); 843 } 844 } else { 845 if (el.css(cssProperty).toString().toLowerCase() === cssValue) { 846 self.ui.toolbar.find("." + className).addClass("active"); 847 } 848 } 849 }; 850 851 if ("fullscreen" !== className) { 852 self.ui.toolbar.find("." + className).removeClass("active"); 853 } 854 855 if (control.tags || (control.options && control.options.tags)) { 856 tags = control.tags || (control.options && control.options.tags); 857 858 elm = element; 859 while (elm) { 860 if (elm.nodeType !== 1) { 861 break; 862 } 863 864 if ($.inArray(elm.tagName.toLowerCase(), tags) !== -1) { 865 self.ui.toolbar.find("." + className).addClass("active"); 866 } 867 868 elm = elm.parentNode; 869 } 870 } 871 872 if (control.css || (control.options && control.options.css)) { 873 css = control.css || (control.options && control.options.css); 874 el = $(element); 875 876 while (el) { 877 if (el[0].nodeType !== 1) { 878 break; 879 } 880 $.each(css, checkActiveStatus); 881 882 el = el.parent(); 883 } 884 } 885 }); 886 }; 887 888 this.ui.designMode = function () { 889 var attempts = 3, 890 self = this.self, 891 runner; 892 runner = function (attempts) { 893 if ("on" === self.editorDoc.designMode) { 894 if (self.timers.designMode) { 895 window.clearTimeout(self.timers.designMode); 896 } 897 898 // IE needs to reget the document element (this.editorDoc) after designMode was set 899 if (self.innerDocument() !== self.editorDoc) { 900 self.ui.initFrame(); 901 } 902 903 return; 904 } 905 906 try { 907 self.editorDoc.designMode = "on"; 908 } catch (e) { 909 } 910 911 attempts -= 1; 912 if (attempts > 0) { 913 self.timers.designMode = window.setTimeout(function () { runner(attempts); }, 100); 914 } 915 }; 916 917 runner(attempts); 918 }; 919 920 this.destroy = function () { 921 this.isDestroyed = true; 922 923 var i, $form = this.element.closest("form"); 924 925 for (i = 0; i < this.timers.length; i += 1) { 926 window.clearTimeout(this.timers[i]); 927 } 928 929 // Remove bindings 930 $form.unbind(".wysiwyg"); 931 this.element.remove(); 932 $.removeData(this.original, "wysiwyg"); 933 $(this.original).show(); 934 return this; 935 }; 936 937 this.getRangeText = function () { 938 var r = this.getInternalRange(); 939 940 if (r.toString) { 941 r = r.toString(); 942 } else if (r.text) { // IE 943 r = r.text; 944 } 945 946 return r; 947 }; 948 //not used? 949 this.execute = function (command, arg) { 950 if (typeof (arg) === "undefined") { 951 arg = null; 952 } 953 this.editorDoc.execCommand(command, false, arg); 954 }; 955 956 this.extendOptions = function (options) { 957 var controls = {}; 958 959 /** 960 * If the user set custom controls, we catch it, and merge with the 961 * defaults controls later. 962 */ 963 if ("object" === typeof options.controls) { 964 controls = options.controls; 965 delete options.controls; 966 } 967 968 options = $.extend(true, {}, this.defaults, options); 969 options.controls = $.extend(true, {}, controls, this.controls, controls); 970 971 if (options.rmUnusedControls) { 972 $.each(options.controls, function (controlName) { 973 if (!controls[controlName]) { 974 delete options.controls[controlName]; 975 } 976 }); 977 } 978 979 return options; 980 }; 981 982 this.ui.focus = function () { 983 var self = this.self; 984 985 self.editor.get(0).contentWindow.focus(); 986 return self; 987 }; 988 989 this.ui.returnRange = function () { 990 var self = this.self, sel; 991 992 if (self.savedRange !== null) { 993 if (window.getSelection) { //non IE and there is already a selection 994 sel = window.getSelection(); 995 if (sel.rangeCount > 0) { 996 sel.removeAllRanges(); 997 } 998 try { 999 sel.addRange(self.savedRange); 1000 } catch (e) { 1001 console.error(e); 1002 } 1003 } else if (window.document.createRange) { // non IE and no selection 1004 window.getSelection().addRange(self.savedRange); 1005 } else if (window.document.selection) { //IE 1006 self.savedRange.select(); 1007 } 1008 1009 self.savedRange = null; 1010 } 1011 }; 1012 1013 this.increaseFontSize = function () { 1014 if ($.browser.mozilla || $.browser.opera) { 1015 this.editorDoc.execCommand('increaseFontSize', false, null); 1016 } else if ($.browser.safari) { 1017 var newNode = this.editorDoc.createElement('big'); 1018 this.getInternalRange().surroundContents(newNode); 1019 } else { 1020 console.error("Internet Explorer?"); 1021 } 1022 }; 1023 1024 this.decreaseFontSize = function () { 1025 if ($.browser.mozilla || $.browser.opera) { 1026 this.editorDoc.execCommand('decreaseFontSize', false, null); 1027 } else if ($.browser.safari) { 1028 var newNode = this.editorDoc.createElement('small'); 1029 this.getInternalRange().surroundContents(newNode); 1030 } else { 1031 console.error("Internet Explorer?"); 1032 } 1033 }; 1034 1035 this.getContent = function () { 1036 if (this.viewHTML) { 1037 this.setContent(this.original.value); 1038 } 1039 return this.events.filter('getContent', this.editorDoc.body.innerHTML); 1040 }; 1041 1042 /** 1043 * A jWysiwyg specific event system. 1044 *
1045 * Example: 1046 * 1047 * $("#editor").getWysiwyg().events.bind("getContent", function (orig) { 1048 * return "<div id='content'>"+orgi+"</div>"; 1049 * }); 1050 * 1051 * This makes it so that when ever getContent is called, it is wrapped in a div#content. 1052 */ 1053 this.events = { 1054 _events : {}, 1055 1056 /** 1057 * Similar to jQuery's bind, but for jWysiwyg only. 1058 */ 1059 bind : function (eventName, callback) { 1060 if (typeof (this._events.eventName) !== "object") { 1061 this._events[eventName] = []; 1062 } 1063 this._events[eventName].push(callback); 1064 }, 1065 1066 /** 1067 * Similar to jQuery's trigger, but for jWysiwyg only. 1068 */ 1069 trigger : function (eventName, args) { 1070 if (typeof (this._events.eventName) === "object") { 1071 var editor = this.editor; 1072 $.each(this._events[eventName], function (k, v) { 1073 if (typeof (v) === "function") { 1074 v.apply(editor, args); 1075 } 1076 }); 1077 } 1078 }, 1079 1080 /** 1081 * This "filters" `originalText` by passing it as the first argument to every callback 1082 * with the name `eventName` and taking the return value and passing it to the next function. 1083 * 1084 * This function returns the result after all the callbacks have been applied to `originalText`. 1085 */ 1086 filter : function (eventName, originalText) { 1087 if (typeof (this._events[eventName]) === "object") { 1088 var editor = this.editor, 1089 args = Array.prototype.slice.call(arguments, 1); 1090 1091 $.each(this._events[eventName], function (k, v) { 1092 if (typeof (v) === "function") { 1093 originalText = v.apply(editor, args); 1094 } 1095 }); 1096 } 1097 return originalText; 1098 } 1099 }; 1100 1101 this.getElementByAttributeValue = function (tagName, attributeName, attributeValue) { 1102 var i, value, elements = this.editorDoc.getElementsByTagName(tagName); 1103 1104 for (i = 0; i < elements.length; i += 1) { 1105 value = elements[i].getAttribute(attributeName); 1106 1107 if ($.browser.msie) { 1108 /** IE add full path, so I check by the last chars. */ 1109 value = value.substr(value.length - attributeValue.length); 1110 } 1111 1112 if (value === attributeValue) { 1113 return elements[i]; 1114 } 1115 } 1116 1117 return false; 1118 }; 1119 1120 this.getInternalRange = function () { 1121 var selection = this.getInternalSelection(); 1122 1123 if (!selection) { 1124 return null; 1125 } 1126 1127 if (selection.rangeCount && selection.rangeCount > 0) { // w3c 1128 return selection.getRangeAt(0); 1129 } else if (selection.createRange) { // ie 1130 return selection.createRange(); 1131 } 1132 1133 return null; 1134 }; 1135 1136 this.getInternalSelection = function () { 1137 // firefox: document.getSelection is deprecated 1138 if (this.editor.get(0).contentWindow) { 1139 if (this.editor.get(0).contentWindow.getSelection) { 1140 return this.editor.get(0).contentWindow.getSelection(); 1141 } 1142 if (this.editor.get(0).contentWindow.selection) { 1143 return this.editor.get(0).contentWindow.selection; 1144 } 1145 } 1146 if (this.editorDoc.getSelection) { 1147 return this.editorDoc.getSelection(); 1148 } 1149 if (this.editorDoc.selection) { 1150 return this.editorDoc.selection; 1151 } 1152 1153 return null; 1154 }; 1155 1156 this.getRange = function () { 1157 var selection = this.getSelection(); 1158 1159 if (!selection) { 1160 return null; 1161 } 1162 1163 if (selection.rangeCount && selection.rangeCount > 0) { // w3c 1164 selection.getRangeAt(0); 1165 } else if (selection.createRange) { // ie 1166 return selection.createRange(); 1167 } 1168 1169 return null; 1170 }; 1171 1172 this.getSelection = function () { 1173 return (window.getSelection) ? window.getSelection() : window.document.selection; 1174 }; 1175 1176 // :TODO: you can type long string and letters will be hidden because of overflow 1177 this.ui.grow = function () { 1178 var self = this.self, 1179 innerBody = $(self.editorDoc.body), 1180 innerHeight = $.browser.msie ? innerBody[0].scrollHeight : innerBody.height() + 2 + 20, // 2 - borders, 20 - to prevent content jumping on grow 1181 minHeight = self.ui.initialHeight, 1182 height = Math.max(innerHeight, minHeight); 1183 1184 height = Math.min(height, self.options.maxHeight); 1185 1186 self.editor.attr("scrolling", height < self.options.maxHeight ? "no" : "auto"); // hide scrollbar firefox 1187 innerBody.css("overflow", height < self.options.maxHeight ? "hidden" : ""); // hide scrollbar chrome 1188 1189 self.editor.get(0).height = height; 1190 1191 return self; 1192 }; 1193 1194 this.init = function (element, options) { 1195 var self = this, 1196 $form = $(element).closest("form"), 1197 newX = element.width || element.clientWidth || 0, 1198 newY = element.height || element.clientHeight || 0 1199 ; 1200 1201 this.options = this.extendOptions(options); 1202 this.original = element; 1203 this.ui.toolbar = $(this.options.toolbarHtml); 1204 1205 if ($.browser.msie && parseInt($.browser.version, 10) < 8) { 1206 this.options.autoGrow = false;
1207 } 1208 1209 if (newX === 0 && element.cols) { 1210 newX = (element.cols * 8) + 21; 1211 } 1212 if (newY === 0 && element.rows) { 1213 newY = (element.rows * 16) + 16; 1214 } 1215 1216 this.editor = $(window.location.protocol === "https:" ? '<iframe src="javascript:false;"></iframe>' : "<iframe></iframe>").attr("frameborder", "0"); 1217 1218 if (this.options.iFrameClass) { 1219 this.editor.addClass(this.options.iFrameClass); 1220 } else { 1221 this.editor.css({ 1222 minHeight: (newY - 6).toString() + "px", 1223 // fix for issue 12 ( http://github.com/akzhan/jwysiwyg/issues/issue/12 ) 1224 width: (newX > 50) ? (newX - 8).toString() + "px" : "" 1225 }); 1226 if ($.browser.msie && parseInt($.browser.version, 10) < 7) { 1227 this.editor.css("height", newY.toString() + "px"); 1228 } 1229 } 1230 /** 1231 * http://code.google.com/p/jwysiwyg/issues/detail?id=96 1232 */ 1233 this.editor.attr("tabindex", $(element).attr("tabindex")); 1234 1235 this.element = $("<div/>").addClass("wysiwyg"); 1236 1237 if (!this.options.iFrameClass) { 1238 this.element.css({ 1239 width: (newX > 0) ? newX.toString() + "px" : "100%" 1240 }); 1241 } 1242 1243 $(element).hide().before(this.element); 1244 1245 this.viewHTML = false; 1246 1247 /** 1248 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52 1249 */ 1250 this.initialContent = $(element).val(); 1251 this.ui.initFrame(); 1252 1253 if (this.options.resizeOptions && $.fn.resizable) { 1254 this.element.resizable($.extend(true, { 1255 alsoResize: this.editor 1256 }, this.options.resizeOptions)); 1257 } 1258 1259 if (this.options.autoSave) { 1260 $form.bind("submit.wysiwyg", function () { self.autoSaveFunction(); }); 1261 } 1262 1263 $form.bind("reset.wysiwyg", function () { self.resetFunction(); }); 1264 }; 1265 1266 this.ui.initFrame = function () { 1267 var self = this.self, 1268 stylesheet, 1269 growHandler, 1270 saveHandler; 1271 1272 self.ui.appendControls(); 1273 self.element.append(self.ui.toolbar) 1274 .append($("<div><!-- --></div>") 1275 .css({ 1276 clear: "both" 1277 })) 1278 .append(self.editor); 1279 1280 self.editorDoc = self.innerDocument(); 1281 1282 if (self.isDestroyed) { 1283 return null; 1284 } 1285 1286 self.ui.designMode(); 1287 self.editorDoc.open(); 1288 self.editorDoc.write( 1289 self.options.html 1290 /** 1291 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=144 1292 */ 1293 .replace(/INITIAL_CONTENT/, function () { return self.wrapInitialContent(); }) 1294 ); 1295 self.editorDoc.close(); 1296 1297 $.wysiwyg.plugin.bind(self); 1298 1299 $(self.editorDoc).trigger("initFrame.wysiwyg"); 1300 1301 $(self.editorDoc).bind("click.wysiwyg", function (event) { 1302 self.ui.checkTargets(event.target ? event.target : event.srcElement); 1303 }); 1304 1305 /** 1306 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20 1307 */ 1308 $(self.original).focus(function () { 1309 if ($(this).filter(":visible")) { 1310 return; 1311 } 1312 self.ui.focus(); 1313 }); 1314 1315 $(self.editorDoc).keydown(function (event) { 1316 var emptyContentRegex; 1317 if (event.keyCode === 8) { // backspace 1318 emptyContentRegex = /^<([\w]+)[^>]*>(<br\/?>)?<\/\1>$/; 1319 if (emptyContentRegex.test(self.getContent())) { // if content is empty 1320 event.stopPropagation(); // prevent remove single empty tag 1321 return false; 1322 } 1323 } 1324 return true; 1325 }); 1326 1327 if (!$.browser.msie) { 1328 $(self.editorDoc).keydown(function (event) { 1329 var controlName; 1330 1331 /* Meta for Macs. [email protected] */ 1332 if (event.ctrlKey || event.metaKey) { 1333 for (controlName in self.controls) { 1334 if (self.controls[controlName].hotkey && self.controls[controlName].hotkey.ctrl) { 1335 if (event.keyCode === self.controls[controlName].hotkey.key) { 1336 self.triggerControl.apply(self, [controlName, self.controls[controlName]]); 1337 1338 return false; 1339 } 1340 } 1341 } 1342 } 1343 1344 return true; 1345 }); 1346 } else if (self.options.brIE) { 1347 $(self.editorDoc).keydown(function (event) { 1348 if (event.keyCode === 13) { 1349 var rng = self.getRange(); 1350 rng.pasteHTML("<br/>"); 1351 rng.collapse(false); 1352 rng.select(); 1353 1354 return false;
1355 } 1356 1357 return true; 1358 }); 1359 } 1360 1361 if (self.options.plugins.rmFormat.rmMsWordMarkup) { 1362 $(self.editorDoc).bind("keyup.wysiwyg", function (event) { 1363 if (event.ctrlKey || event.metaKey) { 1364 // CTRL + V (paste) 1365 if (86 === event.keyCode) { 1366 if ($.wysiwyg.rmFormat) { 1367 if ("object" === typeof (self.options.plugins.rmFormat.rmMsWordMarkup)) { 1368 $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: self.options.plugins.rmFormat.rmMsWordMarkup }}); 1369 } else { 1370 $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: { enabled: true }}}); 1371 } 1372 } 1373 } 1374 } 1375 }); 1376 } 1377 1378 if (self.options.autoSave) { 1379 $(self.editorDoc).keydown(function () { self.autoSaveFunction(); }) 1380 .keyup(function () { self.autoSaveFunction(); }) 1381 .mousedown(function () { self.autoSaveFunction(); }) 1382 .bind($.support.noCloneEvent ? "input.wysiwyg" : "paste.wysiwyg", function () { self.autoSaveFunction(); }); 1383 } 1384 1385 if (self.options.autoGrow) { 1386 if (self.options.initialMinHeight !== null) { 1387 self.ui.initialHeight = self.options.initialMinHeight; 1388 } else { 1389 self.ui.initialHeight = $(self.editorDoc).height(); 1390 } 1391 $(self.editorDoc.body).css("border", "1px solid white"); // cancel margin collapsing 1392 1393 growHandler = function () { 1394 self.ui.grow(); 1395 }; 1396 1397 $(self.editorDoc).keyup(growHandler); 1398 $(self.editorDoc).bind("editorRefresh.wysiwyg", growHandler); 1399 1400 // fix when content height > textarea height 1401 self.ui.grow(); 1402 } 1403 1404 if (self.options.css) { 1405 if (String === self.options.css.constructor) { 1406 if ($.browser.msie) { 1407 stylesheet = self.editorDoc.createStyleSheet(self.options.css); 1408 $(stylesheet).attr({ 1409 "media": "all" 1410 }); 1411 } else { 1412 stylesheet = $("<link/>").attr({ 1413 "href": self.options.css, 1414 "media": "all", 1415 "rel": "stylesheet", 1416 "type": "text/css" 1417 }); 1418 1419 $(self.editorDoc).find("head").append(stylesheet); 1420 } 1421 } else { 1422 self.timers.initFrame_Css = window.setTimeout(function () { 1423 $(self.editorDoc.body).css(self.options.css); 1424 }, 0); 1425 } 1426 } 1427 1428 if (self.initialContent.length === 0) { 1429 if ("function" === typeof (self.options.initialContent)) { 1430 self.setContent(self.options.initialContent()); 1431 } else { 1432 self.setContent(self.options.initialContent); 1433 } 1434 } 1435 1436 if (self.options.maxLength > 0) { 1437 $(self.editorDoc).keydown(function (event) { 1438 if ($(self.editorDoc).text().length >= self.options.maxLength && $.inArray(event.which, self.validKeyCodes) === -1) { 1439 event.preventDefault(); 1440 } 1441 }); 1442 } 1443 1444 // Support event callbacks 1445 $.each(self.options.events, function (key, handler) { 1446 $(self.editorDoc).bind(key + ".wysiwyg", function (event) { 1447 // Trigger event handler, providing the event and api to 1448 // support additional functionality. 1449 handler.apply(self.editorDoc, [event, self]); 1450 }); 1451 }); 1452 1453 // restores selection properly on focus 1454 if ($.browser.msie) { 1455 // Event chain: beforedeactivate => focusout => blur. 1456 // Focusout & blur fired too late to handle internalRange() in dialogs. 1457 // When clicked on input boxes both got range = null 1458 $(self.editorDoc).bind("beforedeactivate.wysiwyg", function () { 1459 self.savedRange = self.getInternalRange(); 1460 }); 1461 } else { 1462 $(self.editorDoc).bind("blur.wysiwyg", function () { 1463 self.savedRange = self.getInternalRange(); 1464 }); 1465 } 1466 1467 $(self.editorDoc.body).addClass("wysiwyg"); 1468 if (self.options.events && self.options.events.save) { 1469 saveHandler = self.options.events.save; 1470 1471 $(self.editorDoc).bind("keyup.wysiwyg", saveHandler); 1472 $(self.editorDoc).bind("change.wysiwyg", saveHandler); 1473 1474 if ($.support.noCloneEvent) { 1475 $(self.editorDoc).bind("input.wysiwyg", saveHandler); 1476 } else { 1477 $(self.editorDoc).bind("paste.wysiwyg", saveHandler); 1478 $(self.editorDoc).bind("cut.wysiwyg", saveHandler); 1479 } 1480 } 1481 1482 /** 1483 * XHTML5 {@link https://github.com/akzhan/jwysiwyg/issues/152} 1484 */ 1485 if (self.options.xhtml5 && self.options.unicode) { 1486 var replacements = {ne:8800,le:8804,para:182,xi:958,darr:8595,nu:957,oacute:243,Uacute:218,omega:969,prime:8242,pound:163,igrave:236,thorn:254,forall:8704,emsp:8195,lowast:8727,brvbar:166,alefsym:8501,nbsp:160,delta:948,clubs:9827,lArr:8656,Omega:937,Auml:196,cedil:184,and:8743,plusmn:177,ge:8805,raquo:187,uml:168,equiv:8801,laquo:171,rdquo:8221,Epsilon:917,divide:247,fnof:402,chi:967,Dagger:8225,iacute:237,rceil:8969,sigma:963,Oslash:216,acute:180,frac34:190,lrm:8206,upsih:978,Scaron:352,part:8706,exist:8707,nabla:8711,image:8465,prop:8733,zwj:8205,omicron:959,aacute:225,Yuml:376,Yacute:221,weierp:8472,rsquo:8217,otimes:8855,kappa:954,thetasym:977,harr:8596,Ouml:214,Iota:921,ograve:242,sdot:8901,copy:169,oplus:8853,acirc:226,sup:8835,zeta:950,Iacute:205,Oacute:211,crarr:8629,Nu:925,bdquo:8222,lsquo:8216,apos:39,Beta:914,eacute:233,egrave:232,lceil:8968,Kappa:922,piv:982,Ccedil:199,ldquo:8220,Xi:926,cent:162,uarr:8593,hellip:8230,Aacute:193,ensp:8194,sect:167,Ugrave:217,aelig:230,ordf:170,curren:164,sbquo:8218,macr:175,Phi:934,Eta:919,rho:961,Omicron:927,sup2:178,euro:8364,aring:229,Theta:920,mdash:8212,uuml:252,otilde:245,eta:951,uacute:250,rArr:8658,nsub
1486:8836,agrave:224,notin:8713,ndash:8211,Psi:936,Ocirc:212,sube:8838,szlig:223,micro:181,not:172,sup1:185,middot:183,iota:953,ecirc:234,lsaquo:8249,thinsp:8201,sum:8721,ntilde:241,scaron:353,cap:8745,atilde:227,lang:10216,__replacement:65533,isin:8712,gamma:947,Euml:203,ang:8736,upsilon:965,Ntilde:209,hearts:9829,Alpha:913,Tau:932,spades:9824,dagger:8224,THORN:222,"int":8747,lambda:955,Eacute:201,Uuml:220,infin:8734,rlm:8207,Aring:197,ugrave:249,Egrave:200,Acirc:194,rsaquo:8250,ETH:208,oslash:248,alpha:945,Ograve:210,Prime:8243,mu:956,ni:8715,real:8476,bull:8226,beta:946,icirc:238,eth:240,prod:8719,larr:8592,ordm:186,perp:8869,Gamma:915,reg:174,ucirc:251,Pi:928,psi:968,tilde:732,asymp:8776,zwnj:8204,Agrave:192,deg:176,AElig:198,times:215,Delta:916,sim:8764,Otilde:213,Mu:924,uArr:8657,circ:710,theta:952,Rho:929,sup3:179,diams:9830,tau:964,Chi:935,frac14:188,oelig:339,shy:173,or:8744,dArr:8659,phi:966,iuml:239,Lambda:923,rfloor:8971,iexcl:161,cong:8773,ccedil:231,Icirc:206,frac12:189,loz:9674,rarr:8594,cup:8746,radic:8730,frasl:8260,euml:235,OElig:338,hArr:8660,Atilde:195,Upsilon:933,there4:8756,ouml:246,oline:8254,Ecirc:202,yacute:253,auml:228,permil:8240,sigmaf:962,iquest:191,empty:8709,pi:960,Ucirc:219,supe:8839,Igrave:204,yen:165,rang:10217,trade:8482,lfloor:8970,minus:8722,Zeta:918,sub:8834,epsilon:949,yuml:255,Sigma:931,Iuml:207,ocirc:244}; 1487 self.events.bind("getContent", function (text) { 1488 return text.replace(/&(?:amp;)?(?!amp|lt|gt|quot)([a-z][a-z0-9]*);/gi, function (str, p1) { 1489 if (!replacements[p1]) { 1490 p1 = p1.toLowerCase(); 1491 if (!replacements[p1]) { 1492 p1 = "__replacement"; 1493 } 1494 } 1495 1496 var num = replacements[p1]; 1497 /* Numeric return if ever wanted: return replacements[p1] ? "&#"+num+";" : ""; */ 1498 return String.fromCharCode(num); 1499 }); 1500 }); 1501 } 1502 }; 1503 1504 this.innerDocument = function () { 1505 var element = this.editor.get(0); 1506 1507 if (element.nodeName.toLowerCase() === "iframe") { 1508 if (element.contentDocument) { // Gecko 1509 return element.contentDocument; 1510 } else if (element.contentWindow) { // IE 1511 return element.contentWindow.document; 1512 } 1513 1514 if (this.isDestroyed) { 1515 return null; 1516 } 1517 1518 console.error("Unexpected error in innerDocument"); 1519 1520 /* 1521 return ( $.browser.msie ) 1522 ? document.frames[element.id].document 1523 : element.contentWindow.document // contentDocument; 1524 */ 1525 } 1526 1527 return element; 1528 }; 1529 1530 this.insertHtml = function (szHTML) { 1531 var img, range; 1532 1533 if (!szHTML || szHTML.length === 0) { 1534 return this; 1535 } 1536 1537 if ($.browser.msie) { 1538 this.ui.focus(); 1539 this.editorDoc.execCommand("insertImage", false, "#jwysiwyg#"); 1540 img = this.getElementByAttributeValue("img", "src", "#jwysiwyg#"); 1541 if (img) { 1542 $(img).replaceWith(szHTML); 1543 } 1544 } else { 1545 if ($.browser.mozilla) { // @link https://github.com/akzhan/jwysiwyg/issues/50 1546 if (1 === $(szHTML).length) { 1547 range = this.getInternalRange(); 1548 range.deleteContents(); 1549 range.insertNode($(szHTML).get(0)); 1550 } else { 1551 this.editorDoc.execCommand("insertHTML", false, szHTML); 1552 } 1553 } else { 1554 if (!this.editorDoc.execCommand("insertHTML", false, szHTML)) { 1555 this.editor.focus(); 1556 /* :TODO: place caret at the end 1557 if (window.getSelection) { 1558 } else { 1559 } 1560 this.editor.focus(); 1561 */ 1562 this.editorDoc.execCommand("insertHTML", false, szHTML); 1563 } 1564 } 1565 } 1566 1567 this.saveContent(); 1568 1569 return this; 1570 }; 1571 1572 this.parseControls = function () { 1573 var self = this; 1574 1575 $.each(this.options.controls, function (controlName, control) { 1576 $.each(control, function (propertyName) { 1577 if (-1 === $.inArray(propertyName, self.availableControlProperties)) { 1578 throw controlName + '["' + propertyName + '"]: property "' + propertyName + '" not exists in Wysiwyg.availableControlProperties'; 1579 } 1580 }); 1581 }); 1582 1583 if (this.options.parseControls) { 1584 return this.options.parseControls.call(this); 1585 } 1586 1587 return this.options.controls; 1588 }; 1589 1590 this.removeFormat = function () { 1591 if ($.browser.msie) { 1592 this.ui.focus(); 1593 } 1594 1595 if (this.options.removeHeadings) { 1596 this.editorDoc.execCommand("formatBlock", false, "<p>"); // remove headings 1597 } 1598 1599 this.editorDoc.execCommand("removeFormat", false, null); 1600 this.editorDoc.execCommand("unlink", false, null); 1601 1602 if ($.wysiwyg.rmFormat && $.wysiwyg.rmFormat.enabled) { 1603 if ("object" === typeof (this.options.plugins.rmFormat.rmMsWordMarkup)) { 1604 $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: this.options.plugins.rmFormat.rmMsWordMarkup }}); 1605 } else { 1606 $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: { enabled: true }}}); 1607 } 1608 } 1609 1610 return this; 1611 }; 1612 1613 this.ui.removeHoverClass = function () { 1614 $(this).removeClass("wysiwyg-button-hover"); 1615 }; 1616 1617 this.resetFunction = function () { 1618 this.setContent(this.initialContent); 1619 }; 1620 1621 this.saveContent = function () { 1622 if (this.viewHTML) 1623 { 1624 return; // no need 1625 } 1626 if (this.original) { 1627 var content, newContent; 1628 1629 content = this.getContent(); 1630 1631 if (this.options.rmUnwantedBr) { 1632 content = content.replace(/<br\/?>$/, ""); 1633 } 1634 1635 if (this.options.replaceDivWithP) { 1636 newContent = $("<div/>").addClass("temp").append(content); 1637 1638 newContent.children("div").each(function () { 1639 var element = $(this), p = element.find("p"), i; 1640 1641 if (0 === p.length) { 1642 p = $("<p></p>"); 1643 1644 if (this.attributes.length > 0) { 1645 for (i = 0; i < this.attributes.length; i += 1) { 1646 p.attr(this.attributes[i].name, element.attr(this.attributes[i].name)); 1647 } 1648 } 1649 1650 p.append(element.html()); 1651 1652 element.replaceWith(p); 1653 } 1654 }); 1655 1656 content = newContent.html(); 1657 } 1658 1659 $(this.original).val(content); 1660 1661 if (this.options.events && this.options.events.save) { 1662 this.options.events.save.call(this); 1663 } 1664 } 1665 1666 return this; 1667 }; 1668 1669 this.setContent = function (newContent) { 1670 this.editorDoc.body.innerHTML = newContent; 1671 this.saveContent(); 1672 1673 return this; 1674 }; 1675 1676 this.triggerControl = function (name, control) { 1677 var cmd = control.command || name, 1678 args = control["arguments"] || []; 1679 1680 if (control.exec) { 1681 control.exec.apply(this); 1682 } else { 1683 this.ui.focus(); 1684 this.ui.withoutCss(); 1685 // when click <Cut>, <Copy> or <Paste>
1685 got "Access to XPConnect service denied" code: "1011" 1686 // in Firefox untrusted JavaScript is not allowed to access the clipboard 1687 try { 1688 this.editorDoc.execCommand(cmd, false, args); 1689 } catch (e) { 1690 console.error(e); 1691 } 1692 } 1693 1694 if (this.options.autoSave) { 1695 this.autoSaveFunction(); 1696 } 1697 }; 1698 1699 this.triggerControlCallback = function (name) { 1700 $(window).trigger("trigger-" + name + ".wysiwyg", [this]); 1701 }; 1702 1703 this.ui.withoutCss = function () { 1704 var self = this.self; 1705 1706 if ($.browser.mozilla) { 1707 try { 1708 self.editorDoc.execCommand("styleWithCSS", false, false); 1709 } catch (e) { 1710 try { 1711 self.editorDoc.execCommand("useCSS", false, true); 1712 } catch (e2) { 1713 } 1714 } 1715 } 1716 1717 return self; 1718 }; 1719 1720 this.wrapInitialContent = function () { 1721 var content = this.initialContent, 1722 found = content.match(/<\/?p>/gi); 1723 1724 if (!found) { 1725 return "<p>" + content + "</p>"; 1726 } else { 1727 // :TODO: checking/replacing 1728 } 1729 1730 return content; 1731 }; 1732 } 1733 1734 /* 1735 * Wysiwyg namespace: public properties and methods 1736 */ 1737 $.wysiwyg = { 1738 messages: { 1739 noObject: "Something goes wrong, check object" 1740 }, 1741 1742 /** 1743 * Custom control support by Alec Gorge ( http://github.com/alecgorge ) 1744 */ 1745 addControl: function (object, name, settings) { 1746 return object.each(function () { 1747 var oWysiwyg = $(this).data("wysiwyg"), 1748 customControl = {}, 1749 toolbar; 1750 1751 if (!oWysiwyg) { 1752 return this; 1753 } 1754 1755 customControl[name] = $.extend(true, {visible: true, custom: true}, settings); 1756 $.extend(true, oWysiwyg.options.controls, customControl); 1757 1758 // render new toolbar 1759 toolbar = $(oWysiwyg.options.toolbarHtml); 1760 oWysiwyg.ui.toolbar.replaceWith(toolbar); 1761 oWysiwyg.ui.toolbar = toolbar; 1762 oWysiwyg.ui.appendControls(); 1763 }); 1764 }, 1765 1766 clear: function (object) { 1767 return object.each(function () { 1768 var oWysiwyg = $(this).data("wysiwyg"); 1769 1770 if (!oWysiwyg) { 1771 return this; 1772 } 1773 1774 oWysiwyg.setContent(""); 1775 }); 1776 }, 1777 1778 console: console, // let our console be available for extensions 1779 1780 destroy: function (object) { 1781 return object.each(function () { 1782 var oWysiwyg = $(this).data("wysiwyg"); 1783 1784 if (!oWysiwyg) { 1785 return this; 1786 } 1787 1788 oWysiwyg.destroy(); 1789 }); 1790 }, 1791 1792 "document": function (object) { 1793 // no chains because of return 1794 var oWysiwyg = object.data("wysiwyg"); 1795 1796 if (!oWysiwyg) { 1797 return undefined; 1798 } 1799 1800 return $(oWysiwyg.editorDoc); 1801 }, 1802 1803 getContent: function (object) { 1804 // no chains because of return 1805 var oWysiwyg = object.data("wysiwyg"); 1806 1807 if (!oWysiwyg) { 1808 return undefined; 1809 } 1810 1811 return oWysiwyg.getContent(); 1812 }, 1813 1814 init: function (object, options) { 1815 return object.each(function () { 1816 var opts = $.extend(true, {}, options), 1817 obj; 1818 1819 // :4fun: 1820 // remove this textarea validation and change line in this.saveContent function 1821 // $(this.original).val(content); to $(this.original).html(content); 1822 // now you can make WYSIWYG editor on h1, p, and many more tags 1823 if (("textarea" !== this.nodeName.toLowerCase()) || $(this).data("wysiwyg")) { 1824 return; 1825 } 1826 1827 obj = new Wysiwyg(); 1828 obj.init(this, opts); 1829 $.data(this, "wysiwyg", obj); 1830 1831 $(obj.editorDoc).trigger("afterInit.wysiwyg"); 1832 }); 1833 }, 1834 1835 insertHtml: function (object, szHTML) { 1836 return object.each(function () { 1837 var oWysiwyg = $(this).data("wysiwyg"); 1838 1839 if (!oWysiwyg) { 1840 return this; 1841 } 1842 1843 oWysiwyg.insertHtml(szHTML); 1844 }); 1845 }, 1846 1847 plugin: { 1848 listeners: {}, 1849 1850 bind: function (Wysiwyg) { 1851 var self = this; 1852 1853 $.each(this.listeners, function (action, handlers) { 1854 var i, plugin; 1855 1856 for (i = 0; i < handlers.length; i += 1) { 1857 plugin = self.parseName(handlers[i]); 1858 1859 $(Wysiwyg.editorDoc).bind(action + ".wysiwyg", {plugin: plugin}, function (event) { 1860 $.wysiwyg[event.data.plugin.name][event.data.plugin.method].apply($.wysiwyg[event.data.plugin.name], [Wysiwyg]); 1861 }); 1862 } 1863 }); 1864 }, 1865 1866 exists: function (name) { 1867 var plugin; 1868 1869 if ("string" !== typeof (name)) { 1870 return false;
1871 } 1872 1873 plugin = this.parseName(name); 1874 1875 if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) { 1876 return false; 1877 } 1878 1879 return true; 1880 }, 1881 1882 listen: function (action, handler) { 1883 var plugin; 1884 1885 plugin = this.parseName(handler); 1886 1887 if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) { 1888 return false; 1889 } 1890 1891 if (!this.listeners[action]) { 1892 this.listeners[action] = []; 1893 } 1894 1895 this.listeners[action].push(handler); 1896 1897 return true; 1898 }, 1899 1900 parseName: function (name) { 1901 var elements; 1902 1903 if ("string" !== typeof (name)) { 1904 return false; 1905 } 1906 1907 elements = name.split("."); 1908 1909 if (2 > elements.length) { 1910 return false; 1911 } 1912 1913 return {name: elements[0], method: elements[1]}; 1914 }, 1915 1916 register: function (data) { 1917 if (!data.name) { 1918 console.error("Plugin name missing"); 1919 } 1920 1921 $.each($.wysiwyg, function (pluginName) { 1922 if (pluginName === data.name) { 1923 console.error("Plugin with name '" + data.name + "' was already registered"); 1924 } 1925 }); 1926 1927 $.wysiwyg[data.name] = data; 1928 1929 return true; 1930 } 1931 }, 1932 1933 removeFormat: function (object) { 1934 return object.each(function () { 1935 var oWysiwyg = $(this).data("wysiwyg"); 1936 1937 if (!oWysiwyg) { 1938 return this; 1939 } 1940 1941 oWysiwyg.removeFormat(); 1942 }); 1943 }, 1944 1945 save: function (object) { 1946 return object.each(function () { 1947 var oWysiwyg = $(this).data("wysiwyg"); 1948 1949 if (!oWysiwyg) { 1950 return this; 1951 } 1952 1953 oWysiwyg.saveContent(); 1954 }); 1955 }, 1956 1957 selectAll: function (object) { 1958 var oWysiwyg = object.data("wysiwyg"), oBody, oRange, selection; 1959 1960 if (!oWysiwyg) { 1961 return this; 1962 } 1963 1964 oBody = oWysiwyg.editorDoc.body; 1965 if (window.getSelection) { 1966 selection = oWysiwyg.getInternalSelection(); 1967 selection.selectAllChildren(oBody); 1968 } else { 1969 oRange = oBody.createTextRange(); 1970 oRange.moveToElementText(oBody); 1971 oRange.select(); 1972 } 1973 }, 1974 1975 setContent: function (object, newContent) { 1976 return object.each(function () { 1977 var oWysiwyg = $(this).data("wysiwyg"); 1978 1979 if (!oWysiwyg) { 1980 return this; 1981 } 1982 1983 oWysiwyg.setContent(newContent); 1984 }); 1985 }, 1986 1987 triggerControl: function (object, controlName) { 1988 return object.each(function () { 1989 var oWysiwyg = $(this).data("wysiwyg"); 1990 1991 if (!oWysiwyg) { 1992 return this; 1993 } 1994 1995 if (!oWysiwyg.controls[controlName]) { 1996 console.error("Control '" + controlName + "' not exists"); 1997 } 1998 1999 oWysiwyg.triggerControl.apply(oWysiwyg, [controlName, oWysiwyg.controls[controlName]]); 2000 }); 2001 }, 2002 2003 support: { 2004 prop: supportsProp 2005 }, 2006 2007 utils: { 2008 extraSafeEntities: [["<", ">", "'", '"', " "], [32]], 2009 2010 encodeEntities: function (str) { 2011 var self = this, aStr, aRet = []; 2012 2013 if (this.extraSafeEntities[1].length === 0) { 2014 $.each(this.extraSafeEntities[0], function (i, ch) { 2015 self.extraSafeEntities[1].push(ch.charCodeAt(0)); 2016 }); 2017 } 2018 aStr = str.split(""); 2019 $.each(aStr, function (i) { 2020 var iC = aStr[i].charCodeAt(0); 2021 if ($.inArray(iC, self.extraSafeEntities[1]) && (iC < 65 || iC > 127 || (iC > 90 && iC < 97))) { 2022 aRet.push('&#' + iC + ';'); 2023 } else { 2024 aRet.push(aStr[i]); 2025 } 2026 }); 2027 2028 return aRet.join(''); 2029 } 2030 } 2031 }; 2032 2033 $.fn.wysiwyg = function (method) { 2034 var args = arguments, plugin; 2035 2036 if ("undefined" !== typeof $.wysiwyg[method]) { 2037 // set argument object to undefined 2038 args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1)); 2039 return $.wysiwyg[method].apply($.wysiwyg, Array.prototype.slice.call(args, 1)); 2040 } else if ("object" === typeof method || !method) { 2041 Array.prototype.unshift.call(args, this); 2042 return $.wysiwyg.init.apply($.wysiwyg, args); 2043 } else if ($.wysiwyg.plugin.exists(method)) { 2044 plugin = $.wysiwyg.plugin.parseName(method); 2045 args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1)); 2046 return $.wysiwyg[plugin.name][plugin.method].apply($.wysiwyg[plugin.name], Array.prototype.slice.call(args, 1)); 2047 } else { 2048 console.error("Method '" + method + "' does not exist on jQuery.wysiwyg.\nTry to include some extra controls or plugins"); 2049 } 2050 }; 2051 2052 $.fn.getWysiwyg = function () { 2053 return $.data(this, "wysiwyg"); 2054 }; 2055 })(jQuery); 2056 2057 2058 2059/** 2060 * Controls: Image plugin 2061 * 2062 * Depends on jWYSIWYG 2063 */ 2064(function ($) { 2065 if (undefined === $.wysiwyg) { 2066 throw "wysiwyg.image.js depends on $.wysiwyg"; 2067 } 2068 2069 if (!$.wysiwyg.controls) { 2070 $.wysiwyg.controls = {}; 2071 } 2072 2073 /* 2074 * Wysiwyg namespace: public properties and methods 2075 */ 2076 $.wysiwyg.controls.image = { 2077 init: function (Wysiwyg) { 2078 var self = this, elements, dialog, formImageHtml, dialogReplacements, key, translation, 2079 img = { 2080 alt: "", 2081 self: Wysiwyg.dom.getElement("img"), // link to element node 2082 src: "http://", 2083 title: "" 2084 }; 2085 2086 dialogReplacements = { 2087 legend : "Insert Image", 2088 preview : "Preview", 2089 url : "URL", 2090 title : "Title", 2091 description : "Description", 2092 width : "Width", 2093 height : "Height", 2094 original : "Original W x H", 2095 "float" : "Float", 2096 floatNone : "None", 2097 floatLeft : "Left", 2098 floatRight : "Right", 2099 submit : "Insert Image", 2100 loading : "loading", 2101 reset : "Cancel" 2102 }; 2103 2104 formImageHtml = '<form class="wysiwyg" title="{legend}"><fieldset>' + 2105 '<label><img src="" alt="{preview}" width="100%"></label>' + 2106 '<label>{url}: <input type="text" name="src" value=""></label>' + 2107 '<label>{title}: <input type="text" name="imgtitle" value=""></label>' + 2108 '<label>{description}: <input type="text" name="description" value=""></label>' + 2109 '<label>{width} x {height}: <input type="text" name="width" value="" class="width integer"> x <input type="text" name="height" value="" class="height integer"></label><br>' + 2110 '<label>{float}: <select name="float">' + 2111 '<option value="">{floatNone}</option>' + 2112 '<option value="left">{floatLeft}</option>' + 2113 '<option value="right">{floatRight}</option></select></label><hr>' + 2114 '<button class="button" id="wysiwyg_submit">{submit}</button> ' + 2115 '<button class="button" id="wysiwyg_reset">{reset}</button></fieldset></form>'; 2116 2117 for (key in dialogReplacements) { 2118 if ($.wysiwyg.i18n) { 2119 translation = $.wysiwyg.i18n.t(dialogReplacements[key], "dialogs.image"); 2120 2121 if (translation === dialogReplacements[key]) { // if not translated search in dialogs 2122 translation = $.wysiwyg.i18n.t(dialogReplacements[key], "dialogs"); 2123 } 2124 2125 dialogReplacements[key] = translation; 2126 } 2127 2128 formImageHtml = formImageHtml.replace("{" + key + "}", dialogReplacements[key]); 2129 } 2130 2131 if (img.self) { 2132 img.src = img.self.src ? img.self.src : ""; 2133 img.alt = img.self.alt ? img.self.alt : ""; 2134 img.title = img.self.title ? img.self.title : ""; 2135 img.width = img.self.width ? img.self.width : ""; 2136 img.height = img.self.height ? img.self.height : ""; 2137 img.asp = img.width/img.width; 2138 } 2139 2140 if ($.modal) { 2141 elements = $(formImageHtml); 2142 elements = self.makeForm(elements, img); 2143 2144 $.modal(elements, { 2145 onShow: function (dialog) { 2146 $("#wysiwyg_submit", dialog.data).click(function (e) { 2147 self.processInsert(dialog.container, Wysiwyg, img); 2148 2149 $.modal.close(); 2150 return false;
2151 }); 2152 $("#wysiwyg_reset", dialog.data).click(function (e) { 2153 $.modal.close(); 2154 return false; 2155 }); 2156 $("fieldset", dialog.data).click(function (e) { 2157 e.stopPropagation(); 2158 }); 2159 2160 $("select, input[type=text]", dialog).uniform(); 2161 $('.integer', dialog).wl_Number(); 2162 $('input[name="src"]', dialog).wl_URL(); 2163 2164 }, 2165 maxWidth: Wysiwyg.defaults.formWidth, 2166 maxHeight: Wysiwyg.defaults.formHeight, 2167 overlayClose: true 2168 }); 2169 } else if ($.fn.dialog) { 2170 elements = $(formImageHtml); 2171 elements = self.makeForm(elements, img); 2172 2173 dialog = elements.appendTo("body"); 2174 dialog.dialog({ 2175 modal: true, 2176 resizable: false, 2177 open: function (ev, ui) { 2178 $("#wysiwyg_submit", dialog).click(function (e) { 2179 self.processInsert(dialog.container, Wysiwyg, img); 2180 2181 $(dialog).dialog("close"); 2182 return false; 2183 }); 2184 $("#wysiwyg_reset", dialog).click(function (e) { 2185 $(dialog).dialog("close"); 2186 return false; 2187 }); 2188 $('fieldset', dialog).click(function (e) { 2189 e.stopPropagation(); 2190 }); 2191 $("select, input[type=text]", dialog).uniform(); 2192 $('.width', dialog).wl_Number({ 2193 step:10, 2194 onChange:function(value){ 2195 $('.height', dialog).val(Math.ceil(value/(img.asp || 1))); 2196 } 2197 }); 2198 $('.height', dialog).wl_Number({ 2199 step:10, 2200 onChange:function(value){ 2201 $('.width', dialog).val(Math.floor(value*(img.asp || 1))); 2202 } 2203 }); 2204 $('input[name="src"]', dialog).wl_URL(); 2205 2206 }, 2207 close: function (ev, ui) { 2208 dialog.dialog("destroy"); 2209 dialog.remove(); 2210 } 2211 }); 2212 } else { 2213 if ($.browser.msie) { 2214 Wysiwyg.ui.focus(); 2215 Wysiwyg.editorDoc.execCommand("insertImage", true, null); 2216 } else { 2217 elements = $("<div/>") 2218 .css({"position": "fixed", 2219 "z-index": 2000, 2220 "left": "50%", "top": "50%", "background": "rgb(0, 0, 0)", 2221 "margin-top": -1 * Math.round(Wysiwyg.defaults.formHeight / 2), 2222 "margin-left": -1 * Math.round(Wysiwyg.defaults.formWidth / 2)}) 2223 .html(formImageHtml); 2224 elements = self.makeForm(elements, img); 2225 2226 $("#wysiwyg_submit", elements).click(function (event) { 2227 self.processInsert(elements, Wysiwyg, img); 2228 2229 $(elements).remove(); 2230 return false; 2231 }); 2232 $("#wysiwyg_reset", elements).click(function (event) { 2233 if ($.browser.msie) { 2234 Wysiwyg.ui.returnRange(); 2235 } 2236 2237 $(elements).remove(); 2238 return false; 2239 }); 2240 2241 $("select, input[type=text]", dialog).uniform(); 2242 $('.integer', dialog).wl_Number(); 2243 $('input[name="src"]', dialog).wl_URL(); 2244 2245 $("body").append(elements); 2246 elements.click(function(e) { 2247 e.stopPropagation(); 2248 }); 2249 } 2250 } 2251 2252 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2253 }, 2254 2255 processInsert: function (context, Wysiwyg, img) { 2256 var image, 2257 url = $('input[name="src"]', context).val(), 2258 title = $('input[name="imgtitle"]', context).val(), 2259 description = $('input[name="description"]', context).val(), 2260 width = $('input[name="width"]', context).val(), 2261 height = $('input[name="height"]', context).val(), 2262 styleFloat = $('select[name="float"]', context).val(), 2263 style = [], 2264 found, 2265 baseUrl; 2266 2267 if (Wysiwyg.options.controlImage.forceRelativeUrls) { 2268 baseUrl = window.location.protocol + "//" + window.location.hostname; 2269 if (0 === url.indexOf(baseUrl)) { 2270 url = url.substr(baseUrl.length); 2271 } 2272 } 2273 2274 if (img.self) { 2275 // to preserve all img attributes 2276 $(img.self).attr("src", url) 2277 .attr("title", title) 2278 .attr("alt", description) 2279 .css("float", styleFloat); 2280 2281 if (width.toString().match(/^[0-9]+(px|%)?$/)) { 2282 $(img.self).css("width", width); 2283 } else { 2284 $(img.self).css("width", ""); 2285 } 2286 2287 if (height.toString().match(/^[0-9]+(px|%)?$/)) { 2288 $(img.self).css("height", height); 2289 } else { 2290 $(img.self).css("height", ""); 2291 } 2292 2293 Wysiwyg.saveContent(); 2294 } else { 2295 found = width.toString().match(/^[0-9]+(px|%)?$/); 2296 if (found) { 2297 if (found[1]) { 2298 style.push("width: " + width + ";"); 2299 } else { 2300 style.push("width: " + width + "px;"); 2301 } 2302 } 2303 2304 found = height.toString().match(/^[0-9]+(px|%)?$/); 2305 if (found) { 2306 if (found[1]) { 2307 style.push("height: " + height + ";"); 2308 } else { 2309 style.push("height: " + height + "px;"); 2310 } 2311 } 2312 2313 if (styleFloat.length > 0) { 2314 style.push("float: " + styleFloat + ";"); 2315 } 2316 2317 if (style.length > 0) { 2318 style = ' style="' + style.join(" ") + '"'; 2319 } 2320 2321 image = "<img src='" + url + "' title='" + title + "' alt='" + description + "'" + style + "/>"; 2322 Wysiwyg.insertHtml(image); 2323 } 2324 }, 2325 2326 makeForm: function (form, img) { 2327 form.find("input[name=src]").val(img.src); 2328 form.find("input[name=imgtitle]").val(img.title); 2329 form.find("input[name=description]").val(img.alt); 2330 form.find('input[name="width"]').val(img.width); 2331 form.find('input[name="height"]').val(img.height); 2332 form.find('img').attr("src", img.src); 2333 img.asp = img.width/img.height; 2334 2335 form.find("input[name=src]").bind("change", function () { 2336 var image = new Image(); 2337 var text = $('#wysiwyg_submit',form).find('span').text(); 2338 form.find('img').removeAttr("src"); 2339 2340 $('#wysiwyg_submit',form).prop('disabled',true).find('span').text('wait...'); 2341 2342 image.onload = function(){ 2343 2344 form.find('img').attr("src", image.src); 2345 img.asp = image.width/image.height;
2346 form.find('input[name="width"]').val(image.width); 2347 form.find('input[name="height"]').val(image.height); 2348 $('#wysiwyg_submit',form).find('span').text(text); 2349 $('#wysiwyg_submit',form).prop('disabled',false); 2350 2351 }; 2352 image.src = this.value; 2353 }); 2354 2355 return form; 2356 } 2357 }; 2358 2359 $.wysiwyg.insertImage = function (object, url, attributes) { 2360 return object.each(function () { 2361 var Wysiwyg = $(this).data("wysiwyg"), 2362 image, 2363 attribute; 2364 2365 if (!Wysiwyg) { 2366 return this; 2367 } 2368 2369 if (!url || url.length === 0) { 2370 return this; 2371 } 2372 2373 if ($.browser.msie) { 2374 Wysiwyg.ui.focus(); 2375 } 2376 2377 if (attributes) { 2378 Wysiwyg.editorDoc.execCommand("insertImage", false, "#jwysiwyg#"); 2379 image = Wysiwyg.getElementByAttributeValue("img", "src", "#jwysiwyg#"); 2380 2381 if (image) { 2382 image.src = url; 2383 2384 for (attribute in attributes) { 2385 if (attributes.hasOwnProperty(attribute)) { 2386 image.setAttribute(attribute, attributes[attribute]); 2387 } 2388 } 2389 } 2390 } else { 2391 Wysiwyg.editorDoc.execCommand("insertImage", false, url); 2392 } 2393 2394 Wysiwyg.saveContent(); 2395 2396 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2397 2398 return this; 2399 }); 2400 }; 2401})(jQuery); 2402 2403 2404/** 2405 * Controls: Table plugin 2406 * 2407 * Depends on jWYSIWYG 2408 */ 2409(function ($) { 2410 if (undefined === $.wysiwyg) { 2411 throw "wysiwyg.table.js depends on $.wysiwyg"; 2412 } 2413 2414 if (!$.wysiwyg.controls) { 2415 $.wysiwyg.controls = {}; 2416 } 2417 2418 var insertTable = function (colCount, rowCount, filler) { 2419 if (isNaN(rowCount) || isNaN(colCount) || rowCount === null || colCount === null) { 2420 return; 2421 } 2422 2423 var i, j, html = ['<table border="1" style="width: 100%;"><tbody>']; 2424 2425 colCount = parseInt(colCount, 10); 2426 rowCount = parseInt(rowCount, 10); 2427 2428 if (filler === null) { 2429 filler = " "; 2430 } 2431 filler = "<td>" + filler + "</td>"; 2432 2433 for (i = rowCount; i > 0; i -= 1) { 2434 html.push("<tr>"); 2435 for (j = colCount; j > 0; j -= 1) { 2436 html.push(filler); 2437 } 2438 html.push("</tr>"); 2439 } 2440 html.push("</tbody></table>"); 2441 2442 return this.insertHtml(html.join("")); 2443 }; 2444 2445 /* 2446 * Wysiwyg namespace: public properties and methods 2447 */ 2448 $.wysiwyg.controls.table = function (Wysiwyg) { 2449 var dialog, colCount, rowCount, formTableHtml, 2450 formTextLegend = "Insert table", 2451 formTextCols = "Count of columns", 2452 formTextRows = "Count of rows", 2453 formTextSubmit = "Insert table", 2454 formTextReset = "Cancel"; 2455 2456 if ($.wysiwyg.i18n) { 2457 formTextLegend = $.wysiwyg.i18n.t(formTextLegend, "dialogs.table"); 2458 formTextCols = $.wysiwyg.i18n.t(formTextCols, "dialogs.table"); 2459 formTextRows = $.wysiwyg.i18n.t(formTextRows, "dialogs.table"); 2460 formTextSubmit = $.wysiwyg.i18n.t(formTextSubmit, "dialogs.table"); 2461 formTextReset = $.wysiwyg.i18n.t(formTextReset, "dialogs"); 2462 } 2463 2464 formTableHtml = '<form class="wysiwyg" title="' + formTextLegend + '"><fieldset>' + 2465 '<label>' + formTextCols + ': <input type="text" name="colCount" value="3" class="integer" /></label><br>' + 2466 '<label>' + formTextRows + ': <input type="text" name="rowCount" value="3" class="integer" /></label><hr>' + 2467 '<button class="button" id="wysiwyg_submit">' + formTextSubmit + '</button> ' + 2468 '<button class="button" id="wysiwyg_reset">' + formTextReset + '</button></fieldset></form>'; 2469 2470 if (!Wysiwyg.insertTable) { 2471 Wysiwyg.insertTable = insertTable; 2472 } 2473 2474 if ($.fn.modal) { 2475 $.modal(formTableHtml, { 2476 onShow: function (dialog) { 2477 $("#wysiwyg_submit", dialog.data).click(function (e) { 2478 e.preventDefault(); 2479 rowCount = $('input[name="rowCount"]', dialog.data).val(); 2480 colCount = $('input[name="colCount"]', dialog.data).val(); 2481 2482 Wysiwyg.insertTable(colCount, rowCount, Wysiwyg.defaults.tableFiller); 2483 $.modal.close(); 2484 }); 2485 $("#wysiwyg_reset", dialog.data).click(function (e) { 2486 e.preventDefault(); 2487 $.modal.close(); 2488 }); 2489 2490 $("select, input[type=text]", dialog).uniform(); 2491 $('.integer', dialog).wl_Number(); 2492 2493 }, 2494 maxWidth: Wysiwyg.defaults.formWidth, 2495 maxHeight: Wysiwyg.defaults.formHeight, 2496 overlayClose: true 2497 }); 2498 } else if ($.fn.dialog) { 2499 dialog = $(formTableHtml).appendTo("body"); 2500 dialog.dialog({ 2501 modal: true, 2502 resizable: false, 2503 open: function (event, ui) { 2504 $("#wysiwyg_submit", dialog).click(function (e) { 2505 e.preventDefault(); 2506 rowCount = $('input[name="rowCount"]', dialog).val(); 2507 colCount = $('input[name="colCount"]', dialog).val(); 2508 2509 Wysiwyg.insertTable(colCount, rowCount, Wysiwyg.defaults.tableFiller); 2510 $(dialog).dialog("close"); 2511 }); 2512 $("#wysiwyg_reset", dialog).click(function (e) { 2513 e.preventDefault(); 2514 $(dialog).dialog("close"); 2515 }); 2516 2517 $("select, input[type=text]", dialog).uniform(); 2518 $('.integer', dialog).wl_Number(); 2519 2520 }, 2521 close: function (event, ui) { 2522 dialog.dialog("destroy"); 2523 dialog.remove(); 2524 } 2525 }); 2526 } else {
2527 colCount = prompt(formTextCols, "3"); 2528 rowCount = prompt(formTextRows, "3"); 2529 2530 Wysiwyg.insertTable(colCount, rowCount, Wysiwyg.defaults.tableFiller); 2531 } 2532 2533 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2534 }; 2535 2536 $.wysiwyg.insertTable = function (object, colCount, rowCount, filler) { 2537 return object.each(function () { 2538 var Wysiwyg = $(this).data("wysiwyg"); 2539 2540 if (!Wysiwyg.insertTable) { 2541 Wysiwyg.insertTable = insertTable; 2542 } 2543 2544 if (!Wysiwyg) { 2545 return this; 2546 } 2547 2548 Wysiwyg.insertTable(colCount, rowCount, filler); 2549 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2550 2551 return this; 2552 }); 2553 }; 2554})(jQuery); 2555 2556/** 2557 * Controls: Link plugin 2558 * 2559 * Depends on jWYSIWYG 2560 * 2561 * By: Esteban Beltran (academo) <[email protected]> 2562 */ 2563(function ($) { 2564 if (undefined === $.wysiwyg) { 2565 throw "wysiwyg.link.js depends on $.wysiwyg"; 2566 } 2567 2568 if (!$.wysiwyg.controls) { 2569 $.wysiwyg.controls = {}; 2570 } 2571 2572 /* 2573 * Wysiwyg namespace: public properties and methods 2574 */ 2575 $.wysiwyg.controls.link = { 2576 init: function (Wysiwyg) { 2577 var self = this, elements, dialog, url, a, selection, 2578 formLinkHtml, formTextLegend, formTextUrl, formTextTitle, formTextTarget, 2579 formTextSubmit, formTextReset, 2580 baseUrl; 2581 2582 formTextLegend = "Insert Link"; 2583 formTextUrl = "Link URL"; 2584 formTextTitle = "Link Title"; 2585 formTextTarget = "Link Target"; 2586 formTextSubmit = "Insert Link"; 2587 formTextReset = "Cancel"; 2588 2589 if ($.wysiwyg.i18n) { 2590 formTextLegend = $.wysiwyg.i18n.t(formTextLegend, "dialogs.link"); 2591 formTextUrl = $.wysiwyg.i18n.t(formTextUrl, "dialogs.link"); 2592 formTextTitle = $.wysiwyg.i18n.t(formTextTitle, "dialogs.link"); 2593 formTextTarget = $.wysiwyg.i18n.t(formTextTarget, "dialogs.link"); 2594 formTextSubmit = $.wysiwyg.i18n.t(formTextSubmit, "dialogs.link"); 2595 formTextReset = $.wysiwyg.i18n.t(formTextReset, "dialogs"); 2596 } 2597 2598 formLinkHtml = '<form class="wysiwyg" title="' + formTextLegend + '"><fieldset>' + 2599 '<label>' + formTextUrl + ': <input type="text" name="linkhref" value=""/></label>' + 2600 '<label>' + formTextTitle + ': <input type="text" name="linktitle" value=""/></label>' + 2601 '<label>' + formTextTarget + ': <input type="text" name="linktarget" value=""/></label><hr>' + 2602 '<button class="button" id="wysiwyg_submit">' + formTextSubmit + '</button> ' + 2603 '<button class="button" id="wysiwyg_reset">' + formTextReset + '</button></fieldset></form>'; 2604 2605 a = { 2606 self: Wysiwyg.dom.getElement("a"), // link to element node 2607 href: "http://", 2608 title: "", 2609 target: "" 2610 }; 2611 2612 if (a.self) { 2613 a.href = a.self.href ? a.self.href : a.href; 2614 a.title = a.self.title ? a.self.title : ""; 2615 a.target = a.self.target ? a.self.target : ""; 2616 } 2617 2618 if ($.fn.dialog) { 2619 elements = $(formLinkHtml); 2620 elements.find("input[name=linkhref]").val(a.href); 2621 elements.find("input[name=linktitle]").val(a.title); 2622 elements.find("input[name=linktarget]").val(a.target); 2623 2624 if ($.browser.msie) { 2625 dialog = elements.appendTo(Wysiwyg.editorDoc.body); 2626 } else { 2627 dialog = elements.appendTo("body"); 2628 } 2629 2630 dialog.dialog({ 2631 modal: true, 2632 resizable: false, 2633 open: function (ev, ui) { 2634 $("#wysiwyg_submit", dialog).click(function (e) { 2635 e.preventDefault(); 2636 2637 var url = $('input[name="linkhref"]', dialog).val(), 2638 title = $('input[name="linktitle"]', dialog).val(), 2639 target = $('input[name="linktarget"]', dialog).val(), 2640 baseUrl; 2641 2642 if (Wysiwyg.options.controlLink.forceRelativeUrls) { 2643 baseUrl = window.location.protocol + "//" + window.location.hostname; 2644 if (0 === url.indexOf(baseUrl)) { 2645 url = url.substr(baseUrl.length); 2646 } 2647 } 2648 2649 if (a.self) { 2650 if ("string" === typeof (url)) { 2651 if (url.length > 0) { 2652 // to preserve all link attributes 2653 $(a.self).attr("href", url).attr("title", title).attr("target", target); 2654 } else { 2655 $(a.self).replaceWith(a.self.innerHTML); 2656 } 2657 } 2658 } else { 2659 if ($.browser.msie) { 2660 Wysiwyg.ui.returnRange(); 2661 } 2662 2663 //Do new link element 2664 selection = Wysiwyg.getRangeText(); 2665 img = Wysiwyg.dom.getElement("img"); 2666 2667 if ((selection && selection.length > 0) || img) { 2668 if ($.browser.msie) { 2669 Wysiwyg.ui.focus(); 2670 } 2671 2672 if ("string" === typeof (url)) { 2673 if (url.length > 0) { 2674 Wysiwyg.editorDoc.execCommand("createLink", false, url); 2675 } else { 2676 Wysiwyg.editorDoc.execCommand("unlink", false, null); 2677 } 2678 } 2679 2680 a.self = Wysiwyg.dom.getElement("a"); 2681 2682 $(a.self).attr("href", url).attr("title", title); 2683 2684 /** 2685 * @url https://github.com/akzhan/jwysiwyg/issues/16 2686 */ 2687 $(a.self).attr("target", target); 2688 } else if (Wysiwyg.options.messages.nonSelection) { 2689 $.dialog(Wysiwyg.options.messages.nonSelection); 2690 } 2691 } 2692 2693 Wysiwyg.saveContent(); 2694 2695 $(dialog).dialog("close"); 2696 }); 2697 $("#wysiwyg_reset", dialog).click(function (e) { 2698 e.preventDefault(); 2699 $(dialog).dialog("close"); 2700 }); 2701 2702 $("select, input", dialog).uniform(); 2703 $('input[name="linkhref"]', dialog).wl_URL(); 2704 2705 }, 2706 close: function (ev, ui) { 2707 dialog.dialog("destroy"); 2708 dialog.remove(); 2709 } 2710 }); 2711 } else { 2712 if (a.self) { 2713 url = window.prompt("URL", a.href); 2714
2715 if (Wysiwyg.options.controlLink.forceRelativeUrls) { 2716 baseUrl = window.location.protocol + "//" + window.location.hostname; 2717 if (0 === url.indexOf(baseUrl)) { 2718 url = url.substr(baseUrl.length); 2719 } 2720 } 2721 2722 if ("string" === typeof (url)) { 2723 if (url.length > 0) { 2724 $(a.self).attr("href", url); 2725 } else { 2726 $(a.self).replaceWith(a.self.innerHTML); 2727 } 2728 } 2729 } else { 2730 //Do new link element 2731 selection = Wysiwyg.getRangeText(); 2732 img = Wysiwyg.dom.getElement("img"); 2733 2734 if ((selection && selection.length > 0) || img) { 2735 if ($.browser.msie) { 2736 Wysiwyg.ui.focus(); 2737 Wysiwyg.editorDoc.execCommand("createLink", true, null); 2738 } else { 2739 url = window.prompt(formTextUrl, a.href); 2740 2741 if (Wysiwyg.options.controlLink.forceRelativeUrls) { 2742 baseUrl = window.location.protocol + "//" + window.location.hostname; 2743 if (0 === url.indexOf(baseUrl)) { 2744 url = url.substr(baseUrl.length); 2745 } 2746 } 2747 2748 if ("string" === typeof (url)) { 2749 if (url.length > 0) { 2750 Wysiwyg.editorDoc.execCommand("createLink", false, url); 2751 } else { 2752 Wysiwyg.editorDoc.execCommand("unlink", false, null); 2753 } 2754 } 2755 } 2756 } else if (Wysiwyg.options.messages.nonSelection) { 2757 window.alert(Wysiwyg.options.messages.nonSelection); 2758 } 2759 } 2760 2761 Wysiwyg.saveContent(); 2762 } 2763 2764 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2765 } 2766 }; 2767 2768 $.wysiwyg.createLink = function (object, url) { 2769 return object.each(function () { 2770 var oWysiwyg = $(this).data("wysiwyg"), 2771 selection; 2772 2773 if (!oWysiwyg) { 2774 return this; 2775 } 2776 2777 if (!url || url.length === 0) { 2778 return this; 2779 } 2780 2781 selection = oWysiwyg.getRangeText(); 2782 2783 if (selection && selection.length > 0) { 2784 if ($.browser.msie) { 2785 oWysiwyg.ui.focus(); 2786 } 2787 oWysiwyg.editorDoc.execCommand("unlink", false, null); 2788 oWysiwyg.editorDoc.execCommand("createLink", false, url); 2789 } else if (oWysiwyg.options.messages.nonSelection) { 2790 window.alert(oWysiwyg.options.messages.nonSelection); 2791 } 2792 }); 2793 }; 2794})(jQuery); 2795 2796/** 2797 * Controls: Element CSS Wrapper plugin 2798 * 2799 * Depends on jWYSIWYG 2800 * 2801 * By Yotam Bar-On (https://github.com/tudmotu) 2802 */ 2803(function ($) { 2804 if (undefined === $.wysiwyg) { 2805 throw "wysiwyg.cssWrap.js depends on $.wysiwyg"; 2806 } 2807 /* For core enhancements #143 2808 $.wysiwyg.ui.addControl("cssWrap", { 2809 visible : false, 2810 groupIndex: 6, 2811 tooltip: "CSS Wrapper", 2812 exec: function () { 2813 $.wysiwyg.controls.cssWrap.init(this); 2814 } 2815 } 2816 */ 2817 if (!$.wysiwyg.controls) { 2818 $.wysiwyg.controls = {}; 2819 } 2820 2821 /* 2822 * Wysiwyg namespace: public properties and methods 2823 */ 2824 $.wysiwyg.controls.cssWrap = { 2825 init: function (Wysiwyg) { 2826 var self = this, formWrapHtml, key, translation, 2827 dialogReplacements = { 2828 legend : "Wrap Element", 2829 wrapperType : "Wrapper Type", 2830 ID : "ID", 2831 "class" : "Class", 2832 wrap : "Wrap", 2833 unwrap: "Unwrap", 2834 cancel : "Cancel" 2835 }; 2836 2837 formWrapHtml = '<form class="wysiwyg" title="{legend}"><fieldset>' + 2838 '<label>{wrapperType}:<select name="type"><option value="span">Span</option><option value="div">Div</option></select></label><br>' + 2839 '<label>{ID}:<input name="id" type="text"></label>' + 2840 '<label>{class}:<input name="class" type="text" ></label><hr>' + 2841 '<button class="cssWrap-unwrap" style="display:none;">{unwrap}</button> ' + 2842 '<button class="cssWrap-submit">{wrap}</button> ' + 2843 '<button class="cssWrap-cancel">{cancel}</button></fieldset></form>'; 2844 2845 for (key in dialogReplacements) { 2846 if ($.wysiwyg.i18n) { 2847 translation = $.wysiwyg.i18n.t(dialogReplacements[key]); 2848 if (translation === dialogReplacements[key]) { // if not translated search in dialogs 2849 translation = $.wysiwyg.i18n.t(dialogReplacements[key], "dialogs"); 2850 } 2851 dialogReplacements[key] = translation; 2852 } 2853 formWrapHtml = formWrapHtml.replace("{" + key + "}", dialogReplacements[key]); 2854 } 2855 if (!$(".wysiwyg-dialog-wrapper").length) { 2856 $(formWrapHtml).appendTo("body"); 2857 $("form.wysiwyg").dialog({ 2858 modal: true, 2859 resizable: false, 2860 open: function (ev, ui) { 2861 $this = $(this); 2862 var range = Wysiwyg.getInternalRange(), common; 2863 // We make sure that there is some selection: 2864 if (range) { 2865 if ($.browser.msie) { 2866 Wysiwyg.ui.focus(); 2867 } 2868 common = $(range.commonAncestorContainer); 2869 } else { 2870 alert("You must select some elements before you can wrap them."); 2871 $this.dialog("close"); 2872 return 0; 2873 } 2874 var $nodeName = range.commonAncestorContainer.nodeName.toLowerCase(); 2875 // If the selection is already a .wysiwygCssWrapper, then we want to change it and not double-wrap it. 2876 if (common.parent(".wysiwygCssWrapper").length) { 2877 alert(common.parent(".wysiwygCssWrapper").get(0).nodeName.toLowerCase()); 2878 $this.find("select[name=type]").val(common.parent(".wysiwygCssWrapper").get(0).nodeName.toLowerCase()); 2879 $this.find("select[name=type]").attr("disabled", "disabled"); 2880 $this.find("input[name=id]").val(common.parent(".wysiwygCssWrapper").attr("id")); 2881 $this.find("input[name=class]").val(common.parent(".wysiwygCssWrapper").attr("class").replace('wysiwygCssWrapper ', '')); 2882 // Add the "unwrap" button: 2883 $("form.wysiwyg").find(".cssWrap-unwrap").show(); 2884 $("form.wysiwyg").find(".cssWrap-unwrap").click(function(e) { 2885 e.preventDefault(); 2886 if ($nodeName !== "body") { 2887 common.unwrap(); 2888 } 2889 $this.dialog("close"); 2890 return 1; 2891 }); 2892 } 2893 // Submit button. 2894 $("form.wysiwyg").find(".cssWrap-submit").click(function(e) { 2895 e.preventDefault(); 2896 var $wrapper = $("form.wysiwyg").find("select[name=type]").val(); 2897 var $id = $("form.wysiwyg").find("input[name=id]").val(); 2898 var $class = $("form.wysiwyg").find("input[name=class]").val(); 2899 if ($nodeName !== "body") { 2900 // If the selection is already a .wysiwygCssWrapper, then we want to change it and not double-wrap it. 2901 if (common.parent(".wysiwygCssWrapper").length) { 2902 common.parent(".wysiwygCssWrapper").attr("id", $class); 2903 common.parent(".wysiwygCssWrapper").attr("class", $class); 2904 } else { 2905 common.wrap('<'+$wrapper+' id="'+$id+'" class="'+"wysiwygCssWrapper "+$class+'"/>'); 2906 } 2907 } else { 2908 // Currently no implemntation for if $nodeName == 'body'. 2909 } 2910 $this.dialog("close"); 2911 }); 2912 // Cancel button. 2913 $("form.wysiwyg").find(".cssWrap-cancel").click(function(e) { 2914 e.preventDefault(); 2915 $this.dialog("close"); 2916 return 1; 2917 }); 2918 $("form.wysiwyg").find("select, input[type=text]").uniform(); 2919 }, 2920 close: function () { 2921 $(this).dialog("destroy"); 2922 $(this).remove(); 2923 } 2924 }); 2925 Wysiwyg.saveContent(); 2926 } 2927 $(Wysiwyg.editorDoc).trigger("editorRefresh.wysiwyg"); 2928 return 1; 2929 } 2930 } 2931})(jQuery); 2932});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.