Adding a custom context menu item to elFinder - javascript

I'm using elfinder and I would like to add new functionality by adding a command to the context menu. I found a solution on the github issue tracker of the project but I can't get it to work. Here's what I do:
var elf;
jQuery().ready(function() {
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype._options.contextmenu.files.push('editimage');
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
console.log('hallo');
}
}
elf = jQuery('#elfinder').elfinder({
...
//elfinder initialization
The context menu item does not show up, no error message is to be found in the console. I also tried putting editimage under contextmenu->"files" in the init part in case that was overwritten by the initialization.

I found the solution: The examples don't show the fact that you need to have a function called this.getstate inside of the elFinder.prototype.commands.yourcommand function. It shall return 0 when the icon is enabled and -1 when it's disabled.
So the full code for adding your own menu item or context menu item looks like this:
var elf;
jQuery().ready(function() {
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
//do whatever
}
this.getstate = function() {
//return 0 to enable, -1 to disable icon access
return 0;
}
}
...
elf = jQuery('#elfinder').elfinder({
lang: 'de', // language (OPTIONAL)
url : '/ext/elfinder-2.0-rc1/php/connector.php', //connector URL
width:'100%',
uiOptions : {
// toolbar configuration
toolbar : [
...
['quicklook', 'editimage'],
/*['copy', 'cut', 'paste'],*/
...
]},
contextmenu : {
...
// current directory file menu
files : [
'getfile', '|','open', 'quicklook', 'editimage', ...
]
}
}).elfinder('instance');
});
Hope this helps someone with the same problem.

Thanks for the answer, great!
One thing that wasn't clear was how the variables pass through.
So, for anyone else who finds this page....
elFinder.prototype.commands.editpres = function() {
this.exec = function(hashes) {
var file = this.files(hashes);
var hash = file[0].hash;
var fm = this.fm;
var url = fm.url(hash);
var scope = angular.element("body").scope();
scope.openEditorEdit(url);
}
// Getstate configured to only light up button if a file is selected.
this.getstate = function() {
var sel = this.files(sel),
cnt = sel.length;
return !this._disabled && cnt ? 0 : -1;
}
}
To get your icon to show up, add the following to your css file:
.elfinder-button-icon-editpres { background:url('../img/icons/editpres.png') no-repeat; }

Related

In CKEditor, how to set link open in a new window as default while removing the target tab?

