Initial switch from Redactor to Froala

This commit is contained in:
Samuel Georges 2016-05-15 06:00:58 +10:00
parent 3eb47e679b
commit 4789616190
11 changed files with 110 additions and 1043 deletions

View File

@ -119,10 +119,13 @@ class RichEditor extends FormWidgetBase
{
$this->addCss('css/richeditor.css', 'core');
$this->addJs('js/build-min.js', 'core');
$this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core');
if ($lang = $this->getValidEditorLang()) {
$this->addJs('vendor/redactor/lang/'.$lang.'.js', 'core');
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// if ($lang = $this->getValidEditorLang()) {
// $this->addJs('vendor/redactor/lang/'.$lang.'.js', 'core');
// }
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
/**

View File

@ -1 +0,0 @@
There's a hack in plugin.figure.js script. Added method destory(). The figure plugin keeps a reference to the editor and toolba which can't be cleaned up after the Editor is destroyed. Also, the figure plugin binds event handlers that are never unbound. --ab Apr 08 2015

View File

@ -7,11 +7,10 @@
* @see build-min.js
*
=require ../vendor/redactor/redactor.js
=require plugin.fullscreen.js
=require plugin.figure.js
=require plugin.table.js
=require plugin.pagelinks.js
=require ../vendor/froala/js/froala_editor.min.js
=require ../vendor/froala/js/plugins/fullscreen.min.js
=require ../vendor/froala/js/plugins/code_beautifier.min.js
=require ../vendor/froala_drm/js/plugins/code_view.js
=require richeditor.js
*/

View File

@ -1,47 +0,0 @@
if (!RedactorPlugins) var RedactorPlugins = {};
(function($) {
RedactorPlugins.definedlinks = function() {
return {
init: function() {
if (!this.opts.definedLinks) return;
this.modal.addCallback('link', $.proxy(this.definedlinks.load, this));
},
load: function() {
var $select = $('<select id="redactor-defined-links" />');
$('#redactor-modal-link-insert').prepend($select);
this.definedlinks.storage = {};
$.getJSON(this.opts.definedLinks, $.proxy(function(data) {
$.each(data, $.proxy(function(key, val) {
this.definedlinks.storage[key] = val;
$select.append($('<option>').val(key).html(val.name));
}, this));
$select.on('change', $.proxy(this.definedlinks.select, this));
}, this));
},
select: function(e) {
var key = $(e.target).val();
var name = '', url = '';
if (key !== 0)
{
name = this.definedlinks.storage[key].name;
url = this.definedlinks.storage[key].url;
}
$('#redactor-link-url').val(url);
var $el = $('#redactor-link-url-text');
if ($el.val() === '') $el.val(name);
}
};
};
})(jQuery);

View File

@ -1,267 +0,0 @@
(function ($) {
'use strict';
window.RedactorPlugins = window.RedactorPlugins || {}
var Figure = function (redactor) {
this.redactor = redactor
this.toolbar = {}
this.init()
}
Figure.prototype = {
control: {
up : { classSuffix: 'arrow-up' },
down : { classSuffix: 'arrow-down' },
'|' : { classSuffix: 'divider' },
remove: { classSuffix: 'delete' }
},
controlGroup: ['up', 'down', 'remove'],
init: function () {
this.observeToolbars()
this.observeKeyboard()
},
showToolbar: function (event) {
var $figure = $(event.currentTarget),
type = $figure.data('type') || 'default',
$toolbar = this.getToolbar(type).data('figure', $figure).prependTo($figure).show()
if (this.redactor[type] && this.redactor[type].onShow) {
this.redactor[type].onShow($figure, $toolbar)
}
},
hideToolbar: function (event) {
$(event.currentTarget).find('.oc-figure-controls').appendTo(this.redactor.$box).hide()
},
observeToolbars: function () {
/*
* Before clicking a command, make sure we save the current node within the editor
*/
this.redactor.$editor.on('mousedown.figure', '.oc-figure-controls', $.proxy(function (event) {
event.preventDefault()
this.current = this.redactor.selection.getCurrent()
}, this))
this.redactor.$editor.on('click.figure', '.oc-figure-controls span, .oc-figure-controls a', $.proxy(function (event) {
event.stopPropagation()
var $target = $(event.currentTarget),
command = $target.data('command'),
$figure = $target.closest('figure'),
plugin = this.redactor[$figure.data('type')]
this.command(command, $figure, plugin)
}, this))
this.redactor.$editor.on('keydown.figure', function () {
$(this).find('figure').triggerHandler('mouseleave')
})
/*
* Mobile
*/
if (this.redactor.utils.isMobile()) {
/*
* If $editor is focused, click doesn't seem to fire
*/
this.redactor.$editor.on('touchstart.figure', 'figure', function (event) {
if (event.target.nodeName !== 'FIGCAPTION' && $(event.target).parents('.oc-figure-controls').length) {
$(this).trigger('click', event)
}
})
this.redactor.$editor.on('click.figure', 'figure', $.proxy(function (event) {
if (event.target.nodeName !== 'FIGCAPTION') {
this.redactor.$editor.trigger('blur')
}
this.showToolbar(event)
}, this))
}
/*
* Desktop
*/
else {
/*
* Move toolbar into figure on mouseenter
*/
this.redactor.$editor.on('mouseenter.figure', 'figure', $.proxy(this.showToolbar, this))
/*
* Remove toolbar from figure on mouseleave
*/
this.redactor.$editor.on('mouseleave.figure', 'figure', $.proxy(this.hideToolbar, this))
}
},
getToolbar: function (type) {
if (this.toolbar[type])
return this.toolbar[type]
var controlGroup = (this.redactor[type] && this.redactor[type].controlGroup) || this.controlGroup,
controls = $.extend({}, this.control, (this.redactor[type] && this.redactor[type].control) || {}),
$controls = this.buildControls(controlGroup, controls),
$toolbar = $('<div class="oc-figure-controls">').append($controls)
this.toolbar[type] = $toolbar
return $toolbar
},
buildControls: function (controlGroup, controls) {
var $controls = $()
$.each(controlGroup, $.proxy(function (index, command) {
var control
/*
* Basic command
*/
if (typeof command === 'string') {
control = controls[command]
$controls = $controls.add($('<span>', {
'class': 'oc-figure-controls-' + control.classSuffix,
'text': control.text
}).data({
command: command,
control: control
}))
}
/*
* Dropdown
*/
else if (typeof command === 'object') {
$.each(command, $.proxy(function (text, commands) {
var $button = $('<span>').text(' ' + text).addClass('oc-figure-controls-table dropdown'),
$dropdown = $('<ul class="dropdown-menu open oc-dropdown-menu" />'),
container = $('<li class="dropdown-container" />'),
list = $('<ul />'),
listItem
$dropdown.append(container.append(list))
$button.append($dropdown)
$button.on('mouseover.figure', function () { $dropdown.show() })
$button.on('mouseout.figure', function () { $dropdown.hide() })
$.each(commands, $.proxy(function (index, command) {
control = controls[command]
if (command === '|') {
$('<li class="divider" />').appendTo(list)
}
else {
listItem = $('<li />')
$('<a />', {
text: control.text
}).data({
command: command,
control: control
}).appendTo(listItem)
if (index == 0) listItem.addClass('first-item')
listItem.appendTo(list)
}
}, this))
$controls = $controls.add($button)
}, this))
}
}, this))
return $controls
},
command: function (command, $figure, plugin) {
/*
* Move the toolbar before carrying out the command so it doesn't break when undoing/redoing
*/
$figure.find('.oc-figure-controls').appendTo(this.redactor.$box)
/*
* Maintain undo history
*/
this.redactor.buffer.set(this.redactor.$editor.html())
/*
* Shared functions
*/
switch (command) {
case 'up':
$figure.prev().before($figure)
break
case 'down':
$figure.next().after($figure)
break
case 'remove':
$figure.remove()
break
default:
if (plugin && plugin.command) {
plugin.command(command, $figure, $(this.current))
}
break
}
this.redactor.code.sync()
},
observeKeyboard: function () {
var redactor = this.redactor
redactor.$editor.on('keydown.figure', function (event) {
/*
* Node at cursor
*/
var currentNode = redactor.selection.getBlock()
/*
* Delete key
*/
if (
event.keyCode === 8
&& !redactor.caret.getOffset(currentNode)
&& currentNode.previousSibling
&& currentNode.previousSibling.nodeName === 'FIGURE'
) {
event.preventDefault()
}
})
},
destroy: function() {
this.redactor.$editor.off('.figure')
for (var type in this.toolbar) {
this.toolbar[type].find('span').off('.figure')
}
this.redactor = null
this.toolbar = null
}
}
window.RedactorPlugins.figure = function() {
return {
init: function () {
this.figure = new Figure(this)
}
}
}
}(jQuery));

View File

@ -1,129 +0,0 @@
(function ($) {
'use strict';
window.RedactorPlugins = window.RedactorPlugins || {};
window.RedactorPlugins.fullscreen = function() {
return {
init: function() {
this.fullscreen.isOpen = false
var button = this.button.add('fullscreen', 'FullScreen')
this.button.addCallback(button, $.proxy(this.fullscreen.toggle, this))
button.addClass('redactor_btn_fullscreen').removeClass('redactor-btn-image')
button.parent().addClass('redactor-btn-right')
if (this.opts.fullscreen)
this.fullscreen.toggle()
},
toggle: function() {
if (!this.fullscreen.isOpen)
this.fullscreen.enable()
else
this.fullscreen.disable()
},
enable: function() {
this.button.changeIcon('fullscreen', 'normalscreen')
this.button.setActive('fullscreen')
this.fullscreen.isOpen = true
if (this.opts.toolbarExternal) {
this.fullscreen.toolcss = {}
this.fullscreen.boxcss = {}
this.fullscreen.toolcss.width = this.$toolbar.css('width')
this.fullscreen.toolcss.top = this.$toolbar.css('top')
this.fullscreen.toolcss.position = this.$toolbar.css('position')
this.fullscreen.boxcss.top = this.$box.css('top')
}
this.fullscreen.height = this.$editor.height()
if (this.opts.maxHeight) this.$editor.css('max-height', '')
if (this.opts.minHeight) this.$editor.css('min-height', '')
if (!this.$fullscreenPlaceholder) this.$fullscreenPlaceholder = $('<div/>')
this.$fullscreenPlaceholder.insertAfter(this.$box)
this.$box.appendTo(document.body)
this.$box.addClass('redactor-box-fullscreen')
$('body, html').css('overflow', 'hidden')
this.fullscreen.resize()
$(window).on('resize.redactor.fullscreen', $.proxy(this.fullscreen.resize, this))
$(document).scrollTop(0, 0)
this.$editor.focus()
this.observe.load()
},
disable: function() {
this.button.removeIcon('fullscreen', 'normalscreen')
this.button.setInactive('fullscreen')
this.fullscreen.isOpen = false
$(window).off('resize.redactor.fullscreen')
$('body, html').css('overflow', '')
this.$box.insertBefore(this.$fullscreenPlaceholder)
this.$fullscreenPlaceholder.remove()
this.$box.removeClass('redactor-box-fullscreen').css({ width: 'auto', height: 'auto' })
this.code.sync()
if (this.opts.toolbarExternal) {
this.$box.css('top', this.fullscreen.boxcss.top)
this.$toolbar.css({
'width': this.fullscreen.toolcss.width,
'top': this.fullscreen.toolcss.top,
'position': this.fullscreen.toolcss.position
})
}
if (this.opts.minHeight) this.$editor.css('minHeight', this.opts.minHeight)
if (this.opts.maxHeight) this.$editor.css('maxHeight', this.opts.maxHeight)
this.$editor.css('height', 'auto')
this.$editor.focus()
this.observe.load()
},
resize: function() {
if (!this.fullscreen.isOpen)
return false
var pad = this.$editor.css('padding-top').replace('px', '')
var toolbarHeight = this.$toolbar.height(),
height = $(window).height() - toolbarHeight
this.$box.width($(window).width() - 2).height(height + toolbarHeight)
if (this.opts.toolbarExternal) {
this.$toolbar.css({
top: '0px',
position: 'absolute',
width: '100%'
})
this.$box.css('top', toolbarHeight + 'px')
}
// if (!this.opts.iframe) {
// this.$editor.height(height - (pad * 2))
// }
// else {
// setTimeout($.proxy(function() {
// this.$frame.height(height)
// }, this), 1)
// }
// this.$editor.height(height)
}
}
}
}(jQuery));

View File

@ -1,52 +0,0 @@
if (!RedactorPlugins) var RedactorPlugins = {};
(function($)
{
RedactorPlugins.pagelinks = function()
{
return {
init: function()
{
if (!this.opts.pageLinksHandler) return
this.modal.addCallback('link', $.proxy(this.pagelinks.load, this))
},
load: function()
{
var $select = $('<select id="redactor-page-links" />')
$('#redactor-modal-link-insert').prepend($select)
this.pagelinks.storage = {};
this.$editor.request(this.opts.pageLinksHandler, {
success: $.proxy(function(data) {
$.each(data.links, $.proxy(function(key, val) {
this.pagelinks.storage[key] = val
$select.append($('<option>').val(key).html(val.name))
}, this))
$select.on('change', $.proxy(this.pagelinks.select, this))
}, this)
})
},
select: function(e)
{
var key = $(e.target).val()
var name = '', url = ''
if (key !== 0) {
name = this.pagelinks.storage[key].name
url = this.pagelinks.storage[key].url
}
$('#redactor-link-url').val(url)
var $el = $('#redactor-link-url-text')
if ($el.val() === '') {
$el.val($.trim($('<span />').html(name).text()))
}
}
};
};
})(jQuery);

View File

@ -1,340 +0,0 @@
if (!RedactorPlugins) var RedactorPlugins = {};
(function($)
{
RedactorPlugins.table = function()
{
return {
getTemplate: function()
{
return String()
+ '<section id="redactor-modal-table-insert">'
+ '<label>' + this.lang.get('rows') + '</label>'
+ '<input type="text" size="5" value="2" id="redactor-table-rows" />'
+ '<label>' + this.lang.get('columns') + '</label>'
+ '<input type="text" size="5" value="3" id="redactor-table-columns" />'
+ '</section>';
},
init: function()
{
var dropdown = {};
dropdown.insert_table = { title: this.lang.get('insert_table'), func: this.table.show };
dropdown.insert_row_above = { title: this.lang.get('insert_row_above'), func: this.table.addRowAbove };
dropdown.insert_row_below = { title: this.lang.get('insert_row_below'), func: this.table.addRowBelow };
dropdown.insert_column_left = { title: this.lang.get('insert_column_left'), func: this.table.addColumnLeft };
dropdown.insert_column_right = { title: this.lang.get('insert_column_right'), func: this.table.addColumnRight };
dropdown.add_head = { title: this.lang.get('add_head'), func: this.table.addHead };
dropdown.delete_head = { title: this.lang.get('delete_head'), func: this.table.deleteHead };
dropdown.delete_column = { title: this.lang.get('delete_column'), func: this.table.deleteColumn };
dropdown.delete_row = { title: this.lang.get('delete_row'), func: this.table.deleteRow };
dropdown.delete_table = { title: this.lang.get('delete_table'), func: this.table.deleteTable };
this.observe.addButton('td', 'table');
this.observe.addButton('th', 'table');
var button = this.button.addBefore('link', 'table', this.lang.get('table'));
this.button.addDropdown(button, dropdown);
button.addClass('redactor_btn_table').removeClass('redactor-btn-image')
},
show: function()
{
this.modal.addTemplate('table', this.table.getTemplate());
this.modal.load('table', this.lang.get('insert_table'), 300);
this.modal.createCancelButton();
var button = this.modal.createActionButton(this.lang.get('insert'));
button.on('click', this.table.insert);
this.selection.save();
this.modal.show();
$('#redactor-table-rows').focus();
},
insert: function()
{
this.placeholder.remove();
this.clean.cleanEmptyParagraph();
var rows = $('#redactor-table-rows').val(),
columns = $('#redactor-table-columns').val(),
$tableBox = $('<div>'),
tableId = Math.floor(Math.random() * 99999),
$table = $('<table id="table' + tableId + '"><tbody></tbody></table>'),
i, $row, z, $column;
for (i = 0; i < rows; i++)
{
$row = $('<tr>');
for (z = 0; z < columns; z++)
{
$column = $('<td>' + this.opts.invisibleSpace + '</td>');
// set the focus to the first td
if (i === 0 && z === 0)
{
$column.append(this.selection.getMarker());
}
$($row).append($column);
}
$table.append($row);
}
$tableBox.append($table);
var html = $tableBox.html();
this.modal.close();
this.selection.restore();
if (this.table.getTable()) return;
this.buffer.set();
var current = this.selection.getBlock() || this.selection.getCurrent();
if (current && current.tagName != 'BODY')
{
if (current.tagName == 'LI') current = $(current).closest('ul, ol');
$(current).after(html);
}
else
{
this.insert.html(html, false);
}
this.selection.restore();
var table = this.$editor.find('#table' + tableId);
if (!this.opts.linebreaks && (this.utils.browser('mozilla') || this.utils.browser('msie')))
{
var $next = table.next();
if ($next.length === 0)
{
table.after(this.opts.emptyHtml);
}
}
this.observe.buttons();
table.find('span.redactor-selection-marker').remove();
table.removeAttr('id');
this.code.sync();
this.core.setCallback('insertedTable', table);
},
getTable: function()
{
var $table = $(this.selection.getParent()).closest('table');
if (!this.utils.isRedactorParent($table)) return false;
if ($table.size() === 0) return false;
return $table;
},
restoreAfterDelete: function($table)
{
this.selection.restore();
$table.find('span.redactor-selection-marker').remove();
this.code.sync();
},
deleteTable: function()
{
var $table = this.table.getTable();
if (!$table) return;
this.buffer.set();
var $next = $table.next();
if (!this.opts.linebreaks && $next.length !== 0)
{
this.caret.setStart($next);
}
else
{
this.caret.setAfter($table);
}
$table.remove();
this.code.sync();
},
deleteRow: function()
{
var $table = this.table.getTable();
if (!$table) return;
var $current = $(this.selection.getCurrent());
this.buffer.set();
var $current_tr = $current.closest('tr');
var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next();
if ($focus_tr.length)
{
var $focus_td = $focus_tr.children('td, th').first();
if ($focus_td.length) $focus_td.prepend(this.selection.getMarker());
}
$current_tr.remove();
this.table.restoreAfterDelete($table);
},
deleteColumn: function()
{
var $table = this.table.getTable();
if (!$table) return;
this.buffer.set();
var $current = $(this.selection.getCurrent());
var $current_td = $current.closest('td, th');
var index = $current_td[0].cellIndex;
$table.find('tr').each($.proxy(function(i, elem)
{
var $elem = $(elem);
var focusIndex = index - 1 < 0 ? index + 1 : index - 1;
if (i === 0) $elem.find('td, th').eq(focusIndex).prepend(this.selection.getMarker());
$elem.find('td, th').eq(index).remove();
}, this));
this.table.restoreAfterDelete($table);
},
addHead: function()
{
var $table = this.table.getTable();
if (!$table) return;
this.buffer.set();
if ($table.find('thead').size() !== 0)
{
this.table.deleteHead();
return;
}
var tr = $table.find('tr').first().clone();
tr.find('td').replaceWith($.proxy(function()
{
return $('<th>').html(this.opts.invisibleSpace);
}, this));
$thead = $('<thead></thead>').append(tr);
$table.prepend($thead);
this.code.sync();
},
deleteHead: function()
{
var $table = this.table.getTable();
if (!$table) return;
var $thead = $table.find('thead');
if ($thead.size() === 0) return;
this.buffer.set();
$thead.remove();
this.code.sync();
},
addRowAbove: function()
{
this.table.addRow('before');
},
addRowBelow: function()
{
this.table.addRow('after');
},
addColumnLeft: function()
{
this.table.addColumn('before');
},
addColumnRight: function()
{
this.table.addColumn('after');
},
addRow: function(type)
{
var $table = this.table.getTable();
if (!$table) return;
this.buffer.set();
var $current = $(this.selection.getCurrent());
var $current_tr = $current.closest('tr');
var new_tr = $current_tr.clone();
new_tr.find('th').replaceWith(function()
{
var $td = $('<td>');
$td[0].attributes = this.attributes;
return $td.append($(this).contents());
});
new_tr.find('td').html(this.opts.invisibleSpace);
if (type == 'after')
{
$current_tr.after(new_tr);
}
else
{
$current_tr.before(new_tr);
}
this.code.sync();
},
addColumn: function (type)
{
var $table = this.table.getTable();
if (!$table) return;
var index = 0;
var current = $(this.selection.getCurrent());
this.buffer.set();
var $current_tr = current.closest('tr');
var $current_td = current.closest('td, th');
$current_tr.find('td, th').each($.proxy(function(i, elem)
{
if ($(elem)[0] === $current_td[0]) index = i;
}, this));
$table.find('tr').each($.proxy(function(i, elem)
{
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);

View File

@ -22,7 +22,6 @@
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
@ -37,7 +36,6 @@
RichEditor.prototype.constructor = RichEditor
RichEditor.DEFAULTS = {
dataLocker: null,
linksHandler: null,
stylesheet: null,
fullpage: false,
@ -49,15 +47,6 @@
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.
*/
if (this.options.dataLocker) {
this.$dataLocker = $(this.options.dataLocker)
this.$textarea.val(this.$dataLocker.val())
}
/*
* Textarea must have an identifier
*/
@ -68,52 +57,66 @@
/*
* Initialize Redactor editor
*/
var redactorOptions = {
lang: this.options.editorLang,
imageEditable: true,
imageResizable: true,
buttonSource: true,
removeDataAttr: false,
toolbarFixed: false,
visualCallback: this.proxy(this.onVisualMode),
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),
pageLinksHandler: this.options.linksHandler,
initCallback: function() { self.build(this) }
var froalaOptions = {
editorClass: 'control-richeditor',
height: Infinity // Height set via CSS, enable the scrollbars
}
if (this.options.fullpage) {
redactorOptions.fullpage = true
froalaOptions.toolbarButtons = [
'fullscreen',
'bold',
'italic',
'underline',
'strikeThrough',
'subscript',
'superscript',
'fontFamily',
'fontSize',
'color',
'emoticons',
'inlineStyle',
'paragraphStyle',
'paragraphFormat',
'align',
'formatOL',
'formatUL',
'outdent',
'indent',
'quote',
'insertHR',
'insertLink',
'insertImage',
'insertVideo',
'insertFile',
'insertTable',
'undo',
'redo',
'clearFormatting',
'selectAll',
'html'
]
froalaOptions.toolbarButtonsMD = froalaOptions.toolbarButtons
froalaOptions.toolbarButtonsSM = froalaOptions.toolbarButtons
froalaOptions.toolbarButtonsXS = froalaOptions.toolbarButtons
froalaOptions.htmlAllowedEmptyTags = ['figure', 'textarea', 'a', 'iframe', 'object', 'video', 'style', 'script']
froalaOptions.htmlDoNotWrapTags = ['figure', 'script', 'style']
$.FroalaEditor.ICON_TEMPLATES = {
font_awesome: '<i class="icon-[NAME]"></i>',
text: '<span style="text-align: center;">[NAME]</span>',
image: '<img src=[SRC] alt=[ALT] />'
}
redactorOptions.plugins = ['fullscreen', 'figure', 'table', 'pagelinks', 'mediamanager']
redactorOptions.buttons = ['html', 'formatting', 'bold', 'italic', 'alignment', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule'],
this.$textarea.on('froalaEditor.initialized', this.proxy(this.build))
this.$textarea.redactor(redactorOptions)
this.redactor = this.$textarea.redactor('core.getObject')
this.$editor = this.redactor.$editor
this.$textarea.froalaEditor(froalaOptions)
}
RichEditor.prototype.dispose = function() {
this.unregisterHandlers()
// Release clickedElement reference inside redactor.js
$(document).trigger('mousedown')
this.redactor.core.destroy()
// The figure plugin keeps references to the editor,
// DOM elements and event handlers. It was hacked and
// extended with the destroy() method.
if (this.redactor.figure) {
this.redactor.figure.destroy()
this.redactor.figure = null
}
this.$textarea.froalaEditor('destroy')
this.$el.removeData('oc.richEditor')
@ -121,14 +124,8 @@
this.$el = null
this.$textarea = null
this.$form = null
this.$dataLocker = null
this.$editor = null
this.redactor.$textarea = null
this.redactor.$element = null
this.redactor = null
BaseProto.dispose.call(this)
}
@ -138,7 +135,7 @@
this.$el.off('dispose-control', this.proxy(this.dispose))
}
RichEditor.prototype.build = function(redactor) {
RichEditor.prototype.build = function(event, editor) {
this.updateLayout()
$(window).on('resize', this.proxy(this.updateLayout))
@ -148,12 +145,12 @@
this.initUiBlocks()
var self = this
redactor.default = {
onShow: function($figure, $toolbar) {
self.onShowFigureToolbar($figure, $toolbar)
}
}
// var self = this
// redactor.default = {
// onShow: function($figure, $toolbar) {
// self.onShowFigureToolbar($figure, $toolbar)
// }
// }
}
RichEditor.prototype.getElement = function() {
@ -175,19 +172,24 @@
}
RichEditor.prototype.updateLayout = function() {
var $editor = $('.redactor-editor', this.$el),
$codeEditor = $('textarea', this.$el),
$toolbar = $('.redactor-toolbar', this.$el)
var $editor = $('.fr-wrapper', this.$el),
$codeEditor = $('.fr-code', this.$el),
$toolbar = $('.fr-toolbar', this.$el),
$box = $('.fr-box', this.$el)
if (!$editor.length) {
return
}
if (this.$el.hasClass('stretch')) {
if (this.$el.hasClass('stretch') && !$box.hasClass('fr-fullscreen')) {
var height = $toolbar.outerHeight(true)
$editor.css('top', height+1)
$codeEditor.css('top', height)
}
else {
$editor.css('top', '')
$codeEditor.css('top', '')
}
}
RichEditor.prototype.sanityCheckContent = function() {
@ -289,7 +291,7 @@
}
RichEditor.prototype.initUiBlocks = function() {
$('.redactor-editor [data-video], .redactor-editor [data-audio]', this.$el).each(function() {
$('.fr-wrapper [data-video], .fr-wrapper [data-audio]', this.$el).each(function() {
$(this).attr({
'data-ui-block': true,
'tabindex': '0'
@ -436,10 +438,6 @@
this.sanityCheckContent()
this.$editor.trigger('mutate')
this.$form.trigger('change')
if (this.$dataLocker) {
this.$dataLocker.val(this.syncBefore(this.$editor.html()))
}
}
// RICHEDITOR PLUGIN DEFINITION

View File

@ -10,8 +10,10 @@
@color-richeditor-toolbar-btn-bg-active: #404040;
@color-richeditor-toolbar-btn-color-hover: #ffffff;
@import "_figures.less";
@import "../vendor/redactor/redactor.less";
@import "../vendor/froala_drm/less/plugins/code_view.less";
@import "../vendor/froala/css/froala_editor.min.css";
@import "../vendor/froala/css/froala_style.min.css";
@import "../vendor/froala/css/plugins/fullscreen.css";
.field-flush .field-richeditor {
&, &.editor-focus {
@ -19,107 +21,36 @@
}
}
.richeditor-set-height(@size) {
.fr-wrapper {
height: @size;
.fr-view {
min-height: @size;
}
}
}
.field-richeditor {
border: 1px solid @color-form-field-border;
.transition(@input-transition);
&, .redactor-box {
.border-radius(5px);
}
.redactor-toolbar {
.border-top-radius(5px);
}
&.editor-focus {
border-color: @color-form-field-border-focus;
}
&.size-tiny .redactor-editor { height: (@size-tiny - @richeditor-toolbar-size) !important; }
&.size-small .redactor-editor { height: (@size-small - @richeditor-toolbar-size) !important; }
&.size-large .redactor-editor { height: (@size-large - @richeditor-toolbar-size) !important; }
&.size-huge .redactor-editor { height: (@size-huge - @richeditor-toolbar-size) !important; }
&.size-giant .redactor-editor { height: (@size-giant - @richeditor-toolbar-size) !important; }
&.size-tiny { .richeditor-set-height(@size-tiny); }
&.size-small { .richeditor-set-height(@size-small); }
&.size-large { .richeditor-set-height(@size-large); }
&.size-huge { .richeditor-set-height(@size-huge); }
&.size-giant { .richeditor-set-height(@size-giant); }
}
//
// Override redactor defaults
// Overrides
//
.redactor-box {
margin-bottom: 0;
overflow: hidden;
& iframe {
border: none; // Oc
}
}
.redactor-box-fullscreen {
z-index: @richeditor-zindex + 115 !important;
}
.redactor-dropdown {
z-index: @richeditor-zindex + 125 !important;
}
#redactor-modal-overlay,
#redactor-modal-box,
#redactor-modal {
z-index: @richeditor-zindex + 120 !important;
}
.redactor-toolbar {
background: @color-richeditor-toolbar;
.box-shadow(none);
z-index: 410 !important;
li.redactor-btn-right {
float: right;
margin-right: 2px;
}
li a {
color: @color-richeditor-toolbar-btn-color;
font-size: 14px;
width: 20px;
line-height: 20px;
.user-select(none);
&:hover {
background-color: @color-richeditor-toolbar-btn-bg-hover;
color: @color-richeditor-toolbar-btn-color-hover;
}
&:active,
&.redactor-act {
background-color: @color-richeditor-toolbar-btn-bg-active;
color: @color-richeditor-toolbar-btn-color-hover;
}
&.fa-redactor-btn {
padding: 9px 10px;
line-height: 20px;
}
&.oc-redactor-button i:before {
font-size: 16px !important;
}
&.oc-autumn-button {
color: #c03f31;
&:hover {
color: white !important;
}
}
}
}
.redactor-editor {
border: none;
font-size: 13px;
color: @input-color;
padding: 15px;
.fr-toolbar {
border-top: none;
}
//
@ -127,7 +58,7 @@
//
.field-richeditor.stretch {
.redactor-box {
.fr-box:not(.fr-fullscreen) {
display: block;
position: relative;
height: 100% !important;
@ -135,17 +66,11 @@
.border-radius(0) !important;
overflow: hidden;
.redactor-toolbar {
.fr-toolbar {
.border-radius(0) !important;
display: block;
border-bottom: none;
position: absolute;
width: 100%;
top: 0;
}
.redactor-editor, textarea {
.fr-wrapper {
width: 100% !important;
left: 0;
top: 0;
@ -155,39 +80,23 @@
padding: 20px;
}
.redactor-editor {
height: auto !important;
.fr-view, textarea {
height: 100%;
padding: 0;
}
textarea {
padding: 10px;
.fr-placeholder {
top: 20px;
left: 20px;
}
}
}
//
// Full screen
//
body .redactor-box-fullscreen {
background: @body-bg;
overflow-y: scroll !important;
width: 100% !important;
.redactor-editor {
background: #fff;
max-width: 960px;
padding: 50px 30px !important;
margin: @richeditor-gutter auto !important;
padding: @richeditor-gutter;
top: 0 !important;
}
}
//
// Placeholders and snippets
//
.redactor-editor {
.control-richeditor {
.richeditor-snippet() {
display: block;
margin: 0 0 15px 0;
@ -237,4 +146,4 @@ body .redactor-box-fullscreen {
.icon(@volume-up);
}
}
}
}

View File

@ -7,14 +7,8 @@
class="field-richeditor size-<?= $size ?> <?= $stretch?'layout-relative stretch':'' ?>"
<?php if ($editorLang): ?>data-editor-lang="<?= $editorLang ?>"<?php endif ?>
<?php if ($fullPage): ?>data-fullpage="true"<?php endif ?>
data-data-locker="#<?= $this->getId('dataLocker') ?>"
data-links-handler="<?= $this->getEventHandler('onGetPageLinks') ?>"
data-control="richeditor">
<textarea id="<?= $this->getId('textarea') ?>"></textarea>
</div>
<!-- Data locker -->
<div style="display: none">
<textarea name="<?= $name ?>" id="<?= $this->getId('dataLocker') ?>"><?= e($value) ?></textarea>
<textarea name="<?= $name ?>" id="<?= $this->getId('textarea') ?>"><?= e($value) ?></textarea>
</div>
<?php endif ?>