// http://wiki.jqueryui.com/w/page/12138135/Widget%20factory
(function( $ ) {
$.widget( 'ui.rte', {
// These options will be used as defaults
options: {
disabled: true,
mode: 'html'
},
// Set up the widget
_create: function() {
console.log('_create');
var self = this,
dirty = false,
textarea = this.element; //.hide(),
pos = textarea.position();
//this.element.text = this.text;
this.mirror = $('
').insertAfter(textarea).show();
textarea.hide();
this.formatText('styleWithCSS', true);
this.validtags = ['A','P','STRONG', 'B', 'I', 'SPAN', 'DIV', 'OL', 'UL', 'LI', 'DL', 'DT', 'DD'];
this.enabled = true;
/*$(window).resize(function() {
console.log('resize: ');
});*/
this.mirror.keydown(function(event){
if(event.which == 13) {
self.insertAtCaret('
');
}
});
this.mirror.keyup(function() {
console.log('keyup, set dirty.');
self.dirty = true;
});
this.mirror.blur(function() {
console.log('blur: ');
if(self.dirty) {
self.mirror.trigger('change');
self.dirty = false;
}
});
},
_init: function() {
console.log('_init');
self = this;
$.each(this.options, function(key, value) {
self._setOption(key, value);
});
},
text: function(str) {
console.log('function text');
if(str != undefined) {
this.mirror.html(str);
this.element.text(str);
} else {
console.log('returning: ' + this.element.val());
return this.element.val();
}
},
html: function(str) {
console.log('function html');
if(str != undefined) {
console.log('str: ' + str);
var $str;
try {
$str = $(str);
this.mirror.empty().html($str); // Call empty() for IE 8.
this.element.text($str.text());
} catch(e) {
console.log(e.message);
this.mirror.empty().html(str);
this.element.text(str);
}
//console.log('length: ' + $str.length);
//this.mirror.get(0).contenteditable=false;
} else {
console.log('returning: ' + this.mirror.html());
return this.mirror.html();
}
},
insertAtCaret: function(myValue){
// Found this at stackoverflow
return this.mirror.each(function(i) {
if (document.selection) {
console.log('IE');
//For browsers like Internet Explorer
this.focus();
sel = document.selection.createRange();
sel.text = myValue;
this.focus();
}
else if (this.selectionStart || this.selectionStart == '0') {
console.log('FF');
//For browsers like Firefox and Webkit based
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos)+myValue+this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
} else {
console.log('Smth.');
this.value += myValue;
this.focus();
}
})
},
showSelection: function() {
var textComponent = this.mirror.get(0); //document.getElementById('Editor');
var selectedText;
// IE version
if (document.selection != undefined) {
textComponent.focus();
var sel = document.selection.createRange();
selectedText = sel.text;
}
// Mozilla version
else if (textComponent.selectionStart != undefined) {
var startPos = textComponent.selectionStart;
var endPos = textComponent.selectionEnd;
selectedText = textComponent.value.substring(startPos, endPos)
}
alert("You selected: " + selectedText);
},
formatText: function(command, option) {
self = this, useDialog = false;
switch(command) {
case 'ulist':
command = 'insertUnorderedList';
break;
case 'olist':
command = 'insertOrderedList';
break;
case 'createlink':
self.showSelection();
option=prompt('Write the URL here')
useDialog = true;
default:
break;
}
try{
document.execCommand(command, useDialog, option);
self.dirty = true; // FIXME: This doesn't work because blur is triggered before dirty is set.
self.mirror.trigger('blur'); // Dirty hack to trigger save. Hmm, if it only worked...
}catch(e){
console.log('Error: ' + e)
}
},
setEnabled: function(state) {
console.log('function setEnabled: ' + state);
if(state != undefined) {
this._setOption('disabled', !state);
}
return this.options['disabled'];
},
mode: function(mode) {
if(mode != undefined) {
this._setOption('mode', mode);
}
return this.options['mode'];
},
/*toggle: function() {
this._setOption('disabled', !this.options['disabled']);
return !this.options['disabled'];
},*/
toggleMode: function() {
this._setOption('mode', (this.options['mode'] == 'html'?'text':'html'));
return this.options['mode'];
},
// Use the _setOption method to respond to changes to options
_setOption: function( key, value ) {
console.log('option ' + key + ': ' + value);
switch( key ) {
case 'disabled':
if(value) {
this.mirror.get(0).contenteditable = false;
this.mirror.attr('contenteditable', false);
this.mirror.removeClass('editable');
this.element.attr('disabled', true);
this.element.removeClass('editable');
} else {
this.mirror.get(0).contenteditable = true;
this.mirror.attr('contenteditable', true);
this.mirror.addClass('editable');
this.element.attr('disabled', false);
this.element.addClass('editable');
}
break;
case 'mode':
switch(value) {
case 'html':
this.mirror.show();
this.element.hide();
break;
case 'text':
this.mirror.hide();
this.element.show();
this.element.trigger('resize');
break;
default:
throw { name: 'UnknownMode', message: 'Invalid mode: ' + value }
break;
}
break;
case 'classes':
if($.isArray(value)) {
var mirror = this.mirror;
$.each(this.options['classes'], function(key, value) {
mirror.addClass(value);
});
} else {
this.mirror.addClass(value);
}
break;
default:
this.options[key] = value;
break;
}
// In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget
$.Widget.prototype._setOption.apply( this, arguments );
// In jQuery UI 1.9 and above, you use the _super method instead
//this._super( "_setOption", key, value );
},
// Use the destroy method to clean up any modifications your widget has made to the DOM
destroy: function() {
this.mirror.remove();
this.element.show();
// In jQuery UI 1.8, you must invoke the destroy method from the base widget
$.Widget.prototype.destroy.call( this );
// In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method
}
});
}( jQuery ) );