Refactored october.hotkey.js, codeeditor.js, richeditor.js. Minor fix in the rich editor styling.
This commit is contained in:
parent
87b34295eb
commit
0e4db692af
|
|
@ -1150,7 +1150,9 @@ Base.call(this)
|
|||
this.init()}
|
||||
HotKey.prototype=Object.create(BaseProto)
|
||||
HotKey.prototype.constructor=HotKey
|
||||
HotKey.prototype.dispose=function(){this.unregisterHandlers()
|
||||
HotKey.prototype.dispose=function(){if(this.$el===null)
|
||||
return
|
||||
this.unregisterHandlers()
|
||||
this.$el.removeData('oc.hotkey')
|
||||
this.$target=null
|
||||
this.$el=null
|
||||
|
|
@ -1165,7 +1167,7 @@ var keys=this.options.hotkey.toLowerCase().split(',')
|
|||
for(var i=0,len=keys.length;i<len;i++){var keysTrimmed=this.trim(keys[i])
|
||||
this.keyConditions.push(this.makeCondition(keysTrimmed))}
|
||||
this.$target.on('keydown',this.proxy(this.onKeyDown))
|
||||
this.$el.on('dispose-control',this.proxy(this.dispose))}
|
||||
this.$el.one('dispose-control',this.proxy(this.dispose))}
|
||||
HotKey.prototype.unregisterHandlers=function(){this.$target.off('keydown',this.proxy(this.onKeyDown))
|
||||
this.$el.off('dispose-control',this.proxy(this.dispose))}
|
||||
HotKey.prototype.makeCondition=function(keyBind){var condition={shift:false,ctrl:false,cmd:false,alt:false,specific:-1},keys=keyBind.split('+')
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
HotKey.prototype.constructor = HotKey
|
||||
|
||||
HotKey.prototype.dispose = function() {
|
||||
if (this.$el === null)
|
||||
return
|
||||
|
||||
this.unregisterHandlers()
|
||||
|
||||
this.$el.removeData('oc.hotkey')
|
||||
|
|
@ -58,7 +61,7 @@
|
|||
}
|
||||
|
||||
this.$target.on('keydown', this.proxy(this.onKeyDown))
|
||||
this.$el.on('dispose-control', this.proxy(this.dispose))
|
||||
this.$el.one('dispose-control', this.proxy(this.dispose))
|
||||
}
|
||||
|
||||
HotKey.prototype.unregisterHandlers = function() {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
this.$toolbar = this.$el.find('>.editor-toolbar:first')
|
||||
this.$code = null
|
||||
this.editor = null
|
||||
this.$form = null
|
||||
|
||||
// Toolbar links
|
||||
this.isFullscreen = false
|
||||
|
|
@ -97,21 +98,16 @@
|
|||
options = this.options,
|
||||
$form = this.$el.closest('form');
|
||||
|
||||
this.$form = $form
|
||||
|
||||
this.$textarea.hide();
|
||||
editor.getSession().setValue(this.$textarea.val())
|
||||
|
||||
$form.on('oc.beforeRequest', function(){
|
||||
self.$textarea.val(editor.getSession().getValue())
|
||||
})
|
||||
|
||||
editor.on('change', function() {
|
||||
$form.trigger('change')
|
||||
self.$textarea.trigger('oc.codeEditorChange')
|
||||
})
|
||||
|
||||
$(window).on('resize, oc.updateUi', function() {
|
||||
editor.resize()
|
||||
})
|
||||
editor.on('change', this.proxy(this.onChange))
|
||||
$form.on('oc.beforeRequest', this.proxy(this.onBeforeRequest))
|
||||
$(window).on('resize', this.proxy(this.onResize))
|
||||
$(window).on('oc.updateUi', this.proxy(this.onResize))
|
||||
this.$el.on('dispose-control', this.proxy(this.dispose))
|
||||
|
||||
/*
|
||||
* Set language and theme
|
||||
|
|
@ -144,8 +140,8 @@
|
|||
editor.setReadOnly(options.readOnly)
|
||||
editor.getSession().setFoldStyle(options.codeFolding)
|
||||
editor.setFontSize(options.fontSize)
|
||||
editor.on('blur.codeeditor', function(){ self.$el.removeClass('editor-focus') })
|
||||
editor.on('focus.codeeditor', function(){ self.$el.addClass('editor-focus') })
|
||||
editor.on('blur', this.proxy(this.onBlur))
|
||||
editor.on('focus', this.proxy(this.onFocus))
|
||||
this.setWordWrap(options.wordWrap)
|
||||
|
||||
editor.renderer.setScrollMargin(options.margin, options.margin, 0, 0)
|
||||
|
|
@ -178,9 +174,11 @@
|
|||
/*
|
||||
* Hotkeys
|
||||
*/
|
||||
this.$el.hotKey({ hotkey: 'esc', hotkeyMac: 'esc', callback: function() {
|
||||
self.isFullscreen && self.toggleFullscreen.apply(self)
|
||||
}})
|
||||
this.$el.hotKey({
|
||||
hotkey: 'esc',
|
||||
hotkeyMac: 'esc',
|
||||
callback: this.proxy(this.onEscape)
|
||||
})
|
||||
|
||||
editor.commands.addCommand({
|
||||
name: 'toggleFullscreen',
|
||||
|
|
@ -191,23 +189,90 @@
|
|||
}
|
||||
|
||||
CodeEditor.prototype.dispose = function() {
|
||||
this.editor.off('.codeeditor')
|
||||
this.editor.destroy()
|
||||
// Currently it's not possible to dispose Ace Editor
|
||||
// completely because of the internal organization of
|
||||
// because of the internal organization of the class.
|
||||
// The class instance contains multiple references to
|
||||
// DOM elements in closures and event handlers.
|
||||
// See https://github.com/ajaxorg/ace/issues/2469
|
||||
// --ab 2015-04-23
|
||||
|
||||
this.$fullscreenEnable.off('.codeeditor')
|
||||
this.$fullscreenDisable.off('.codeeditor')
|
||||
if (this.$el === null)
|
||||
return
|
||||
|
||||
this.unregisterHandlers()
|
||||
this.disposeAttachedControls()
|
||||
|
||||
this.$el = null
|
||||
this.$textarea = null
|
||||
this.$toolbar = null
|
||||
this.$code = null
|
||||
this.editor = null
|
||||
this.$fullscreenEnable = null
|
||||
this.$fullscreenDisable = null
|
||||
this.$form = null
|
||||
this.options = null
|
||||
|
||||
BaseProto.dispose.call(this)
|
||||
}
|
||||
|
||||
CodeEditor.prototype.disposeAttachedControls = function() {
|
||||
this.editor.destroy()
|
||||
|
||||
var keys = Object.keys(this.editor.renderer)
|
||||
for (var i=0, len=keys.length; i<len; i++)
|
||||
this.editor.renderer[keys[i]] = null
|
||||
|
||||
keys = Object.keys(this.editor)
|
||||
for (var i=0, len=keys.length; i<len; i++)
|
||||
this.editor[keys[i]] = null
|
||||
|
||||
this.editor = null
|
||||
|
||||
this.$toolbar.find('>ul>li>a').tooltip('destroy')
|
||||
this.$el.removeData('oc.codeEditor')
|
||||
this.$el.hotKey('dispose')
|
||||
}
|
||||
|
||||
CodeEditor.prototype.unregisterHandlers = function() {
|
||||
this.editor.off('change', this.proxy(this.onChange))
|
||||
this.editor.off('blur', this.proxy(this.onBlur))
|
||||
this.editor.off('focus', this.proxy(this.onFocus))
|
||||
|
||||
this.$fullscreenEnable.off('.codeeditor')
|
||||
this.$fullscreenDisable.off('.codeeditor')
|
||||
this.$form.off('oc.beforeRequest', this.proxy(this.onBeforeRequest))
|
||||
|
||||
this.$el.off('dispose-control', this.proxy(this.dispose))
|
||||
|
||||
$(window).off('resize', this.proxy(this.onResize))
|
||||
$(window).off('oc.updateUi', this.proxy(this.onResize))
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onBeforeRequest = function() {
|
||||
this.$textarea.val(this.editor.getSession().getValue())
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onChange = function() {
|
||||
this.$form.trigger('change')
|
||||
this.$textarea.trigger('oc.codeEditorChange')
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onResize = function() {
|
||||
this.editor.resize()
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onBlur = function() {
|
||||
this.$el.removeClass('editor-focus')
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onFocus = function() {
|
||||
this.$el.addClass('editor-focus')
|
||||
}
|
||||
|
||||
CodeEditor.prototype.onEscape = function() {
|
||||
this.isFullscreen && this.toggleFullscreen()
|
||||
}
|
||||
|
||||
CodeEditor.prototype.setWordWrap = function(mode) {
|
||||
var session = this.editor.getSession(),
|
||||
renderer = this.editor.renderer
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ to{background-position:0 0}
|
|||
.field-richeditor.size-large .redactor-editor{height:170px !important}
|
||||
.field-richeditor.size-huge .redactor-editor{height:220px !important}
|
||||
.field-richeditor.size-giant .redactor-editor{height:320px !important}
|
||||
.redactor-box{margin-bottom:0}
|
||||
.redactor-box{margin-bottom:0;overflow:hidden}
|
||||
.redactor-box iframe{border:none}
|
||||
.redactor-box-fullscreen{z-index:715 !important}
|
||||
.redactor-dropdown{z-index:725 !important}
|
||||
|
|
|
|||
|
|
@ -1816,27 +1816,45 @@ this.code.sync();},addColumn:function(type)
|
|||
{var $current=$(elem).find('td, th').eq(index);var td=$current.clone();td.html(this.opts.invisibleSpace);if(type=='after')
|
||||
{$current.after(td);}
|
||||
else
|
||||
{$current.before(td);}},this));this.code.sync();}};};})(jQuery);+function($){"use strict";var RichEditor=function(element,options){this.options=options
|
||||
{$current.before(td);}},this));this.code.sync();}};};})(jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype
|
||||
var RichEditor=function(element,options){this.options=options
|
||||
this.$el=$(element)
|
||||
this.$textarea=this.$el.find('>textarea:first')
|
||||
this.$form=this.$el.closest('form')
|
||||
this.$dataLocker=null
|
||||
this.$editor=null
|
||||
this.redactor=null
|
||||
Base.call(this)
|
||||
this.init();}
|
||||
RichEditor.prototype=Object.create(BaseProto)
|
||||
RichEditor.prototype.constructor=RichEditor
|
||||
RichEditor.DEFAULTS={stylesheet:null,fullpage:false}
|
||||
RichEditor.prototype.init=function(){var self=this;if(this.options.dataLocker){this.$dataLocker=$(this.options.dataLocker)
|
||||
RichEditor.prototype.init=function(){var self=this;this.$el.one('dispose-control',this.proxy(this.dispose))
|
||||
if(this.options.dataLocker){this.$dataLocker=$(this.options.dataLocker)
|
||||
this.$textarea.val(this.$dataLocker.val())}
|
||||
if(!this.$textarea.attr('id')){this.$textarea.attr('id','element-'+Math.random().toString(36).substring(7))}
|
||||
var redactorOptions={imageEditable:true,imageResizable:true,buttonSource:true,removeDataAttr:false,syncBeforeCallback:function(html){return self.syncBefore(html)},focusCallback:function(){self.$el.addClass('editor-focus')},blurCallback:function(){self.$el.removeClass('editor-focus')},keydownCallback:function(e){return self.keydown(e,this.$editor)},enterCallback:function(e){return self.enter(e,this.$editor)},initCallback:function(){self.build(this)},changeCallback:function(){self.sanityCheckContent(this.$editor)
|
||||
this.$editor.trigger('mutate')
|
||||
self.$form.trigger('change')
|
||||
if(self.$dataLocker)
|
||||
self.$dataLocker.val(self.syncBefore(this.$editor.html()))}}
|
||||
var redactorOptions={imageEditable:true,imageResizable:true,buttonSource:true,removeDataAttr:false,syncBeforeCallback:this.proxy(this.onSyncBefore),focusCallback:this.proxy(this.onFocus),blurCallback:this.proxy(this.onBlur),keydownCallback:this.proxy(this.onKeydown),enterCallback:this.proxy(this.onEnter),changeCallback:this.proxy(this.onChange),initCallback:function(){self.build(this)}}
|
||||
if(this.options.fullpage){redactorOptions.fullpage=true}
|
||||
redactorOptions.plugins=['fullscreen','table','mediamanager']
|
||||
redactorOptions.buttons=['formatting','bold','italic','unorderedlist','orderedlist','link','horizontalrule','html'],this.$textarea.redactor(redactorOptions)}
|
||||
redactorOptions.buttons=['formatting','bold','italic','unorderedlist','orderedlist','link','horizontalrule','html'],this.$textarea.redactor(redactorOptions)
|
||||
this.redactor=this.$textarea.redactor('core.getObject')
|
||||
this.$editor=this.redactor.$editor}
|
||||
RichEditor.prototype.dispose=function(){this.unregisterHandlers()
|
||||
this.$textarea.redactor('core.destroy');this.$el.removeData('oc.richEditor')
|
||||
this.options=null
|
||||
this.$el=null
|
||||
this.$textarea=null
|
||||
this.$form=null
|
||||
this.$dataLocker=null
|
||||
this.$editor=null
|
||||
this.redactor=null
|
||||
BaseProto.dispose.call(this)}
|
||||
RichEditor.prototype.unregisterHandlers=function(){$(window).off('resize',this.proxy(this.updateLayout))
|
||||
$(window).off('oc.updateUi',this.proxy(this.updateLayout))
|
||||
this.$el.off('dispose-control',this.proxy(this.dispose))}
|
||||
RichEditor.prototype.build=function(redactor){this.updateLayout()
|
||||
$(window).resize($.proxy(this.updateLayout,this))
|
||||
$(window).on('oc.updateUi',$.proxy(this.updateLayout,this))
|
||||
$(window).on('resize',this.proxy(this.updateLayout))
|
||||
$(window).on('oc.updateUi',this.proxy(this.updateLayout))
|
||||
this.$textarea.trigger('init.oc.richeditor',[this.$el])
|
||||
this.initUiBlocks()
|
||||
var self=this
|
||||
|
|
@ -1847,9 +1865,9 @@ return
|
|||
if(this.$el.hasClass('stretch')){var height=$toolbar.outerHeight(true)
|
||||
$editor.css('top',height+1)
|
||||
$codeEditor.css('top',height)}}
|
||||
RichEditor.prototype.sanityCheckContent=function($editor){var safeElements='p, h1, h2, h3, h4, h5, pre, figure';if(!$editor.children(':last-child').is(safeElements)){$editor.append('<p><br></p>')}
|
||||
if(!$editor.children(':first-child').is(safeElements)){$editor.prepend('<p><br></p>')}
|
||||
this.$textarea.trigger('sanitize.oc.richeditor',[$editor])}
|
||||
RichEditor.prototype.sanityCheckContent=function(){var safeElements='p, h1, h2, h3, h4, h5, pre, figure';if(!this.$editor.children(':last-child').is(safeElements)){this.$editor.append('<p><br></p>')}
|
||||
if(!this.$editor.children(':first-child').is(safeElements)){this.$editor.prepend('<p><br></p>')}
|
||||
this.$textarea.trigger('sanitize.oc.richeditor',[this.$editor])}
|
||||
RichEditor.prototype.syncBefore=function(html){var container={html:html}
|
||||
this.$textarea.trigger('syncBefore.oc.richeditor',[container])
|
||||
var $domTree=$('<div>'+container.html+'</div>')
|
||||
|
|
@ -1861,73 +1879,79 @@ $(this).remove()})
|
|||
$domTree.find('[data-video], [data-audio]').each(function(){$(this).removeAttr('contenteditable data-ui-block tabindex')})
|
||||
$domTree.find('div.oc-figure-controls').remove()
|
||||
return $domTree.html()}
|
||||
RichEditor.prototype.keydown=function(e,$editor){this.$textarea.trigger('keydown.oc.richeditor',[e,$editor,this.$textarea])
|
||||
if(e.isDefaultPrevented())
|
||||
return false
|
||||
this.handleUiBlocksKeydown(e,$editor,this.$textarea)
|
||||
if(e.isDefaultPrevented())
|
||||
return false}
|
||||
RichEditor.prototype.enter=function(e,$editor){this.$textarea.trigger('enter.oc.richeditor',[e,$editor,this.$textarea])
|
||||
if(e.isDefaultPrevented())
|
||||
return false
|
||||
this.handleUiBlocksKeydown(e,$editor,this.$textarea)
|
||||
if(e.isDefaultPrevented())
|
||||
return false}
|
||||
RichEditor.prototype.onShowFigureToolbar=function($figure,$toolbar){var toolbarTop=$figure.position().top-$toolbar.height()-10
|
||||
$toolbar.toggleClass('bottom',toolbarTop<0)}
|
||||
RichEditor.prototype.insertUiBlock=function($node){var redactor=this.$textarea.redactor('core.getObject'),current=redactor.selection.getCurrent(),inserted=false
|
||||
RichEditor.prototype.insertUiBlock=function($node){var current=this.redactor.selection.getCurrent(),inserted=false
|
||||
if(current===false)
|
||||
redactor.focus.setStart()
|
||||
current=redactor.selection.getCurrent()
|
||||
this.redactor.focus.setStart()
|
||||
current=this.redactor.selection.getCurrent()
|
||||
if(current!==false){var $paragraph=$(current).closest('p')
|
||||
if($paragraph.length>0){redactor.caret.setAfter($paragraph.get(0))
|
||||
if($paragraph.length>0){this.redactor.caret.setAfter($paragraph.get(0))
|
||||
if($.trim($paragraph.text()).length==0)
|
||||
$paragraph.remove()}else{var $closestBlock=$(current).closest('[data-ui-block]')
|
||||
if($closestBlock.length>0){$node.insertBefore($closestBlock.get(0))
|
||||
inserted=true}}}
|
||||
if(!inserted)
|
||||
redactor.insert.node($node)
|
||||
redactor.code.sync()
|
||||
this.redactor.insert.node($node)
|
||||
this.redactor.code.sync()
|
||||
$node.focus()}
|
||||
RichEditor.prototype.initUiBlocks=function(){$('.redactor-editor [data-video], .redactor-editor [data-audio]',this.$el).each(function(){$(this).attr({'data-ui-block':true,'tabindex':'0'})
|
||||
this.contentEditable=false})}
|
||||
RichEditor.prototype.handleUiBlocksKeydown=function(originalEv,$editor,$textarea){if($textarea===undefined)
|
||||
RichEditor.prototype.handleUiBlocksKeydown=function(ev){if(this.$textarea===undefined)
|
||||
return
|
||||
var redactor=$textarea.redactor('core.getObject')
|
||||
if(originalEv.target&&$(originalEv.target).attr('data-ui-block')!==undefined){this.uiBlockKeyDown(originalEv,originalEv.target)
|
||||
originalEv.preventDefault()
|
||||
if(ev.target&&$(ev.target).attr('data-ui-block')!==undefined){this.uiBlockKeyDown(ev,ev.target)
|
||||
ev.preventDefault()
|
||||
return}
|
||||
switch(originalEv.which){case 38:var block=redactor.selection.getBlock()
|
||||
switch(ev.which){case 38:var block=this.redactor.selection.getBlock()
|
||||
if(block)
|
||||
this.handleUiBlockCaretIn($(block).prev(),redactor)
|
||||
this.handleUiBlockCaretIn($(block).prev())
|
||||
break
|
||||
case 40:var block=redactor.selection.getBlock()
|
||||
case 40:var block=this.redactor.selection.getBlock()
|
||||
if(block)
|
||||
this.handleUiBlockCaretIn($(block).next(),redactor)
|
||||
this.handleUiBlockCaretIn($(block).next())
|
||||
break}}
|
||||
RichEditor.prototype.handleUiBlockCaretIn=function($block,redactor){if($block.attr('data-ui-block')!==undefined){$block.focus()
|
||||
redactor.selection.remove()
|
||||
RichEditor.prototype.handleUiBlockCaretIn=function($block){if($block.attr('data-ui-block')!==undefined){$block.focus()
|
||||
this.redactor.selection.remove()
|
||||
return true}
|
||||
return false}
|
||||
RichEditor.prototype.uiBlockKeyDown=function(ev,block){if(ev.which==40||ev.which==38||ev.which==13||ev.which==8){var $textarea=$(block).closest('.redactor-box').find('textarea'),redactor=$textarea.redactor('core.getObject')
|
||||
switch(ev.which){case 40:this.focusUiBlockOrText(redactor,$(block).next(),true)
|
||||
RichEditor.prototype.uiBlockKeyDown=function(ev,block){if(ev.which==40||ev.which==38||ev.which==13||ev.which==8){switch(ev.which){case 40:this.focusUiBlockOrText($(block).next(),true)
|
||||
break
|
||||
case 38:this.focusUiBlockOrText(redactor,$(block).prev(),false)
|
||||
case 38:this.focusUiBlockOrText($(block).prev(),false)
|
||||
break
|
||||
case 13:var $paragraph=$('<p><br/></p>')
|
||||
$paragraph.insertAfter(block)
|
||||
redactor.caret.setStart($paragraph.get(0))
|
||||
this.redactor.caret.setStart($paragraph.get(0))
|
||||
break
|
||||
case 8:var $nextFocus=$(block).next(),gotoStart=true
|
||||
if($nextFocus.length==0){$nextFocus=$(block).prev()
|
||||
gotoStart=false}
|
||||
this.focusUiBlockOrText(redactor,$nextFocus,gotoStart)
|
||||
this.focusUiBlockOrText($nextFocus,gotoStart)
|
||||
$(block).remove()
|
||||
break}}}
|
||||
RichEditor.prototype.focusUiBlockOrText=function(redactor,$block,gotoStart){if($block.length>0){if(!this.handleUiBlockCaretIn($block,redactor)){if(gotoStart)
|
||||
redactor.caret.setStart($block.get(0))
|
||||
RichEditor.prototype.focusUiBlockOrText=function($block,gotoStart){if($block.length>0){if(!this.handleUiBlockCaretIn($block,this.redactor)){if(gotoStart)
|
||||
this.redactor.caret.setStart($block.get(0))
|
||||
else
|
||||
redactor.caret.setEnd($block.get(0))}}}
|
||||
this.redactor.caret.setEnd($block.get(0))}}}
|
||||
RichEditor.prototype.onSyncBefore=function(html){return this.syncBefore(html)}
|
||||
RichEditor.prototype.onFocus=function(){this.$el.addClass('editor-focus')}
|
||||
RichEditor.prototype.onBlur=function(){this.$el.removeClass('editor-focus')}
|
||||
RichEditor.prototype.onKeydown=function(ev){this.$textarea.trigger('keydown.oc.richeditor',[ev,this.$editor,this.$textarea])
|
||||
if(ev.isDefaultPrevented())
|
||||
return false
|
||||
this.handleUiBlocksKeydown(ev)
|
||||
if(ev.isDefaultPrevented())
|
||||
return false}
|
||||
RichEditor.prototype.onEnter=function(ev){this.$textarea.trigger('enter.oc.richeditor',[ev,this.$editor,this.$textarea])
|
||||
if(ev.isDefaultPrevented())
|
||||
return false
|
||||
this.handleUiBlocksKeydown(ev)
|
||||
if(ev.isDefaultPrevented())
|
||||
return false}
|
||||
RichEditor.prototype.onChange=function(ev){this.sanityCheckContent()
|
||||
this.$editor.trigger('mutate')
|
||||
this.$form.trigger('change')
|
||||
if(this.$dataLocker)
|
||||
this.$dataLocker.val(this.syncBefore(this.$editor.html()))}
|
||||
var old=$.fn.richEditor
|
||||
$.fn.richEditor=function(option){var args=arguments;return this.each(function(){var $this=$(this)
|
||||
var data=$this.data('oc.richEditor')
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
* - Redactor Editor (redactor.js)
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
var Base = $.oc.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
|
||||
// RICHEDITOR CLASS DEFINITION
|
||||
// ============================
|
||||
|
|
@ -21,19 +24,27 @@
|
|||
this.$textarea = this.$el.find('>textarea:first')
|
||||
this.$form = this.$el.closest('form')
|
||||
this.$dataLocker = null
|
||||
this.$editor = null
|
||||
this.redactor = null
|
||||
|
||||
Base.call(this)
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
RichEditor.prototype = Object.create(BaseProto)
|
||||
RichEditor.prototype.constructor = RichEditor
|
||||
|
||||
RichEditor.DEFAULTS = {
|
||||
stylesheet: null,
|
||||
fullpage: false
|
||||
}
|
||||
|
||||
RichEditor.prototype.init = function (){
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$el.one('dispose-control', this.proxy(this.dispose))
|
||||
|
||||
/*
|
||||
* Sync all changes to a data locker, since fullscreen mode
|
||||
* will pull the textarea outside of the form element.
|
||||
|
|
@ -58,20 +69,13 @@
|
|||
imageResizable: true,
|
||||
buttonSource: true,
|
||||
removeDataAttr: false,
|
||||
syncBeforeCallback: function(html) { return self.syncBefore(html) },
|
||||
focusCallback: function() { self.$el.addClass('editor-focus') },
|
||||
blurCallback: function() { self.$el.removeClass('editor-focus') },
|
||||
keydownCallback: function(e) { return self.keydown(e, this.$editor) },
|
||||
enterCallback: function(e) { return self.enter(e, this.$editor) },
|
||||
initCallback: function() { self.build(this) },
|
||||
changeCallback: function() {
|
||||
self.sanityCheckContent(this.$editor)
|
||||
this.$editor.trigger('mutate')
|
||||
self.$form.trigger('change')
|
||||
|
||||
if (self.$dataLocker)
|
||||
self.$dataLocker.val(self.syncBefore(this.$editor.html()))
|
||||
}
|
||||
syncBeforeCallback: this.proxy(this.onSyncBefore),
|
||||
focusCallback: this.proxy(this.onFocus),
|
||||
blurCallback: this.proxy(this.onBlur),
|
||||
keydownCallback: this.proxy(this.onKeydown),
|
||||
enterCallback: this.proxy(this.onEnter),
|
||||
changeCallback: this.proxy(this.onChange),
|
||||
initCallback: function() { self.build(this) }
|
||||
}
|
||||
|
||||
if (this.options.fullpage) {
|
||||
|
|
@ -82,13 +86,39 @@
|
|||
redactorOptions.buttons = ['formatting', 'bold', 'italic', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule', 'html'],
|
||||
|
||||
this.$textarea.redactor(redactorOptions)
|
||||
|
||||
this.redactor = this.$textarea.redactor('core.getObject')
|
||||
this.$editor = this.redactor.$editor
|
||||
}
|
||||
|
||||
RichEditor.prototype.dispose = function() {
|
||||
this.unregisterHandlers()
|
||||
|
||||
this.$textarea.redactor('core.destroy');
|
||||
this.$el.removeData('oc.richEditor')
|
||||
|
||||
this.options = null
|
||||
this.$el = null
|
||||
this.$textarea = null
|
||||
this.$form = null
|
||||
this.$dataLocker = null
|
||||
this.$editor = null
|
||||
this.redactor = null
|
||||
|
||||
BaseProto.dispose.call(this)
|
||||
}
|
||||
|
||||
RichEditor.prototype.unregisterHandlers = function() {
|
||||
$(window).off('resize', this.proxy(this.updateLayout))
|
||||
$(window).off('oc.updateUi', this.proxy(this.updateLayout))
|
||||
this.$el.off('dispose-control', this.proxy(this.dispose))
|
||||
}
|
||||
|
||||
RichEditor.prototype.build = function(redactor) {
|
||||
this.updateLayout()
|
||||
|
||||
$(window).resize($.proxy(this.updateLayout, this))
|
||||
$(window).on('oc.updateUi', $.proxy(this.updateLayout, this))
|
||||
$(window).on('resize', this.proxy(this.updateLayout))
|
||||
$(window).on('oc.updateUi', this.proxy(this.updateLayout))
|
||||
|
||||
this.$textarea.trigger('init.oc.richeditor', [this.$el])
|
||||
|
||||
|
|
@ -117,19 +147,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
RichEditor.prototype.sanityCheckContent = function($editor) {
|
||||
RichEditor.prototype.sanityCheckContent = function() {
|
||||
// First and last elements should always be paragraphs or pre
|
||||
var safeElements = 'p, h1, h2, h3, h4, h5, pre, figure';
|
||||
|
||||
if (!$editor.children(':last-child').is(safeElements)) {
|
||||
$editor.append('<p><br></p>')
|
||||
if (!this.$editor.children(':last-child').is(safeElements)) {
|
||||
this.$editor.append('<p><br></p>')
|
||||
}
|
||||
|
||||
if (!$editor.children(':first-child').is(safeElements)) {
|
||||
$editor.prepend('<p><br></p>')
|
||||
if (!this.$editor.children(':first-child').is(safeElements)) {
|
||||
this.$editor.prepend('<p><br></p>')
|
||||
}
|
||||
|
||||
this.$textarea.trigger('sanitize.oc.richeditor', [$editor])
|
||||
this.$textarea.trigger('sanitize.oc.richeditor', [this.$editor])
|
||||
}
|
||||
|
||||
RichEditor.prototype.syncBefore = function(html) {
|
||||
|
|
@ -165,30 +195,6 @@
|
|||
return $domTree.html()
|
||||
}
|
||||
|
||||
RichEditor.prototype.keydown = function(e, $editor) {
|
||||
this.$textarea.trigger('keydown.oc.richeditor', [e, $editor, this.$textarea])
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return false
|
||||
|
||||
this.handleUiBlocksKeydown(e, $editor, this.$textarea)
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return false
|
||||
}
|
||||
|
||||
RichEditor.prototype.enter = function(e, $editor) {
|
||||
this.$textarea.trigger('enter.oc.richeditor', [e, $editor, this.$textarea])
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return false
|
||||
|
||||
this.handleUiBlocksKeydown(e, $editor, this.$textarea)
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return false
|
||||
}
|
||||
|
||||
RichEditor.prototype.onShowFigureToolbar = function($figure, $toolbar) {
|
||||
// Deal with the case when the toolbar top has negative
|
||||
// value
|
||||
|
|
@ -201,20 +207,19 @@
|
|||
* Inserts non-editable block (used for snippets, audio and video)
|
||||
*/
|
||||
RichEditor.prototype.insertUiBlock = function($node) {
|
||||
var redactor = this.$textarea.redactor('core.getObject'),
|
||||
current = redactor.selection.getCurrent(),
|
||||
var current = this.redactor.selection.getCurrent(),
|
||||
inserted = false
|
||||
|
||||
if (current === false)
|
||||
redactor.focus.setStart()
|
||||
this.redactor.focus.setStart()
|
||||
|
||||
current = redactor.selection.getCurrent()
|
||||
current = this.redactor.selection.getCurrent()
|
||||
|
||||
if (current !== false) {
|
||||
// If the block is inserted into a paragraph, insert it after the paragraph.
|
||||
var $paragraph = $(current).closest('p')
|
||||
if ($paragraph.length > 0) {
|
||||
redactor.caret.setAfter($paragraph.get(0))
|
||||
this.redactor.caret.setAfter($paragraph.get(0))
|
||||
|
||||
// If the paragraph is empty, remove it.
|
||||
if ($.trim($paragraph.text()).length == 0)
|
||||
|
|
@ -230,9 +235,9 @@
|
|||
}
|
||||
|
||||
if (!inserted)
|
||||
redactor.insert.node($node)
|
||||
this.redactor.insert.node($node)
|
||||
|
||||
redactor.code.sync()
|
||||
this.redactor.code.sync()
|
||||
|
||||
$node.focus()
|
||||
}
|
||||
|
|
@ -247,39 +252,37 @@
|
|||
})
|
||||
}
|
||||
|
||||
RichEditor.prototype.handleUiBlocksKeydown = function(originalEv, $editor, $textarea) {
|
||||
if ($textarea === undefined)
|
||||
RichEditor.prototype.handleUiBlocksKeydown = function(ev) {
|
||||
if (this.$textarea === undefined)
|
||||
return
|
||||
|
||||
var redactor = $textarea.redactor('core.getObject')
|
||||
if (ev.target && $(ev.target).attr('data-ui-block') !== undefined) {
|
||||
this.uiBlockKeyDown(ev, ev.target)
|
||||
|
||||
if (originalEv.target && $(originalEv.target).attr('data-ui-block') !== undefined) {
|
||||
this.uiBlockKeyDown(originalEv, originalEv.target)
|
||||
|
||||
originalEv.preventDefault()
|
||||
ev.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
switch (originalEv.which) {
|
||||
switch (ev.which) {
|
||||
case 38:
|
||||
// Up arrow
|
||||
var block = redactor.selection.getBlock()
|
||||
var block = this.redactor.selection.getBlock()
|
||||
if (block)
|
||||
this.handleUiBlockCaretIn($(block).prev(), redactor)
|
||||
this.handleUiBlockCaretIn($(block).prev())
|
||||
break
|
||||
case 40:
|
||||
// Down arrow
|
||||
var block = redactor.selection.getBlock()
|
||||
var block = this.redactor.selection.getBlock()
|
||||
if (block)
|
||||
this.handleUiBlockCaretIn($(block).next(), redactor)
|
||||
this.handleUiBlockCaretIn($(block).next())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
RichEditor.prototype.handleUiBlockCaretIn = function($block, redactor) {
|
||||
RichEditor.prototype.handleUiBlockCaretIn = function($block) {
|
||||
if ($block.attr('data-ui-block') !== undefined) {
|
||||
$block.focus()
|
||||
redactor.selection.remove()
|
||||
this.redactor.selection.remove()
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -289,23 +292,20 @@
|
|||
|
||||
RichEditor.prototype.uiBlockKeyDown = function(ev, block) {
|
||||
if (ev.which == 40 || ev.which == 38 || ev.which == 13 || ev.which == 8) {
|
||||
var $textarea = $(block).closest('.redactor-box').find('textarea'),
|
||||
redactor = $textarea.redactor('core.getObject')
|
||||
|
||||
switch (ev.which) {
|
||||
case 40:
|
||||
// Down arrow
|
||||
this.focusUiBlockOrText(redactor, $(block).next(), true)
|
||||
this.focusUiBlockOrText($(block).next(), true)
|
||||
break
|
||||
case 38:
|
||||
// Up arrow
|
||||
this.focusUiBlockOrText(redactor, $(block).prev(), false)
|
||||
this.focusUiBlockOrText($(block).prev(), false)
|
||||
break
|
||||
case 13:
|
||||
// Enter key
|
||||
var $paragraph = $('<p><br/></p>')
|
||||
$paragraph.insertAfter(block)
|
||||
redactor.caret.setStart($paragraph.get(0))
|
||||
this.redactor.caret.setStart($paragraph.get(0))
|
||||
break
|
||||
case 8:
|
||||
// Backspace key
|
||||
|
|
@ -317,7 +317,7 @@
|
|||
gotoStart = false
|
||||
}
|
||||
|
||||
this.focusUiBlockOrText(redactor, $nextFocus, gotoStart)
|
||||
this.focusUiBlockOrText($nextFocus, gotoStart)
|
||||
|
||||
$(block).remove()
|
||||
break
|
||||
|
|
@ -325,17 +325,65 @@
|
|||
}
|
||||
}
|
||||
|
||||
RichEditor.prototype.focusUiBlockOrText = function(redactor, $block, gotoStart) {
|
||||
RichEditor.prototype.focusUiBlockOrText = function($block, gotoStart) {
|
||||
if ($block.length > 0) {
|
||||
if (!this.handleUiBlockCaretIn($block, redactor)) {
|
||||
if (!this.handleUiBlockCaretIn($block, this.redactor)) {
|
||||
if (gotoStart)
|
||||
redactor.caret.setStart($block.get(0))
|
||||
this.redactor.caret.setStart($block.get(0))
|
||||
else
|
||||
redactor.caret.setEnd($block.get(0))
|
||||
this.redactor.caret.setEnd($block.get(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EVENT HANDLERS
|
||||
// ============================
|
||||
|
||||
RichEditor.prototype.onSyncBefore = function(html) {
|
||||
return this.syncBefore(html)
|
||||
}
|
||||
|
||||
RichEditor.prototype.onFocus = function() {
|
||||
this.$el.addClass('editor-focus')
|
||||
}
|
||||
|
||||
RichEditor.prototype.onBlur = function() {
|
||||
this.$el.removeClass('editor-focus')
|
||||
}
|
||||
|
||||
RichEditor.prototype.onKeydown = function(ev) {
|
||||
this.$textarea.trigger('keydown.oc.richeditor', [ev, this.$editor, this.$textarea])
|
||||
|
||||
if (ev.isDefaultPrevented())
|
||||
return false
|
||||
|
||||
this.handleUiBlocksKeydown(ev)
|
||||
|
||||
if (ev.isDefaultPrevented())
|
||||
return false
|
||||
}
|
||||
|
||||
RichEditor.prototype.onEnter = function(ev) {
|
||||
this.$textarea.trigger('enter.oc.richeditor', [ev, this.$editor, this.$textarea])
|
||||
|
||||
if (ev.isDefaultPrevented())
|
||||
return false
|
||||
|
||||
this.handleUiBlocksKeydown(ev)
|
||||
|
||||
if (ev.isDefaultPrevented())
|
||||
return false
|
||||
}
|
||||
|
||||
RichEditor.prototype.onChange = function(ev) {
|
||||
this.sanityCheckContent()
|
||||
this.$editor.trigger('mutate')
|
||||
this.$form.trigger('change')
|
||||
|
||||
if (this.$dataLocker)
|
||||
this.$dataLocker.val(this.syncBefore(this.$editor.html()))
|
||||
}
|
||||
|
||||
// RICHEDITOR PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
.redactor-box {
|
||||
margin-bottom: 0;
|
||||
overflow: hidden;
|
||||
|
||||
& iframe {
|
||||
border: none; // Oc
|
||||
|
|
|
|||
Loading…
Reference in New Issue