META-INF.resources.scripts.vendor.plugins.wysiwyg.jquery.wysiwyg.js Maven / Gradle / Ivy
/**
* WYSIWYG - jQuery plugin 0.97
* (0.97.2 - From infinity)
*
* Copyright (c) 2008-2009 Juan M Martinez, 2010-2011 Akzhan Abdulin and all contributors
* https://github.com/akzhan/jwysiwyg
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/*jslint browser: true, forin: true */
(function ( $ ) {
"use strict";
/* Wysiwyg namespace: private properties and methods */
var console = window.console ? window.console : {
log: $.noop,
error: function ( msg ) {
$.error( msg );
}
};
var supportsProp = (('prop' in $.fn) && ('removeProp' in $.fn));
function Wysiwyg() {
// - the item is added by this.ui.appendControls and then appendItem
// - click triggers this.triggerControl
// cmd or[key] - designMode exec function name
// tags - activates control for these tags (@see checkTargets)
// css - activates control if one of css is applied
this.controls = {
bold: {
groupIndex: 0,
visible: true,
tags: ["b", "strong"],
css: {
fontWeight: "bold"
},
tooltip: "Bold",
hotkey: {"ctrl": 1, "key": 66}
},
copy: {
groupIndex: 8,
visible: false,
tooltip: "Copy"
},
createLink: {
groupIndex: 6,
visible: true,
exec: function () {
var self = this;
if ( $.wysiwyg.controls && $.wysiwyg.controls.link ) {
$.wysiwyg.controls.link.init( this );
} else if ( $.wysiwyg.autoload ) {
$.wysiwyg.autoload.control( "wysiwyg.link.js", function () {
self.controls.createLink.exec.apply( self );
} );
} else {
console.error( "$.wysiwyg.controls.link not defined. You need to include wysiwyg.link.js file" );
}
},
tags: ["a"],
tooltip: "Create link"
},
cut: {
groupIndex: 8,
visible: false,
tooltip: "Cut"
},
decreaseFontSize: {
groupIndex: 9,
visible: false,
tags: ["small"],
tooltip: "Decrease font size",
exec: function () {
this.decreaseFontSize();
}
},
h1: {
groupIndex: 7,
visible: true,
className: "h1",
command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
"arguments": ($.browser.msie || $.browser.safari) ? "" : "h1",
tags: ["h1"],
tooltip: "Header 1"
},
h2: {
groupIndex: 7,
visible: true,
className: "h2",
command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
"arguments": ($.browser.msie || $.browser.safari) ? "" : "h2",
tags: ["h2"],
tooltip: "Header 2"
},
h3: {
groupIndex: 7,
visible: true,
className: "h3",
command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
"arguments": ($.browser.msie || $.browser.safari) ? "" : "h3",
tags: ["h3"],
tooltip: "Header 3"
},
highlight: {
tooltip: "Highlight",
className: "highlight",
groupIndex: 1,
visible: false,
css: {
backgroundColor: "rgb(255, 255, 102)"
},
exec: function () {
var command, node, selection, args;
if ( $.browser.msie || $.browser.safari ) {
command = "backcolor";
} else {
command = "hilitecolor";
}
if ( $.browser.msie ) {
node = this.getInternalRange().parentElement();
} else {
selection = this.getInternalSelection();
node = selection.extentNode || selection.focusNode;
while ( node.style === undefined ) {
node = node.parentNode;
if ( node.tagName && node.tagName.toLowerCase() === "body" ) {
return;
}
}
}
if ( node.style.backgroundColor === "rgb(255, 255, 102)" || node.style.backgroundColor === "#ffff66" ) {
args = "#ffffff";
} else {
args = "#ffff66";
}
this.editorDoc.execCommand( command, false, args );
}
},
html: {
groupIndex: 10,
visible: false,
exec: function () {
var elementHeight;
if ( this.options.resizeOptions && $.fn.resizable ) {
elementHeight = this.element.height();
}
if ( this.viewHTML ) { //textarea is shown
this.setContent( this.original.value );
$( this.original ).hide();
this.editor.show();
if ( this.options.resizeOptions && $.fn.resizable ) {
// if element.height still the same after frame was shown
if ( elementHeight === this.element.height() ) {
this.element.height( elementHeight + this.editor.height() );
}
this.element.resizable( $.extend( true, {
alsoResize: this.editor
}, this.options.resizeOptions ) );
}
this.ui.toolbar.find( "li" ).each( function () {
var li = $( this );
if ( li.hasClass( "html" ) ) {
li.removeClass( "active" );
} else {
li.removeClass( 'disabled' );
}
} );
} else { //wysiwyg is shown
this.saveContent();
$( this.original ).css( {
width: this.element.outerWidth() - 6,
height: this.element.height() - this.ui.toolbar.height() - 6,
resize: "none"
} ).show();
this.editor.hide();
if ( this.options.resizeOptions && $.fn.resizable ) {
// if element.height still the same after frame was hidden
if ( elementHeight === this.element.height() ) {
this.element.height( this.ui.toolbar.height() );
}
this.element.resizable( "destroy" );
}
this.ui.toolbar.find( "li" ).each( function () {
var li = $( this );
if ( li.hasClass( "html" ) ) {
li.addClass( "active" );
} else {
if ( false === li.hasClass( "fullscreen" ) ) {
li.removeClass( "active" ).addClass( 'disabled' );
}
}
} );
}
this.viewHTML = !(this.viewHTML);
},
tooltip: "View source code"
},
increaseFontSize: {
groupIndex: 9,
visible: false,
tags: ["big"],
tooltip: "Increase font size",
exec: function () {
this.increaseFontSize();
}
},
indent: {
groupIndex: 2,
visible: true,
tooltip: "Indent"
},
insertHorizontalRule: {
groupIndex: 6,
visible: true,
tags: ["hr"],
tooltip: "Insert Horizontal Rule"
},
insertImage: {
groupIndex: 6,
visible: true,
exec: function () {
var self = this;
if ( $.wysiwyg.controls && $.wysiwyg.controls.image ) {
$.wysiwyg.controls.image.init( this );
} else if ( $.wysiwyg.autoload ) {
$.wysiwyg.autoload.control( "wysiwyg.image.js", function () {
self.controls.insertImage.exec.apply( self );
} );
} else {
console.error( "$.wysiwyg.controls.image not defined. You need to include wysiwyg.image.js file" );
}
},
tags: ["img"],
tooltip: "Insert image"
},
insertOrderedList: {
groupIndex: 5,
visible: true,
tags: ["ol"],
tooltip: "Insert Ordered List"
},
insertTable: {
groupIndex: 6,
visible: true,
exec: function () {
var self = this;
if ( $.wysiwyg.controls && $.wysiwyg.controls.table ) {
$.wysiwyg.controls.table( this );
} else if ( $.wysiwyg.autoload ) {
$.wysiwyg.autoload.control( "wysiwyg.table.js", function () {
self.controls.insertTable.exec.apply( self );
} );
} else {
console.error( "$.wysiwyg.controls.table not defined. You need to include wysiwyg.table.js file" );
}
},
tags: ["table"],
tooltip: "Insert table"
},
insertUnorderedList: {
groupIndex: 5,
visible: true,
tags: ["ul"],
tooltip: "Insert Unordered List"
},
italic: {
groupIndex: 0,
visible: true,
tags: ["i", "em"],
css: {
fontStyle: "italic"
},
tooltip: "Italic",
hotkey: {"ctrl": 1, "key": 73}
},
justifyCenter: {
groupIndex: 1,
visible: true,
tags: ["center"],
css: {
textAlign: "center"
},
tooltip: "Justify Center"
},
justifyFull: {
groupIndex: 1,
visible: true,
css: {
textAlign: "justify"
},
tooltip: "Justify Full"
},
justifyLeft: {
visible: true,
groupIndex: 1,
css: {
textAlign: "left"
},
tooltip: "Justify Left"
},
justifyRight: {
groupIndex: 1,
visible: true,
css: {
textAlign: "right"
},
tooltip: "Justify Right"
},
ltr: {
groupIndex: 10,
visible: false,
exec: function () {
var p = this.dom.getElement( "p" );
if ( !p ) {
return false;
}
$( p ).attr( "dir", "ltr" );
return true;
},
tooltip: "Left to Right"
},
outdent: {
groupIndex: 2,
visible: true,
tooltip: "Outdent"
},
paragraph: {
groupIndex: 7,
visible: false,
className: "paragraph",
command: "FormatBlock",
"arguments": ($.browser.msie || $.browser.safari) ? "
" : "p",
tags: ["p"],
tooltip: "Paragraph"
},
paste: {
groupIndex: 8,
visible: false,
tooltip: "Paste"
},
redo: {
groupIndex: 4,
visible: true,
tooltip: "Redo"
},
removeFormat: {
groupIndex: 10,
visible: true,
exec: function () {
this.removeFormat();
},
tooltip: "Remove formatting"
},
rtl: {
groupIndex: 10,
visible: false,
exec: function () {
var p = this.dom.getElement( "p" );
if ( !p ) {
return false;
}
$( p ).attr( "dir", "rtl" );
return true;
},
tooltip: "Right to Left"
},
strikeThrough: {
groupIndex: 0,
visible: true,
tags: ["s", "strike"],
css: {
textDecoration: "line-through"
},
tooltip: "Strike-through"
},
subscript: {
groupIndex: 3,
visible: true,
tags: ["sub"],
tooltip: "Subscript"
},
superscript: {
groupIndex: 3,
visible: true,
tags: ["sup"],
tooltip: "Superscript"
},
underline: {
groupIndex: 0,
visible: true,
tags: ["u"],
css: {
textDecoration: "underline"
},
tooltip: "Underline",
hotkey: {"ctrl": 1, "key": 85}
},
undo: {
groupIndex: 4,
visible: true,
tooltip: "Undo"
},
code: {
visible: true,
groupIndex: 6,
tooltip: "Code snippet",
exec: function () {
var range = this.getInternalRange(), common = $( range.commonAncestorContainer ), $nodeName = range.commonAncestorContainer.nodeName.toLowerCase();
if ( common.parent( "code" ).length ) {
common.unwrap();
} else {
if ( $nodeName !== "body" ) {
common.wrap( "
" );
}
}
}
},
cssWrap: {
visible: false,
groupIndex: 6,
tooltip: "CSS Wrapper",
exec: function () {
$.wysiwyg.controls.cssWrap.init( this );
}
}
};
this.defaults = {
html: '
INITIAL_CONTENT',
debug: false,
controls: {},
css: {},
events: {},
autoGrow: false,
autoSave: true,
brIE: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=15
formHeight: 270,
formWidth: 440,
iFrameClass: null,
initialContent: "",
maxHeight: 10000, // see autoGrow
maxLength: 0,
messages: {
nonSelection: "Select the text you wish to link"
},
toolbarHtml: ' ',
removeHeadings: false,
replaceDivWithP: false,
resizeOptions: false,
rmUnusedControls: false, // https://github.com/akzhan/jwysiwyg/issues/52
rmUnwantedBr: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=11
tableFiller: "Lorem ipsum",
initialMinHeight: null,
controlImage: {
forceRelativeUrls: false
},
controlLink: {
forceRelativeUrls: false
},
plugins: { // placeholder for plugins settings
autoload: false,
i18n: false,
rmFormat: {
rmMsWordMarkup: false
}
},
dialog: "default"
};
//these properties are set from control hashes
this.availableControlProperties = [
"arguments", "callback", "className", "command", "css", "custom", "exec", "groupIndex", "hotkey", "icon", "tags", "tooltip", "visible"
];
this.editor = null; //jquery iframe holder
this.editorDoc = null;
this.element = null;
this.options = {};
this.original = null;
this.savedRange = null;
this.timers = [];
this.validKeyCodes = [8, 9, 13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46];
this.isDestroyed = false;
this.dom = { // DOM related properties and methods
ie: {
parent: null // link to dom
},
w3c: {
parent: null // link to dom
}
};
this.dom.parent = this;
this.dom.ie.parent = this.dom;
this.dom.w3c.parent = this.dom;
this.ui = {}; // UI related properties and methods
this.ui.self = this;
this.ui.toolbar = null;
this.ui.initialHeight = null; // ui.grow
this.dom.getAncestor = function ( element, filterTagName ) {
filterTagName = filterTagName.toLowerCase();
while ( element && typeof element.tagName != "undefined" && "body" !== element.tagName.toLowerCase() ) {
if ( filterTagName === element.tagName.toLowerCase() ) {
return element;
}
element = element.parentNode;
}
if ( !element.tagName && (element.previousSibling || element.nextSibling) ) {
if ( element.previousSibling ) {
if ( element.previousSibling.tagName.toLowerCase() == filterTagName ) {
return element.previousSibling;
}
}
if ( element.nextSibling ) {
if ( element.nextSibling.tagName.toLowerCase() == filterTagName ) {
return element.nextSibling;
}
}
}
return null;
};
this.dom.getElement = function ( filterTagName ) {
var dom = this;
filterTagName = filterTagName.toLowerCase();
if ( window.getSelection ) {
return dom.w3c.getElement( filterTagName );
} else {
return dom.ie.getElement( filterTagName );
}
};
this.dom.ie.getElement = function ( filterTagName ) {
var dom = this.parent, selection = dom.parent.getInternalSelection(), range = selection.createRange(), element;
if ( "Control" === selection.type ) {
// control selection
if ( 1 === range.length ) {
element = range.item( 0 );
} else {
// multiple control selection
return null;
}
} else {
element = range.parentElement();
}
return dom.getAncestor( element, filterTagName );
};
this.dom.w3c.getElement = function ( filterTagName ) {
var dom = this.parent, range = dom.parent.getInternalRange(), element;
if ( !range ) {
return null;
}
element = range.commonAncestorContainer;
if ( 3 === element.nodeType ) {
element = element.parentNode;
}
// if startContainer not Text, Comment, or CDATASection element then
// startOffset is the number of child nodes between the start of the
// startContainer and the boundary point of the Range
if ( element === range.startContainer ) {
element = element.childNodes[range.startOffset];
}
if ( !element.tagName && (element.previousSibiling || element.nextSibling) ) {
if ( element.previousSibiling ) {
if ( element.previousSibiling.tagName.toLowerCase() == filterTagName ) {
return element.previousSibiling;
}
}
if ( element.nextSibling ) {
if ( element.nextSibling.tagName.toLowerCase() == filterTagName ) {
return element.nextSibling;
}
}
}
return dom.getAncestor( element, filterTagName );
};
this.ui.addHoverClass = function () {
$( this ).addClass( "wysiwyg-button-hover" );
};
this.ui.appendControls = function () {
var ui = this, self = this.self, controls = self.parseControls(), hasVisibleControls = true, // to prevent separator before first item
groups = [], controlsByGroup = {}, i, currentGroupIndex, // jslint wants all vars at top of function
iterateGroup = function ( controlName, control ) { //called for every group when adding
if ( control.groupIndex && currentGroupIndex !== control.groupIndex ) {
currentGroupIndex = control.groupIndex;
hasVisibleControls = false;
}
if ( !control.visible ) {
return;
}
if ( !hasVisibleControls ) {
ui.appendItemSeparator();
hasVisibleControls = true;
}
if ( control.custom ) {
ui.appendItemCustom( controlName, control );
} else {
ui.appendItem( controlName, control );
}
};
$.each( controls, function ( name, c ) { //sort by groupIndex
var index = "empty";
if ( undefined !== c.groupIndex ) {
if ( "" === c.groupIndex ) {
index = "empty";
} else {
index = c.groupIndex;
}
}
if ( undefined === controlsByGroup[index] ) {
groups.push( index );
controlsByGroup[index] = {};
}
controlsByGroup[index][name] = c;
} );
groups.sort( function ( a, b ) { //just sort group indexes by
if ( "number" === typeof (a) && typeof (a) === typeof (b) ) {
return (a - b);
} else {
a = a.toString();
b = b.toString();
if ( a > b ) {
return 1;
}
if ( a === b ) {
return 0;
}
return -1;
}
} );
if ( 0 < groups.length ) {
// set to first index in groups to proper placement of separator
currentGroupIndex = groups[0];
}
for ( i = 0; i < groups.length; i += 1 ) {
$.each( controlsByGroup[groups[i]], iterateGroup );
}
};
this.ui.appendItem = function ( name, control ) {
var self = this.self, className = control.className || control.command || name || "empty", tooltip = control.tooltip || control.command || name || "";
return $( '' + (className) + " " ).addClass( className ).attr( "title", tooltip ).hover( this.addHoverClass, this.removeHoverClass ).click(function ( event ) {
if ( $( this ).hasClass( "disabled" ) ) {
return false;
}
self.triggerControl.apply( self, [name, control] );
/**
* @link https://github.com/akzhan/jwysiwyg/issues/219
*/
var $target = $( event.target );
for ( var controlName in self.controls ) {
if ( $target.hasClass( controlName ) ) {
self.ui.toolbar.find( "." + controlName ).toggleClass( "active" );
self.editorDoc.rememberCommand = true;
break;
}
}
this.blur();
self.ui.returnRange();
self.ui.focus();
return true;
} ).appendTo( self.ui.toolbar );
};
this.ui.appendItemCustom = function ( name, control ) {
var self = this.self, tooltip = control.tooltip || control.command || name || "";
if ( control.callback ) {
$( window ).bind( "trigger-" + name + ".wysiwyg", control.callback );
}
return $( '' ).addClass( "custom-command-" + name ).addClass( "wysiwyg-custom-command" ).addClass( name ).attr( "title", tooltip ).hover( this.addHoverClass, this.removeHoverClass ).click(function () {
if ( $( this ).hasClass( "disabled" ) ) {
return false;
}
self.triggerControl.apply( self, [name, control] );
this.blur();
self.ui.returnRange();
self.ui.focus();
self.triggerControlCallback( name );
return true;
} ).appendTo( self.ui.toolbar );
};
this.ui.appendItemSeparator = function () {
var self = this.self;
return $( '' ).appendTo( self.ui.toolbar );
};
this.autoSaveFunction = function () {
this.saveContent();
};
//called after click in wysiwyg "textarea"
this.ui.checkTargets = function ( element ) {
var self = this.self;
//activate controls
$.each( self.options.controls, function ( name, control ) {
var className = control.className || control.command || name || "empty", tags, elm, css, el, checkActiveStatus = function ( cssProperty, cssValue ) {
var handler;
if ( "function" === typeof (cssValue) ) {
handler = cssValue;
if ( handler( el.css( cssProperty ).toString().toLowerCase(), self ) ) {
self.ui.toolbar.find( "." + className ).addClass( "active" );
}
} else {
if ( el.css( cssProperty ).toString().toLowerCase() === cssValue ) {
self.ui.toolbar.find( "." + className ).addClass( "active" );
}
}
};
if ( "fullscreen" !== className ) {
self.ui.toolbar.find( "." + className ).removeClass( "active" );
}
//activate by allowed tags
if ( control.tags || (control.options && control.options.tags) ) {
tags = control.tags || (control.options && control.options.tags);
elm = element;
while ( elm ) {
if ( elm.nodeType !== 1 ) {
break;
}
if ( $.inArray( elm.tagName.toLowerCase(), tags ) !== -1 ) {
self.ui.toolbar.find( "." + className ).addClass( "active" );
}
elm = elm.parentNode;
}
}
//activate by supposed css
if ( control.css || (control.options && control.options.css) ) {
css = control.css || (control.options && control.options.css);
el = $( element );
while ( el ) {
if ( el[0].nodeType !== 1 ) {
break;
}
$.each( css, checkActiveStatus );
el = el.parent();
}
}
} );
};
this.ui.designMode = function () {
var attempts = 3, self = this.self, runner;
runner = function ( attempts ) {
if ( "on" === self.editorDoc.designMode ) {
if ( self.timers.designMode ) {
window.clearTimeout( self.timers.designMode );
}
// IE needs to reget the document element (this.editorDoc) after designMode was set
if ( self.innerDocument() !== self.editorDoc ) {
self.ui.initFrame();
}
return;
}
try {
self.editorDoc.designMode = "on";
} catch ( e ) {
}
attempts -= 1;
if ( attempts > 0 ) {
self.timers.designMode = window.setTimeout( function () {
runner( attempts );
}, 100 );
}
};
runner( attempts );
};
this.destroy = function () {
this.isDestroyed = true;
var i, $form = this.element.closest( "form" );
for ( i = 0; i < this.timers.length; i += 1 ) {
window.clearTimeout( this.timers[i] );
}
// Remove bindings
$form.unbind( ".wysiwyg" );
this.element.remove();
$.removeData( this.original, "wysiwyg" );
$( this.original ).show();
return this;
};
this.getRangeText = function () {
var r = this.getInternalRange();
if ( r.toString ) {
r = r.toString();
} else if ( r.text ) { // IE
r = r.text;
}
return r;
};
//not used?
this.execute = function ( command, arg ) {
if ( typeof (arg) === "undefined" ) {
arg = null;
}
this.editorDoc.execCommand( command, false, arg );
};
this.extendOptions = function ( options ) {
var controls = {};
/**
* If the user set custom controls, we catch it, and merge with the
* defaults controls later.
*/
if ( "object" === typeof options.controls ) {
controls = options.controls;
delete options.controls;
}
options = $.extend( true, {}, this.defaults, options );
options.controls = $.extend( true, {}, controls, this.controls, controls );
if ( options.rmUnusedControls ) {
$.each( options.controls, function ( controlName ) {
if ( !controls[controlName] ) {
delete options.controls[controlName];
}
} );
}
return options;
};
this.ui.focus = function () {
var self = this.self;
self.editor.get( 0 ).contentWindow.focus();
return self;
};
this.ui.returnRange = function () {
var self = this.self, sel;
if ( self.savedRange !== null ) {
if ( window.getSelection ) { //non IE and there is already a selection
sel = window.getSelection();
if ( sel.rangeCount > 0 ) {
sel.removeAllRanges();
}
try {
sel.addRange( self.savedRange );
} catch ( e ) {
console.error( e );
}
} else if ( window.document.createRange ) { // non IE and no selection
window.getSelection().addRange( self.savedRange );
} else if ( window.document.selection ) { //IE
self.savedRange.select();
}
self.savedRange = null;
}
};
this.increaseFontSize = function () {
if ( $.browser.mozilla || $.browser.opera ) {
this.editorDoc.execCommand( "increaseFontSize", false, null );
} else if ( $.browser.safari ) {
var Range = this.getInternalRange(), Selection = this.getInternalSelection(), newNode = this.editorDoc.createElement( "big" );
// If cursor placed on text node
if ( true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType ) {
var text = Range.commonAncestorContainer.nodeValue.toString(), start = text.lastIndexOf( " ", Range.startOffset ) + 1, end = (-1 === text.indexOf( " ", Range.startOffset )) ? text : text.indexOf( " ", Range.startOffset );
Range.setStart( Range.commonAncestorContainer, start );
Range.setEnd( Range.commonAncestorContainer, end );
Range.surroundContents( newNode );
Selection.addRange( Range );
} else {
Range.surroundContents( newNode );
Selection.removeAllRanges();
Selection.addRange( Range );
}
} else {
console.error( "Internet Explorer?" );
}
};
this.decreaseFontSize = function () {
if ( $.browser.mozilla || $.browser.opera ) {
this.editorDoc.execCommand( "decreaseFontSize", false, null );
} else if ( $.browser.safari ) {
var Range = this.getInternalRange(), Selection = this.getInternalSelection(), newNode = this.editorDoc.createElement( "small" );
// If cursor placed on text node
if ( true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType ) {
var text = Range.commonAncestorContainer.nodeValue.toString(), start = text.lastIndexOf( " ", Range.startOffset ) + 1, end = (-1 === text.indexOf( " ", Range.startOffset )) ? text : text.indexOf( " ", Range.startOffset );
Range.setStart( Range.commonAncestorContainer, start );
Range.setEnd( Range.commonAncestorContainer, end );
Range.surroundContents( newNode );
Selection.addRange( Range );
} else {
Range.surroundContents( newNode );
Selection.removeAllRanges();
Selection.addRange( Range );
}
} else {
console.error( "Internet Explorer?" );
}
};
this.getContent = function () {
if ( this.viewHTML ) {
this.setContent( this.original.value );
}
return this.events.filter( 'getContent', this.editorDoc.body.innerHTML );
};
/**
* A jWysiwyg specific event system.
*
* Example:
*
* $("#editor").getWysiwyg().events.bind("getContent", function (orig) {
* return ""+orgi+"";
* });
*
* This makes it so that when ever getContent is called, it is wrapped in a div#content.
*/
this.events = {
_events: {},
/**
* Similar to jQuery's bind, but for jWysiwyg only.
*/
bind: function ( eventName, callback ) {
if ( typeof (this._events.eventName) !== "object" ) {
this._events[eventName] = [];
}
this._events[eventName].push( callback );
},
/**
* Similar to jQuery's trigger, but for jWysiwyg only.
*/
trigger: function ( eventName, args ) {
if ( typeof (this._events.eventName) === "object" ) {
var editor = this.editor;
$.each( this._events[eventName], function ( k, v ) {
if ( typeof (v) === "function" ) {
v.apply( editor, args );
}
} );
}
},
/**
* This "filters" `originalText` by passing it as the first argument to every callback
* with the name `eventName` and taking the return value and passing it to the next function.
*
* This function returns the result after all the callbacks have been applied to `originalText`.
*/
filter: function ( eventName, originalText ) {
if ( typeof (this._events[eventName]) === "object" ) {
var editor = this.editor, args = Array.prototype.slice.call( arguments, 1 );
$.each( this._events[eventName], function ( k, v ) {
if ( typeof (v) === "function" ) {
originalText = v.apply( editor, args );
}
} );
}
return originalText;
}
};
this.getElementByAttributeValue = function ( tagName, attributeName, attributeValue ) {
var i, value, elements = this.editorDoc.getElementsByTagName( tagName );
for ( i = 0; i < elements.length; i += 1 ) {
value = elements[i].getAttribute( attributeName );
if ( $.browser.msie ) {
/** IE add full path, so I check by the last chars. */
value = value.substr( value.length - attributeValue.length );
}
if ( value === attributeValue ) {
return elements[i];
}
}
return false;
};
this.getInternalRange = function () {
var selection = this.getInternalSelection();
if ( !selection ) {
return null;
}
if ( selection.rangeCount && selection.rangeCount > 0 ) { // w3c
return selection.getRangeAt( 0 );
} else if ( selection.createRange ) { // ie
return selection.createRange();
}
return null;
};
this.getInternalSelection = function () {
// firefox: document.getSelection is deprecated
if ( this.editor.get( 0 ).contentWindow ) {
if ( this.editor.get( 0 ).contentWindow.getSelection ) {
return this.editor.get( 0 ).contentWindow.getSelection();
}
if ( this.editor.get( 0 ).contentWindow.selection ) {
return this.editor.get( 0 ).contentWindow.selection;
}
}
if ( this.editorDoc.getSelection ) {
return this.editorDoc.getSelection();
}
if ( this.editorDoc.selection ) {
return this.editorDoc.selection;
}
return null;
};
this.getRange = function () {
var selection = this.getSelection();
if ( !selection ) {
return null;
}
if ( selection.rangeCount && selection.rangeCount > 0 ) { // w3c
selection.getRangeAt( 0 );
} else if ( selection.createRange ) { // ie
return selection.createRange();
}
return null;
};
this.getSelection = function () {
return (window.getSelection) ? window.getSelection() : window.document.selection;
};
// :TODO: you can type long string and letters will be hidden because of overflow
this.ui.grow = function () {
var self = this.self, innerBody = $( self.editorDoc.body ), innerHeight = $.browser.msie ? innerBody[0].scrollHeight : innerBody.height() + 2 + 20, // 2 - borders, 20 - to prevent content jumping on grow
minHeight = self.ui.initialHeight, height = Math.max( innerHeight, minHeight );
height = Math.min( height, self.options.maxHeight );
self.editor.attr( "scrolling", height < self.options.maxHeight ? "no" : "auto" ); // hide scrollbar firefox
innerBody.css( "overflow", height < self.options.maxHeight ? "hidden" : "" ); // hide scrollbar chrome
self.editor.get( 0 ).height = height;
return self;
};
this.init = function ( element, options ) {
var self = this, $form = $( element ).closest( "form" ), newX = (element.width || element.clientWidth || 0), newY = (element.height || element.clientHeight || 0);
this.options = this.extendOptions( options );
this.original = element;
this.ui.toolbar = $( this.options.toolbarHtml );
if ( $.browser.msie && parseInt( $.browser.version, 10 ) < 8 ) {
this.options.autoGrow = false;
}
if ( newX === 0 && element.cols ) {
newX = (element.cols * 8) + 21;
}
if ( newY === 0 && element.rows ) {
newY = (element.rows * 16) + 16;
}
this.editor = $( window.location.protocol === "https:" ? '' : "" ).attr( "frameborder", "0" );
if ( this.options.iFrameClass ) {
this.editor.addClass( this.options.iFrameClass );
} else {
this.editor.css( {
minHeight: (newY - 6).toString() + "px",
// fix for issue 12 ( http://github.com/akzhan/jwysiwyg/issues/issue/12 )
width: (newX > 50) ? (newX - 8).toString() + "px" : ""
} );
if ( $.browser.msie && parseInt( $.browser.version, 10 ) < 7 ) {
this.editor.css( "height", newY.toString() + "px" );
}
}
/**
* Automagically add id to iframe if textarea has its own when possible
* ( http://github.com/akzhan/jwysiwyg/issues/245 )
*/
if ( element.id ) {
var proposedId = element.id + '-wysiwyg-iframe';
if ( !document.getElementById( proposedId ) ) {
this.editor.attr( 'id', proposedId );
}
}
/**
* http://code.google.com/p/jwysiwyg/issues/detail?id=96
*/
this.editor.attr( "tabindex", $( element ).attr( "tabindex" ) );
this.element = $( "" ).addClass( "wysiwyg" );
if ( !this.options.iFrameClass ) {
this.element.css( {
width: (newX > 0) ? newX.toString() + "px" : "100%"
} );
}
$( element ).hide().before( this.element );
this.viewHTML = false;
/**
* @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
*/
this.initialContent = $( element ).val();
this.ui.initFrame();
if ( this.options.resizeOptions && $.fn.resizable ) {
this.element.resizable( $.extend( true, {
alsoResize: this.editor
}, this.options.resizeOptions ) );
}
if ( this.options.autoSave ) {
$form.bind( "submit.wysiwyg", function () {
self.autoSaveFunction();
} );
}
$form.bind( "reset.wysiwyg", function () {
self.resetFunction();
} );
};
this.ui.initFrame = function () {
var self = this.self, stylesheet, growHandler, saveHandler;
self.ui.appendControls();
self.element.append( self.ui.toolbar ).append( $( "" ).css( {
clear: "both"
} ) ).append( self.editor );
self.editorDoc = self.innerDocument();
if ( self.isDestroyed ) {
return null;
}
self.ui.designMode();
self.editorDoc.open();
self.editorDoc.write( self.options.html/**
* @link http://code.google.com/p/jwysiwyg/issues/detail?id=144
*/.replace( /INITIAL_CONTENT/, function () {
return self.wrapInitialContent();
} ) );
self.editorDoc.close();
$.wysiwyg.plugin.bind( self );
$( self.editorDoc ).trigger( "initFrame.wysiwyg" );
$( self.editorDoc ).bind( "click.wysiwyg", function ( event ) {
self.ui.checkTargets( event.target ? event.target : event.srcElement );
} );
/**
* @link https://github.com/akzhan/jwysiwyg/issues/251
*/
setInterval( function () {
var offset = null;
try {
var range = self.getInternalRange();
if ( range ) {
offset = {
range: range,
parent: $.browser.msie ? range.parentElement() : range.endContainer.parentNode,
width: ($.browser.msie ? range.boundingWidth : range.startOffset - range.endOffset) || 0
};
}
} catch ( e ) {
console.error( e );
}
if ( offset && offset.width == 0 && !self.editorDoc.rememberCommand ) {
self.ui.checkTargets( offset.parent );
}
}, 400 );
/**
* @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
*/
$( self.original ).focus( function () {
if ( $( this ).filter( ":visible" ).length === 0 ) {
return;
}
self.ui.focus();
} );
$( self.editorDoc ).keydown( function ( event ) {
var emptyContentRegex;
if ( event.keyCode === 8 ) { // backspace
emptyContentRegex = /^<([\w]+)[^>]*>(
)?<\/\1>$/;
if ( emptyContentRegex.test( self.getContent() ) ) { // if content is empty
event.stopPropagation(); // prevent remove single empty tag
return false;
}
}
self.editorDoc.rememberCommand = false;
return true;
} );
if ( !$.browser.msie ) {
$( self.editorDoc ).keydown( function ( event ) {
var controlName;
/* Meta for Macs. [email protected] */
if ( event.ctrlKey || event.metaKey ) {
for ( controlName in self.controls ) {
if ( self.controls[controlName].hotkey && self.controls[controlName].hotkey.ctrl ) {
if ( event.keyCode === self.controls[controlName].hotkey.key ) {
self.triggerControl.apply( self, [controlName, self.controls[controlName]] );
return false;
}
}
}
}
return true;
} );
} else if ( self.options.brIE ) {
$( self.editorDoc ).keydown( function ( event ) {
if ( event.keyCode === 13 ) {
var rng = self.getRange();
rng.pasteHTML( "
" );
rng.collapse( false );
rng.select();
return false;
}
return true;
} );
}
if ( self.options.plugins.rmFormat.rmMsWordMarkup ) {
$( self.editorDoc ).bind( "keyup.wysiwyg", function ( event ) {
if ( event.ctrlKey || event.metaKey ) {
// CTRL + V (paste)
if ( 86 === event.keyCode ) {
if ( $.wysiwyg.rmFormat ) {
if ( "object" === typeof (self.options.plugins.rmFormat.rmMsWordMarkup) ) {
$.wysiwyg.rmFormat.run( self, {rules: { msWordMarkup: self.options.plugins.rmFormat.rmMsWordMarkup }} );
} else {
$.wysiwyg.rmFormat.run( self, {rules: { msWordMarkup: { enabled: true }}} );
}
}
}
}
} );
}
if ( self.options.autoSave ) {
$( self.editorDoc ).keydown(function () {
self.autoSaveFunction();
} ).keyup(function () {
self.autoSaveFunction();
} ).mousedown(function () {
self.autoSaveFunction();
} ).bind( $.support.noCloneEvent ? "input.wysiwyg" : "paste.wysiwyg", function () {
self.autoSaveFunction();
} );
}
if ( self.options.autoGrow ) {
if ( self.options.initialMinHeight !== null ) {
self.ui.initialHeight = self.options.initialMinHeight;
} else {
self.ui.initialHeight = $( self.editorDoc ).height();
}
$( self.editorDoc.body ).css( "border", "1px solid white" ); // cancel margin collapsing
growHandler = function () {
self.ui.grow();
};
$( self.editorDoc ).keyup( growHandler );
$( self.editorDoc ).bind( "editorRefresh.wysiwyg", growHandler );
// fix when content height > textarea height
self.ui.grow();
}
if ( self.options.css ) {
if ( String === self.options.css.constructor ) {
if ( $.browser.msie ) {
stylesheet = self.editorDoc.createStyleSheet( self.options.css );
$( stylesheet ).attr( {
"media": "all"
} );
} else {
stylesheet = $( "" ).attr( {
"href": self.options.css,
"media": "all",
"rel": "stylesheet",
"type": "text/css"
} );
$( self.editorDoc ).find( "head" ).append( stylesheet );
}
} else {
self.timers.initFrame_Css = window.setTimeout( function () {
$( self.editorDoc.body ).css( self.options.css );
}, 0 );
}
}
if ( self.initialContent.length === 0 ) {
if ( "function" === typeof (self.options.initialContent) ) {
self.setContent( self.options.initialContent() );
} else {
self.setContent( self.options.initialContent );
}
}
if ( self.options.maxLength > 0 ) {
$( self.editorDoc ).keydown( function ( event ) {
if ( $( self.editorDoc ).text().length >= self.options.maxLength && $.inArray( event.which, self.validKeyCodes ) === -1 ) {
event.preventDefault();
}
} );
}
// Support event callbacks
$.each( self.options.events, function ( key, handler ) {
$( self.editorDoc ).bind( key + ".wysiwyg", function ( event ) {
// Trigger event handler, providing the event and api to
// support additional functionality.
handler.apply( self.editorDoc, [event, self] );
} );
} );
// restores selection properly on focus
if ( $.browser.msie ) {
// Event chain: beforedeactivate => focusout => blur.
// Focusout & blur fired too late to handle internalRange() in dialogs.
// When clicked on input boxes both got range = null
$( self.editorDoc ).bind( "beforedeactivate.wysiwyg", function () {
self.savedRange = self.getInternalRange();
} );
} else {
$( self.editorDoc ).bind( "blur.wysiwyg", function () {
self.savedRange = self.getInternalRange();
} );
}
$( self.editorDoc.body ).addClass( "wysiwyg" );
if ( self.options.events && self.options.events.save ) {
saveHandler = self.options.events.save;
$( self.editorDoc ).bind( "keyup.wysiwyg", saveHandler );
$( self.editorDoc ).bind( "change.wysiwyg", saveHandler );
if ( $.support.noCloneEvent ) {
$( self.editorDoc ).bind( "input.wysiwyg", saveHandler );
} else {
$( self.editorDoc ).bind( "paste.wysiwyg", saveHandler );
$( self.editorDoc ).bind( "cut.wysiwyg", saveHandler );
}
}
/**
* XHTML5 {@link https://github.com/akzhan/jwysiwyg/issues/152}
*/
if ( self.options.xhtml5 && self.options.unicode ) {
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: 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};
self.events.bind( "getContent", function ( text ) {
return text.replace( /&(?:amp;)?(?!amp|lt|gt|quot)([a-z][a-z0-9]*);/gi, function ( str, p1 ) {
if ( !replacements[p1] ) {
p1 = p1.toLowerCase();
if ( !replacements[p1] ) {
p1 = "__replacement";
}
}
var num = replacements[p1];
/* Numeric return if ever wanted: return replacements[p1] ? ""+num+";" : ""; */
return String.fromCharCode( num );
} );
} );
}
$( self.original ).trigger( 'ready.jwysiwyg', [self.editorDoc, self] );
};
this.innerDocument = function () {
var element = this.editor.get( 0 );
if ( element.nodeName.toLowerCase() === "iframe" ) {
if ( element.contentDocument ) { // Gecko
return element.contentDocument;
} else if ( element.contentWindow ) { // IE
return element.contentWindow.document;
}
if ( this.isDestroyed ) {
return null;
}
console.error( "Unexpected error in innerDocument" );
/*
return ( $.browser.msie )
? document.frames[element.id].document
: element.contentWindow.document // contentDocument;
*/
}
return element;
};
this.insertHtml = function ( szHTML ) {
var img, range;
if ( !szHTML || szHTML.length === 0 ) {
return this;
}
if ( $.browser.msie ) {
this.ui.focus();
this.editorDoc.execCommand( "insertImage", false, "#jwysiwyg#" );
img = this.getElementByAttributeValue( "img", "src", "#jwysiwyg#" );
if ( img ) {
$( img ).replaceWith( szHTML );
}
} else {
if ( $.browser.mozilla ) { // @link https://github.com/akzhan/jwysiwyg/issues/50
if ( 1 === $( szHTML ).length ) {
range = this.getInternalRange();
range.deleteContents();
range.insertNode( $( szHTML ).get( 0 ) );
} else {
this.editorDoc.execCommand( "insertHTML", false, szHTML );
}
} else {
if ( !this.editorDoc.execCommand( "insertHTML", false, szHTML ) ) {
this.editor.focus();
/* :TODO: place caret at the end
if (window.getSelection) {
} else {
}
this.editor.focus();
*/
this.editorDoc.execCommand( "insertHTML", false, szHTML );
}
}
}
this.saveContent();
return this;
};
//check allowed properties
this.parseControls = function () {
var self = this;
$.each( this.options.controls, function ( controlName, control ) {
$.each( control, function ( propertyName ) {
if ( -1 === $.inArray( propertyName, self.availableControlProperties ) ) {
throw controlName + '["' + propertyName + '"]: property "' + propertyName + '" not exists in Wysiwyg.availableControlProperties';
}
} );
} );
if ( this.options.parseControls ) { //user callback
return this.options.parseControls.call( this );
}
return this.options.controls;
};
this.removeFormat = function () {
if ( $.browser.msie ) {
this.ui.focus();
}
if ( this.options.removeHeadings ) {
this.editorDoc.execCommand( "formatBlock", false, "" ); // remove headings
}
this.editorDoc.execCommand( "removeFormat", false, null );
this.editorDoc.execCommand( "unlink", false, null );
if ( $.wysiwyg.rmFormat && $.wysiwyg.rmFormat.enabled ) {
if ( "object" === typeof (this.options.plugins.rmFormat.rmMsWordMarkup) ) {
$.wysiwyg.rmFormat.run( this, {rules: { msWordMarkup: this.options.plugins.rmFormat.rmMsWordMarkup }} );
} else {
$.wysiwyg.rmFormat.run( this, {rules: { msWordMarkup: { enabled: true }}} );
}
}
return this;
};
this.ui.removeHoverClass = function () {
$( this ).removeClass( "wysiwyg-button-hover" );
};
this.resetFunction = function () {
this.setContent( this.initialContent );
};
this.saveContent = function () {
if ( this.viewHTML ) {
return; // no need
}
if ( this.original ) {
var content, newContent;
content = this.getContent();
if ( this.options.rmUnwantedBr ) {
content = content.replace( /
$/, "" );
}
if ( this.options.replaceDivWithP ) {
newContent = $( "
" ).addClass( "temp" ).append( content );
newContent.children( "div" ).each( function () {
var element = $( this ), p = element.find( "p" ), i;
if ( 0 === p.length ) {
p = $( "" );
if ( this.attributes.length > 0 ) {
for ( i = 0; i < this.attributes.length; i += 1 ) {
p.attr( this.attributes[i].name, element.attr( this.attributes[i].name ) );
}
}
p.append( element.html() );
element.replaceWith( p );
}
} );
content = newContent.html();
}
$( this.original ).val( content );
if ( this.options.events && this.options.events.save ) {
this.options.events.save.call( this );
}
}
return this;
};
this.setContent = function ( newContent ) {
this.editorDoc.body.innerHTML = newContent;
this.saveContent();
return this;
};
this.triggerControl = function ( name, control ) {
var cmd = control.command || name, //command directly for designMode=on iframe (this.editorDoc)
args = control["arguments"] || [];
if ( control.exec ) {
control.exec.apply( this ); //custom exec function in control, allows DOM changing
} else {
this.ui.focus();
this.ui.withoutCss(); //disable style="" attr inserting in mozzila's designMode
// when click , or got "Access to XPConnect service denied" code: "1011"
// in Firefox untrusted JavaScript is not allowed to access the clipboard
try {
this.editorDoc.execCommand( cmd, false, args );
} catch ( e ) {
console.error( e );
}
}
if ( this.options.autoSave ) {
this.autoSaveFunction();
}
};
this.triggerControlCallback = function ( name ) {
$( window ).trigger( "trigger-" + name + ".wysiwyg", [this] );
};
this.ui.withoutCss = function () {
var self = this.self;
if ( $.browser.mozilla ) {
try {
self.editorDoc.execCommand( "styleWithCSS", false, false );
} catch ( e ) {
try {
self.editorDoc.execCommand( "useCSS", false, true );
} catch ( e2 ) {
}
}
}
return self;
};
this.wrapInitialContent = function () {
var content = this.initialContent, found = content.match( /<\/?p>/gi );
if ( !found ) {
return "" + content + "
";
} else {
// :TODO: checking/replacing
}
return content;
};
}
/*
* Wysiwyg namespace: public properties and methods
*/
$.wysiwyg = {
messages: {
noObject: "Something goes wrong, check object"
},
/**
* Custom control support by Alec Gorge ( http://github.com/alecgorge )
*/
addControl: function ( object, name, settings ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" ), customControl = {}, toolbar;
if ( !oWysiwyg ) {
return this;
}
customControl[name] = $.extend( true, {visible: true, custom: true}, settings );
$.extend( true, oWysiwyg.options.controls, customControl );
// render new toolbar
toolbar = $( oWysiwyg.options.toolbarHtml );
oWysiwyg.ui.toolbar.replaceWith( toolbar );
oWysiwyg.ui.toolbar = toolbar;
oWysiwyg.ui.appendControls();
} );
},
clear: function ( object ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.setContent( "" );
} );
},
console: console, // let our console be available for extensions
destroy: function ( object ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.destroy();
} );
},
"document": function ( object ) {
// no chains because of return
var oWysiwyg = object.data( "wysiwyg" );
if ( !oWysiwyg ) {
return undefined;
}
return $( oWysiwyg.editorDoc );
},
getContent: function ( object ) {
// no chains because of return
var oWysiwyg = object.data( "wysiwyg" );
if ( !oWysiwyg ) {
return undefined;
}
return oWysiwyg.getContent();
},
init: function ( object, options ) {
return object.each( function () {
var opts = $.extend( true, {}, options ), obj;
// :4fun:
// remove this textarea validation and change line in this.saveContent function
// $(this.original).val(content); to $(this.original).html(content);
// now you can make WYSIWYG editor on h1, p, and many more tags
if ( ("textarea" !== this.nodeName.toLowerCase()) || $( this ).data( "wysiwyg" ) ) {
return;
}
obj = new Wysiwyg();
obj.init( this, opts );
$.data( this, "wysiwyg", obj );
$( obj.editorDoc ).trigger( "afterInit.wysiwyg" );
} );
},
insertHtml: function ( object, szHTML ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.insertHtml( szHTML );
} );
},
plugin: {
listeners: {},
bind: function ( Wysiwyg ) {
var self = this;
$.each( this.listeners, function ( action, handlers ) {
var i, plugin;
for ( i = 0; i < handlers.length; i += 1 ) {
plugin = self.parseName( handlers[i] );
$( Wysiwyg.editorDoc ).bind( action + ".wysiwyg", {plugin: plugin}, function ( event ) {
$.wysiwyg[event.data.plugin.name][event.data.plugin.method].apply( $.wysiwyg[event.data.plugin.name], [Wysiwyg] );
} );
}
} );
},
exists: function ( name ) {
var plugin;
if ( "string" !== typeof (name) ) {
return false;
}
plugin = this.parseName( name );
if ( !$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method] ) {
return false;
}
return true;
},
listen: function ( action, handler ) {
var plugin;
plugin = this.parseName( handler );
if ( !$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method] ) {
return false;
}
if ( !this.listeners[action] ) {
this.listeners[action] = [];
}
this.listeners[action].push( handler );
return true;
},
parseName: function ( name ) {
var elements;
if ( "string" !== typeof (name) ) {
return false;
}
elements = name.split( "." );
if ( 2 > elements.length ) {
return false;
}
return {name: elements[0], method: elements[1]};
},
register: function ( data ) {
if ( !data.name ) {
console.error( "Plugin name missing" );
}
$.each( $.wysiwyg, function ( pluginName ) {
if ( pluginName === data.name ) {
console.error( "Plugin with name '" + data.name + "' was already registered" );
}
} );
$.wysiwyg[data.name] = data;
return true;
}
},
removeFormat: function ( object ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.removeFormat();
} );
},
save: function ( object ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.saveContent();
} );
},
selectAll: function ( object ) {
var oWysiwyg = object.data( "wysiwyg" ), oBody, oRange, selection;
if ( !oWysiwyg ) {
return this;
}
oBody = oWysiwyg.editorDoc.body;
if ( window.getSelection ) {
selection = oWysiwyg.getInternalSelection();
selection.selectAllChildren( oBody );
} else {
oRange = oBody.createTextRange();
oRange.moveToElementText( oBody );
oRange.select();
}
},
setContent: function ( object, newContent ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
oWysiwyg.setContent( newContent );
} );
},
triggerControl: function ( object, controlName ) {
return object.each( function () {
var oWysiwyg = $( this ).data( "wysiwyg" );
if ( !oWysiwyg ) {
return this;
}
if ( !oWysiwyg.controls[controlName] ) {
console.error( "Control '" + controlName + "' not exists" );
}
oWysiwyg.triggerControl.apply( oWysiwyg, [controlName, oWysiwyg.controls[controlName]] );
} );
},
support: {
prop: supportsProp
},
utils: {
extraSafeEntities: [
["<", ">", "'", '"', " "],
[32]
],
encodeEntities: function ( str ) {
var self = this, aStr, aRet = [];
if ( this.extraSafeEntities[1].length === 0 ) {
$.each( this.extraSafeEntities[0], function ( i, ch ) {
self.extraSafeEntities[1].push( ch.charCodeAt( 0 ) );
} );
}
aStr = str.split( "" );
$.each( aStr, function ( i ) {
var iC = aStr[i].charCodeAt( 0 );
if ( $.inArray( iC, self.extraSafeEntities[1] ) && (iC < 65 || iC > 127 || (iC > 90 && iC < 97)) ) {
aRet.push( '' + iC + ';' );
} else {
aRet.push( aStr[i] );
}
} );
return aRet.join( '' );
}
}
};
/**
* Unifies dialog methods to allow custom implementations
*
* Events:
* * afterOpen
* * beforeShow
* * afterShow
* * beforeHide
* * afterHide
* * beforeClose
* * afterClose
*
* Example:
* var dialog = new ($.wysiwyg.dialog)($('#idToTextArea').data('wysiwyg'), {"title": "Test", "content": "form data, etc."});
*
* dialog.bind("afterOpen", function () { alert('you should see a dialog behind this one!'); });
*
* dialog.open();
*
*
*/
$.wysiwyg.dialog = function ( jWysiwyg, opts ) {
var theme = (jWysiwyg && jWysiwyg.options && jWysiwyg.options.dialog) ? jWysiwyg.options.dialog : (opts.theme ? opts.theme : "default"), obj = new $.wysiwyg.dialog.createDialog( theme ), that = this, $that = $( that );
this.options = {
"modal": true,
"draggable": true,
"title": "Title",
"content": "Content",
"width": "auto",
"height": "auto",
"zIndex": 2000,
"open": false,
"close": false
};
this.isOpen = false;
$.extend( this.options, opts );
this.object = obj;
// Opens a dialog with the specified content
this.open = function () {
this.isOpen = true;
obj.init.apply( that, [] );
var $dialog = obj.show.apply( that, [] );
$that.trigger( "afterOpen", [$dialog] );
};
this.show = function () {
this.isOpen = true;
$that.trigger( "beforeShow" );
var $dialog = obj.show.apply( that, [] );
$that.trigger( "afterShow" );
};
this.hide = function () {
this.isOpen = false;
$that.trigger( "beforeHide" );
var $dialog = obj.hide.apply( that, [] );
$that.trigger( "afterHide", [$dialog] );
};
// Closes the dialog window.
this.close = function () {
this.isOpen = false;
var $dialog = obj.hide.apply( that, [] );
$that.trigger( "beforeClose", [$dialog] );
obj.destroy.apply( that, [] );
$that.trigger( "afterClose", [$dialog] );
};
if ( this.options.open ) {
$that.bind( "afterOpen", this.options.open );
}
if ( this.options.close ) {
$that.bind( "afterClose", this.options.close );
}
return this;
};
// "Static" Dialog methods.
$.extend( true, $.wysiwyg.dialog, {
_themes: {}, // sample {"Theme Name": object}
_theme: "", // the current theme
register: function ( name, obj ) {
$.wysiwyg.dialog._themes[name] = obj;
},
deregister: function ( name ) {
delete $.wysiwyg.dialog._themes[name];
},
createDialog: function ( name ) {
return new ($.wysiwyg.dialog._themes[name]);
},
getDimensions: function () {
var width = document.body.scrollWidth, height = document.body.scrollHeight;
if ( $.browser.opera ) {
height = Math.max( $( document ).height(), $( window ).height(), document.documentElement.clientHeight );
}
return [width, height];
}
} );
$( function () { // need access to jQuery UI stuff.
if ( jQuery.ui ) {
$.wysiwyg.dialog.register( "jqueryui", function () {
var that = this;
this._$dialog = null;
this.init = function () {
var abstractDialog = this, content = this.options.content;
if ( typeof content === 'object' ) {
if ( typeof content.html === 'function' ) {
content = content.html();
} else if ( typeof content.toString === 'function' ) {
content = content.toString();
}
}
that._$dialog = $( '' ).attr( 'title', this.options.title ).html( content );
var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height, dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
// console.log(that._$dialog);
that._$dialog.dialog( {
modal: this.options.modal,
draggable: this.options.draggable,
height: dialogHeight,
width: dialogWidth
} );
return that._$dialog;
};
this.show = function () {
that._$dialog.dialog( "open" );
return that._$dialog;
};
this.hide = function () {
that._$dialog.dialog( "close" );
return that._$dialog;
};
this.destroy = function () {
that._$dialog.dialog( "destroy" );
return that._$dialog;
};
} );
}
$.wysiwyg.dialog.register( "default", function () {
var that = this;
this._$dialog = null;
this.init = function () {
var abstractDialog = this, content = this.options.content;
if ( typeof content === 'object' ) {
if ( typeof content.html === 'function' ) {
content = content.html();
} else if ( typeof content.toString === 'function' ) {
content = content.toString();
}
}
that._$dialog = $( '' ).css( {"z-index": this.options.zIndex} );
var $topbar = $( ' ' );
var $link = $( 'X' );
$link.click( function () {
abstractDialog.close(); // this is important it makes sure that is close from the abstract $.wysiwyg.dialog instace, not just locally
} );
$topbar.find( '.wysiwyg-dialog-close-wrapper' ).prepend( $link );
var $dcontent = $( '' + content + '' );
that._$dialog.append( $topbar ).append( $dcontent );
// Set dialog's height & width, and position it correctly:
var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height, dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
that._$dialog.hide().css( {
"width": dialogWidth,
"height": dialogHeight,
"left": (($( window ).width() - dialogWidth) / 2),
"top": (($( window ).height() - dialogHeight) / 3)
} );
$( "body" ).append( that._$dialog );
return that._$dialog;
};
this.show = function () {
// Modal feature:
if ( this.options.modal ) {
var dimensions = $.wysiwyg.dialog.getDimensions(), wrapper = $( '' ).css( {"width": dimensions[0], "height": dimensions[1]} );
that._$dialog.wrap( wrapper );
}
// Draggable feature:
if ( this.options.draggable ) {
var mouseDown = false;
that._$dialog.find( "div.wysiwyg-dialog-topbar" ).bind( "mousedown", function ( e ) {
e.preventDefault();
$( this ).css( { "cursor": "move" } );
var $topbar = $( this ), _dialog = $( this ).parents( ".wysiwyg-dialog" ), offsetX = (e.pageX - parseInt( _dialog.css( "left" ), 10 )), offsetY = (e.pageY - parseInt( _dialog.css( "top" ), 10 ));
mouseDown = true;
$( this ).css( { "cursor": "move" } );
$( document ).bind( "mousemove",function ( e ) {
e.preventDefault();
if ( mouseDown ) {
_dialog.css( {
"top": (e.pageY - offsetY),
"left": (e.pageX - offsetX)
} );
}
} ).bind( "mouseup", function ( e ) {
e.preventDefault();
mouseDown = false;
$topbar.css( { "cursor": "auto" } );
$( document ).unbind( "mousemove" ).unbind( "mouseup" );
} );
} );
}
that._$dialog.show();
return that._$dialog;
};
this.hide = function () {
that._$dialog.hide();
return that._$dialog;
};
this.destroy = function () {
// Modal feature:
if ( this.options.modal ) {
that._$dialog.unwrap();
}
// Draggable feature:
if ( this.options.draggable ) {
that._$dialog.find( "div.wysiwyg-dialog-topbar" ).unbind( "mousedown" );
}
that._$dialog.remove();
return that._$dialog;
};
} );
} );
// end Dialog
$.fn.wysiwyg = function ( method ) {
var args = arguments, plugin;
if ( "undefined" !== typeof $.wysiwyg[method] ) {
// set argument object to undefined
args = Array.prototype.concat.call( [args[0]], [this], Array.prototype.slice.call( args, 1 ) );
return $.wysiwyg[method].apply( $.wysiwyg, Array.prototype.slice.call( args, 1 ) );
} else if ( "object" === typeof method || !method ) {
Array.prototype.unshift.call( args, this );
return $.wysiwyg.init.apply( $.wysiwyg, args );
} else if ( $.wysiwyg.plugin.exists( method ) ) {
plugin = $.wysiwyg.plugin.parseName( method );
args = Array.prototype.concat.call( [args[0]], [this], Array.prototype.slice.call( args, 1 ) );
return $.wysiwyg[plugin.name][plugin.method].apply( $.wysiwyg[plugin.name], Array.prototype.slice.call( args, 1 ) );
} else {
console.error( "Method '" + method + "' does not exist on jQuery.wysiwyg.\nTry to include some extra controls or plugins" );
}
};
$.fn.getWysiwyg = function () {
return this.data( "wysiwyg" );
};
})( jQuery );