Implement autocomplete link and mediatag

This commit is contained in:
Ludovic Dubost 2019-05-19 17:12:14 +02:00
parent 135182ea0a
commit 278b51e17e
8 changed files with 123 additions and 13 deletions

View File

@ -21,7 +21,7 @@
"jquery": "~2.1.3", "jquery": "~2.1.3",
"tweetnacl": "0.12.2", "tweetnacl": "0.12.2",
"components-font-awesome": "^4.6.3", "components-font-awesome": "^4.6.3",
"ckeditor": "4.7.3", "ckeditor": "4.10.1",
"codemirror": "^5.19.0", "codemirror": "^5.19.0",
"requirejs": "2.3.5", "requirejs": "2.3.5",
"marked": "0.5.0", "marked": "0.5.0",

View File

@ -10,7 +10,7 @@ CKEDITOR.editorConfig = function( config ) {
// document itself and causes problems when it's sent across the wire and reflected back // document itself and causes problems when it's sent across the wire and reflected back
config.removePlugins= 'resize,elementspath'; config.removePlugins= 'resize,elementspath';
config.resize_enabled= false; //bottom-bar config.resize_enabled= false; //bottom-bar
config.extraPlugins= 'autolink,colorbutton,colordialog,font,indentblock,justify,mediatag,print,blockbase64,mathjax'; config.extraPlugins= 'autolink,colorbutton,colordialog,font,indentblock,justify,mediatag,print,blockbase64,mathjax,autocomplete,textmatch,cryptpadautocomplete';
config.toolbarGroups= [ config.toolbarGroups= [
// {"name":"clipboard","groups":["clipboard","undo"]}, // {"name":"clipboard","groups":["clipboard","undo"]},
//{"name":"editing","groups":["find","selection"]}, //{"name":"editing","groups":["find","selection"]},

View File

@ -451,6 +451,12 @@ define([
if (!common.isLoggedIn()) { return; } if (!common.isLoggedIn()) { return; }
common.initFilePicker({ common.initFilePicker({
onSelect: function (data) { onSelect: function (data) {
// Supporting inserting links to documents and not only mediatags
if (data.filters.link === true) {
mediaTagEmbedder(null, data);
return;
}
if (data.type !== 'file') { if (data.type !== 'file') {
console.log("Unexpected data type picked " + data.type); console.log("Unexpected data type picked " + data.type);
return; return;

View File

@ -8,6 +8,7 @@
var afterLoaded = function (req) { var afterLoaded = function (req) {
req.cfg = req.cfg || {}; req.cfg = req.cfg || {};
if (req.pfx) { if (req.pfx) {
reg.cfg.pfx = pfx;
req.cfg.onNodeCreated = function (node /*, config, module, path*/) { req.cfg.onNodeCreated = function (node /*, config, module, path*/) {
node.setAttribute('src', req.pfx + node.getAttribute('src')); node.setAttribute('src', req.pfx + node.getAttribute('src'));
}; };

View File

@ -700,7 +700,8 @@ define([
SFrameChannel: SFrameChannel, SFrameChannel: SFrameChannel,
Utils: Utils Utils: Utils
}; };
FP.$iframe = $('<iframe>', {id: 'sbox-filePicker-iframe'}).appendTo($('body')); // var iframeClasses = (typeof cfg === undefined && cfg.classes) ? cfg.classes : "";
FP.$iframe = $('<iframe>', {id: 'sbox-filePicker-iframe' /* , class: iframeClasses */ }).appendTo($('body'));
FP.picker = FilePicker.create(config); FP.picker = FilePicker.create(config);
} else if (!cfg.hidden) { } else if (!cfg.hidden) {
FP.$iframe.show(); FP.$iframe.show();

View File

@ -32,7 +32,7 @@ define([
var $body = $('body'); var $body = $('body');
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
var filters = metadataMgr.getPrivateData().types; var filters = metadataMgr.getPrivateData().types;
var origin = metadataMgr.getPrivateData().origin;
var hideFileDialog = function () { var hideFileDialog = function () {
sframeChan.event('EV_FILE_PICKER_CLOSE'); sframeChan.event('EV_FILE_PICKER_CLOSE');
}; };
@ -45,16 +45,21 @@ define([
var key = Hash.encodeBase64(secret.keys.cryptKey); var key = Hash.encodeBase64(secret.keys.cryptKey);
sframeChan.event("EV_FILE_PICKED", { sframeChan.event("EV_FILE_PICKED", {
type: parsed.type, type: parsed.type,
src: src, href: data.url,
origin: origin,
name: data.name, name: data.name,
key: key src: src,
key: key,
filters : filters
}); });
return; return;
} }
sframeChan.event("EV_FILE_PICKED", { sframeChan.event("EV_FILE_PICKED", {
type: parsed.type, type: parsed.type,
href: data.url, href: data.url,
name: data.name origin: origin,
name: data.name,
filters : filters
}); });
}; };
@ -146,6 +151,12 @@ define([
$input.focus(); $input.focus();
}; };
common.getFilesList(filters, todo); common.getFilesList(filters, todo);
if (filters.caretRect) {
$(".cp-modal")[0].style.top = (filters.caretRect.top) + "px";
$(".cp-modal")[0].style.left = (filters.caretRect.left) + "px";
$(".cp-modal")[0].style.width = "500px";
$(".cp-modal")[0].style.height = "400px";
}
}; };
updateContainer(); updateContainer();
}; };

View File

@ -0,0 +1,74 @@
( function() {
// For simplicity we define the plugin in the sample, but normally
// it would be extracted to a separate file.
CKEDITOR.plugins.add( 'cryptpadautocomplete', {
requires: 'autocomplete,textmatch',
init: function(editor) {
editor.on( 'instanceReady', function() {
var config = {};
var view = new CKEDITOR.plugins.autocomplete.view(editor);
var autocomplete;
var caretRect;
var selectionRange;
// Called when the user types in the editor or moves the caret.
// The range represents the caret position.
function textTestCallback( range ) {
// You do not want to autocomplete a non-empty selection.
if ( !range.collapsed ) {
return null;
}
CKEDITOR.plugins.autocomplete.selectionRange = range;
caretRect = view.getViewPosition( range );
// Use the text match plugin which does the tricky job of performing
// a text search in the DOM. The "matchCallback" function should return
// a matching fragment of the text.
return CKEDITOR.plugins.textMatch.match( range, matchCallback );
return result;
}
// Returns the position of the matching text.
// It matches a word starting from the '#' character
// up to the caret position.
function matchCallback( text, offset ) {
// Get the text before the caret.
var left = text.slice( 0, offset ),
// Will look for a '#' character followed by a ticket number.
matchAt = left.match( /@\d*$/ );
matchSlash = left.match( /\/\d*$/ );
if ( !matchAt && !matchSlash ) {
return null;
}
// we match, but we can't use the remaining of autocomplete
var pickerCfg = {
types: (matchSlash) ? ['file'] : [],
where: ['root'],
classes: 'sbox-filePicker-iframe-inplace',
caretRect : caretRect,
inplace : true,
link : (matchSlash) ? false : true
};
window.APP.framework._.sfCommon.openFilePicker(pickerCfg);
return null;
}
config.textTestCallback = textTestCallback;
// Returns (through its callback) the suggestions for the current query.
function dataCallback( matchInfo, callback ) {
}
config.dataCallback = dataCallback;
// Define the templates of the autocomplete suggestions dropdown and output text.
config.itemTemplate = '<li data-id="{id}" class="issue-{type}">#{id}: {name}</li>';
config.outputTemplate = '<a href="https://github.com/ckeditor/ckeditor-dev/issues/{id}">{name} (#{id})</a> ';
// Attach autocomplete to the editor.
autocomplete = new CKEDITOR.plugins.autocomplete( editor, config );
});
}
});
})();

View File

@ -552,13 +552,29 @@ define([
$inner.css({ background: unlocked ? '#fff' : '#eee' }); $inner.css({ background: unlocked ? '#fff' : '#eee' });
}); });
framework.setMediaTagEmbedder(function ($mt) { framework.setMediaTagEmbedder(function ($mt, data) {
//MEDIATAG
if (data.filters.inplace===true) {
console.log("Inplace inserting: " + JSON.stringify(data));
var selection = editor.getSelection();
var range = CKEDITOR.plugins.autocomplete.selectionRange;
var crange = editor.createRange();
crange.selectNodeContents(range.startContainer)
crange.startOffset = range.startOffset - 1;
crange.endOffset = range.endOffset;
editor.getSelection().selectRanges( [crange] );
}
if (data.filters.link===true) {
var href = data.origin + data.href;
editor.insertHtml("<a href='" + href + "'>" + data.name + "</a>", 'text' );
} else {
$mt.attr('contenteditable', 'false'); $mt.attr('contenteditable', 'false');
//$mt.attr('tabindex', '1'); //$mt.attr('tabindex', '1');
//MEDIATAG
var element = new window.CKEDITOR.dom.element($mt[0]); var element = new window.CKEDITOR.dom.element($mt[0]);
editor.insertElement(element); editor.insertElement(element);
editor.widgets.initOn( element, 'mediatag' ); editor.widgets.initOn( element, 'mediatag' );
}
}); });
framework.setTitleRecommender(function () { framework.setTitleRecommender(function () {
@ -944,6 +960,7 @@ define([
'import': Messages.pad_mediatagImport, 'import': Messages.pad_mediatagImport,
options: Messages.pad_mediatagOptions options: Messages.pad_mediatagOptions
}; };
Ckeditor.plugins.addExternal('cryptpadautocomplete','/pad/', 'autocomplete-page-plugin.js');
Ckeditor.plugins.addExternal('mediatag','/pad/', 'mediatag-plugin.js'); Ckeditor.plugins.addExternal('mediatag','/pad/', 'mediatag-plugin.js');
Ckeditor.plugins.addExternal('blockbase64','/pad/', 'disable-base64.js'); Ckeditor.plugins.addExternal('blockbase64','/pad/', 'disable-base64.js');
module.ckeditor = editor = Ckeditor.replace('editor1', { module.ckeditor = editor = Ckeditor.replace('editor1', {