alekseybobkov 2015-04-23 17:59:37 -07:00
parent 04369861ad
commit 594a849171
23 changed files with 921 additions and 3000 deletions

View File

File diff suppressed because one or more lines are too long

480
modules/backend/formwidgets/richeditor/assets/js/build-min.js vendored Normal file → Executable file

File diff suppressed because one or more lines are too long

View File

@ -10,10 +10,7 @@
=require ../vendor/redactor/redactor.js
=require plugin.cleanup.js
=require plugin.fullscreen.js
=require plugin.figure.js
=require plugin.quote.js
=require plugin.table.js
=require plugin.image.js
=require richeditor.js
*/

View File

View File

@ -0,0 +1,47 @@
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,307 +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.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.caret.setEnd(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.selection.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.code.sync()
}
},
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', '.oc-figure-controls', $.proxy(function (event) {
event.preventDefault()
this.current = this.redactor.selection.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.utils.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.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', 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()
}
})
}
}
window.RedactorPlugins.figure = function() {
return {
init: function () {
this.figure = new Figure(this)
}
}
}
}(jQuery));

View File

View File

@ -1,187 +0,0 @@
(function ($) {
'use strict';
window.RedactorPlugins = window.RedactorPlugins || {}
var Image = function (redactor) {
this.redactor = redactor
this.init()
}
Image.prototype = {
control: {
left : { classSuffix: 'arrow-left' },
right : { classSuffix: 'arrow-right' },
small : { classSuffix: 'small', text: 'S' },
medium : { classSuffix: 'medium', text: 'M' },
resize_full : { classSuffix: 'resize-full' },
resize_small: { classSuffix: 'resize-small' }
},
controlGroup: ['left', 'up', 'down', 'right', '|', 'small', 'medium', 'resize_full', 'resize_small', 'remove'],
init: function () {
this.redactor.$editor.on('focus', $.proxy(this.addCaptions, this))
this.addCaptions()
},
addCaptions: function () {
/*
* Find images without captions, adds an empty caption
*/
this.redactor.$editor.find('figure[data-type=image]:not(:has(figcaption))').each(function () {
$(this).append('<figcaption>')
})
},
onShow: function ($figure, $toolbar) {
$toolbar.children().removeClass('on')
if ($figure.hasClass('oc-figure-small')) {
$toolbar.find('.oc-figure-controls-small').show().addClass('on')
$toolbar.find('.oc-figure-controls-medium').show()
$toolbar.find('.oc-figure-controls-resize-full').show()
$toolbar.find('.oc-figure-controls-resize-small').hide()
}
else if ($figure.hasClass('oc-figure-medium')) {
$toolbar.find('.oc-figure-controls-small').show()
$toolbar.find('.oc-figure-controls-medium').show().addClass('on')
$toolbar.find('.oc-figure-controls-resize-full').show()
$toolbar.find('.oc-figure-controls-resize-small').hide()
}
else {
$toolbar.find('.oc-figure-controls-small').hide()
$toolbar.find('.oc-figure-controls-medium').hide()
$toolbar.find('.oc-figure-controls-large').hide()
$toolbar.find('.oc-figure-controls-resize-full').hide()
$toolbar.find('.oc-figure-controls-resize-small').show()
}
if ($figure.hasClass('oc-figure-right')) {
$toolbar.find('.oc-figure-controls-arrow-right').addClass('on')
}
if ($figure.hasClass('oc-figure-left')) {
$toolbar.find('.oc-figure-controls-arrow-left').addClass('on')
}
},
command: function (command, $figure) {
var classString = function (suffixArray, separator, prefix, dot) {
var baseClass = (dot ? '.' : '') + 'oc-figure-' + (prefix || '')
return baseClass + suffixArray.join((separator || ' ') + baseClass)
}
var changeSuffix = function (removeArray, addArray) {
$figure.removeClass(classString(removeArray)).addClass(classString(addArray))
$.each(addArray, function (index, command) {
$figure.trigger('imageCommand', command)
})
}
switch (command) {
case 'left':
case 'right':
changeSuffix(['left', 'right'], [command])
if (!$figure.hasClass('oc-figure-medium') && !$figure.hasClass('oc-figure-small')) {
$figure.addClass('oc-figure-medium')
$figure.trigger('medium')
}
break
case 'small':
case 'medium':
changeSuffix(['small', 'medium', 'large'], [command])
if (!$figure.hasClass('oc-figure-left') && !$figure.hasClass('oc-figure-right')) {
$figure.addClass('oc-figure-left')
$figure.trigger('left')
}
break
case 'resize_full':
changeSuffix(['small', 'medium', 'left', 'right'], ['large'])
break
case 'resize_small':
changeSuffix(['small', 'large', 'right'], ['medium', 'left'])
break
}
}
}
window.RedactorPlugins.image = function() {
return {
init: function () {
this.image = new Image(this)
// This is a work in progress
var button = this.button.addBefore('video', 'image', 'Image')
this.button.addCallback(button, $.proxy(function () {
/*
* Maintain undo history
*/
this.buffer.set()
/*
* Remember the cursor pos
*/
var cursor = this.selection.getBlock() || this.selection.getCurrent()
/*
* Display the image upload modal
*/
/*
* Add button
*/
var url = 'http://placehold.it/100x100'
var data = '<figure data-type="image"><a href="' + url + '"><img src="' + url + '"></a><figcaption></figcaption></figure>'
this.selection.restore()
if (cursor) {
$(cursor).after(data)
}
else {
this.insert.html(data)
}
this.selection.restore()
this.code.sync()
}, this))
/*
* Detect resize command, update the image src
*/
this.$editor.on('imageCommand', 'figure', function (event, command) {
var size = null
if (command == 'small')
size = 300
else if (command == 'medium')
size = 600
else if (command == 'large')
size = 900
else
return
// @todo
var newUrl, $img = $(this).find('img')
$img.attr('src', newUrl)
})
button.addClass('redactor_btn_image').removeClass('redactor-btn-image')
}
}
}
}(jQuery));

View File

