Skip to content
Snippets Groups Projects

Issue #3350059: Remove CKEditor4 support.

Merged Adam Nagy requested to merge issue/maxlength-3350059:3350059-remove-ckeditor-4 into 3.x
Files
10
+ 56
120
@@ -4,17 +4,18 @@
var ml = ml || {};
ml.options = ml.options || {};
/**
* Maxlength JS behaviour.
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.maxlength = {
attach: function(context) {
var $context = $(context);
if (Drupal.ckeditor != undefined) {
ml.ckeditor();
}
let $context = $(context);
$(once('maxlength', $context.find('.maxlength').filter(':input'))).each(function () {
var options = {};
var $this = $(this);
let options = {};
let $this = $(this);
options['counterText'] = $this.attr('maxlength_js_label');
if ($this.hasClass('maxlength_js_enforce')) {
options['enforce'] = true;
@@ -31,7 +32,7 @@
});
},
detach: function(context, settings) {
var $context = $(context);
let $context = $(context);
$(once.remove('maxlength', $context.find('.maxlength'))).each(function () {
$(this).charCount({
action: 'detach'
@@ -62,14 +63,14 @@
* The name of the data setter function.
*/
ml.calculate = function(obj, options, count, wysiwyg, getter, setter) {
var counter = $('#' + obj.attr('id') + '-' + options.css);
var limit = parseInt(obj.attr('data-maxlength'));
let counter = $('#' + obj.attr('id') + '-' + options.css);
let limit = parseInt(obj.attr('data-maxlength'));
if (count == undefined) {
if (count === undefined) {
count = ml.strip_tags(obj.val()).length;
}
var available = limit - count;
let available = limit - count;
if (available <= options.warning) {
counter.addClass(options.cssWarning);
@@ -82,9 +83,9 @@
counter.addClass(options.cssExceeded);
// Trim text.
if (options.enforce) {
if (wysiwyg != undefined) {
if (wysiwyg !== undefined) {
if (typeof ml[getter] == 'function' && typeof ml[setter] == 'function') {
var new_html = ml.truncate_html(ml[getter](wysiwyg), limit);
let new_html = ml.truncate_html(ml[getter](wysiwyg), limit);
ml[setter](wysiwyg, new_html);
count = ml.strip_tags(new_html).length;
}
@@ -136,15 +137,15 @@
.toLowerCase()
.match(/<[a-z][a-z0-9]*>/g) || [])
.join('');
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi,
emptyTags = />[ ]{1,}</gi;
let tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi,
emptyTags = />[ ]{1,}</gi;
input = input
.replace(emptyTags, '><')
.replace(commentsAndPhpTags, '')
.replace(tags, function($0, $1){
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
.replace(emptyTags, '><')
.replace(commentsAndPhpTags, '')
.replace(tags, function($0, $1){
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
// Replace all html entities with a single character (#) placeholder.
return input.replace(/&([a-z]+);/g, '#');
@@ -160,13 +161,13 @@
*/
ml.truncate_html = function(text, limit) {
// The html result after cut.
var result_html = '';
let result_html = '';
// The text result, that will be actually used when counting characters.
var result_text = '';
let result_text = '';
// A stack that will keep the tags that are open at a given time.
var tags_open = new Array();
let tags_open = [];
// List of self-closing tags
var self_closing_tags = [
let self_closing_tags = [
'area',
'base',
'br',
@@ -189,30 +190,30 @@
while (result_text.length < limit && text.length > 0) {
switch (text.charAt(0)) {
case '<': {
if (text.charAt(1) != '/') {
var tag_name = '';
var tag_name_completed = false;
while (text.charAt(0) != '>' && text.length > 0) {
var first_char = text.charAt(0).toString();
if (text.charAt(1) !== '/') {
let tag_name = '';
let tag_name_completed = false;
while (text.charAt(0) !== '>' && text.length > 0) {
let first_char = text.charAt(0).toString();
// Until the tag is closed, we do not append anything
// to the visible text, only to the html.
result_html += first_char;
// Also, check if we have a valid tag name.
if (!tag_name_completed && first_char == ' ') {
if (!tag_name_completed && first_char === ' ') {
// We have the tag name, so push it into the open tags stack.
tag_name_completed = true;
if (self_closing_tags.indexOf(tag_name) == -1) {
if (self_closing_tags.indexOf(tag_name) === -1) {
tags_open.push(tag_name);
}
}
// Check if we are still in the tag name.
if (!tag_name_completed && first_char != '<') {
if (!tag_name_completed && first_char !== '<') {
tag_name += first_char;
}
// Done with this char, remove it from the original text.
text = text.substring(1);
}
if (!tag_name_completed && self_closing_tags.indexOf(tag_name) == -1) {
if (!tag_name_completed && self_closing_tags.indexOf(tag_name) === -1) {
// In this case we have a tag like "<strong>some text</strong>" so
// we did not have any attributes in the tag, but still, the tag
// has to be marked as open. If tag is self-closing, we skip.
@@ -226,11 +227,11 @@
} else {
// In this case, we have an ending tag.
// The name of the ending tag should match the last open tag,
// otherwise, something is wrong with th html text.
var tag_name = '';
while (text.charAt(0) != '>' && text.length > 0) {
var first_char = text.charAt(0).toString();
if (first_char != '<' && first_char != '/') {
// otherwise, something is wrong with the html text.
let tag_name = '';
while (text.charAt(0) !== '>' && text.length > 0) {
let first_char = text.charAt(0).toString();
if (first_char !== '<' && first_char !== '/') {
tag_name += first_char;
}
result_html += first_char;
@@ -241,8 +242,8 @@
}
// Pop the last element from the tags stack and compare it with
// the tag name.
var expected_tag_name = tags_open.pop();
if (expected_tag_name != tag_name) {
let expected_tag_name = tags_open.pop();
if (expected_tag_name !== tag_name) {
// Should throw an exception, but for the moment just alert.
alert('Expected end tag: ' + expected_tag_name + '; Found end tag: '+tag_name);
}
@@ -263,7 +264,7 @@
default: {
// In this case, we have a character that should also count for the
// limit, so append it to both, the html and text result.
var first_char = text.charAt(0).toString();
let first_char = text.charAt(0).toString();
result_html += first_char;
result_text += first_char;
break;
@@ -274,7 +275,7 @@
}
// Restore the open tags that were not closed. This happens when the text
// got truncated in the middle of one or more html tags.
var tag = '';
let tag = '';
while (tag = tags_open.pop()) {
result_html += '</' + tag + ">";
}
@@ -288,8 +289,8 @@
* The array containing maxlength configurations.
*/
$.fn.charCount = function(options) {
// default configuration properties
var defaults = {
// Default configuration properties.
let defaults = {
warning: 10,
css: 'counter',
counterElement: 'div',
@@ -300,20 +301,20 @@
enforce: false,
};
var options = $.extend(defaults, options);
options = $.extend(defaults, options);
ml.options[$(this).attr('id')] = options;
if (options.action == 'detach') {
if (options.action === 'detach') {
$(once.remove('maxlength', $(this)));
$('#' + $(this).attr('id') + '-' + options.css).remove();
delete ml.options[$(this).attr('id')];
return 'removed';
}
var sanitizedId = ($(this).attr('id') + '-' + options.css).replace(/[^0-9a-z-_]/gi, '');
var counterElement = $('<' + options.counterElement + ' id="' + sanitizedId + '" class="' + options.css + '"></' + options.counterElement + '>');
let sanitizedId = ($(this).attr('id') + '-' + options.css).replace(/[^0-9a-z-_]/gi, '');
let counterElement = $('<' + options.counterElement + ' id="' + sanitizedId + '" class="' + options.css + '"></' + options.counterElement + '>');
// Use there is a description element use it to place the counterElement.
var describedBy = $(this).attr('aria-describedby');
let describedBy = $(this).attr('aria-describedby');
if (describedBy && $('#' + describedBy).length) {
$('#' + describedBy).after(counterElement);
}
@@ -337,71 +338,6 @@
};
ml.ckeditorOnce = false;
/**
* Integrate with CKEditor4.
* Detect changes on editors and invoke ml.calculate()
*/
ml.ckeditor = function() {
// Since Drupal.attachBehaviors() can be called more than once, and
// ml.ckeditor() is being called in maxlength behavior, only run this once.
if (!ml.ckeditorOnce) {
ml.ckeditorOnce = true;
CKEDITOR.on('instanceReady', function(e) {
var editor = $('#' + e.editor.name + '.maxlength');
if (editor.length == 1) {
if (editor.hasClass('maxlength_js_enforce')) {
ml.options[e.editor.element.getId()].enforce = true;
} else {
ml.options[e.editor.element.getId()].enforce = false;
}
// Add the events on the editor.
e.editor.on('key', function(e) {
setTimeout(function(){ml.ckeditorChange(e)}, 100);
});
e.editor.on('paste', function(e) {
setTimeout(function(){ml.ckeditorChange(e)}, 500);
});
e.editor.on('elementsPathUpdate', function(e) {
setTimeout(function(){ml.ckeditorChange(e)}, 100);
});
}
});
}
}
// Invoke ml.calculate() for editor
ml.ckeditorChange = function(e) {
// Clone to avoid changing defaults
var options = $.extend({}, ml.options[e.editor.element.getId()]);
ml.calculate($('#' + e.editor.element.getId()), options, ml.strip_tags(ml.ckeditorGetData(e)).length, e, 'ckeditorGetData', 'ckeditorSetData');
};
// Gets the data from the ckeditor.
ml.ckeditorGetData = function(e) {
return e.editor.getData();
}
// Sets the data into a ckeditor.
ml.ckeditorSetData = function(e, data) {
// WYSIWYG can convert '\r\n' to '\n' and insert '\n' after some tags, this
// can result in circular changes as what is attempted to be inserted and
// what is actually inserted is different. We save the last inserted value
// on the editor to stop this issue.
if (e.editor.mlLastBeforeInsert !== e.editor.getData()) {
e.editor.mlLastBeforeInsert = e.editor.getData();
// Calling setData() will place the cursor at the beginning, so we need to
// implement a callback to place it at the end, which is where the text is
// being truncated.
e.editor.setData(data, {callback: function() {
e.editor.focus();
var range = e.editor.createRange();
range.moveToElementEditablePosition(e.editor.editable(), true);
e.editor.getSelection().selectRanges([range]);
}});
}
}
/**
* Function that integrates maxlength behaviour with CKEditor 5.
*
@@ -418,14 +354,14 @@
if (options['enforce']) {
let maxlength = $(editor.sourceElement).data('maxlength');
let data = editor.getData();
let trimmed = ml.truncate_html(data, maxlength);
const trimmed = ml.truncate_html(data, maxlength);
if (data.length !== trimmed.length) {
editor.setData(trimmed);
setTimeout(() => {
editor.model.change( writer => {
writer.setSelection( writer.createPositionAt( editor.model.document.getRoot(), 'end' ) );
}
)}, 1);
writer.setSelection( writer.createPositionAt( editor.model.document.getRoot(), 'end' ) );
}
)}, 1);
}
}
editor.updateSourceElement();
Loading