1947 lines
87 KiB
JavaScript
1947 lines
87 KiB
JavaScript
(function ( $ ) {
|
||
|
||
$.fn.richText = function( options ) {
|
||
|
||
// set default options
|
||
// and merge them with the parameter options
|
||
var settings = $.extend({
|
||
//id
|
||
//id: "",
|
||
// text formatting
|
||
bold: true,
|
||
italic: true,
|
||
underline: true,
|
||
|
||
// text alignment
|
||
leftAlign: true,
|
||
centerAlign: true,
|
||
rightAlign: true,
|
||
justify: true,
|
||
|
||
// lists
|
||
ol: true,
|
||
ul: true,
|
||
|
||
// title
|
||
heading: false,
|
||
|
||
// fonts
|
||
fonts: false,
|
||
fontList: ["Arial",
|
||
"Arial Black",
|
||
"Comic Sans MS",
|
||
"Courier New",
|
||
"Geneva",
|
||
"Georgia",
|
||
"Helvetica",
|
||
"Impact",
|
||
"Lucida Console",
|
||
"Tahoma",
|
||
"Times New Roman",
|
||
"Verdana"
|
||
],
|
||
fontColor: false,
|
||
fontSize: false,
|
||
|
||
// uploads
|
||
imageUpload: false,
|
||
fileUpload: false,
|
||
|
||
// media
|
||
videoEmbed: false,
|
||
|
||
// link
|
||
urls: false,
|
||
|
||
// tables
|
||
table: false,
|
||
|
||
// code
|
||
removeStyles: false,
|
||
code: false,
|
||
|
||
// colors
|
||
colors: [],
|
||
|
||
// dropdowns
|
||
fileHTML: '',
|
||
imageHTML: '',
|
||
|
||
// translations
|
||
translations: {
|
||
'title': 'Título',
|
||
'white': 'Blanco',
|
||
'black': 'Negro',
|
||
'brown': 'Café',
|
||
'beige': 'Beige',
|
||
'darkBlue': 'Azul Marino',
|
||
'blue': 'Azul',
|
||
'lightBlue': 'Azul Claro',
|
||
'darkRed': 'Rojo Obscuro',
|
||
'red': 'Rojo',
|
||
'darkGreen': 'Verde Obscuro',
|
||
'green': 'Verde',
|
||
'purple': 'Morado',
|
||
'darkTurquois': 'Turquesa Obscuro',
|
||
'turquois': 'Turquesa',
|
||
'darkOrange': 'naranja Obscuro',
|
||
'orange': 'Naranja',
|
||
'yellow': 'Amarillo',
|
||
'imageURL': 'URL Imagen',
|
||
'fileURL': 'URL Archivo',
|
||
'linkText': 'Hipervínculo',
|
||
'url': 'URL',
|
||
'size': 'Tamaño',
|
||
'responsive': 'Responsivo',
|
||
'text': 'Texto',
|
||
'openIn': 'Abrir en',
|
||
'sameTab': 'Misma página',
|
||
'newTab': 'Nueva Página',
|
||
'align': 'Alinear',
|
||
'left': 'Izquierda',
|
||
'justify': 'Justificado',
|
||
'center': 'Centrado',
|
||
'right': 'Derecha',
|
||
'rows': 'Renglones',
|
||
'columns': 'Columnas',
|
||
'add': 'Agregar',
|
||
'pleaseEnterURL': 'Ingresa una URL',
|
||
'videoURLnotSupported': 'URL de video no soportado',
|
||
'pleaseSelectImage': 'Seleccione una imagen',
|
||
'pleaseSelectFile': 'Seleccione un archivo',
|
||
'bold': 'Negrita',
|
||
'italic': 'Cursiva',
|
||
'underline': 'Subrayado',
|
||
'alignLeft': 'Alinear a la izquierda',
|
||
'alignCenter': 'Alinear centrado',
|
||
'alignRight': 'Alinear a la derecha',
|
||
'addOrderedList': 'Numeración',
|
||
'addUnorderedList': 'Viñetas',
|
||
'addHeading': 'Títulos',
|
||
'addFont': 'Cambiar fuente',
|
||
'addFontColor': 'Cambiar color de fuente',
|
||
'addFontSize' : 'Cambiar tamaño de fuente',
|
||
'addImage': 'Agregar imagen',
|
||
'addVideo': 'Agregar video',
|
||
'addFile': 'Agregar archivo',
|
||
'addURL': 'Vínculo',
|
||
'addTable': 'Tabla',
|
||
'removeStyles': 'Remover estilos',
|
||
'code': 'Mostrar código',
|
||
'undo': 'Deshacer',
|
||
'redo': 'Repetir',
|
||
'close': 'Cerrar'
|
||
},
|
||
|
||
// privacy
|
||
youtubeCookies: false,
|
||
|
||
// dev settings
|
||
useSingleQuotes: false,
|
||
height: 0,
|
||
heightPercentage: 0,
|
||
id: "",
|
||
class: "",
|
||
useParagraph: false
|
||
|
||
}, options );
|
||
|
||
|
||
/* prepare toolbar */
|
||
var $inputElement = $(this);
|
||
$inputElement.addClass("richText-initial");
|
||
var $editor,
|
||
$toolbarList = $('<ul />'),
|
||
$toolbarElement = $('<li />'),
|
||
$btnBold = $('<a />', {class: "richText-btn", "data-command": "bold", "title": settings.translations.bold, html: '<span class="fa fa-bold"></span>'}), // bold
|
||
$btnItalic = $('<a />', {class: "richText-btn", "data-command": "italic", "title": settings.translations.italic, html: '<span class="fa fa-italic"></span>'}), // italic
|
||
$btnUnderline = $('<a />', {class: "richText-btn", "data-command": "underline", "title": settings.translations.underline, html: '<span class="fa fa-underline"></span>'}), // underline
|
||
$btnJustify = $('<a />', {class: "richText-btn", "data-command": "justifyFull", "title": settings.translations.justify, html: '<span class="fa fa-align-justify"></span>'}), // left align
|
||
$btnLeftAlign = $('<a />', {class: "richText-btn", "data-command": "justifyLeft", "title": settings.translations.alignLeft, html: '<span class="fa fa-align-left"></span>'}), // left align
|
||
$btnCenterAlign = $('<a />', {class: "richText-btn", "data-command": "justifyCenter", "title": settings.translations.alignCenter, html: '<span class="fa fa-align-center"></span>'}), // centered
|
||
$btnRightAlign = $('<a />', {class: "richText-btn", "data-command": "justifyRight", "title": settings.translations.alignRight, html: '<span class="fa fa-align-right"></span>'}), // right align
|
||
$btnOL = $('<a />', {class: "richText-btn", "data-command": "insertOrderedList", "title": settings.translations.addOrderedList, html: '<span class="fa fa-list-ol"></span>'}), // ordered list
|
||
$btnUL = $('<a />', {class: "richText-btn", "data-command": "insertUnorderedList", "title": settings.translations.addUnorderedList, html: '<span class="fa fa-list"></span>'}), // unordered list
|
||
$btnHeading = $('<a />', {class: "richText-btn", "title": settings.translations.addHeading, html: '<span class="fa fa-header fa-heading"></span>'}), // title/header
|
||
$btnFont = $('<a />', {class: "richText-btn", "title": settings.translations.addFont, html: '<span class="fa fa-font"></span>'}), // font color
|
||
$btnFontColor = $('<a />', {class: "richText-btn", "title": settings.translations.addFontColor, html: '<span class="fa fa-paint-brush"></span>'}), // font color
|
||
$btnFontSize = $('<a />', {class: "richText-btn", "title": settings.translations.addFontSize, html: '<span class="fa fa-text-height"></span>'}), // font color
|
||
$btnImageUpload = $('<a />', {class: "richText-btn", "title": settings.translations.addImage, html: '<span class="fa fa-image"></span>'}), // image
|
||
$btnVideoEmbed = $('<a />', {class: "richText-btn", "title": settings.translations.addVideo, html: '<span class="fa fa-video-camera fa-video"></span>'}), // video
|
||
$btnFileUpload = $('<a />', {class: "richText-btn", "title": settings.translations.addFile, html: '<span class="fa fa-file-text-o far fa-file-alt"></span>'}), // file
|
||
$btnURLs = $('<a />', {class: "richText-btn", "title": settings.translations.addURL, html: '<span class="fa fa-link"></span>'}), // urls/links
|
||
$btnTable = $('<a />', {class: "richText-btn", "title": settings.translations.addTable, html: '<span class="fa fa-table"></span>'}), // table
|
||
$btnRemoveStyles = $('<a />', {class: "richText-btn", "data-command": "removeFormat", "title": settings.translations.removeStyles, html: '<span class="fa fa-recycle"></span>'}), // clean up styles
|
||
$btnCode = $('<a />', {class: "richText-btn ocultar", "data-command": "toggleCode", "title": settings.translations.code, html: '<span class="fa fa-code"></span>'}); // code
|
||
$btnUndo = $('<a />', {class: 'richText-undo is-disabled', html: '<span class="fa fa-undo"></span>', 'title': settings.translations.undo}); //undo
|
||
$btnRedo = $('<a />', {class: 'richText-redo is-disabled', html: '<span class="fa fa-repeat fa-redo"></span>', 'title': settings.translations.redo});//redo
|
||
|
||
|
||
/* prepare toolbar dropdowns */
|
||
var $dropdownOuter = $('<div />', {class: "richText-dropdown-outer"});
|
||
var $dropdownClose = $('<span />', {class: "richText-dropdown-close", html: '<span title="' + settings.translations.close + '"><span class="fa fa-times"></span></span>'});
|
||
var $dropdownList = $('<ul />', {class: "richText-dropdown"}), // dropdown lists
|
||
$dropdownBox = $('<div />', {class: "richText-dropdown"}), // dropdown boxes / custom dropdowns
|
||
$form = $('<div />', {class: "richText-form"}), // symbolic form
|
||
$formItem = $('<div />', {class: 'richText-form-item'}), // form item
|
||
$formLabel = $('<label />'), // form label
|
||
$formInput = $('<input />', {type: "text"}), //form input field
|
||
$formRadio = $('<input />', {type: "radio"}), //form input field
|
||
$formInputFile = $('<input />', {type: "file"}), // form file input field
|
||
$formInputSelect = $('<select />'),
|
||
$formButton = $('<button />', {text: settings.translations.add, class: "btn btn-accept"}); // button
|
||
|
||
/* internal settings */
|
||
var savedSelection; // caret position/selection
|
||
var editorID = "richText-" + Math.random().toString(36).substring(7);
|
||
//var editorID = settings.id;
|
||
var ignoreSave = false, $resizeImage = null;
|
||
|
||
/* prepare editor history */
|
||
var history = [];
|
||
history[editorID] = [];
|
||
var historyPosition = [];
|
||
historyPosition[editorID] = 0;
|
||
|
||
/* list dropdown for titles */
|
||
var $titles = $dropdownList.clone();
|
||
$titles.append($('<li />', {html: '<a data-command="formatBlock" data-option="h1">' + settings.translations.title + ' #1</a>'}));
|
||
$titles.append($('<li />', {html: '<a data-command="formatBlock" data-option="h2">' + settings.translations.title + ' #2</a>'}));
|
||
$titles.append($('<li />', {html: '<a data-command="formatBlock" data-option="h3">' + settings.translations.title + ' #3</a>'}));
|
||
$titles.append($('<li />', {html: '<a data-command="formatBlock" data-option="h4">' + settings.translations.title + ' #4</a>'}));
|
||
$btnHeading.append($dropdownOuter.clone().append($titles.prepend($dropdownClose.clone())));
|
||
|
||
/* list dropdown for fonts */
|
||
var fonts = settings.fontList;
|
||
var $fonts = $dropdownList.clone();
|
||
for(var i = 0; i < fonts.length; i++) {
|
||
$fonts.append($('<li />', {html: '<a style="font-family:' + fonts[i] + ';" data-command="fontName" data-option="' + fonts[i] + '">' + fonts[i] + '</a>'}));
|
||
}
|
||
$btnFont.append($dropdownOuter.clone().append($fonts.prepend($dropdownClose.clone())));
|
||
|
||
/* list dropdown for font sizes */
|
||
var fontSizes = [24,18,16,14,12];
|
||
var $fontSizes = $dropdownList.clone();
|
||
for(var i = 0; i < fontSizes.length; i++) {
|
||
$fontSizes.append($('<li />', {html: '<a style="font-size:' + fontSizes[i] + 'px;" data-command="fontSize" data-option="' + fontSizes[i] + '">Text ' + fontSizes[i] + 'px</a>'}));
|
||
}
|
||
$btnFontSize.append($dropdownOuter.clone().append($fontSizes.prepend($dropdownClose.clone())));
|
||
|
||
/* font colors */
|
||
var $fontColors = $dropdownList.clone();
|
||
$fontColors.html(loadColors("forecolor"));
|
||
$btnFontColor.append($dropdownOuter.clone().append($fontColors.prepend($dropdownClose.clone())));
|
||
|
||
|
||
/* background colors */
|
||
//var $bgColors = $dropdownList.clone();
|
||
//$bgColors.html(loadColors("hiliteColor"));
|
||
//$btnBGColor.append($dropdownOuter.clone().append($bgColors));
|
||
|
||
/* box dropdown for links */
|
||
var $linksDropdown = $dropdownBox.clone();
|
||
var $linksForm = $form.clone().attr("id", "richText-URL").attr("data-editor", editorID);
|
||
$linksForm.append(
|
||
$formItem.clone().addClass('my-2')
|
||
.append($formLabel.clone().text(settings.translations.url).attr("for", "url").addClass('col-lg-3'))
|
||
.append($formInput.clone().attr("id", "url"))
|
||
);
|
||
$linksForm.append(
|
||
$formItem.clone().addClass('my-2')
|
||
.append($formLabel.clone().text(settings.translations.text).attr("for", "urlText").addClass('col-lg-3'))
|
||
.append($formInput.clone().attr("id", "urlText"))
|
||
);
|
||
$linksForm.append(
|
||
$formItem.clone().addClass('my-2')
|
||
.append($formLabel.clone().text(settings.translations.openIn).attr("for", "openIn").addClass('col-lg-3'))
|
||
.append($formInputSelect
|
||
.clone().attr("id", "openIn")
|
||
.append($("<option />", {value: '_self', text: settings.translations.sameTab}))
|
||
.append($("<option />", {value: '_blank', text: settings.translations.newTab}))
|
||
)
|
||
);
|
||
$linksForm.append( $formItem.clone().append($formButton.clone()).addClass('justify-content-center'));
|
||
$linksDropdown.append($linksForm);
|
||
$btnURLs.append($dropdownOuter.clone().append($linksDropdown.prepend($dropdownClose.clone())));
|
||
|
||
/* box dropdown for video embedding */
|
||
var $videoDropdown = $dropdownBox.clone();
|
||
var $videoForm = $form.clone().attr("id", "richText-Video").attr("data-editor", editorID);
|
||
$videoForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.url).attr("for", "videoURL"))
|
||
.append($formInput.clone().attr("id", "videoURL"))
|
||
);
|
||
$videoForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.size).attr("for", "size"))
|
||
.append(
|
||
$formInputSelect
|
||
.clone().attr("id", "size")
|
||
.append($("<option />", {value: 'responsive', text: settings.translations.responsive}))
|
||
.append($("<option />", {value: '640x360', text: '640x360'}))
|
||
.append($("<option />", {value: '560x315', text: '560x315'}))
|
||
.append($("<option />", {value: '480x270', text: '480x270'}))
|
||
.append($("<option />", {value: '320x180', text: '320x180'}))
|
||
)
|
||
);
|
||
$videoForm.append( $formItem.clone().append($formButton.clone()) );
|
||
$videoDropdown.append($videoForm);
|
||
$btnVideoEmbed.append($dropdownOuter.clone().append($videoDropdown.prepend($dropdownClose.clone())));
|
||
|
||
/* box dropdown for image upload/image selection */
|
||
var $imageDropdown = $dropdownBox.clone();
|
||
var $imageForm = $form.clone().attr("id", "richText-Image").attr("data-editor", editorID);
|
||
|
||
if(settings.imageHTML
|
||
&& ($(settings.imageHTML).find('#imageURL').length > 0 || $(settings.imageHTML).attr("id") === "imageURL")) {
|
||
// custom image form
|
||
$imageForm.html(settings.imageHTML);
|
||
} else {
|
||
// default image form
|
||
$imageForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.imageURL).attr("for", "imageURL"))
|
||
.append($formInput.clone().attr("id", "imageURL"))
|
||
);
|
||
$imageForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.align).attr("for", "align"))
|
||
.append(
|
||
$formInputSelect
|
||
.clone().attr("id", "align")
|
||
.append($("<option />", {value: 'left', text: settings.translations.left}))
|
||
.append($("<option />", {value: 'center', text: settings.translations.center}))
|
||
.append($("<option />", {value: 'right', text: settings.translations.right}))
|
||
)
|
||
);
|
||
}
|
||
$imageForm.append( $formItem.clone().append($formButton.clone()) );
|
||
$imageDropdown.append($imageForm);
|
||
$btnImageUpload.append($dropdownOuter.clone().append($imageDropdown.prepend($dropdownClose.clone())));
|
||
|
||
/* box dropdown for file upload/file selection */
|
||
var $fileDropdown = $dropdownBox.clone();
|
||
var $fileForm = $form.clone().attr("id", "richText-File").attr("data-editor", editorID);
|
||
|
||
if(settings.fileHTML
|
||
&& ($(settings.fileHTML).find('#fileURL').length > 0 || $(settings.fileHTML).attr("id") === "fileURL")) {
|
||
// custom file form
|
||
$fileForm.html(settings.fileHTML);
|
||
} else {
|
||
// default file form
|
||
$fileForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.fileURL).attr("for", "fileURL"))
|
||
.append($formInput.clone().attr("id", "fileURL"))
|
||
);
|
||
$fileForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.linkText).attr("for", "fileText"))
|
||
.append($formInput.clone().attr("id", "fileText"))
|
||
);
|
||
}
|
||
$fileForm.append( $formItem.clone().append($formButton.clone()) );
|
||
$fileDropdown.append($fileForm);
|
||
$btnFileUpload.append($dropdownOuter.clone().append($fileDropdown.prepend($dropdownClose.clone())));
|
||
|
||
/* box dropdown for tables */
|
||
var $tableDropdown = $dropdownBox.clone();
|
||
var $tableForm = $form.clone().attr("id", "richText-Table").attr("data-editor", editorID);
|
||
$tableForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.rows).attr("for", "tableRows"))
|
||
.append($formInput.clone().attr("id", "tableRows").attr("type", "number"))
|
||
);
|
||
$tableForm.append(
|
||
$formItem.clone()
|
||
.append($formLabel.clone().text(settings.translations.columns).attr("for", "tableColumns"))
|
||
.append($formInput.clone().attr("id", "tableColumns").attr("type", "number"))
|
||
);
|
||
$tableForm.append( $formItem.clone().append($formButton.clone()) );
|
||
$tableDropdown.append($tableForm);
|
||
$btnTable.append($dropdownOuter.clone().append($tableDropdown.prepend($dropdownClose.clone())));
|
||
|
||
|
||
/* initizalize editor */
|
||
function init() {
|
||
var value, attributes, attributes_html = '';
|
||
|
||
if(settings.useParagraph !== false) {
|
||
// set default tag when pressing ENTER to <p> instead of <div>
|
||
document.execCommand("DefaultParagraphSeparator", false, 'p');
|
||
}
|
||
|
||
|
||
// reformat $inputElement to textarea
|
||
if($inputElement.prop("tagName") === "TEXTAREA") {
|
||
// everything perfect
|
||
} else if($inputElement.val()) {
|
||
value = $inputElement.val();
|
||
attributes = $inputElement.prop("attributes");
|
||
// loop through <select> attributes and apply them on <div>
|
||
$.each(attributes, function() {
|
||
if(this.name) {
|
||
attributes_html += ' ' + this.name + '="' + this.value + '"';
|
||
}
|
||
});
|
||
$inputElement.replaceWith($('<textarea' + attributes_html + ' data-richtext="init">' + value + '</textarea>'));
|
||
$inputElement = $('[data-richtext="init"]');
|
||
$inputElement.removeAttr("data-richtext");
|
||
} else if($inputElement.html()) {
|
||
value = $inputElement.html();
|
||
attributes = $inputElement.prop("attributes");
|
||
// loop through <select> attributes and apply them on <div>
|
||
$.each(attributes, function() {
|
||
if(this.name) {
|
||
attributes_html += ' ' + this.name + '="' + this.value + '"';
|
||
}
|
||
});
|
||
$inputElement.replaceWith($('<textarea' + attributes_html + ' data-richtext="init">' + value + '</textarea>'));
|
||
$inputElement = $('[data-richtext="init"]');
|
||
$inputElement.removeAttr("data-richtext");
|
||
} else {
|
||
attributes = $inputElement.prop("attributes");
|
||
// loop through <select> attributes and apply them on <div>
|
||
$.each(attributes, function() {
|
||
if(this.name) {
|
||
attributes_html += ' ' + this.name + '="' + this.value + '"';
|
||
}
|
||
});
|
||
$inputElement.replaceWith($('<textarea' + attributes_html + ' data-richtext="init"></textarea>'));
|
||
$inputElement = $('[data-richtext="init"]');
|
||
$inputElement.removeAttr("data-richtext");
|
||
}
|
||
|
||
$editor = $('<div />', {class: "richText"});
|
||
var $toolbar = $('<div />', {class: "richText-toolbar"});
|
||
//var $editorView = $('<div />', {class: "richText-editor", id: editorID, contenteditable: true, name: settings.id});
|
||
var $editorView = $('<div />', {class: "richText-editor", id: editorID, contenteditable: true});
|
||
$toolbar.append($toolbarList);
|
||
|
||
$toolbarList.append($toolbarElement.clone().append($btnUndo));
|
||
$toolbarList.append($toolbarElement.clone().append($btnRedo));
|
||
|
||
/* text formatting */
|
||
if(settings.bold === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnBold));
|
||
}
|
||
if(settings.italic === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnItalic));
|
||
}
|
||
if(settings.underline === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnUnderline));
|
||
}
|
||
|
||
/* align */
|
||
if(settings.leftAlign === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnLeftAlign));
|
||
}
|
||
if(settings.centerAlign === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnCenterAlign));
|
||
}
|
||
if(settings.rightAlign === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnRightAlign));
|
||
}
|
||
if(settings.justify === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnJustify));
|
||
}
|
||
|
||
/* lists */
|
||
if(settings.ol === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnOL));
|
||
}
|
||
if(settings.ul === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnUL));
|
||
}
|
||
|
||
/* fonts */
|
||
if(settings.fonts === true && settings.fontList.length > 0) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnFont));
|
||
}
|
||
if(settings.fontSize === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnFontSize));
|
||
}
|
||
|
||
/* heading */
|
||
if(settings.heading === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnHeading));
|
||
}
|
||
|
||
/* colors */
|
||
if(settings.fontColor === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnFontColor));
|
||
}
|
||
|
||
/* uploads */
|
||
if(settings.imageUpload === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnImageUpload));
|
||
}
|
||
if(settings.fileUpload === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnFileUpload));
|
||
}
|
||
|
||
/* media */
|
||
if(settings.videoEmbed === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnVideoEmbed));
|
||
}
|
||
|
||
/* urls */
|
||
if(settings.urls === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnURLs));
|
||
}
|
||
|
||
if(settings.table === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnTable));
|
||
}
|
||
|
||
/* code */
|
||
if(settings.removeStyles === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnRemoveStyles));
|
||
}
|
||
if(settings.code === true) {
|
||
$toolbarList.append($toolbarElement.clone().append($btnCode));
|
||
}
|
||
|
||
// set current textarea value to editor
|
||
$editorView.html($inputElement.val());
|
||
|
||
$editor.append($toolbar);
|
||
$editor.append($editorView);
|
||
$editor.append($inputElement.clone().hide());
|
||
$inputElement.replaceWith($editor);
|
||
|
||
// append bottom toolbar
|
||
/*$editor.append(
|
||
$('<div />', {class: 'richText-toolbar'})
|
||
.append($('<a />', {class: 'richText-undo is-disabled', html: '<span class="fa fa-undo"></span>', 'title': settings.translations.undo}))
|
||
.append($('<a />', {class: 'richText-redo is-disabled', html: '<span class="fa fa-repeat fa-redo"></span>', 'title': settings.translations.redo}))
|
||
.append($('<a />', {class: 'richText-help', html: '<span class="fa fa-question-circle"></span>'}))
|
||
);*/
|
||
|
||
if(settings.height && settings.height > 0) {
|
||
// set custom editor height
|
||
$editor.children(".richText-editor, .richText-initial").css({'min-height' : settings.height + 'px', 'height' : settings.height + 'px'});
|
||
} else if(settings.heightPercentage && settings.heightPercentage > 0) {
|
||
// set custom editor height in percentage
|
||
var parentHeight = $editor.parent().innerHeight(); // get editor parent height
|
||
var height = (settings.heightPercentage/100) * parentHeight; // calculate pixel value from percentage
|
||
height -= $toolbar.outerHeight()*2; // remove toolbar size
|
||
height -= parseInt($editor.css("margin-top")); // remove margins
|
||
height -= parseInt($editor.css("margin-bottom")); // remove margins
|
||
height -= parseInt($editor.find(".richText-editor").css("padding-top")); // remove paddings
|
||
height -= parseInt($editor.find(".richText-editor").css("padding-bottom")); // remove paddings
|
||
$editor.children(".richText-editor, .richText-initial").css({'min-height' : height + 'px', 'height' : height + 'px'});
|
||
}
|
||
|
||
// add custom class
|
||
if(settings.class) {
|
||
$editor.addClass(settings.class);
|
||
}
|
||
if(settings.id) {
|
||
$editor.attr("id", settings.id);
|
||
}
|
||
|
||
// fix the first line
|
||
fixFirstLine();
|
||
|
||
// save history
|
||
history[editorID].push($editor.find("textarea").val());
|
||
}
|
||
|
||
// initialize editor
|
||
init();
|
||
|
||
|
||
/** EVENT HANDLERS */
|
||
|
||
// Help popup
|
||
$editor.find(".richText-help").on("click", function() {
|
||
var $editor = $(this).parents(".richText");
|
||
if($editor) {
|
||
var $outer = $('<div />', {class: 'richText-help-popup', style: 'position:absolute;top:0;right:0;bottom:0;left:0;background-color: rgba(0,0,0,0.3);'});
|
||
var $inner = $('<div />', {style: 'position:relative;margin:60px auto;padding:20px;background-color:#FAFAFA;width:70%;font-family:Calibri,Verdana,Helvetica,sans-serif;font-size:small;'});
|
||
var $content = $('<div />', {html: '<span id="closeHelp" style="display:block;position:absolute;top:0;right:0;padding:10px;cursor:pointer;" title="' + settings.translations.close + '"><span class="fa fa-times"></span></span>'});
|
||
$content.append('<h3 style="margin:0;">RichText</h3>');
|
||
$content.append('<hr><br>Powered by <a href="https://github.com/webfashionist/RichText" target="_blank">webfashionist/RichText</a> (Github) <br>License: <a href="https://github.com/webfashionist/RichText/blob/master/LICENSE" target="_blank">AGPL-3.0</a>');
|
||
|
||
$outer.append($inner.append($content));
|
||
$editor.append($outer);
|
||
|
||
$outer.on("click", "#closeHelp", function() {
|
||
$(this).parents('.richText-help-popup').remove();
|
||
});
|
||
}
|
||
});
|
||
|
||
// undo / redo
|
||
$(document).on("click", ".richText-undo, .richText-redo", function(e) {
|
||
var $this = $(this);
|
||
var $editor = $this.parents('.richText');
|
||
if($this.hasClass("richText-undo") && !$this.hasClass("is-disabled")) {
|
||
undo($editor);
|
||
} else if($this.hasClass("richText-redo") && !$this.hasClass("is-disabled")) {
|
||
redo($editor);
|
||
}
|
||
});
|
||
|
||
|
||
// Saving changes from editor to textarea
|
||
$(document).on("input change blur keydown keyup", ".richText-editor", function(e) {
|
||
if((e.keyCode === 9 || e.keyCode === "9") && e.type === "keydown") {
|
||
// tab through table cells
|
||
e.preventDefault();
|
||
tabifyEditableTable(window, e);
|
||
return false;
|
||
}
|
||
fixFirstLine();
|
||
updateTextarea();
|
||
doSave($(this).attr("id"));
|
||
});
|
||
|
||
|
||
// add context menu to several Node elements
|
||
$(document).on('contextmenu', '.richText-editor', function(e) {
|
||
|
||
var $list = $('<ul />', {'class': 'list-rightclick richText-list'});
|
||
var $li = $('<li />');
|
||
// remove Node selection
|
||
$('.richText-editor').find('.richText-editNode').removeClass('richText-editNode');
|
||
|
||
var $target = $(e.target);
|
||
var $richText = $target.parents('.richText');
|
||
var $toolbar = $richText.find('.richText-toolbar');
|
||
|
||
var positionX = e.pageX - $richText.offset().left;
|
||
var positionY = e.pageY - $richText.offset().top;
|
||
|
||
$list.css({
|
||
'top': positionY,
|
||
'left': positionX
|
||
});
|
||
|
||
|
||
if($target.prop("tagName") === "A") {
|
||
// edit URL
|
||
e.preventDefault();
|
||
|
||
$list.append($li.clone().html('<span class="fa fa-link"></span>'));
|
||
$target.parents('.richText').append($list);
|
||
$list.find('.fa-link').on('click', function() {
|
||
$('.list-rightclick.richText-list').remove();
|
||
$target.addClass('richText-editNode');
|
||
var $popup = $toolbar.find('#richText-URL');
|
||
$popup.find('input#url').val($target.attr('href'));
|
||
$popup.find('input#urlText').val($target.text());
|
||
$popup.find('select#openIn').val($target.attr('target'));
|
||
$toolbar.find('.richText-btn').children('.fa-link').parents('li').addClass('is-selected');
|
||
});
|
||
|
||
return false;
|
||
} else if($target.prop("tagName") === "IMG") {
|
||
// edit image
|
||
e.preventDefault();
|
||
|
||
$list.append($li.clone().html('<span class="fa fa-image"></span>'));
|
||
$target.parents('.richText').append($list);
|
||
$list.find('.fa-image').on('click', function() {
|
||
var align;
|
||
if($target.parent('div').length > 0 && $target.parent('div').attr('style') === 'text-align:center;') {
|
||
align = 'center';
|
||
} else {
|
||
align = $target.attr('align');
|
||
}
|
||
$('.list-rightclick.richText-list').remove();
|
||
$target.addClass('richText-editNode');
|
||
var $popup = $toolbar.find('#richText-Image');
|
||
$popup.find('input#imageURL').val($target.attr('src'));
|
||
$popup.find('select#align').val(align);
|
||
$toolbar.find('.richText-btn').children('.fa-image').parents('li').addClass('is-selected');
|
||
});
|
||
|
||
return false;
|
||
}
|
||
|
||
});
|
||
|
||
// Saving changes from textarea to editor
|
||
$(document).on("input change blur", ".richText-initial", function() {
|
||
if(settings.useSingleQuotes === true) {
|
||
$(this).val(changeAttributeQuotes($(this).val()));
|
||
}
|
||
var editorID = $(this).siblings('.richText-editor').attr("id");
|
||
updateEditor(editorID);
|
||
doSave(editorID);
|
||
});
|
||
|
||
// Save selection seperately (mainly needed for Safari)
|
||
$(document).on("dblclick mouseup", ".richText-editor", function() {
|
||
var editorID = $(this).attr("id");
|
||
doSave(editorID);
|
||
});
|
||
|
||
// embedding video
|
||
$(document).on("click", "#richText-Video button.btn", function(event) {
|
||
event.preventDefault();
|
||
var $button = $(this);
|
||
var $form = $button.parent('.richText-form-item').parent('.richText-form');
|
||
if($form.attr("data-editor") === editorID) {
|
||
// only for the currently selected editor
|
||
var url = $form.find('input#videoURL').val();
|
||
var size = $form.find('select#size').val();
|
||
|
||
if(!url) {
|
||
// no url set
|
||
$form.prepend($('<div />', {style: 'color:red;display:none;', class: 'form-item is-error', text: settings.translations.pleaseEnterURL}));
|
||
$form.children('.form-item.is-error').slideDown();
|
||
setTimeout(function() {
|
||
$form.children('.form-item.is-error').slideUp(function () {
|
||
$(this).remove();
|
||
});
|
||
}, 5000);
|
||
} else {
|
||
// write html in editor
|
||
var html = '';
|
||
html = getVideoCode(url, size);
|
||
if(!html) {
|
||
$form.prepend($('<div />', {style: 'color:red;display:none;', class: 'form-item is-error', text: settings.translations.videoURLnotSupported}));
|
||
$form.children('.form-item.is-error').slideDown();
|
||
setTimeout(function() {
|
||
$form.children('.form-item.is-error').slideUp(function () {
|
||
$(this).remove();
|
||
});
|
||
}, 5000);
|
||
} else {
|
||
if(settings.useSingleQuotes === true) {
|
||
|
||
} else {
|
||
|
||
}
|
||
restoreSelection(editorID, true);
|
||
pasteHTMLAtCaret(html);
|
||
updateTextarea();
|
||
// reset input values
|
||
$form.find('input#videoURL').val('');
|
||
$('.richText-toolbar li.is-selected').removeClass("is-selected");
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// Resize images
|
||
$(document).on('mousedown', function(e) {
|
||
var $target = $(e.target);
|
||
if(!$target.hasClass('richText-list') && $target.parents('.richText-list').length === 0) {
|
||
// remove context menu
|
||
$('.richText-list.list-rightclick').remove();
|
||
if(!$target.hasClass('richText-form') && $target.parents('.richText-form').length === 0) {
|
||
$('.richText-editNode').each(function () {
|
||
var $this = $(this);
|
||
$this.removeClass('richText-editNode');
|
||
if ($this.attr('class') === '') {
|
||
$this.removeAttr('class');
|
||
}
|
||
});
|
||
}
|
||
}
|
||
if($target.prop("tagName") === "IMG" && $target.parents("#" + editorID)) {
|
||
startX = e.pageX;
|
||
startY = e.pageY;
|
||
startW = $target.innerWidth();
|
||
startH = $target.innerHeight();
|
||
|
||
var left = $target.offset().left;
|
||
var right = $target.offset().left + $target.innerWidth();
|
||
var bottom = $target.offset().top + $target.innerHeight();
|
||
var top = $target.offset().top;
|
||
var resize = false;
|
||
$target.css({'cursor' : 'default'});
|
||
|
||
if(startY <= bottom && startY >= bottom-20 && startX >= right-20 && startX <= right) {
|
||
// bottom right corner
|
||
$resizeImage = $target;
|
||
$resizeImage.css({'cursor' : 'nwse-resize'});
|
||
resize = true;
|
||
}
|
||
|
||
if((resize === true || $resizeImage) && !$resizeImage.data("width")) {
|
||
// set initial image size and prevent dragging image while resizing
|
||
$resizeImage.data("width", $target.parents("#" + editorID).innerWidth());
|
||
$resizeImage.data("height", $target.parents("#" + editorID).innerHeight()*3);
|
||
e.preventDefault();
|
||
} else if(resize === true || $resizeImage) {
|
||
// resizing active, prevent other events
|
||
e.preventDefault();
|
||
} else {
|
||
// resizing disabled, allow dragging image
|
||
$resizeImage = null;
|
||
}
|
||
|
||
}
|
||
});
|
||
$(document)
|
||
.mouseup(function(){
|
||
if($resizeImage) {
|
||
$resizeImage.css({'cursor' : 'default'});
|
||
}
|
||
$resizeImage = null;
|
||
})
|
||
.mousemove(function(e){
|
||
if($resizeImage!==null){
|
||
var maxWidth = $resizeImage.data('width');
|
||
var currentWidth = $resizeImage.width();
|
||
var maxHeight = $resizeImage.data('height');
|
||
var currentHeight = $resizeImage.height();
|
||
if((startW + e.pageX-startX) <= maxWidth && (startH + e.pageY-startY) <= maxHeight) {
|
||
// only resize if new size is smaller than the original image size
|
||
$resizeImage.innerWidth (startW + e.pageX-startX); // only resize width to adapt height proportionally
|
||
// $box.innerHeight(startH + e.pageY-startY);
|
||
updateTextarea();
|
||
} else if((startW + e.pageX-startX) <= currentWidth && (startH + e.pageY-startY) <= currentHeight) {
|
||
// only resize if new size is smaller than the previous size
|
||
$resizeImage.innerWidth (startW + e.pageX-startX); // only resize width to adapt height proportionally
|
||
updateTextarea();
|
||
}
|
||
}
|
||
});
|
||
|
||
// adding URL
|
||
$(document).on("click", "#richText-URL button.btn", function(event) {
|
||
event.preventDefault();
|
||
var $button = $(this);
|
||
var $form = $button.parent('.richText-form-item').parent('.richText-form');
|
||
if($form.attr("data-editor") === editorID) {
|
||
// only for currently selected editor
|
||
var url = $form.find('input#url').val();
|
||
var text = $form.find('input#urlText').val();
|
||
var target = $form.find('#openIn').val();
|
||
|
||
// set default values
|
||
if(!target) {
|
||
target = '_self';
|
||
}
|
||
if(!text) {
|
||
text = url;
|
||
}
|
||
if(!url) {
|
||
// no url set
|
||
$form.prepend($('<div />', {style: 'color:red;display:none;', class: 'form-item is-error', text: settings.translations.pleaseEnterURL}));
|
||
$form.children('.form-item.is-error').slideDown();
|
||
setTimeout(function() {
|
||
$form.children('.form-item.is-error').slideUp(function () {
|
||
$(this).remove();
|
||
});
|
||
}, 5000);
|
||
} else {
|
||
// write html in editor
|
||
var html = '';
|
||
if(settings.useSingleQuotes === true) {
|
||
html = "<a href='" + url + "' target='" + target + "'>" + text + "</a>";
|
||
} else {
|
||
html = '<a href="' + url + '" target="' + target + '">' + text + '</a>';
|
||
}
|
||
restoreSelection(editorID, false, true);
|
||
|
||
var $editNode = $('.richText-editNode');
|
||
if($editNode.length > 0 && $editNode.prop("tagName") === "A") {
|
||
$editNode.attr("href", url);
|
||
$editNode.attr("target", target);
|
||
$editNode.text(text);
|
||
$editNode.removeClass('richText-editNode');
|
||
if($editNode.attr('class') === '') {
|
||
$editNode.removeAttr('class');
|
||
}
|
||
} else {
|
||
pasteHTMLAtCaret(html);
|
||
}
|
||
// reset input values
|
||
$form.find('input#url').val('');
|
||
$form.find('input#urlText').val('');
|
||
$('.richText-toolbar li.is-selected').removeClass("is-selected");
|
||
}
|
||
}
|
||
});
|
||
|
||
// adding image
|
||
$(document).on("click", "#richText-Image button.btn", function(event) {
|
||
event.preventDefault();
|
||
var $button = $(this);
|
||
var $form = $button.parent('.richText-form-item').parent('.richText-form');
|
||
if($form.attr("data-editor") === editorID) {
|
||
// only for currently selected editor
|
||
var url = $form.find('#imageURL').val();
|
||
var align = $form.find('select#align').val();
|
||
|
||
// set default values
|
||
if(!align) {
|
||
align = 'center';
|
||
}
|
||
if(!url) {
|
||
// no url set
|
||
$form.prepend($('<div />', {style: 'color:red;display:none;', class: 'form-item is-error', text: settings.translations.pleaseSelectImage}));
|
||
$form.children('.form-item.is-error').slideDown();
|
||
setTimeout(function() {
|
||
$form.children('.form-item.is-error').slideUp(function () {
|
||
$(this).remove();
|
||
});
|
||
}, 5000);
|
||
} else {
|
||
// write html in editor
|
||
var html = '';
|
||
if(settings.useSingleQuotes === true) {
|
||
if(align === "center") {
|
||
html = "<div style='text-align:center;'><img src='" + url + "'></div>";
|
||
} else {
|
||
html = "<img src='" + url + "' align='" + align + "'>";
|
||
}
|
||
} else {
|
||
if(align === "center") {
|
||
html = '<div style="text-align:center;"><img src="' + url + '"></div>';
|
||
} else {
|
||
html = '<img src="' + url + '" align="' + align + '">';
|
||
}
|
||
}
|
||
restoreSelection(editorID, true);
|
||
var $editNode = $('.richText-editNode');
|
||
if($editNode.length > 0 && $editNode.prop("tagName") === "IMG") {
|
||
$editNode.attr("src", url);
|
||
if($editNode.parent('div').length > 0 && $editNode.parent('div').attr('style') === 'text-align:center;' && align !== 'center') {
|
||
$editNode.unwrap('div');
|
||
$editNode.attr('align', align);
|
||
} else if(($editNode.parent('div').length === 0 || $editNode.parent('div').attr('style') !== 'text-align:center;') && align === 'center' ) {
|
||
$editNode.wrap('<div style="text-align:center;"></div>');
|
||
$editNode.removeAttr('align');
|
||
} else {
|
||
$editNode.attr('align', align);
|
||
}
|
||
$editNode.removeClass('richText-editNode');
|
||
if($editNode.attr('class') === '') {
|
||
$editNode.removeAttr('class');
|
||
}
|
||
} else {
|
||
pasteHTMLAtCaret(html);
|
||
}
|
||
// reset input values
|
||
$form.find('input#imageURL').val('');
|
||
$('.richText-toolbar li.is-selected').removeClass("is-selected");
|
||
}
|
||
}
|
||
});
|
||
|
||
// adding file
|
||
$(document).on("click", "#richText-File button.btn", function(event) {
|
||
event.preventDefault();
|
||
var $button = $(this);
|
||
var $form = $button.parent('.richText-form-item').parent('.richText-form');
|
||
if($form.attr("data-editor") === editorID) {
|
||
// only for currently selected editor
|
||
var url = $form.find('#fileURL').val();
|
||
var text = $form.find('#fileText').val();
|
||
|
||
// set default values
|
||
if(!text) {
|
||
text = url;
|
||
}
|
||
if(!url) {
|
||
// no url set
|
||
$form.prepend($('<div />', {style: 'color:red;display:none;', class: 'form-item is-error', text: settings.translations.pleaseSelectFile}));
|
||
$form.children('.form-item.is-error').slideDown();
|
||
setTimeout(function() {
|
||
$form.children('.form-item.is-error').slideUp(function () {
|
||
$(this).remove();
|
||
});
|
||
}, 5000);
|
||
} else {
|
||
// write html in editor
|
||
var html = '';
|
||
if(settings.useSingleQuotes === true) {
|
||
html = "<a href='" + url + "' target='_blank'>" + text + "</a>";
|
||
} else {
|
||
html = '<a href="' + url + '" target="_blank">' + text + '</a>';
|
||
}
|
||
restoreSelection(editorID, true);
|
||
pasteHTMLAtCaret(html);
|
||
// reset input values
|
||
$form.find('input#fileURL').val('');
|
||
$form.find('input#fileText').val('');
|
||
$('.richText-toolbar li.is-selected').removeClass("is-selected");
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
// adding table
|
||
$(document).on("click", "#richText-Table button.btn", function(event) {
|
||
event.preventDefault();
|
||
var $button = $(this);
|
||
var $form = $button.parent('.richText-form-item').parent('.richText-form');
|
||
if($form.attr("data-editor") === editorID) {
|
||
// only for currently selected editor
|
||
var rows = $form.find('input#tableRows').val();
|
||
var columns = $form.find('input#tableColumns').val();
|
||
|
||
// set default values
|
||
if(!rows || rows <= 0) {
|
||
rows = 2;
|
||
}
|
||
if(!columns || columns <= 0) {
|
||
columns = 2;
|
||
}
|
||
|
||
// generate table
|
||
var html = '';
|
||
if(settings.useSingleQuotes === true) {
|
||
html = "<table class='table-1'><tbody>";
|
||
} else {
|
||
html = '<table class="table-1"><tbody>';
|
||
}
|
||
for(var i = 1; i <= rows; i++) {
|
||
// start new row
|
||
html += '<tr>';
|
||
for(var n = 1; n <= columns; n++) {
|
||
// start new column in row
|
||
html += '<td> </td>';
|
||
}
|
||
html += '</tr>';
|
||
}
|
||
html += '</tbody></table>';
|
||
|
||
// write html in editor
|
||
restoreSelection(editorID, true);
|
||
pasteHTMLAtCaret(html);
|
||
// reset input values
|
||
$form.find('input#tableColumns').val('');
|
||
$form.find('input#tableRows').val('');
|
||
$('.richText-toolbar li.is-selected').removeClass("is-selected");
|
||
}
|
||
});
|
||
|
||
// opening / closing toolbar dropdown
|
||
$(document).on("click", function(event) {
|
||
var $clickedElement = $(event.target);
|
||
|
||
if($clickedElement.parents('.richText-toolbar').length === 0) {
|
||
// element not in toolbar
|
||
// ignore
|
||
} else if($clickedElement.hasClass("richText-dropdown-outer")) {
|
||
// closing dropdown by clicking inside the editor
|
||
$clickedElement.parent('a').parent('li').removeClass("is-selected");
|
||
} else if($clickedElement.find(".richText").length > 0) {
|
||
// closing dropdown by clicking outside of the editor
|
||
$('.richText-toolbar li').removeClass("is-selected");
|
||
} else if($clickedElement.parent().hasClass("richText-dropdown-close")) {
|
||
// closing dropdown by clicking on the close button
|
||
$('.richText-toolbar li').removeClass("is-selected");
|
||
} else if($clickedElement.hasClass("richText-btn") && $(event.target).children('.richText-dropdown-outer').length > 0) {
|
||
// opening dropdown by clicking on toolbar button
|
||
$clickedElement.parent('li').addClass("is-selected");
|
||
|
||
if($clickedElement.children('.fa,svg').hasClass("fa-link")) {
|
||
// put currently selected text in URL form to replace it
|
||
restoreSelection(editorID, false, true);
|
||
var selectedText = getSelectedText();
|
||
$clickedElement.find("input#urlText").val('');
|
||
$clickedElement.find("input#url").val('');
|
||
if(selectedText) {
|
||
$clickedElement.find("input#urlText").val(selectedText);
|
||
}
|
||
} else if($clickedElement.hasClass("fa-image")) {
|
||
// image
|
||
}
|
||
}
|
||
});
|
||
|
||
// Executing editor commands
|
||
$(document).on("click", ".richText-toolbar a[data-command]", function(event) {
|
||
var $button = $(this);
|
||
var $toolbar = $button.closest('.richText-toolbar');
|
||
var $editor = $toolbar.siblings('.richText-editor');
|
||
var id = $editor.attr("id");
|
||
if($editor.length > 0 && id === editorID && (!$button.parent("li").attr('data-disable') || $button.parent("li").attr('data-disable') === "false")) {
|
||
event.preventDefault();
|
||
var command = $(this).data("command");
|
||
|
||
if(command === "toggleCode") {
|
||
toggleCode($editor.attr("id"));
|
||
} else {
|
||
var option = null;
|
||
if ($(this).data('option')) {
|
||
option = $(this).data('option').toString();
|
||
if (option.match(/^h[1-6]$/)) {
|
||
command = "heading";
|
||
}
|
||
}
|
||
|
||
formatText(command, option, id);
|
||
if (command === "removeFormat") {
|
||
// remove HTML/CSS formatting
|
||
$editor.find('*').each(function() {
|
||
// remove all, but very few, attributes from the nodes
|
||
var keepAttributes = [
|
||
"id", "class",
|
||
"name", "action", "method",
|
||
"src", "align", "alt", "title",
|
||
"style", "webkitallowfullscreen", "mozallowfullscreen", "allowfullscreen",
|
||
"width", "height", "frameborder"
|
||
];
|
||
var element = $(this);
|
||
var attributes = $.map(this.attributes, function(item) {
|
||
return item.name;
|
||
});
|
||
$.each(attributes, function(i, item) {
|
||
if(keepAttributes.indexOf(item) < 0 && item.substr(0, 5) !== 'data-') {
|
||
element.removeAttr(item);
|
||
}
|
||
});
|
||
if(element.prop('tagName') === "A") {
|
||
// remove empty URL tags
|
||
element.replaceWith(function() {
|
||
return $('<span />', {html: $(this).html()});
|
||
});
|
||
}
|
||
});
|
||
formatText('formatBlock', 'div', id);
|
||
}
|
||
// clean up empty tags, which can be created while replacing formatting or when copy-pasting from other tools
|
||
$editor.find('div:empty,p:empty,li:empty,h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty').remove();
|
||
$editor.find('h1,h2,h3,h4,h5,h6').unwrap('h1,h2,h3,h4,h5,h6');
|
||
}
|
||
}
|
||
// close dropdown after click
|
||
$button.parents('li.is-selected').removeClass('is-selected');
|
||
});
|
||
|
||
|
||
|
||
/** INTERNAL METHODS **/
|
||
|
||
/**
|
||
* Format text in editor
|
||
* @param {string} command
|
||
* @param {string|null} option
|
||
* @param {string} editorID
|
||
* @private
|
||
*/
|
||
function formatText(command, option, editorID) {
|
||
if (typeof option === "undefined") {
|
||
option = null;
|
||
}
|
||
// restore selection from before clicking on any button
|
||
doRestore(editorID);
|
||
// Temporarily enable designMode so that
|
||
// document.execCommand() will work
|
||
// document.designMode = "ON";
|
||
// Execute the command
|
||
if(command === "heading" && getSelectedText()) {
|
||
// IE workaround
|
||
pasteHTMLAtCaret('<' + option + '>' + getSelectedText() + '</' + option + '>');
|
||
} else if(command === "fontSize" && parseInt(option) > 0) {
|
||
var selection = getSelectedText();
|
||
selection = (selection + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2');
|
||
var html = (settings.useSingleQuotes ? "<span style='font-size:" + option + "px;'>" + selection + "</span>" : '<span style="font-size:' + option + 'px;">' + selection + '</span>');
|
||
pasteHTMLAtCaret(html);
|
||
} else {
|
||
document.execCommand(command, false, option);
|
||
}
|
||
// Disable designMode
|
||
// document.designMode = "OFF";
|
||
}
|
||
|
||
|
||
/**
|
||
* Update textarea when updating editor
|
||
* @private
|
||
*/
|
||
function updateTextarea() {
|
||
var $editor = $('#' + editorID);
|
||
var content = $editor.html();
|
||
if(settings.useSingleQuotes === true) {
|
||
content = changeAttributeQuotes(content);
|
||
}
|
||
$editor.siblings('.richText-initial').val(content);
|
||
}
|
||
|
||
|
||
/**
|
||
* Update editor when updating textarea
|
||
* @private
|
||
*/
|
||
function updateEditor(editorID) {
|
||
var $editor = $('#' + editorID);
|
||
var content = $editor.siblings('.richText-initial').val();
|
||
$editor.html(content);
|
||
}
|
||
|
||
|
||
/**
|
||
* Save caret position and selection
|
||
* @return object
|
||
**/
|
||
function saveSelection(editorID) {
|
||
var containerEl = document.getElementById(editorID);
|
||
var range, start, end, type;
|
||
if(window.getSelection && document.createRange) {
|
||
var sel = window.getSelection && window.getSelection();
|
||
if (sel && sel.rangeCount > 0 && $(sel.anchorNode).parents('#' + editorID).length > 0) {
|
||
range = window.getSelection().getRangeAt(0);
|
||
var preSelectionRange = range.cloneRange();
|
||
preSelectionRange.selectNodeContents(containerEl);
|
||
preSelectionRange.setEnd(range.startContainer, range.startOffset);
|
||
|
||
start = preSelectionRange.toString().length;
|
||
end = (start + range.toString().length);
|
||
|
||
type = (start === end ? 'caret' : 'selection');
|
||
anchor = sel.anchorNode; //(type === "caret" && sel.anchorNode.tagName ? sel.anchorNode : false);
|
||
start = (type === 'caret' && anchor !== false ? 0 : preSelectionRange.toString().length);
|
||
end = (type === 'caret' && anchor !== false ? 0 : (start + range.toString().length));
|
||
|
||
return {
|
||
start: start,
|
||
end: end,
|
||
type: type,
|
||
anchor: anchor,
|
||
editorID: editorID
|
||
}
|
||
}
|
||
}
|
||
return (savedSelection ? savedSelection : {
|
||
start: 0,
|
||
end: 0
|
||
});
|
||
}
|
||
|
||
|
||
/**
|
||
* Restore selection
|
||
**/
|
||
function restoreSelection(editorID, media, url) {
|
||
var containerEl = document.getElementById(editorID);
|
||
var savedSel = savedSelection;
|
||
if(!savedSel) {
|
||
// fix selection if editor has not been focused
|
||
savedSel = {
|
||
'start': 0,
|
||
'end': 0,
|
||
'type': 'caret',
|
||
'editorID': editorID,
|
||
'anchor': $('#' + editorID).children('div')[0]
|
||
};
|
||
}
|
||
|
||
if(savedSel.editorID !== editorID) {
|
||
return false;
|
||
} else if(media === true) {
|
||
containerEl = (savedSel.anchor ? savedSel.anchor : containerEl); // fix selection issue
|
||
} else if(url === true) {
|
||
if(savedSel.start === 0 && savedSel.end === 0) {
|
||
containerEl = (savedSel.anchor ? savedSel.anchor : containerEl); // fix selection issue
|
||
}
|
||
}
|
||
|
||
if (window.getSelection && document.createRange) {
|
||
var charIndex = 0, range = document.createRange();
|
||
if(!range || !containerEl) { window.getSelection().removeAllRanges(); return true; }
|
||
range.setStart(containerEl, 0);
|
||
range.collapse(true);
|
||
var nodeStack = [containerEl], node, foundStart = false, stop = false;
|
||
|
||
while (!stop && (node = nodeStack.pop())) {
|
||
if (node.nodeType === 3) {
|
||
var nextCharIndex = charIndex + node.length;
|
||
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
|
||
range.setStart(node, savedSel.start - charIndex);
|
||
foundStart = true;
|
||
}
|
||
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
|
||
range.setEnd(node, savedSel.end - charIndex);
|
||
stop = true;
|
||
}
|
||
charIndex = nextCharIndex;
|
||
} else {
|
||
var i = node.childNodes.length;
|
||
while (i--) {
|
||
nodeStack.push(node.childNodes[i]);
|
||
}
|
||
}
|
||
}
|
||
var sel = window.getSelection();
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* Save caret position and selection
|
||
* @return object
|
||
**/
|
||
/*
|
||
function saveSelection(editorID) {
|
||
var containerEl = document.getElementById(editorID);
|
||
var start;
|
||
if (window.getSelection && document.createRange) {
|
||
var sel = window.getSelection && window.getSelection();
|
||
if (sel && sel.rangeCount > 0) {
|
||
var range = window.getSelection().getRangeAt(0);
|
||
var preSelectionRange = range.cloneRange();
|
||
preSelectionRange.selectNodeContents(containerEl);
|
||
preSelectionRange.setEnd(range.startContainer, range.startOffset);
|
||
start = preSelectionRange.toString().length;
|
||
|
||
return {
|
||
start: start,
|
||
end: start + range.toString().length,
|
||
editorID: editorID
|
||
}
|
||
} else {
|
||
return (savedSelection ? savedSelection : {
|
||
start: 0,
|
||
end: 0
|
||
});
|
||
}
|
||
} else if (document.selection && document.body.createTextRange) {
|
||
var selectedTextRange = document.selection.createRange();
|
||
var preSelectionTextRange = document.body.createTextRange();
|
||
preSelectionTextRange.moveToElementText(containerEl);
|
||
preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
|
||
start = preSelectionTextRange.text.length;
|
||
|
||
return {
|
||
start: start,
|
||
end: start + selectedTextRange.text.length,
|
||
editorID: editorID
|
||
};
|
||
}
|
||
}
|
||
*/
|
||
|
||
/**
|
||
* Restore selection
|
||
**/
|
||
/*
|
||
function restoreSelection(editorID) {
|
||
var containerEl = document.getElementById(editorID);
|
||
var savedSel = savedSelection;
|
||
if(savedSel.editorID !== editorID) {
|
||
return false;
|
||
}
|
||
if (window.getSelection && document.createRange) {
|
||
var charIndex = 0, range = document.createRange();
|
||
range.setStart(containerEl, 0);
|
||
range.collapse(true);
|
||
var nodeStack = [containerEl], node, foundStart = false, stop = false;
|
||
|
||
while (!stop && (node = nodeStack.pop())) {
|
||
if (node.nodeType === 3) {
|
||
var nextCharIndex = charIndex + node.length;
|
||
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
|
||
range.setStart(node, savedSel.start - charIndex);
|
||
foundStart = true;
|
||
}
|
||
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
|
||
range.setEnd(node, savedSel.end - charIndex);
|
||
stop = true;
|
||
}
|
||
charIndex = nextCharIndex;
|
||
} else {
|
||
var i = node.childNodes.length;
|
||
while (i--) {
|
||
nodeStack.push(node.childNodes[i]);
|
||
}
|
||
}
|
||
}
|
||
var sel = window.getSelection();
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
} else if (document.selection && document.body.createTextRange) {
|
||
var textRange = document.body.createTextRange();
|
||
textRange.moveToElementText(containerEl);
|
||
textRange.collapse(true);
|
||
textRange.moveEnd("character", savedSel.end);
|
||
textRange.moveStart("character", savedSel.start);
|
||
textRange.select();
|
||
}
|
||
}
|
||
*/
|
||
|
||
/**
|
||
* Enables tabbing/shift-tabbing between contentEditable table cells
|
||
* @param {Window} win - Active window context.
|
||
* @param {Event} e - jQuery Event object for the keydown that fired.
|
||
*/
|
||
function tabifyEditableTable(win, e) {
|
||
|
||
if (e.keyCode !== 9) {
|
||
return false;
|
||
}
|
||
|
||
var sel;
|
||
if (win.getSelection) {
|
||
sel = win.getSelection();
|
||
if (sel.rangeCount > 0) {
|
||
|
||
var textNode = null,
|
||
direction = null;
|
||
|
||
if (!e.shiftKey) {
|
||
direction = "next";
|
||
textNode = (sel.focusNode.nodeName === "TD")
|
||
? (sel.focusNode.nextSibling != null)
|
||
? sel.focusNode.nextSibling
|
||
: (sel.focusNode.parentNode.nextSibling != null)
|
||
? sel.focusNode.parentNode.nextSibling.childNodes[0]
|
||
: null
|
||
: (sel.focusNode.parentNode.nextSibling != null)
|
||
? sel.focusNode.parentNode.nextSibling
|
||
: (sel.focusNode.parentNode.parentNode.nextSibling != null)
|
||
? sel.focusNode.parentNode.parentNode.nextSibling.childNodes[0]
|
||
: null;
|
||
} else {
|
||
direction = "previous";
|
||
textNode = (sel.focusNode.nodeName === "TD")
|
||
? (sel.focusNode.previousSibling != null)
|
||
? sel.focusNode.previousSibling
|
||
: (sel.focusNode.parentNode.previousSibling != null)
|
||
? sel.focusNode.parentNode.previousSibling.childNodes[sel.focusNode.parentNode.previousSibling.childNodes.length - 1]
|
||
: null
|
||
: (sel.focusNode.parentNode.previousSibling != null)
|
||
? sel.focusNode.parentNode.previousSibling
|
||
: (sel.focusNode.parentNode.parentNode.previousSibling != null)
|
||
? sel.focusNode.parentNode.parentNode.previousSibling.childNodes[sel.focusNode.parentNode.parentNode.previousSibling.childNodes.length - 1]
|
||
: null;
|
||
}
|
||
|
||
if (textNode != null) {
|
||
sel.collapse(textNode, Math.min(textNode.length, sel.focusOffset + 1));
|
||
if (textNode.textContent != null) {
|
||
sel.selectAllChildren(textNode);
|
||
}
|
||
e.preventDefault();
|
||
return true;
|
||
} else if(textNode === null && direction === "next" && sel.focusNode.nodeName === "TD") {
|
||
// add new row on TAB if arrived at the end of the row
|
||
var $table = $(sel.focusNode).parents("table");
|
||
var cellsPerLine = $table.find("tr").first().children("td").length;
|
||
var $tr = $("<tr />");
|
||
var $td = $("<td />");
|
||
for(var i = 1; i <= cellsPerLine; i++) {
|
||
$tr.append($td.clone());
|
||
}
|
||
$table.append($tr);
|
||
// simulate tabing through table
|
||
tabifyEditableTable(window, {keyCode: 9, shiftKey: false, preventDefault: function(){}});
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Returns the text from the current selection
|
||
* @private
|
||
* @return {string|boolean}
|
||
*/
|
||
function getSelectedText() {
|
||
var range;
|
||
if (window.getSelection) { // all browsers, except IE before version 9
|
||
range = window.getSelection();
|
||
return range.toString() ? range.toString() : range.focusNode.nodeValue;
|
||
} else if (document.selection.createRange) { // Internet Explorer
|
||
range = document.selection.createRange();
|
||
return range.text;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Save selection
|
||
*/
|
||
function doSave(editorID) {
|
||
var $textarea = $('.richText-editor#' + editorID).siblings('.richText-initial');
|
||
addHistory($textarea.val(), editorID);
|
||
savedSelection = saveSelection(editorID);
|
||
}
|
||
|
||
/**
|
||
* Add to history
|
||
* @param val Editor content
|
||
* @param id Editor ID
|
||
*/
|
||
function addHistory(val, id) {
|
||
if(!history[id]) {
|
||
return false;
|
||
}
|
||
if(history[id].length-1 > historyPosition[id]) {
|
||
history[id].length = historyPosition[id] + 1;
|
||
}
|
||
|
||
if(history[id][history[id].length-1] !== val) {
|
||
history[id].push(val);
|
||
}
|
||
|
||
historyPosition[id] = history[id].length-1;
|
||
setHistoryButtons(id);
|
||
}
|
||
|
||
function setHistoryButtons(id) {
|
||
if(historyPosition[id] <= 0) {
|
||
$editor.find(".richText-undo").addClass("is-disabled");
|
||
} else {
|
||
$editor.find(".richText-undo").removeClass("is-disabled");
|
||
}
|
||
|
||
if(historyPosition[id] >= history[id].length-1 || history[id].length === 0) {
|
||
$editor.find(".richText-redo").addClass("is-disabled");
|
||
} else {
|
||
$editor.find(".richText-redo").removeClass("is-disabled");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Undo
|
||
* @param $editor
|
||
*/
|
||
function undo($editor) {
|
||
var id = $editor.children('.richText-editor').attr('id');
|
||
historyPosition[id]--;
|
||
if(!historyPosition[id] && historyPosition[id] !== 0) {
|
||
return false;
|
||
}
|
||
var value = history[id][historyPosition[id]];
|
||
$editor.find('textarea').val(value);
|
||
$editor.find('.richText-editor').html(value);
|
||
setHistoryButtons(id);
|
||
}
|
||
|
||
/**
|
||
* Undo
|
||
* @param $editor
|
||
*/
|
||
function redo($editor) {
|
||
var id = $editor.children('.richText-editor').attr('id');
|
||
historyPosition[id]++;
|
||
if(!historyPosition[id] && historyPosition[id] !== 0) {
|
||
return false;
|
||
}
|
||
var value = history[id][historyPosition[id]];
|
||
$editor.find('textarea').val(value);
|
||
$editor.find('.richText-editor').html(value);
|
||
setHistoryButtons(id);
|
||
}
|
||
|
||
/**
|
||
* Restore selection
|
||
*/
|
||
function doRestore(id) {
|
||
if(savedSelection) {
|
||
restoreSelection((id ? id : savedSelection.editorID));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Paste HTML at caret position
|
||
* @param {string} html HTML code
|
||
* @private
|
||
*/
|
||
function pasteHTMLAtCaret(html) {
|
||
// add HTML code for Internet Explorer
|
||
var sel, range;
|
||
if (window.getSelection) {
|
||
// IE9 and non-IE
|
||
sel = window.getSelection();
|
||
if (sel.getRangeAt && sel.rangeCount) {
|
||
range = sel.getRangeAt(0);
|
||
range.deleteContents();
|
||
|
||
// Range.createContextualFragment() would be useful here but is
|
||
// only relatively recently standardized and is not supported in
|
||
// some browsers (IE9, for one)
|
||
var el = document.createElement("div");
|
||
el.innerHTML = html;
|
||
var frag = document.createDocumentFragment(), node, lastNode;
|
||
while ( (node = el.firstChild) ) {
|
||
lastNode = frag.appendChild(node);
|
||
}
|
||
range.insertNode(frag);
|
||
|
||
// Preserve the selection
|
||
if (lastNode) {
|
||
range = range.cloneRange();
|
||
range.setStartAfter(lastNode);
|
||
range.collapse(true);
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
}
|
||
}
|
||
} else if (document.selection && document.selection.type !== "Control") {
|
||
// IE < 9
|
||
document.selection.createRange().pasteHTML(html);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Change quotes around HTML attributes
|
||
* @param {string} string
|
||
* @return {string}
|
||
*/
|
||
function changeAttributeQuotes(string) {
|
||
if(!string) {
|
||
return '';
|
||
}
|
||
|
||
var regex;
|
||
var rstring;
|
||
if(settings.useSingleQuotes === true) {
|
||
regex = /\s+(\w+\s*=\s*(["][^"]*["])|(['][^']*[']))+/g;
|
||
rstring = string.replace(regex, function($0,$1,$2){
|
||
if(!$2) {return $0;}
|
||
return $0.replace($2, $2.replace(/\"/g, "'"));
|
||
});
|
||
} else {
|
||
regex = /\s+(\w+\s*=\s*(['][^']*['])|(["][^"]*["]))+/g;
|
||
rstring = string.replace(regex, function($0,$1,$2){
|
||
if(!$2) {return $0;}
|
||
return $0.replace($2, $2.replace(/'/g, '"'));
|
||
});
|
||
}
|
||
return rstring;
|
||
}
|
||
|
||
|
||
/**
|
||
* Load colors for font or background
|
||
* @param {string} command Command
|
||
* @returns {string}
|
||
* @private
|
||
*/
|
||
function loadColors(command) {
|
||
var colors = [];
|
||
var result = '';
|
||
|
||
colors["#FFFFFF"] = settings.translations.white;
|
||
colors["#000000"] = settings.translations.black;
|
||
colors["#7F6000"] = settings.translations.brown;
|
||
colors["#938953"] = settings.translations.beige;
|
||
colors["#1F497D"] = settings.translations.darkBlue;
|
||
colors["blue"] = settings.translations.blue;
|
||
colors["#4F81BD"] = settings.translations.lightBlue;
|
||
colors["#953734"] = settings.translations.darkRed;
|
||
colors["red"] = settings.translations.red;
|
||
colors["#4F6128"] = settings.translations.darkGreen;
|
||
colors["green"] = settings.translations.green;
|
||
colors["#3F3151"] = settings.translations.purple;
|
||
colors["#31859B"] = settings.translations.darkTurquois;
|
||
colors["#4BACC6"] = settings.translations.turquois;
|
||
colors["#E36C09"] = settings.translations.darkOrange;
|
||
colors["#F79646"] = settings.translations.orange;
|
||
colors["#FFFF00"] = settings.translations.yellow;
|
||
|
||
if(settings.colors && settings.colors.length > 0) {
|
||
colors = settings.colors;
|
||
}
|
||
|
||
for (var i in colors) {
|
||
result += '<li class="inline"><a data-command="' + command + '" data-option="' + i + '" style="text-align:left;" title="' + colors[i] + '"><span class="box-color" style="background-color:' + i + '"></span></a></li>';
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
/**
|
||
* Toggle (show/hide) code or editor
|
||
* @private
|
||
*/
|
||
function toggleCode(editorID) {
|
||
doRestore(editorID);
|
||
if($editor.find('.richText-editor').is(":visible")) {
|
||
// show code
|
||
$editor.find('.richText-initial').show();
|
||
$editor.find('.richText-editor').hide();
|
||
// disable non working buttons
|
||
$('.richText-toolbar').find('.richText-btn').each(function() {
|
||
if($(this).children('.fa-code').length === 0) {
|
||
$(this).parent('li').attr("data-disable", "true");
|
||
}
|
||
});
|
||
convertCaretPosition(editorID, savedSelection);
|
||
} else {
|
||
// show editor
|
||
$editor.find('.richText-initial').hide();
|
||
$editor.find('.richText-editor').show();
|
||
convertCaretPosition(editorID, savedSelection, true);
|
||
// enable all buttons again
|
||
$('.richText-toolbar').find('li').removeAttr("data-disable");
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Convert caret position from editor to code view (or in reverse)
|
||
* @param {string} editorID
|
||
* @param {object} selection
|
||
* @param {boolean} reverse
|
||
**/
|
||
function convertCaretPosition(editorID, selection, reverse) {
|
||
var $editor = $('#' + editorID);
|
||
var $textarea = $editor.siblings(".richText-initial");
|
||
|
||
var code = $textarea.val();
|
||
if(!selection || !code) {
|
||
return {start: 0, end: 0};
|
||
}
|
||
|
||
if(reverse === true) {
|
||
savedSelection = {start: $editor.text().length, end: $editor.text().length, editorID: editorID};
|
||
restoreSelection(editorID);
|
||
return true;
|
||
}
|
||
selection.node = $textarea[0];
|
||
var states = {start: false, end: false, tag: false, isTag: false, tagsCount: 0, isHighlight: (selection.start !== selection.end)};
|
||
for(var i = 0; i < code.length; i++) {
|
||
if(code[i] === "<") {
|
||
// HTML tag starts
|
||
states.isTag = true;
|
||
states.tag = false;
|
||
states.tagsCount++;
|
||
} else if(states.isTag === true && code[i] !== ">") {
|
||
states.tagsCount++;
|
||
} else if(states.isTag === true && code[i] === ">") {
|
||
states.isTag = false;
|
||
states.tag = true;
|
||
states.tagsCount++;
|
||
} else if(states.tag === true) {
|
||
states.tag = false;
|
||
}
|
||
|
||
if(!reverse) {
|
||
if((selection.start + states.tagsCount) <= i && states.isHighlight && !states.isTag && !states.tag && !states.start) {
|
||
selection.start = i;
|
||
states.start = true;
|
||
} else if((selection.start + states.tagsCount) <= i+1 && !states.isHighlight && !states.isTag && !states.tag && !states.start) {
|
||
selection.start = i+1;
|
||
states.start = true;
|
||
}
|
||
if((selection.end + states.tagsCount) <= i+1 && !states.isTag && !states.tag && !states.end) {
|
||
selection.end = i+1;
|
||
states.end = true;
|
||
}
|
||
}
|
||
|
||
}
|
||
createSelection(selection.node, selection.start, selection.end);
|
||
return selection;
|
||
}
|
||
|
||
/**
|
||
* Create selection on node element
|
||
* @param {Node} field
|
||
* @param {int} start
|
||
* @param {int} end
|
||
**/
|
||
function createSelection(field, start, end) {
|
||
if( field.createTextRange ) {
|
||
var selRange = field.createTextRange();
|
||
selRange.collapse(true);
|
||
selRange.moveStart('character', start);
|
||
selRange.moveEnd('character', end);
|
||
selRange.select();
|
||
field.focus();
|
||
} else if( field.setSelectionRange ) {
|
||
field.focus();
|
||
field.setSelectionRange(start, end);
|
||
} else if( typeof field.selectionStart != 'undefined' ) {
|
||
field.selectionStart = start;
|
||
field.selectionEnd = end;
|
||
field.focus();
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Get video embed code from URL
|
||
* @param {string} url Video URL
|
||
* @param {string} size Size in the form of widthxheight
|
||
* @return {string|boolean}
|
||
* @private
|
||
**/
|
||
function getVideoCode(url, size) {
|
||
var video = getVideoID(url);
|
||
var responsive = false, success = false;
|
||
|
||
if(!video) {
|
||
// video URL not supported
|
||
return false;
|
||
}
|
||
|
||
if(!size) {
|
||
size = "640x360";
|
||
size = size.split("x");
|
||
} else if(size !== "responsive") {
|
||
size = size.split("x");
|
||
} else {
|
||
responsive = true;
|
||
size = "640x360";
|
||
size = size.split("x");
|
||
}
|
||
|
||
var html = '<br><br>';
|
||
if(responsive === true) {
|
||
html += '<div class="videoEmbed" style="position:relative;height:0;padding-bottom:56.25%">';
|
||
}
|
||
var allowfullscreen = 'webkitallowfullscreen mozallowfullscreen allowfullscreen';
|
||
|
||
if(video.platform === "YouTube") {
|
||
var youtubeDomain = (settings.youtubeCookies ? 'www.youtube.com' : 'www.youtube-nocookie.com');
|
||
html += '<iframe src="https://' + youtubeDomain + '/embed/' + video.id + '?ecver=2" width="' + size[0] + '" height="' + size[1] + '" frameborder="0"' + (responsive === true ? ' style="position:absolute;width:100%;height:100%;left:0"' : '') + ' ' + allowfullscreen + '></iframe>';
|
||
success = true;
|
||
} else if(video.platform === "Vimeo") {
|
||
html += '<iframe src="https://player.vimeo.com/video/' + video.id + '" width="' + size[0] + '" height="' + size[1] + '" frameborder="0"' + (responsive === true ? ' style="position:absolute;width:100%;height:100%;left:0"' : '') + ' ' + allowfullscreen + '></iframe>';
|
||
success = true;
|
||
} else if(video.platform === "Facebook") {
|
||
html += '<iframe src="https://www.facebook.com/plugins/video.php?href=' + encodeURI(url) + '&show_text=0&width=' + size[0] + '" width="' + size[0] + '" height="' + size[1] + '" style="' + (responsive === true ? 'position:absolute;width:100%;height:100%;left:0;border:none;overflow:hidden"' : 'border:none;overflow:hidden') + '" scrolling="no" frameborder="0" allowTransparency="true" ' + allowfullscreen + '></iframe>';
|
||
success = true;
|
||
} else if(video.platform === "Dailymotion") {
|
||
html += '<iframe frameborder="0" width="' + size[0] + '" height="' + size[1] + '" src="//www.dailymotion.com/embed/video/' + video.id + '"' + (responsive === true ? ' style="position:absolute;width:100%;height:100%;left:0"' : '') + ' ' + allowfullscreen + '></iframe>';
|
||
success = true;
|
||
}
|
||
|
||
if(responsive === true) {
|
||
html += '</div>';
|
||
}
|
||
html += '<br><br>';
|
||
|
||
if(success) {
|
||
return html;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Returns the unique video ID
|
||
* @param {string} url
|
||
* return {object|boolean}
|
||
**/
|
||
function getVideoID(url) {
|
||
var vimeoRegExp = /(?:http?s?:\/\/)?(?:www\.)?(?:vimeo\.com)\/?(.+)/;
|
||
var youtubeRegExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
|
||
var facebookRegExp = /(?:http?s?:\/\/)?(?:www\.)?(?:facebook\.com)\/.*\/videos\/[0-9]+/;
|
||
var dailymotionRegExp = /(?:http?s?:\/\/)?(?:www\.)?(?:dailymotion\.com)\/video\/([a-zA-Z0-9]+)/;
|
||
var youtubeMatch = url.match(youtubeRegExp);
|
||
var vimeoMatch = url.match(vimeoRegExp);
|
||
var facebookMatch = url.match(facebookRegExp);
|
||
var dailymotionMatch = url.match(dailymotionRegExp);
|
||
|
||
if (youtubeMatch && youtubeMatch[2].length === 11) {
|
||
return {
|
||
"platform": "YouTube",
|
||
"id": youtubeMatch[2]
|
||
};
|
||
} else if(vimeoMatch && vimeoMatch[1]) {
|
||
return {
|
||
"platform": "Vimeo",
|
||
"id": vimeoMatch[1]
|
||
};
|
||
} else if(facebookMatch && facebookMatch[0]) {
|
||
return {
|
||
"platform": "Facebook",
|
||
"id" : facebookMatch[0]
|
||
};
|
||
} else if(dailymotionMatch && dailymotionMatch[1]) {
|
||
return {
|
||
"platform": "Dailymotion",
|
||
"id" : dailymotionMatch[1]
|
||
};
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
/**
|
||
* Fix the first line as by default the first line has no tag container
|
||
*/
|
||
function fixFirstLine() {
|
||
if($editor && !$editor.find(".richText-editor").html()) {
|
||
// set first line with the right tags
|
||
if(settings.useParagraph !== false) {
|
||
$editor.find(".richText-editor").html('<p><br></p>');
|
||
} else {
|
||
//$editor.find(".richText-editor").html('<div><br></div>');
|
||
$editor.find(".richText-editor").html('');
|
||
}
|
||
} else {
|
||
// replace tags, to force <div> or <p> tags and fix issues
|
||
if(settings.useParagraph !== false) {
|
||
$editor.find(".richText-editor").find('div:not(.videoEmbed)').replaceWith(function() {
|
||
return $('<p />', {html: $(this).html()});
|
||
});
|
||
} else {
|
||
$editor.find(".richText-editor").find('p').replaceWith(function() {
|
||
return $('<div />', {html: $(this).html()});
|
||
});
|
||
}
|
||
}
|
||
updateTextarea();
|
||
}
|
||
|
||
return $(this);
|
||
};
|
||
|
||
$.fn.unRichText = function( options ) {
|
||
|
||
// set default options
|
||
// and merge them with the parameter options
|
||
var settings = $.extend({
|
||
delay: 0 // delay in ms
|
||
}, options);
|
||
|
||
var $editor, $textarea, $main;
|
||
var $el = $(this);
|
||
|
||
/**
|
||
* Initialize undoing RichText and call remove() method
|
||
*/
|
||
function init() {
|
||
|
||
if($el.hasClass('richText')) {
|
||
$main = $el;
|
||
} else if($el.hasClass('richText-initial') || $el.hasClass('richText-editor')) {
|
||
$main = $el.parents('.richText');
|
||
}
|
||
|
||
if(!$main) {
|
||
// node element does not correspond to RichText elements
|
||
return false;
|
||
}
|
||
|
||
$editor = $main.find('.richText-editor');
|
||
$textarea = $main.find('.richText-initial');
|
||
|
||
if(parseInt(settings.delay) > 0) {
|
||
// a delay has been set
|
||
setTimeout(remove, parseInt(settings.delay));
|
||
} else {
|
||
remove();
|
||
}
|
||
}
|
||
init();
|
||
|
||
/**
|
||
* Remove RichText elements
|
||
*/
|
||
function remove() {
|
||
$main.find('.richText-toolbar').remove();
|
||
$main.find('.richText-editor').remove();
|
||
$textarea
|
||
.unwrap('.richText')
|
||
.data('editor', 'richText')
|
||
.removeClass('richText-initial')
|
||
.show();
|
||
}
|
||
|
||
};
|
||
|
||
}( jQuery )); |