diff --git a/includes/ckeditor_mentions.ajax.inc b/includes/ckeditor_mentions.ajax.inc index 5627d6d..33f4681 100644 --- a/includes/ckeditor_mentions.ajax.inc +++ b/includes/ckeditor_mentions.ajax.inc @@ -22,7 +22,7 @@ function ckeditor_mentions_getpeople() { $count = count($view->result); if ($count > 0) { $html = $view->render(); - drupal_json_output(array('html' => $html)); + return $html; } } } diff --git a/plugins/mentions/plugin.js b/plugins/mentions/plugin.js index 34ec54d..04843ae 100644 --- a/plugins/mentions/plugin.js +++ b/plugins/mentions/plugin.js @@ -1,4 +1,4 @@ -´╗┐ /** + /** * @file * Written by Albert Skibinski * http://www.merge.nl @@ -16,11 +16,12 @@ * @returns {null} */ function CKEDITOR_mentions (editor) { - this.editor = editor; - this.observe = 0; - this.char_input = []; + this.editor = editor; + this.observe = 0; + this.char_input = []; + this.timeout_id = null; - if ( CKEDITOR_mentions.caller != CKEDITOR_mentions.get_instance ) { + if ( CKEDITOR_mentions.caller !== CKEDITOR_mentions.get_instance ) { throw new Error("This object cannot be instanciated"); } } @@ -33,6 +34,20 @@ function CKEDITOR_mentions (editor) { CKEDITOR_mentions.instances = []; /* + * Delay of the timeout between the last key pressed and the ajax query. It's use to prevent ajax flooding when user types fast. + * + * @type Number + */ +CKEDITOR_mentions.timeout_delay = 500; + +/* + * Minimum number of characters needed to start searching for users (includes the @). + * + * @type Number + */ +CKEDITOR_mentions.start_observe_count = 3; + +/* * Method used to get an instance of CKEDITOR_mentions linked to an instance of CKEDITOR. * Its design is based on the singleton design pattern. * @@ -43,7 +58,7 @@ CKEDITOR_mentions.get_instance = function (editor) { // we browse our collection of instances for (var i in this.instances) { // if we find an CKEDITOR instance in our collection - if (this.instances[i].id == editor.id) { + if (this.instances[i].id === editor.id) { // we return the instance of CKEDITOR_mentions that match return this.instances[i].instance; } @@ -82,45 +97,58 @@ CKEDITOR_mentions.prototype.start_observing = function () { * @returns {null} */ CKEDITOR_mentions.prototype.stop_observing = function () { - this.observe = 0; - this.char_input = []; + this.observe = 0; + this.char_input = []; this.delete_tooltip(); }; /* * This methods send an ajax query to durpal ckeditor_mentions module and retrieve matching user. * + * @param {Object} selection result of CKEDITOR.editor.getSelection() * @returns {null} */ CKEDITOR_mentions.prototype.get_people = function (selection) { - //if less than 3 char are input (including @) we don't try to get people - - var str = this.char_input.join(''); + if (null !== this.timeout_id) { + clearTimeout(this.timeout_id); + } + this.timeout_id = setTimeout(this.timeout_callback, CKEDITOR_mentions.timeout_delay, [this, selection]); +}; - if (str.length < 3) { - this.delete_tooltip(); +/* + * This methods send an ajax query to durpal ckeditor_mentions module and retrieve matching user. + * + * @param {Array} args An Array of parameters containing the current instance of CKEDITOR_mentions and selection (cf. CKEDITOR_mentions.prototype.get_people) + * @returns {null} + */ +CKEDITOR_mentions.prototype.timeout_callback = function (args) { + var mentions = args[0]; + var selection = args[1]; + var str = mentions.char_input.join(''); + //if less than 3 char are input (including @) we don't try to get people + if (str.length < CKEDITOR_mentions.start_observe_count) { + mentions.delete_tooltip(); return; } var $ = jQuery; - var editor = this.editor, - element_id = editor.element.getId(); - - var range = selection.getRanges()[0], - startOffset = range.startOffset - str.length + 1, - element = range.startContainer.$; + var editor = mentions.editor; + var element_id = editor.element.getId(); + var range = selection.getRanges()[0]; + var startOffset = range.startOffset - str.length + 1; + var element = range.startContainer.$; - $.get(Drupal.settings.basePath + 'ckeditor/mentions', {typed: str}, function(rsp) { + /*$.get(Drupal.settings.basePath + 'ckeditor/mentions', {typed: str}, function(rsp) { - var ckel = $('#' + element_id); - var par = ckel.parent(); + var ckel = $('#' + element_id); + var par = ckel.parent(); $('.mention-suggestions').remove(); if (rsp) { - $('
' + rsp.html + '
').insertAfter(par); - } + $('
' + rsp.html + '
').insertAfter(par); + } $('.mention-users').click(function(e) { e.preventDefault(); @@ -146,12 +174,68 @@ CKEDITOR_mentions.prototype.get_people = function (selection) { editor.focus(); - var range = editor.createRange(), - el = new CKEDITOR.dom.element(link.parentNode); + var range = editor.createRange(); + var el = new CKEDITOR.dom.element(link.parentNode); range.moveToElementEditablePosition(el, link.parentNode.textContent.length); range.select(); }); + });*/ + + $.ajax({ + url: Drupal.settings.basePath + 'ckeditor/mentions', + data: {typed: str}, + success: function(data, textStatus, jqXHR) { + var ckel = $('#' + element_id); + var par = ckel.parent(); + + $('.mention-suggestions').remove(); + + var html; + for (var i in data) { + if (data[i].command === 'insert' && data[i].method === null) { + html = data[i].data; + } + } + + if (html) { + $('
' + html + '
').insertAfter(par); + } + $('.mention-users').click(function(e) { + e.preventDefault(); + + var mentions = CKEDITOR_mentions.get_instance(editor); + mentions.stop_observing(); + + // Shorten text node + element.textContent = element.textContent.substr(0, startOffset); + + // Create link + var link = document.createElement('a'); + link.href = Drupal.settings.basePath + 'user/' + $(this).data('uid'); + link.textContent = '@' + $(this).data('realname'); + + // Insert link after text node + if ( element.nextSibling ) { + element.parentNode.insertBefore(link, element.nextSibling); + } + else { + element.parentNode.appendChild(link); + } + + editor.focus(); + + var range = editor.createRange(); + var el = new CKEDITOR.dom.element(link.parentNode); + range.moveToElementEditablePosition(el, link.parentNode.textContent.length); + range.select(); + }); + }, + dataType: 'json', + error: function () { + console.log(arguments); + throw 'Request to /ckeditor/mentions failed.'; + } }); }; @@ -210,7 +294,6 @@ CKEDITOR_mentions.prototype.break_on = function (charcode) { if (mentions.break_on(evt.data.$.which)) { mentions.stop_observing(); } - }); editable.attachListener(editable, 'keypress', function(evt) { @@ -230,13 +313,14 @@ CKEDITOR_mentions.prototype.break_on = function (charcode) { * OR detect another @ while we are already observing * OR the length is longer than 11 */ - if ((mentions.char_input.length > 0 && typed_char === '@') || mentions.char_input.length > 11) { + if ((mentions.char_input.length > 0 && typed_char === '@') || mentions.char_input.length > 11) { mentions.stop_observing(); - } else { - mentions.char_input.push(typed_char); - var selection = this.editor.getSelection(); - mentions.get_people(selection); - } + } + else { + mentions.char_input.push(typed_char); + var selection = this.editor.getSelection(); + mentions.get_people(selection); + } } }); }); // end editor.on