mirror of https://github.com/xwiki-labs/cryptpad
Implement autocomplete link and mediatag
This commit is contained in:
parent
135182ea0a
commit
278b51e17e
|
@ -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",
|
||||||
|
|
|
@ -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"]},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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'));
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
|
@ -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', {
|
||||||
|
|
Loading…
Reference in New Issue