@ -1,151 +0,0 @@
(function ($) {
'use strict';
window.RedactorPlugins = window.RedactorPlugins || {};
var Quote = function (redactor) {
this.redactor = redactor
this.init()
}
Quote.prototype = {
control: {
left : { classSuffix: 'arrow-left' },
right : { classSuffix: 'arrow-right' },
small : { classSuffix: 'small', text: 'S' },
medium : { classSuffix: 'medium', text: 'M' },
large : { classSuffix: 'large', text: 'L' },
resizeFull : { classSuffix: 'resize-full' },
resizeSmall : { classSuffix: 'resize-small' }
},
controlGroup: ['left', 'up', 'down', 'right', '|', 'small', 'medium', 'large', 'resizeFull', 'resizeSmall', 'remove'],
init: function () {
this.redactor.$editor.on('focus', $.proxy(this.addCites, this))
this.addCites()
this.observe()
},
addCites: function () {
/*
* Find any quotes missing citations and add an empty one
*/
this.redactor.$editor
.find('figure[data-type=quote] blockquote:not(:has(cite))')
.each(function () {
$(this).append('<cite>')
})
},
observe: function () {
this.redactor.$editor.on('mutate', $.proxy(this.orphanCheck, this))
},
orphanCheck: function () {
this.redactor.$editor.find('blockquote').filter(function () {
return $(this).closest('figure').length == 0
}).each(function () {
$(this).append($('<cite />'))
$(this).wrap('<figure data-type="quote" />')
})
},
onShow: function ($figure, $toolbar) {
$toolbar.children().removeClass('on')
if ($figure.hasClass('oc-figure-medium')) {
$toolbar.find('.oc-figure-controls-medium').addClass('on')
}
else if ($figure.hasClass('oc-figure-large')) {
$toolbar.find('.oc-figure-controls-large').addClass('on')
}
else {
$toolbar.find('.oc-figure-controls-small').addClass('on')
}
if ($figure.hasClass('oc-figure-left')) {
$toolbar.find('.oc-figure-controls-arrow-left').addClass('on')
$toolbar.find('.oc-figure-controls-resize-small').hide()
$toolbar.find('.oc-figure-controls-resize-full').show()
}
else if ($figure.hasClass('oc-figure-right')) {
$toolbar.find('.oc-figure-controls-arrow-right').addClass('on')
$toolbar.find('.oc-figure-controls-resize-small').hide()
$toolbar.find('.oc-figure-controls-resize-full').show()
}
else {
$toolbar.find('.oc-figure-controls-resize-small').show()
$toolbar.find('.oc-figure-controls-resize-full').hide()
}
},
command: function (command, $figure) {
switch (command) {
case 'left':
$figure.removeClass('oc-figure-right').addClass('oc-figure-left')
break
case 'right':
$figure.removeClass('oc-figure-left').addClass('oc-figure-right')
break
case 'resize_full':
$figure.removeClass('oc-figure-left oc-figure-right')
break
case 'resize_small':
$figure.addClass('oc-figure-left')
break
case 'small':
$figure.removeClass('oc-figure-medium oc-figure-large').addClass('oc-figure-small')
break
case 'medium':
$figure.removeClass('oc-figure-small oc-figure-large').addClass('oc-figure-medium')
break
case 'large':
$figure.removeClass('oc-figure-small oc-figure-medium').addClass('oc-figure-large')
break
}
},
toggle: function () {
this.redactor.block.format('blockquote')
var $target = $(this.redactor.selection.getBlock() || this.redactor.selection.getCurrent())
if ($target.is('blockquote')) {
$target.append($('<cite />'))
$target.wrap('<figure data-type="quote" />')
}
else {
$target.find('cite').remove()
$target.closest('figure').before($target).remove()
}
this.redactor.code.sync()
}
}
window.RedactorPlugins.quote = function() {
return {
init: function () {
this.quote = new Quote(this)
var button = this.button.addBefore('link', 'quote', 'Quote')
this.button.addCallback(button, $.proxy(this.quote.toggle, this.quote))
button.addClass('redactor_btn_quote').removeClass('redactor-btn-image')
}
}
}
}(jQuery));

View File

@ -1,234 +1,338 @@
(function ($) {
'use strict';
if (!RedactorPlugins) var RedactorPlugins = {};
window.RedactorPlugins = window.RedactorPlugins || {}
var Table = function (redactor) {
this.redactor = redactor
}
Table.prototype = {
control: {
rowUp : { text: 'Add row above' },
rowDown : { text: 'Add row below' },
colLeft : { text: 'Add column left' },
colRight : { text: 'Add column right' },
addHead : { text: 'Add header' },
delHead : { text: 'Delete header' },
delCol : { text: 'Delete column' },
delRow : { text: 'Delete row' },
delTable : { text: 'Delete table' },
stripe : { text: 'Striped row' },
border : { text: 'Borders on rows' },
fullBorder: { text: 'Borders everywhere' }
},
controlGroup: [ 'up', 'down', '|', {
'Table Options': [
'rowUp', 'rowDown', 'colLeft', 'colRight', '|',
'addHead', 'delHead', '|',
'delCol', 'delRow', 'delTable', '|',
'border', 'stripe', 'fullBorder'
]
}, 'remove'],
insertTable: function (rows, columns) {
this.redactor.buffer.set(false)
var $tableBox = $('<div></div>'),
tableId = Math.floor(Math.random() * 99999),
$table = $('<table id="table' + tableId + '">'),
$thead = $('<thead>').appendTo($table),
$tbody = $('<tbody>').appendTo($table),
$row,
$column
$row = $('<tr>').appendTo($thead)
for (var z = 0; z < columns; z++) {
$('<th>Header</th>').appendTo($row)
}
for (var i = 0; i < rows; i++) {
$row = $('<tr>')
for (var z = 0; z < columns; z++) {
$column = $('<td>Data</td>')
/*
* Set the focus to the first table data row
*/
if (i === 0 && z === 0) {
$column.append('<span id="selection-marker-1">' + this.redactor.opts.invisibleSpace + '</span>')
}
$($row).append($column)
}
$tbody.append($row)
}
$('<figure data-type="table">').addClass('oc-table oc-table-bordered-rows').append($table).appendTo($tableBox)
var html = $tableBox.html()
this.redactor.modal.close()
this.redactor.selection.restore()
var current = this.redactor.selection.getBlock() || this.redactor.selection.getCurrent()
if (current) {
$(current).after(html)
}
else {
this.redactor.insert.html(html)
}
this.redactor.selection.restore()
var table = this.redactor.$editor.find('#table' + tableId)
table.find('span#selection-marker-1').remove()
table.removeAttr('id')
this.redactor.code.sync()
},
command: function (command, $figure, $target) {
switch (command) {
case 'rowUp':
case 'rowDown':
$.proxy(function () {
var $row = $target.closest('tr'),
$clone = $('<tr>'),
childCount = $row.children().length
for (var i = 0; i < childCount; i++) {
$('<td>').text('Data').appendTo($clone)
}
if (command === 'rowUp') {
$clone.insertBefore($row)
}
else {
$clone.insertAfter($row)
}
}, this)()
break
case 'colLeft':
case 'colRight':
$.proxy(function () {
var $cell = $target.closest('td'),
$row = $cell.closest('tr'),
$table = $row.closest('table'),
position = $row.children().index($cell) + 1,
insertPosition = command === 'colLeft' ? 'before' : 'after'
$table.find('thead tr').children(':nth-child(' + position + ')')[insertPosition]($('<th>').text('Header'))
$table.find('tbody tr').children(':nth-child(' + position + ')')[insertPosition]($('<td>').text('Data'))
}, this)()
break
case 'addHead':
if (!$figure.find('table thead').length) {
$.proxy(function () {
var numCols = $figure.find('tr').first().children().length,
$table = $figure.find('table'),
$thead = $('<thead>').prependTo($table),
$row = $('<tr>').appendTo($thead)
for (var i = 0; i < numCols; i++) {
$('<th>').text('Header').appendTo($row)
}
}, this)()
}
break
case 'delHead':
$figure.find('thead').remove()
break
case 'delCol':
$.proxy(function () {
var $cell = $target.closest('td'),
position = $cell.parent().children().index($cell) + 1
$cell.closest('table').find('tr').children(':nth-child(' + position + ')').remove()
}, this)()
break
case 'delRow':
$target.closest('tr').remove()
break
case 'delTable':
$figure.remove()
break
case 'border':
$figure.removeClass('oc-table-bordered-all').toggleClass('oc-table-bordered-rows')
break
case 'stripe':
$figure.toggleClass('oc-table-striped')
break
case 'fullBorder':
$figure.removeClass('oc-table-bordered-rows').toggleClass('oc-table-bordered-all')
break
}
}
}
window.RedactorPlugins.table = function() {
(function($)
{
RedactorPlugins.table = function()
{
return {
init: function () {
this.table = new Table(this)
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 button = this.button.addBefore('link', 'table', 'Table')
this.button.addCallback(button, $.proxy(function () {
var dropdown = {};
/*
* Save cursor position
*/
this.selection.save()
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 };
var callback = $.proxy(function () {
setTimeout(function () {
$('#redactor_table_rows').trigger('focus')
}, 200)
this.observe.addButton('td', 'table');
this.observe.addButton('th', 'table');
}, this)
var button = this.button.addBefore('link', 'table', this.lang.get('table'));
this.button.addDropdown(button, dropdown);
},
show: function()
{
this.modal.addTemplate('table', this.table.getTemplate());
var insert = $.proxy(function () {
this.table.insertTable($('#redactor_table_rows').val(), $('#redactor_table_columns').val())
this.button.setInactive('table')
}, this)
this.modal.load('table', this.lang.get('insert_table'), 300);
this.modal.createCancelButton();
var modal = String()
+ '<section id="redactor-modal-table-insert">'
+ '<label>' + this.opts.curLang.rows + '</label>'
+ '<input type="text" size="5" value="2" id="redactor_table_rows" class="redactor_input">'
+ '<label>' + this.opts.curLang.columns + '</label>'
+ '<input type="text" size="5" value="3" id="redactor_table_columns" class="redactor_input">'
+ '</section>'
var button = this.modal.createActionButton(this.lang.get('insert'));
button.on('click', this.table.insert);
this.modal.addTemplate('insert-table', modal)
this.modal.addCallback('insert-table', callback)
this.modal.load('insert-table', 'Insert Table', 500)
this.selection.save();
this.modal.show();
this.modal.createCancelButton()
this.modal.createActionButton(this.lang.get('insert')).on('click', insert)
this.modal.show()
$('#redactor-table-rows').focus();
}, this))
},
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;
button.addClass('redactor_btn_table').removeClass('redactor-btn-image')
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());
}
}
}
}(jQuery));
$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