I want links to open on a new window as default. I tried:
CKEDITOR.on('dialogDefinition', function ( ev ){
if(ev.data.name == 'link'){
ev.data.definition.getContents('target').get('linkTargetType')['default']='_blank';
}
});
It doesn't work. But I figured out that if I remove the following line. It works.
config.removeDialogTabs = 'image:advanced;image:Link;link:advanced;link:target';
But then the problem is now there is the target tab that allow user to change the link target.
What I want to keep the editor as simple as possible and don't want to allow users to change the link target. Yet, I want to set default target as target:_blank. Any suggestions? Thanks!
It seems that if you remove the Target tab, you cannot change the default value to "new window".
However, you can remove all the options in the Target list except "new window", and set it as the default value.
Try the following code:
CKEDITOR.on('dialogDefinition', function(e) {
if (e.data.name === 'link') {
var target = e.data.definition.getContents('target');
var options = target.get('linkTargetType').items;
for (var i = options.length-1; i >= 0; i--) {
var label = options[i][0];
if (!label.match(/new window/i)) {
options.splice(i, 1);
}
}
var targetField = target.get( 'linkTargetType' );
targetField['default'] = '_blank';
}
});
In this case, the Target tab still exists, but there's only one value ("new window") to select, so the users can't change this.
Hope this helps.
Another way to do it to provide the necessary data in onOk function,
see this particular commit
You add target attribute to data object in the onOk function in plugins/link/dialogs/link.js
onOk: function() {
var data = {};
// Collect data from fields.
this.commitContent( data );
// Overwrite, always set target="_blank"
data.target = {
dependent: "",
fullscreen: "",
height: "",
left: "",
location: "",
menubar: "",
name: "_blank",
resizable: "",
scrollbars: "",
status: "",
toolbar: "",
top: "",
type: "_blank",
width: ""
};
//more code below
}
Here is how I updated my links so they open in new tab, without affecting any other links on the page but only those from ckEditor. This is in Angular, but you can use the same idea depending on your platform.
I created a Pipe to transform the link to include a target:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'setlinktarget'
})
export class SetLinkTarget implements PipeTransform {
transform(value: any): any {
return value.split('<a ').join('<a target="_new"');
}
}
I then applied the pipe to my content:
<div [innerHTML]="myRecord.commentsWithHTML | setlinktarget">
This seems much easier than all the other options out there where you have to modify the ckeditor files. Hope this helps someone.
CKEDITOR.on('dialogDefinition', function (ev) {
var dialogName = ev.data.name;
var dialog = ev.data.definition.dialog;
var dialogDefinition = ev.data.definition;
if(dialogName == 'link') {
dialogDefinition.onLoad = function () {
if(dialogName == 'link'){
dialogDefinition.getContents('target').get('linkTargetType')['default']='_blank';
}
dialog.hidePage( 'target' );
};
}
});
//And configure the below
config.removeDialogTabs = 'image:advanced;link:advanced;link:upload;';
Go to ckeditor/plugins/link/dialogs/link.js
and paste the below code:
/* Here we are latching on an event ... in this case, the dialog open event */
CKEDITOR.on('dialogDefinition', function(ev) {
try {
/* this just gets the name of the dialog */
var dialogName = ev.data.name;
/* this just gets the contents of the opened dialog */
var dialogDefinition = ev.data.definition;
/* Make sure that the dialog opened is the link plugin ... otherwise do nothing */
if(dialogName == 'link') {`enter code here`
/* Getting the contents of the Target tab */
var informationTab = dialogDefinition.getContents('target');
/* Getting the contents of the dropdown field "Target" so we can set it */
var targetField = informationTab.get('linkTargetType');
/* Now that we have the field, we just set the default to _blank
A good modification would be to check the value of the
URL field and if the field does not start with "mailto:" or a
relative path, then set the value to "_blank" */
targetField['default'] = '_blank';
}
} catch(exception) {
alert('Error ' + ev.message);
}
});

How to detect multiple selections in elFinder

I added a new toolbar button and an new context menu item to elFinder.
Works nicely but this item should be enabled only if one plain file is selected. So should be dimmed when no file selected and should be dimmed when multiple files are selected or if is selected an directory.
I learned than in the elFinder.prototype.commands.mycmd I should set the this.getstate return value to:
0 if the toolbar/context-menu item should be enabled and
-1 if it should be disabled
So, now have this:
el
Finder.prototype.commands.mycmd= function() {
var self = this,
fm = self.fm;
self.disableOnSearch = true;
self.title = 'mycmd';
self.getstate = function() {
// need help here to add the "directory is selected check"
return fm.selected().length == 1 ? 0 : -1;
}
self.exec = function() {
alert("hello");
}
}
Unfortunately, i know only Perl, so it is a bit hard for me digging thru all elFinder's javascript code to figure out how to master the condition.
Know anybody elFinder enough deeply to help me with the condition?
Just find the solution in the elFinder's download.js.
This works - at least for now.. ;)
elFinder.prototype.commands.mycmd= function() {
var self = this,
fm = self.fm;
self.disableOnSearch = true;
filter = function(hashes) {
return $.map(self.files(hashes), function(f) { return f.mime == 'directory' ? null : f });
};
self.title = 'mycmd';
self.getstate = function() {
var sel = self.fm.selected(),
cnt = sel.length;
return !self._disabled && cnt == 1 && cnt == filter(sel).length ? 0 : -1;
}
self.exec = function() {
alert("hello");
}
}

Changing erik vold toolbarbutton image on the fly

