ORIENT/modules/backend/formwidgets/richeditor/assets/js/plugin.figure.js

300 lines
10 KiB
JavaScript

(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.observeCaptions()
this.observeToolbars()
this.observeKeyboard()
},
observeCaptions: function () {
/*
* Adding a line-break to empty captions and citations on click will place the cursor in the expected place
*/
this.redactor.$editor.on('click', 'figcaption:empty, cite:empty', $.proxy(function (event) {
$(event.target).prepend('<br />')
this.redactor.selectionEnd(event.target)
event.stopPropagation()
}, this))
/*
* Remove generated line-breaks empty figcaptions
*/
$(window).on('click', $.proxy(this.cleanCaptions, this))
this.redactor.$editor.on('blur', $.proxy(this.cleanCaptions, this))
this.redactor.$editor.closest('form').one('submit', $.proxy(this.clearCaptions, this))
/*
* Prevent user from removing captions or citations with delete/backspace keys
*/
this.redactor.$editor.on('keydown', $.proxy(function (event) {
var current = this.redactor.getCurrent(),
isEmpty = !current.length,
isCaptionNode = !!$(current).closest('figcaption, cite').length,
isDeleteKey = $.inArray(event.keyCode, [this.redactor.keyCode.BACKSPACE, this.redactor.keyCode.DELETE]) >= 0
if (isEmpty && isDeleteKey && isCaptionNode) {
event.preventDefault()
}
}, this))
},
cleanCaptions: function () {
this.redactor.$editor.find('figcaption, cite').filter(function () {
return $(this).text() == ''
}).empty()
},
clearCaptions: function () {
this.redactor.$editor.find('figcaption, cite').filter(function () {
return $(this).text() == ''
}).remove()
if (this.redactor.opts.visual) {
this.redactor.sync()
}
},
showToolbar: function (event) {
var $figure = $(event.currentTarget),
type = $figure.data('type') || 'default',
$toolbar = this.getToolbar(type).data('figure', $figure).prependTo($figure)
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)
},
observeToolbars: function () {
/*
* Before clicking a command, make sure we save the current node within the editor
*/
this.redactor.$editor.on('mousedown', '.oc-figure-controls', $.proxy(function () {
event.preventDefault()
this.current = this.redactor.getCurrent()
}, this))
this.redactor.$editor.on('click', '.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', function () {
$(this).find('figure').triggerHandler('mouseleave')
})
/*
* Mobile
*/
if (this.redactor.isMobile()) {
/*
* If $editor is focused, click doesn't seem to fire
*/
this.redactor.$editor.on('touchstart', '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', $.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', $.proxy(this.showToolbar, this))
/*
* Remove toolbar from figure on mouseleave
*/
this.redactor.$editor.on('mouseleave', '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', function () { $dropdown.show() })
$button.on('mouseout', 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.bufferSet(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.sync()
},
observeKeyboard: function () {
var redactor = this.redactor
redactor.$editor.on('keydown', function (event) {
/*
* Node at cursor
*/
var currentNode = redactor.getBlock()
/*
* Delete key
*/
if (event.keyCode === 8 && !redactor.getCaretOffset(currentNode) && currentNode.previousSibling && currentNode.previousSibling.nodeName === 'FIGURE') {
event.preventDefault()
}
})
}
}
window.RedactorPlugins.figure = {
init: function () {
this.figure = new Figure(this)
}
}
}(jQuery));