@ -54,8 +54,8 @@
* Initialize Redactor editor
*/
var redactorOptions = {
imageEditable: false,
imageResizable: false,
imageEditable: true,
imageResizable: true,
buttonSource: true,
removeDataAttr: false,
syncBeforeCallback: function(html) { return self.syncBefore(html) },
@ -78,10 +78,7 @@
redactorOptions.fullpage = true
}
// redactorOptions.plugins = ['cleanup', 'fullscreen', 'figure', 'image', 'quote', 'table']
// redactorOptions.buttons = ['formatting', 'bold', 'italic', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule', 'html'],
redactorOptions.plugins = ['cleanup', 'fullscreen', 'figure', 'quote', 'table', 'mediamanager']
redactorOptions.plugins = ['fullscreen', 'table', 'mediamanager']
redactorOptions.buttons = ['formatting', 'bold', 'italic', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule', 'html'],
this.$textarea.redactor(redactorOptions)

View File

@ -1,316 +0,0 @@
//
// Figures
//
.redactor-editor {
figure {
position: relative;
}
figcaption {
text-align: center;
line-height: @line-height-computed;
font-size: @font-size-base;
}
figure[data-type=table] {
clear: both;
}
figure[data-type=video] {
position: relative;
margin-bottom: @line-height-computed;
text-align: center;
clear: both;
p {
margin: 0;
}
&.oc-figure-full {
&:before {
position: relative;
padding-bottom: 51%;
width: 100%;
height: 0;
content: "";
display: block;
}
iframe {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
}
}
figure[data-type=image] {
position: relative;
margin-bottom: @line-height-computed;
.oc-figure-controls {
top: 0px;
}
img {
width: 100%;
}
&.oc-figure-large {
width: 100%;
clear: both;
}
&.oc-figure-medium {
width: 50%;
}
&.oc-figure-small {
width: 33%;
}
}
figure[data-type=quote] {
font-family: Georgia, serif;
margin-bottom: @line-height-computed;
margin-left: @line-height-computed;
font-style: italic;
position: relative;
border-left: solid 4px @color-border;
padding-left: @line-height-computed;
figcaption {
font-weight: bold;
text-align: left;
}
.oc-figure-controls {
margin-left: -5px;
}
&.oc-figure-medium {
&, blockquote { font-size: 20px; }
}
&.oc-figure-large {
&, blockquote { font-size: 24px; }
}
&.oc-figure-right {
width: 33%;
}
&.oc-figure-left {
width: 33%;
border-left: none;
border-right: solid 4px @color-border;
padding-left: 0;
padding-right: @line-height-computed;
margin-left: 0;
margin-right: @line-height-computed;
.oc-figure-controls {
margin-left: 0;
margin-right: -5px;
}
}
cite {
display: block;
text-align: left;
font-weight: normal;
&:before {
content: "\2014\00a0";
}
&:empty:before {
opacity: 0.4;
// @todo Convert to language value
content: "\2014 Type to add citation (optional)";
}
}
}
}
.redactor-box {
figcaption {
&:empty:before {
opacity: .4;
// @todo Convert to language value
content: "Type to add caption (optional)";
}
}
.oc-figure-controls {
background: #2b3e50 !important;
padding: 0;
.border-radius(4px);
position: absolute;
display: none;
// min-width: 100%;
white-space: nowrap;
left: 10px;
top: -50px;
margin: 0 auto;
font-family: @font-family-base;
line-height: @line-height-computed;
font-style: normal;
z-index: @richeditor-zindex + 500;
text-align: center;
&:after {
content: ' ';
left: 0;
position: absolute;
display: block;
height: 10px;
background: rgba(0,0,0,0.1);
width: 100%;
bottom: -10px;
.opacity(0.1);
}
&:before {
.triangle(down, 17px, 9px, #2b3e50);
position: absolute;
left: 14px;
bottom: -8px;
}
}
figure:hover .oc-figure-controls {
display: block;
}
.oc-figure-controls.bottom {
bottom: -50px;
top: auto;
&:after {
bottom: auto;
top: -10px;
}
&:before {
.triangle(up, 17px, 9px, #2b3e50)!important;
border-top: none;
top: -8px;
}
}
.oc-figure-controls span {
display: inline-block;
border: none;
background: none;
color: #ffffff;
vertical-align: top;
font-size: 14px;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
cursor: pointer;
&:before {
line-height: 24px;
}
&:hover {
color: #fff;
background: rgba(255, 255, 255, 0.1);
}
&.on {
background: #fff;
color: @gray;
background-color: #1f9e84;
color: white;
}
&:last-child {
.border-right-radius(4px);
}
&:first-child {
.border-right-radius(4px);
}
}
.oc-figure-controls span {
&.oc-figure-controls-divider {
width: 1px;
background: @color-border;
padding: 0;
margin: 0 4px;
cursor: normal;
}
&.oc-figure-controls-small {
font-size: 7px;
}
&.oc-figure-controls-medium {
font-size: 10px;
}
&.oc-figure-controls-arrow-left:before {
.icon(@arrow-left);
}
&.oc-figure-controls-arrow-right:before {
.icon(@arrow-right);
}
&.oc-figure-controls-arrow-up:before {
.icon(@arrow-up);
}
&.oc-figure-controls-arrow-down:before {
.icon(@arrow-down);
}
&.oc-figure-controls-resize-full:before {
.icon(@expand);
}
&.oc-figure-controls-resize-small:before {
.icon(@compress);
}
&.oc-figure-controls-delete {
margin-left: @line-height-computed;
&:before { .icon(@trash-o); }
&:hover { background: @color-btn-danger; }
}
&.oc-figure-controls-table {
width: auto;
padding-left: @line-height-computed / 2;
padding-right: @line-height-computed / 2;
text-align: left;
&:before { .icon(@table); }
}
}
.oc-figure-right {
float: right;
margin-left: @line-height-computed;
.oc-figure-controls {
right: 0;
}
}
.oc-figure-left {
float: left;
margin-right: @line-height-computed;
}
.oc-dropdown-menu {
&, ul { padding: 0 !important; }
ul {
background-color: @dropdown-bg !important;
}
a {
text-decoration: none;
padding: 0 15px !important;
color: @dropdown-link-color !important;
text-decoration: none !important;
line-height: 25px;
&:hover,
&:focus {
color: @color-dropdown-hover-text !important;
}
}
}
@media (max-width: @menu-breakpoint-max) {
figure[data-type=image] {
width: 100% !important;
float: none !important;
margin-left: 0;
margin-right: 0;
}
figure[data-type=video] iframe {
width: 100% !important;
height: auto !important;
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,118 +0,0 @@
.oc-table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
margin-bottom: @line-height-computed;
caption {
color: #000;
font: italic 85%/1 arial, sans-serif;
padding: 1em 0;
text-align: center;
}
td, th {
font-size: 90%;
margin: 0;
overflow: visible;
padding: @table-cell-padding;
}
td:first-child, th:first-child {
border-left-width: 0;
}
thead {
color: #000;
text-align: left;
vertical-align: bottom;
white-space: nowrap;
th {
font-weight: bold;
border-bottom: solid 2px @table-border-color;
}
}
td {
background-color: transparent;
vertical-align: middle;
}
}
.oc-table td p {
line-height: @line-height-computed * .75;
&:last-child {
margin-bottom: 0;
}
}
.oc-table .oc-table-cell-min {
width: 1%;
padding-right: 0;
input[type=checkbox], input[type=checkbox] {
margin: 0;
}
}
.oc-table-secondary {
color: @text-color;
font-size: 90%;
}
.oc-table-tertiary {
color: @text-color;
font-size: 80%;
}
//
// Striped tables
//
.oc-table-odd td, .oc-table-striped tr:nth-child(2n-1) td {
background-color: @table-bg-accent;
}
.oc-table-backed {
background-color: @table-bg-accent;
}
//
// Bordered tables
//
.oc-table-bordered-all {
border: 1px solid @table-border-color;
td {
border-bottom: 1px solid @table-border-color;
border-left: 1px solid @table-border-color;
}
tbody > tr:last-child td {
border-bottom-width: 0;
}
}
.oc-table-bordered {
border: 1px solid @table-border-color;
}
.oc-table-bordered-rows {
td {
border-bottom: 1px solid @table-border-color;
}
tbody > tr:last-child td {
border-bottom-width: 0;
}
}
.oc-table-horizontal {
tbody > tr:last-child td {
border-bottom-width: 0;
}
td, th {
border-width: 0 0 1px 0;
border-bottom: 1px solid @table-border-color;
}
tbody > tr:last-child td {
border-bottom-width: 0;
}
}

View File

@ -1,132 +0,0 @@
@import "../../../../assets/less/core/boot.less";
figure {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
figure {
position: relative;
}
figcaption {
text-align: center;
line-height: 24px;
font-size: 16px;
}
figure[data-type=table] {
clear: both;
}
figure[data-type=video] {
position: relative;
margin-bottom: 24px;
text-align: center;
clear: both;
}
figure[data-type=video] p {
margin: 0;
}
figure[data-type=video].oc-figure-full p {
position: relative;
padding-bottom: 51%;
width: 100%;
height: 0;
}
figure[data-type=video].oc-figure-full iframe {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
figure[data-type=image] {
position: relative;
margin-bottom: 24px;
}
figure[data-type=image] img {
width: 100%;
}
figure[data-type=image].oc-figure-large {
width: 100%;
clear: both;
}
figure[data-type=image].oc-figure-medium {
width: 50%;
}
figure[data-type=image].oc-figure-small {
width: 33%;
}
figure[data-type=quote] {
font-family: "Georgia", serif;
margin-bottom: 24px;
margin-left: 24px;
font-style: italic;
position: relative;
border-left: solid 5px #404040;
padding-left: 24px;
}
figure[data-type=quote] figcaption {
font-weight: bold;
text-align: left;
}
figure[data-type=quote].oc-figure-medium {
font-size: 20px;
}
figure[data-type=quote].oc-figure-large {
font-size: 24px;
}
figure[data-type=quote].oc-figure-right {
width: 33%;
}
figure[data-type=quote].oc-figure-left {
width: 33%;
border-left: none;
border-right: solid 5px #404040;
padding-left: 0;
padding-right: 24px;
margin-left: 0;
margin-right: 24px;
}
figure[data-type=quote] cite {
display: block;
text-align: left;
font-weight: bold;
}
figure[data-type=quote] cite:before {
content: "\2014\00a0";
}
.oc-figure-right {
float: right;
margin-left: 24px;
}
.oc-figure-right .oc-figure-controls {
right: 0;
}
.oc-figure-left {
float: left;
margin-right: 24px;
}
@media screen and (max-width: 480px) {
figure[data-type=image] {
width: 100% !important;
float: none !important;
margin-left: 0;
margin-right: 0;
}
figure[data-type=video] iframe {
width: 100% !important;
height: auto !important;
}
}
@import "_shared.less";

View File

@ -4,9 +4,7 @@
@richeditor-zindex: 600;
@richeditor-gutter: 20px;
@import "_redactor.less";
@import "_figures.less";
@import "_shared.less";
@import "../vendor/redactor/redactor.less";
.field-flush .field-richeditor {
&, &.editor-focus {

View File

View File

@ -227,6 +227,12 @@ body .redactor-box-fullscreen {
background-color: transparent !important;
cursor: default;
}
/*
CodeMirror
*/
.redactor-box .CodeMirror {
display: none;
}
/*
Icons
*/
@ -845,6 +851,12 @@ body .redactor-box-fullscreen {
padding-left: 2em;
border: none;
}
.redactor-editor ol ol li {
list-style-type: lower-alpha;
}
.redactor-editor ol ol ol li {
list-style-type: lower-roman;
}
.redactor-editor dl dt {
font-weight: bold;
}

View File

@ -1,6 +1,6 @@
/*
Redactor v10.0.9
Updated: March 16, 2015
Redactor v10.1.0
Updated: April 16, 2015
http://imperavi.com/redactor/
@ -28,9 +28,6 @@
var uuid = 0;
var reUrlYoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig;
var reUrlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/;
// Plugin
$.fn.redactor = function(options)
{
@ -94,13 +91,13 @@
// Functionality
$.Redactor = Redactor;
$.Redactor.VERSION = '10.0.9';
$.Redactor.VERSION = '10.1.0';
$.Redactor.modules = ['alignment', 'autosave', 'block', 'buffer', 'build', 'button',
'caret', 'clean', 'code', 'core', 'dropdown', 'file', 'focus',
'image', 'indent', 'inline', 'insert', 'keydown', 'keyup',
'lang', 'line', 'link', 'list', 'modal', 'observe', 'paragraphize',
'paste', 'placeholder', 'progress', 'selection', 'shortcuts',
'tabifier', 'tidy', 'toolbar', 'upload', 'utils'];
'tabifier', 'tidy', 'toolbar', 'upload', 'utils', 'linkify'];
$.Redactor.opts = {
@ -328,7 +325,18 @@
upload_label: 'Drop file here or '
}
}
},
linkify: {
regexps: {
youtube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig,
vimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,
image: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/ig,
url: /((?:http[s]?:\/\/(?:www\.)?|www\.){1}(?:[0-9A-Za-z\-%_]+\.)+[a-zA-Z]{2,}(?::[0-9]+)?(?:(?:\/[0-9A-Za-z\-#\.%\+_]*)+)?(?:\?(?:[0-9A-Za-z\-\.%_]+(?:=[0-9A-Za-z\-\.%_\+]*)?)?(?:&(?:[0-9A-Za-z\-\.%_]+(?:=[0-9A-Za-z\-\.%_\+]*)?)?)*)?(?:#[0-9A-Za-z\-\.%_\+=\?&;]*)?)/ig,
}
},
codemirror: false
};
// Functionality
@ -529,11 +537,11 @@
autosave: function()
{
return {
html: false,
enable: function()
{
if (!this.opts.autosave) return;
this.autosave.html = false;
this.autosave.name = (this.opts.autosaveName) ? this.opts.autosaveName : this.$textarea.attr('name');
if (this.opts.autosaveOnChange) return;
@ -549,7 +557,7 @@
this.autosave.source = this.code.get();
if (this.autosave.html === this.autosave.source) return;
if (this.utils.isEmpty(this.autosave.source)) return;
//if (this.utils.isEmpty(this.autosave.source)) return;
// data
var data = {};
@ -940,7 +948,7 @@
},
formatListToBlockquote: function()
{
var block = $(this.block.blocks[0]).closest('ul, ol');
var block = $(this.block.blocks[0]).closest('ul, ol', this.$editor[0]);
$(block).find('ul, ol').contents().unwrap();
$(block).find('li').append($('<br>')).contents().unwrap();
@ -1033,10 +1041,10 @@
},
formatTableWrapping: function($formatted)
{
if ($formatted.closest('table').length === 0) return;
if ($formatted.closest('table', this.$editor[0]).length === 0) return;
if ($formatted.closest('tr').length === 0) $formatted.wrap('<tr>');
if ($formatted.closest('td').length === 0 && $formatted.closest('th').length === 0)
if ($formatted.closest('tr', this.$editor[0]).length === 0) $formatted.wrap('<tr>');
if ($formatted.closest('td', this.$editor[0]).length === 0 && $formatted.closest('th').length === 0)
{
$formatted.wrap('<td>');
}
@ -1395,8 +1403,11 @@
},
setHelpers: function()
{
// autosave
this.autosave.enable();
// linkify
if (this.linkify.isEnabled())
{
this.linkify.format();
}
// placeholder
this.placeholder.enable();
@ -1974,13 +1985,13 @@
html = html.replace(new RegExp('<br\\s?/?></li>', 'gi'), '</li>');
html = html.replace(new RegExp('</li><br\\s?/?>', 'gi'), '</li>');
// remove verified
html = html.replace(new RegExp('<div(.*?[^>]) data-tagblock="redactor"(.*?[^>])>', 'gi'), '<div$1$2>');
html = html.replace(new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', 'gi'), '<$1$2>');
html = html.replace(new RegExp('<span(.*?[^>])\srel="(.*?[^>])"(.*?[^>])>', 'gi'), '<span$1$3>');
html = html.replace(new RegExp('<img(.*?[^>])\srel="(.*?[^>])"(.*?[^>])>', 'gi'), '<img$1$3>');
html = html.replace(new RegExp('<img(.*?[^>])\sstyle="" (.*?[^>])>', 'gi'), '<img$1 $2>');
html = html.replace(new RegExp('<img(.*?[^>])\sstyle (.*?[^>])>', 'gi'), '<img$1 $2>');
html = html.replace(new RegExp('<span class="redactor-invisible-space">(.*?)</span>', 'gi'), '$1');
html = html.replace(/<div(.*?[^>]) data-tagblock="redactor"(.*?[^>])>/gi, '<div$1$2>');
html = html.replace(/<(.*?) data-verified="redactor"(.*?[^>])>/gi, '<$1$2>');
html = html.replace(/<span(.*?[^>])\srel="(.*?[^>])"(.*?[^>])>/gi, '<span$1$3>');
html = html.replace(/<img(.*?[^>])\srel="(.*?[^>])"(.*?[^>])>/gi, '<img$1$3>');
html = html.replace(/<img(.*?[^>])\sstyle="" (.*?[^>])>'/gi, '<img$1 $2>');
html = html.replace(/<img(.*?[^>])\sstyle (.*?[^>])>'/gi, '<img$1 $2>');
html = html.replace(/<span class="redactor-invisible-space">(.*?)<\/span>/gi, '$1');
html = html.replace(/ data-save-url="(.*?[^>])"/gi, '');
// remove image resize
@ -2498,6 +2509,15 @@
});
},
cleanEmptyParagraph: function()
{
var p = this.$editor.find("p").first();
if (this.utils.isEmpty(p.html()))
{
p.remove();
}
},
setVerified: function(html)
{
if (this.utils.browser('msie')) return html;
@ -2684,8 +2704,14 @@
this.start = false;
// autosave on change
if (this.autosave.html == false)
{
this.autosave.html = this.code.get();
}
//autosave
this.autosave.onChange();
this.autosave.enable();
},
toggle: function()
{
@ -2703,7 +2729,8 @@
this.code.offset = this.caret.getOffset();
var scroll = $(window).scrollTop();
var height = this.$editor.innerHeight();
var width = this.$editor.innerWidth(),
height = this.$editor.innerHeight();
this.$editor.hide();
@ -2713,17 +2740,33 @@
// indent code
html = this.tabifier.get(html);
this.$textarea.val(html).height(height).show().focus();
this.$textarea.on('keydown.redactor-textarea-indenting', this.code.textareaIndenting);
this.$textarea.val(html);
$(window).scrollTop(scroll);
if (this.$textarea[0].setSelectionRange)
if (this.opts.codemirror)
{
this.$textarea[0].setSelectionRange(0, 0);
this.$textarea.next('.CodeMirror').each(function(i, el)
{
$(el).show();
el.CodeMirror.setValue(html);
el.CodeMirror.setSize(width, height);
el.CodeMirror.refresh();
el.CodeMirror.focus();
});
}
else
{
this.$textarea.height(height).show().focus();
this.$textarea.on('keydown.redactor-textarea-indenting', this.code.textareaIndenting);
this.$textarea[0].scrollTop = 0;
$(window).scrollTop(scroll);
if (this.$textarea[0].setSelectionRange)
{
this.$textarea[0].setSelectionRange(0, 0);
}
this.$textarea[0].scrollTop = 0;
}
this.opts.visual = false;
@ -2733,15 +2776,32 @@
},
showVisual: function()
{
var html;
if (this.opts.visual) return;
var html = this.$textarea.hide().val();
if (this.opts.codemirror)
{
this.$textarea.next('.CodeMirror').each(function(i, el)
{
html = el.CodeMirror.getValue();
});
}
else
{
html = this.$textarea.hide().val();
}
if (this.modified !== this.clean.removeSpaces(html))
{
this.code.set(html);
}
if (this.opts.codemirror)
{
this.$textarea.next('.CodeMirror').hide();
}
this.$editor.show();
if (!this.utils.isEmpty(html))
@ -2890,14 +2950,24 @@
{
$.each(this.opts.formattingAdd, $.proxy(function(i,s)
{
var name = s.tag;
var name = s.tag,
func;
if (typeof s['class'] != 'undefined')
{
name = name + '-' + s['class'];
}
s.type = (this.utils.isBlockTag(s.tag)) ? 'block' : 'inline';
var func = (s.type == 'inline') ? 'inline.formatting' : 'block.formatting';
if (typeof s.func !== "undefined")
{
func = s.func;
}
else
{
func = (s.type == 'inline') ? 'inline.formatting' : 'block.formatting';
}
if (this.opts.linebreaks && s.type == 'block' && s.tag == 'p') return;
@ -3215,7 +3285,7 @@
},
showEdit: function($image)
{
var $link = $image.closest('a');
var $link = $image.closest('a', this.$editor[0]);
this.modal.load('imageEdit', this.lang.get('edit'), 705);
@ -3292,7 +3362,7 @@
this.image.hideResize();
this.buffer.set();
var $link = $image.closest('a');
var $link = $image.closest('a', this.$editor[0]);
$image.attr('alt', $('#redactor-image-title').val());
@ -3465,7 +3535,7 @@
},
hideResize: function(e)
{
if (e && $(e.target).closest('#redactor-image-box').length !== 0) return;
if (e && $(e.target).closest('#redactor-image-box', this.$editor[0]).length !== 0) return;
if (e && e.target.tagName == 'IMG')
{
var $image = $(e.target);
@ -3577,8 +3647,8 @@
remove: function(image)
{
var $image = $(image);
var $link = $image.closest('a');
var $figure = $image.closest('figure');
var $link = $image.closest('a', this.$editor[0]);
var $figure = $image.closest('figure', this.$editor[0]);
var $parent = $image.parent();
if ($('#redactor-image-box').length !== 0)
{
@ -3763,7 +3833,7 @@
var current = this.selection.getCurrent();
var $item = $(current).closest('li');
var $item = $(current).closest('li', this.$editor[0]);
var $parent = $item.parent();
if ($item.length !== 0 && $parent.length !== 0 && $parent[0].tagName == 'LI')
{
@ -3871,7 +3941,7 @@
formatCollapsed: function(tag)
{
var current = this.selection.getCurrent();
var $parent = $(current).closest(tag + '[data-redactor-tag=' + tag + ']');
var $parent = $(current).closest(tag + '[data-redactor-tag=' + tag + ']', this.$editor[0]);
// inline there is
if ($parent.length !== 0 && (this.inline.type != 'style' && $parent[0].tagName != 'SPAN'))
@ -4527,7 +4597,7 @@
var $table = false;
if (this.keydown.block && this.keydown.block.tagName === 'TD')
{
$table = $(this.keydown.block).closest('table');
$table = $(this.keydown.block).closest('table', this.$editor[0]);
}
if ($table && $table.find('td').last()[0] === this.keydown.block)
@ -4642,11 +4712,13 @@
else
{
current = this.selection.getCurrent();
var $parent = $(current).closest('li');
var $list = $parent.closest('ul,ol');
var $parent = $(current).closest('li', this.$editor[0]);
var $list = $parent.closest('ul,ol', this.$editor[0]);
if ($parent.length !== 0 && this.utils.isEmpty($parent.html()) && $list.next().length === 0)
if ($parent.length !== 0 && this.utils.isEmpty($parent.html()) && $list.next().length === 0 && this.utils.isEmpty($list.find("li").last().html()))
{
$list.find("li").last().remove();
var node = $(this.opts.emptyHtml);
$list.after(node);
this.caret.setStart(node);
@ -5053,9 +5125,9 @@
{
var $current = $(this.keydown.current);
var $parent = $(this.keydown.parent);
var td = $current.closest('td');
var td = $current.closest('td', this.$editor[0]);
if (td.length !== 0 && $current.closest('li') && $parent.children('li').length === 1)
if (td.length !== 0 && $current.closest('li', this.$editor[0]) && $parent.children('li').length === 1)
{
if (!this.utils.isEmpty($current.text())) return;
@ -5110,13 +5182,8 @@
}
// linkify
if (this.keyup.isLinkify(key))
{
this.formatLinkify(this.opts.linkProtocol, this.opts.convertLinks, this.opts.convertUrlLinks, this.opts.convertImageLinks, this.opts.convertVideoLinks, this.opts.linkSize);
this.observe.load();
this.code.sync();
}
if (this.linkify.isEnabled() && this.linkify.isKey(key))
this.linkify.format();
if (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE)
{
@ -5151,10 +5218,6 @@
return this.keyup.formatEmpty(e);
}
},
isLinkify: function(key)
{
return this.opts.convertLinks && (this.opts.convertUrlLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && key === this.keyCode.ENTER && !this.utils.isCurrentOrParent('PRE');
},
replaceToParagraph: function(clone)
{
var $current = $(this.keyup.current);
@ -5351,7 +5414,7 @@
{
this.link.$node = false;
var $el = $(this.selection.getCurrent()).closest('a');
var $el = $(this.selection.getCurrent()).closest('a', this.$editor[0]);
if ($el.length !== 0 && $el[0].tagName === 'A')
{
this.link.$node = $el;
@ -5370,6 +5433,8 @@
},
insert: function()
{
this.placeholder.remove();
var target = '';
var link = this.link.$inputUrl.val();
var text = this.link.$inputText.val();
@ -5426,16 +5491,37 @@
{
this.buffer.set();
this.link.$node.text(text).attr('href', link);
if (target !== '')
var $link = this.link.$node,
$el = $link.children();
if ($el.length > 0)
{
this.link.$node.attr('target', target);
while ($el.length)
{
$el = $el.children();
}
$el = $el.end();
}
else
{
this.link.$node.removeAttr('target');
$el = $link;
}
$link.attr('href', link);
$el.text(text);
if (target !== '')
{
$link.attr('target', target);
}
else
{
$link.removeAttr('target');
}
this.selection.selectElement($link);
this.code.sync();
}
else
@ -5457,13 +5543,19 @@
if (target !== '') $a.attr('target', target);
$a = $(this.insert.node($a));
if (this.selection.getText().match(/\s$/))
{
$a.after(" ");
}
this.selection.selectElement($a);
}
else
{
document.execCommand('createLink', false, link);
$a = $(this.selection.getCurrent()).closest('a');
$a = $(this.selection.getCurrent()).closest('a', this.$editor[0]);
if (this.utils.browser('mozilla'))
{
$a = $('a[_moz_dirty=""]');
@ -5472,10 +5564,15 @@
if (target !== '') $a.attr('target', target);
$a.removeAttr('style').removeAttr('_moz_dirty');
if (this.selection.getText().match(/\s$/))
{
$a.after(" ");
}
if (this.link.text !== '' || this.link.text != text)
{
$a.text(text);
this.selection.selectElement($a);
}
}
@ -5508,7 +5605,7 @@
var len = nodes.length;
for (var i = 0; i < len; i++)
{
var $node = $(nodes[i]).closest('a');
var $node = $(nodes[i]).closest('a', this.$editor[0]);
$node.replaceWith($node.contents());
}
@ -5554,7 +5651,7 @@
this.selection.save();
var parent = this.selection.getParent();
var $list = $(parent).closest('ol, ul');
var $list = $(parent).closest('ol, ul', this.$editor[0]);
if (!this.utils.isRedactorParent($list) && $list.length !== 0)
{
@ -5592,7 +5689,6 @@
}
}
this.selection.restore();
this.code.sync();
},
@ -5600,7 +5696,7 @@
{
var parent = this.selection.getParent();
var current = this.selection.getCurrent();
var $td = $(current).closest('td, th');
var $td = $(current).closest('td, th', this.$editor[0]);
if (this.utils.browser('msie') && this.opts.linebreaks)
{
@ -5611,7 +5707,7 @@
document.execCommand('insert' + cmd);
}
var $list = $(this.selection.getParent()).closest('ol, ul');
var $list = $(this.selection.getParent()).closest('ol, ul', this.$editor[0]);
if ($td.length !== 0)
{
@ -5698,13 +5794,13 @@
this.indent.fixEmptyIndent();
if (!this.opts.linebreaks && $current.closest('li, th, td').length === 0)
if (!this.opts.linebreaks && $current.closest('li, th, td', this.$editor[0]).length === 0)
{
document.execCommand('formatblock', false, 'p');
this.$editor.find('ul, ol, blockquote').each($.proxy(this.utils.removeEmpty, this));
}
var $table = $(this.selection.getCurrent()).closest('table');
var $table = $(this.selection.getCurrent()).closest('table', this.$editor[0]);
var $prev = $table.prev();
if (!this.opts.linebreaks && $table.length !== 0 && $prev.length !== 0 && $prev[0].tagName == 'BR')
{
@ -6085,19 +6181,19 @@
$.each(this.opts.activeButtonsStates, $.proxy(function(key, value)
{
var parentEl = $(parent).closest(key);
var currentEl = $(current).closest(key);
var parentEl = $(parent).closest(key, this.$editor[0]);
var currentEl = $(current).closest(key, this.$editor[0]);
if (parentEl.length !== 0 && !this.utils.isRedactorParent(parentEl)) return;
if (!this.utils.isRedactorParent(currentEl)) return;
if (parentEl.length !== 0 || currentEl.closest(key).length !== 0)
if (parentEl.length !== 0 || currentEl.closest(key, this.$editor[0]).length !== 0)
{
this.button.setActive(value);
}
}, this));
var $parent = $(parent).closest(this.opts.alignmentTags.toString().toLowerCase());
var $parent = $(parent).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]);
if (this.utils.isRedactorParent(parent) && $parent.length)
{
var align = ($parent.css('text-align') === '') ? 'left' : $parent.css('text-align');
@ -6116,7 +6212,7 @@
var $img = $(img);
// IE fix (when we clicked on an image and then press backspace IE does goes to image's url)
$img.closest('a').on('click', function(e) { e.preventDefault(); });
$img.closest('a', this.$editor[0]).on('click', function(e) { e.preventDefault(); });
if (this.utils.browser('msie')) $img.attr('unselectable', 'on');
@ -6149,20 +6245,18 @@
},
showTooltip: function(e)
{
var $link = $(e.target);
var $parent = $link.closest('a');
var tag = ($link.length !== 0) ? $link[0].tagName : false;
var $el = $(e.target);
if ($parent[0].tagName === 'A')
{
if (tag === 'IMG') return;
else if (tag !== 'A') $link = $parent;
}
if (tag !== 'A')
{
if ($el[0].tagName == 'IMG')
return;
}
if ($el[0].tagName !== 'A')
$el = $el.closest('a', this.$editor[0]);
if ($el[0].tagName !== 'A')
return;
var $link = $el;
var pos = this.observe.getTooltipPosition($link);
var tooltip = $('<span class="redactor-link-tooltip"></span>');
@ -6193,7 +6287,7 @@
e = e.originalEvent || e;
var target = e.target;
var $parent = $(target).closest('a');
var $parent = $(target).closest('a', this.$editor[0]);
if ($parent.length !== 0 && $parent[0].tagName === 'A' && target.tagName !== 'A')
{
return;
@ -6382,8 +6476,10 @@
$(window).off('scroll.redactor-freeze');
}, this), 1);
if (this.linkify.isEnabled())
this.linkify.format();
}, this), 1);
},
createPasteBox: function()
{
@ -7805,6 +7901,9 @@
left: left
});
if (scrollTop > end)
$('.redactor-dropdown-' + this.uuid + ':visible').hide();
this.toolbar.setDropdownsFixed();
this.$toolbar.css('visibility', (scrollTop < end) ? 'visible' : 'hidden');
},
@ -7820,8 +7919,6 @@
this.toolbar.unsetDropdownsFixed();
this.$toolbar.removeClass('toolbar-fixed-box');
},
setDropdownsFixed: function()
{
@ -7971,6 +8068,7 @@
var xhr = new XMLHttpRequest();
xhr.open('POST', this.upload.url);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
// complete
xhr.onreadystatechange = $.proxy(function()
@ -8406,7 +8504,7 @@
// tag detection
isTag: function(current, tag)
{
var element = $(current).closest(tag);
var element = $(current).closest(tag, this.$editor[0]);
if (element.length == 1)
{
return element[0];
@ -8514,6 +8612,122 @@
return browser == match[1];
}
};
},
linkify: function()
{
return {
isKey: function(key)
{
return key == this.keyCode.ENTER || key == this.keyCode.SPACE;
},
isEnabled: function()
{
return this.opts.convertLinks && (this.opts.convertUrlLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && !this.utils.isCurrentOrParent('PRE');
},
format: function()
{
var linkify = this.linkify,
opts = this.opts;
this.$editor
.find(":not(iframe,img,a,pre)")
.addBack()
.contents()
.filter(function()
{
return this.nodeType === 3 && $.trim(this.nodeValue) != "" && !$(this).parent().is("pre") && (this.nodeValue.match(opts.linkify.regexps.youtube) || this.nodeValue.match(opts.linkify.regexps.vimeo) || this.nodeValue.match(opts.linkify.regexps.image) || this.nodeValue.match(opts.linkify.regexps.url));
})
.each(function()
{
var text = $(this).text(),
html = text;
if (opts.convertImageLinks && html.match(opts.linkify.regexps.image))
{
html = linkify.convertImages(html);
}
else if (opts.convertUrlLinks && !html.match(opts.linkify.regexps.youtube) && !html.match(opts.linkify.regexps.vimeo))
{
html = linkify.convertLinks(html);
}
if (opts.convertVideoLinks)
{
html = linkify.convertVideoLinks(html);
}
$(this).before(text.replace(text, html))
.remove();
});
this.linkify.after();
},
convertVideoLinks: function(html)
{
var iframeStart = '<iframe width="500" height="281" src="',
iframeEnd = '" frameborder="0" allowfullscreen></iframe>';
if (html.match(this.opts.linkify.regexps.youtube))
{
html = html.replace(this.opts.linkify.regexps.youtube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd);
}
if (html.match(this.opts.linkify.regexps.vimeo))
{
html = html.replace(this.opts.linkify.regexps.vimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd);
}
return html;
},
convertImages: function(html)
{
var matches = html.match(this.opts.linkify.regexps.image);
if (matches)
html = html.replace(html, '<img src="' + matches + '" />');
return html;
},
convertLinks: function(html)
{
var matches = html.match(this.opts.linkify.regexps.url);
if (matches)
{
matches = $.grep(matches, function(v, k) { return $.inArray(v, matches) === k; });
var length = matches.length;
for (var i = 0; i < length; i++)
{
var href = matches[i],
text = href,
linkProtocol = this.opts.linkProtocol + '://';
if (href.match(/(https?|ftp):\/\//i) !== null)
linkProtocol = "";
if (text.length > this.opts.linkSize)
text = text.substring(0, this.opts.linkSize) + '...';
text = decodeURIComponent(text);
// escaping url
var regexp = new RegExp('(' + href.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + ')\\b', 'g');
html = html.replace(regexp, '<a href="' + linkProtocol + $.trim(href) + '">' + $.trim(text) + '</a>');
}
}
return html;
},
after: function()
{
this.observe.load();
this.code.sync();
}
}
}
};
@ -8524,106 +8738,4 @@
// constructor
Redactor.prototype.init.prototype = Redactor.prototype;
// LINKIFY
$.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertUrlLinks, convertImageLinks, convertVideoLinks, linkSize)
{
var urlCheck = '((?:http[s]?:\\/\\/(?:www\\.)?|www\\.){1}(?:[0-9A-Za-z\\-%_]+\\.)+[a-zA-Z]{2,}(?::[0-9]+)?(?:(?:/[0-9A-Za-z\\-#\\.%\+_]*)+)?(?:\\?(?:[0-9A-Za-z\\-\\.%_]+(?:=[0-9A-Za-z\\-\\.%_\\+]*)?)?(?:&(?:[0-9A-Za-z\\-\\.%_]+(?:=[0-9A-Za-z\\-\\.%_\\+]*)?)?)*)?(?:#[0-9A-Za-z\\-\\.%_\\+=\\?&;]*)?)';
var regex = new RegExp(urlCheck, 'gi');
var rProtocol = /(https?|ftp):\/\//i;
var urlImage = new RegExp('(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*\\.(?:jpg|gif|png))(?:\\?([^#]*))?(?:#(.*))?', 'gi');
var childNodes = (this.$editor ? this.$editor[0] : this).childNodes, i = childNodes.length;
while (i--)
{
var n = childNodes[i];
if (n.nodeType === 3 && n.parentNode !== 'PRE')
{
var html = n.nodeValue;
// youtube & vimeo
if (convertVideoLinks && html)
{
var iframeStart = '<iframe width="500" height="281" src="',
iframeEnd = '" frameborder="0" allowfullscreen></iframe>';
if (html.match(reUrlYoutube))
{
html = html.replace(reUrlYoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd);
$(n).after(html).remove();
}
else if (html.match(reUrlVimeo))
{
html = html.replace(reUrlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd);
$(n).after(html).remove();
}
}
// image
if (convertImageLinks && html && html.match(urlImage))
{
var matches = html.match(urlImage);
html = html.replace(urlImage, '<img src="' + matches + '" />');
$(n).after(html).remove();
return;
}
// link
if (html.search(/\$/g) != -1) html = html.replace(/\$/g, '&#36;');
var matches = html.match(regex);
if (convertUrlLinks && html && matches)
{
var len = matches.length;
for (var z = 0; z < len; z++)
{
// remove dot in the end
if (matches[z].match(/\.$/) !== null) matches[z] = matches[z].replace(/\.$/, '');
var href = matches[z];
var text = href;
var space = '';
if (href.match(/\s$/) !== null) space = ' ';
var addProtocol = protocol + '://';
if (href.match(rProtocol) !== null) addProtocol = '';
if (text.length > linkSize) text = text.substring(0, linkSize) + '...';
text = text.replace(/&#36;/g, '$').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
// buffer
var buffer = [];
var links = html.match('<a(.*?)</a>');
if (links !== null)
{
var len = links.length;
for (i = 0; i < len; i++)
{
buffer[i] = links[i];
html = html.replace(links[i], '{abuffer' + i + '}');
}
}
html = html.replace(href, '<a href=\"' + addProtocol + $.trim(href) + '\">' + $.trim(text) + '</a>' + space);
// rebuffer
$.each(buffer, function(i,s)
{
html = html.replace('{abuffer' + i + '}', s);
});
}
$(n).after(html).remove();
}
}
else if (n.nodeType === 1 && !/^(pre|a|button|textarea)$/i.test(n.tagName))
{
$.Redactor.fn.formatLinkify.call(n, protocol, convertLinks, convertUrlLinks, convertImageLinks, convertVideoLinks, linkSize);
}
}
};
})(jQuery);

View File

@ -279,6 +279,13 @@ body .redactor-box-fullscreen {
}
}
/*
CodeMirror
*/
.redactor-box .CodeMirror {
display:none;
}
/*
Icons
*/
@ -906,6 +913,12 @@ body .redactor-box-fullscreen {
padding-left: 2em;
border: none;
}
ol ol li {
list-style-type: lower-alpha;
}
ol ol ol li {
list-style-type: lower-roman;
}
dl dt {
font-weight: bold;
}

File diff suppressed because one or more lines are too long

View File