I'm trying to make a firefox extension with the SDK. (if I can avoid XUL i'm happy)
I'm using erik vold toolbarbutton
But I need to change the toolbar image on the fly.
My lib/main.js (background page) is :
var tbb = require("toolbarbutton").ToolbarButton({
id: "My-button",
label: "My menu",
image: Data.url('off.png'),
onCommand: function(){
Tabs.open(Data.url("signin.html"));
}
});
tbb.setIcon({image:Data.url('on.png')});
console.log(tbb.image);
tbb.moveTo({
toolbarID: "nav-bar",
forceMove: false // only move once
});
tbb.image is correct, but the button isn't refreshed.
I tried to change packages/toolbarbutton-jplib/lib/toolbarbutton.js
function setIcon(aOptions) {
options.image = aOptions.image || aOptions.url;
getToolbarButtons(function(tbb) {
tbb.image = options.image;
tbb.setAttribute("image", options.image); // added line
}, options.id);
return options.image;
}
But it doesn't seem to refresh...
Is erik vold lib enough for this kind of need ?
also be sure to update with this fix https://github.com/voldsoftware/toolbarbutton-jplib/pull/13/files
there is a setIcon method and a image setter that you can use to update the toolbar button's image
I had the same problem so I just wrote the code my self using this tutorial:
http://kendsnyder.com/posts/firefox-extensions-add-button-to-nav-bar
Try this, I rewrote my code to fit your needs:
var btn = null;
var btnId = 'My-button';
var btnLabel = 'My menu';
var btnIconOn = 'on.png';
var btnIconOff = 'off.png';
var {Cc, Ci} = require('chrome');
var self = require("sdk/self");
var mediator = Cc['#mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
// exports.main is called when extension is installed or re-enabled
exports.main = function(options, callbacks) {
btn = addToolbarButton();
// do other stuff
};
// exports.onUnload is called when Firefox starts and when the extension is disabled or uninstalled
exports.onUnload = function(reason) {
removeToolbarButton();
// do other stuff
};
// add our button
function addToolbarButton() {
// this document is an XUL document
var document = mediator.getMostRecentWindow('navigator:browser').document;
var navBar = document.getElementById('nav-bar');
if (!navBar) {
return;
}
var btn = document.createElement('toolbarbutton');
btn.setAttribute('id', btnId);
btn.setAttribute('type', 'button');
// the toolbarbutton-1 class makes it look like a traditional button
btn.setAttribute('class', 'toolbarbutton-1');
// the data.url is relative to the data folder
btn.setAttribute('image', self.data.url(btnIconOff));
btn.setAttribute('orient', 'horizontal');
// this text will be shown when the toolbar is set to text or text and iconss
btn.setAttribute('label', btnLabel);
navBar.appendChild(btn);
return btn;
}
function removeToolbarButton() {
// this document is an XUL document
var document = mediator.getMostRecentWindow('navigator:browser').document;
var navBar = document.getElementById('nav-bar');
var btn = document.getElementById(btnId);
if (navBar && btn) {
navBar.removeChild(btn);
}
}
btn.addEventListener('click', function() {
Tabs.open(Data.url("signin.html"));
}, false);
tbb.setIcon({image:self.data.url(btnIconOn)});

Titanium TabGroup

I am having trouble with tabGroups. I have created a new app (this is my first app) and when I click an option in the table I am calling:
win.open(win,{annimated:true});
The problem is there is no tab at the top of the page to get back to where I was. So I need to use tabgroups. My question is I am not sure how to use them. When I replace the above with:
Ti.UI.currentTab.open(win);
I get an error that currentTab is not defined. How do I enable tabGroups? I have another file called AppTabGroup.js that has the: var self = Ti.UI.createTabGroup(); in it but I am not sure how to use it.
Below is the entire page incase I am doing something way off base.
function AppWindow(title) {
var self = Ti.UI.createWindow({
title:title,
backgroundColor:'white'
});
var data = [
{ title:"Catalog", hasChild:true, test:'ui/CatalogWindow.js', header:'' },
{ title:"Service Calculator", hasChild:true, header:'' }
];
var tableview = Titanium.UI.createTableView({
data:data,
style:Titanium.UI.iPhone.TableViewStyle.GROUPED
});
tableview.addEventListener('click', function(e)
{
if (e.rowData.test)
{
var win =
Titanium.UI.createWindow({
url:e.rowData.test,
title:e.rowData.title
});
win.open(win,{annimated:true});
}
});
self.add(tableview);
return self;
};
module.exports = AppWindow;
You are not alone. Other people (myself included) have been confused by Ti.UI.currentTab being undefined:
http://developer.appcelerator.com/question/98501/titaniumuicurrenttab-is-null
The way I've worked around this in the past is to pass down the containing tab to the window, so that it can use that reference to open another window. So in your example, AppTabGroup.js would look like:
var AppWindow = require('src/AppWindow');
var self = Ti.UI.createTabGroup();
//create app tabs
var appTab = Ti.UI.createTab({
title : L('app'),
icon : '/images/app_tab.png',
window : AppWindow
});
AppWindow.setContainingTab(appTab);
Then in AppWindow.js:
exports.setContainingTab = function(tab) {
containingTab = tab;
}
var win = Titanium.UI.createWindow({
url:e.rowData.test,
title:e.rowData.title
});
containingTab.open(win);

Is it possible to reinitialize a CKEditor Combobox/Drop Down Menu?

How do I dynamically update the items in a drop down?
I have a custom plugin for CKEditor that populates a drop down menu with a list of items which I can inject into my textarea.
This list of items comes from a Javascript array called maptags, which is updated dynamically for each page.
var maptags = []
This list of tags gets added to the drop down when you first click on it by the init: function. My problem is what if the items in that array change as the client changes things on the page, how can I reload that list to the updated array?
Here is my CKEditor Plugin code:
CKEDITOR.plugins.add('mapitems', {
requires: ['richcombo'], //, 'styles' ],
init: function (editor) {
var config = editor.config,
lang = editor.lang.format;
editor.ui.addRichCombo('mapitems',
{
label: "Map Items",
title: "Map Items",
voiceLabel: "Map Items",
className: 'cke_format',
multiSelect: false,
panel:
{
css: [config.contentsCss, CKEDITOR.getUrl(editor.skinPath + 'editor.css')],
voiceLabel: lang.panelVoiceLabel
},
init: function () {
this.startGroup("Map Items");
//this.add('value', 'drop_text', 'drop_label');
for (var this_tag in maptags) {
this.add(maptags[this_tag][0], maptags[this_tag][1], maptags[this_tag][2]);
}
},
onClick: function (value) {
editor.focus();
editor.fire('saveSnapshot');
editor.insertHtml(value);
editor.fire('saveSnapshot');
}
});
}
});
I think I just solved this actually.
Change your init like this:
init: function () {
var rebuildList = CKEDITOR.tools.bind(buildList, this);
rebuildList();
$(editor).bind('rebuildList', rebuildList);
},
And define the buildList function outside that scope.
var buildListHasRunOnce = 0;
var buildList = function () {
if (buildListHasRunOnce) {
// Remove the old unordered list from the dom.
// This is just to cleanup the old list within the iframe
$(this._.panel._.iframe.$).contents().find("ul").remove();
// reset list
this._.items = {};
this._.list._.items = {};
}
for (var i in yourListOfItems) {
var item = yourListOfItems[i];
// do your add calls
this.add(item.id, 'something here as html', item.text);
}
if (buildListHasRunOnce) {
// Force CKEditor to commit the html it generates through this.add
this._.committed = 0; // We have to set to false in order to trigger a complete commit()
this.commit();
}
buildListHasRunOnce = 1;
};
The clever thing about the CKEDITOR.tools.bind function is that we supply "this" when we bind it, so whenever the rebuildList is triggered, this refer to the richcombo object itself which I was not able to get any other way.
Hope this helps, it works fine for me!
ElChe
I could not find any helpful documenatation around richcombo, i took a look to the source code and got an idea of the events i needed.
#El Che solution helped me to get through this issue but i had another approach to the problem because i had a more complex combobox structure (search,groups)
var _this = this;
populateCombo.call(_this, data);
function populateCombo(data) {
/* I have a search workaround added here */
this.startGroup('Default'); /* create default group */
/* add items with your logic */
for (var i = 0; i < data.length; i++) {
var dataitem = data[i];
this.add(dataitem.name, dataitem.description, dataitem.name);
}
/* other groups .... */
}
var buildListHasRunOnce = 0;
/* triggered when combo is shown */
editor.on("panelShow", function(){
if (buildListHasRunOnce) {
// reset list
populateCombo.call(_this, data);
}
buildListHasRunOnce = 1;
});
/* triggered when combo is hidden */
editor.on("panelHide", function(){
$(_this._.list.element.$).empty();
_this._.items = {};
_this._.list._.items = {};
});
NOTE
All above code is inside addRichCombo init callback
I remove combobox content on "panelHide" event
I repopulate combobox on "panelShow" event
Hope this helps

Categories

Resources