Custom the right click menu of elfinder (a jquery file manager plugin) - javascript

I am working on a customized share button with the elfinder, there is tutorial about how to custom the right click menu, and I have implemented it. However, there are some rules I would like to apply for the menu
1) For folder only, exclude the button for file
2) For root level only, exclude the button for sub level folder
3) For single folder only, if select more than one folder will exclude the button
Here is the current code, right now have the share button but not with the above rules:
elFinder.prototype.i18.zh_TW.messages['cmdsharefolder'] = 'Share';
elFinder.prototype._options.commands.push('sharefolder');
elFinder.prototype.commands.sharefolder = function () {
this.exec = function (hashes) {
//open share menu
}
this.getstate = function () {
return 0;
}
}
And the elfinder instance:
var elfinder = $('#elfinder').elfinder({
url: '<?= $connector; ?>',
soundPath: '<?= site_url('assets/plugins/elFinder/sounds/rm.wav'); ?>',
height: 700,
lang: 'zh_TW',
uiOptions: {
// toolbar configuration
toolbar: [
['back', 'forward'],
['reload'],
['mkdir', 'upload'],
['copy', 'cut', 'paste', 'rm'],
['rename'],
['view', 'sort']
]
},
contextmenu: {
navbar: ['open', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', '|', 'info'],
cwd: ['reload', 'back', '|', 'upload', 'mkdir', 'paste', '|', 'info'],
files: [
'open', 'quicklook', 'sharefolder', '|', 'download', '|', 'copy', 'cut', 'paste', 'rm', '|', 'rename', '|', 'info'
]
},
ui: ['toolbar', 'tree', 'stat']
}).elfinder('instance');
The problems are :
1) how to apply the rules above? (if the rules can not apply, can workaround with checking and popup alert box, please suggest the way for checking, thanks)
2) are there any way to capture which folder is selected e.g. full folder path etc...
Here is the doc I have studied , the sample case is for general use:
https://github.com/Studio-42/elFinder/wiki/Custom-context-menu-command
Thanks a lot for helping.

What you're trying to accomplish is possible, but it highly depends on how your connector works.
In order to work with your rules, you either have to add code in this.exec or this.getstate. There are pros and cons for each option.
If you add the code to this.getstate your code might be executed more than once for a single action (example: when you select multiple folders, the function is executed when you click on the first folder, on the last and when you right click).
However, using this.getstate you're able to hide the option (button) on any situation that doesn't meet the requirements (rules).
Adding code to this.exec assures the code is only executed once per action, but the button is always present even if the rules don't apply.
If you choose this, you'll need to work with some kind of alert or dialog messages to the user, to inform them why the share menu isn't displayed.
In the following code, I've used this.getstate, but you can move the code to this.exec. On the Javascript side you need to use something like this:
elFinder.prototype.i18.zh_TW.messages['cmdsharefolder'] = 'Share';
elFinder.prototype._options.commands.push('sharefolder');
elFinder.prototype.commands.sharefolder = function () {
var self = this,
fm = self.fm;
this.exec = function (hashes) {
// Display the share menu
};
this.getstate = function () {
var hashes = self.fm.selected(), result = 0;
// Verifies rule nr 3: For single folder only,
// if select more than one folder will exclude the button
if (hashes.length > 1) {
return -1;
}
// Rule 1 and 2 exclude itself. By this I mean that rule nr 2
// takes precedence over rule nr 1, so you just need to check
// if the selected hash is a root folder.
$.ajax({
url: 'file-manager/check-rule-on-hash',
data: hashes,
type: 'get',
async: false,
dataType: 'json',
success: function(response) {
if (!response.isRoot) {
result = -1;
}
}
});
return result;
}
}
Explanation:
Rule nr 3 is easy, because you have access to the number of selected items through Javascript. So you just need to count the number of selected hashes. If that number is greater than 1, that means the user selected more than one item and the menu shouldn't be displayed.
Rule nr 2 is a little trickier, because you need to "validate" the selected hash, and this is why I started to say that this depends on how your connector works.
For instance, I have a custom PHP connector, where the folder structure is defined through a database table. Although all files are physically stored on the hard drive, the meta data is stored on the same table (mostly because all permissions are defined via database). In my case it's somewhat easy to perform an ajax call and check if a given hash is a root folder, because that info is stored on the database and I can retrieve that info with a simple query.
Since I can't be sure on how your connector works, the generic solution is to perform an ajax call to the server, with the selected hash, and verify if that hash is a root folder. The server should return an object with the property isRoot that's either true or false.

Related

how to make the URL tag of a store dynamic rather than giving it a constant string in sencha touch

I am stuck with this problem for a while and not able to find a solution anywhere
Ext.define('RmitPorject.store.Alerts', {
extend: 'Ext.data.Store',
/* gCameraID: function(){
var d = this.data,
id =d.CameraID
return id.join(" ");
},*/
config: {
model: 'RmitPorject.model.Alert',
//sorters: 'CameraID',
autoLoad: true,
proxy: {
type: 'ajax',
// url: 'txt.json',
url: 'Camera/'+'100001'+'.json',
/*here, we have to make a dynamic loading url
* for example, we need to make a function handler
* It will handle the particular cameraid to request different folder camerid (url)
* *
* */
//url:'http://52.64.86.42/RmitPorject/txt.json',
reader: {
type: 'json',
rootProperty: 'data'
}
}
}
});
this is a store file
what i want is when the user touches one of the item from the list it will use this store file to load that particular list item's JSON file.
but i don't know how to transfer that list item's value to this store file so that it knows what JSON file to use
In other words , I want to make this URL tag dynamic depending on the user's response it should load data from a different JSON files , but unfortunately i dont know how to make this store dynamic.
on user's response you can change store's url and then load store using below code
Ext.getStore('Alerts').getProxy().setUrl('Camera/'+'100001'+'.json');// create dynamic url string and pass it in setUrl method
Ext.getStore('Alerts').load();
remove "autoLoad:true" because it trys to load store instantly , might it will give you error.

Extjs 4, How to send multiple metaData for multiple dynamic grids, using a single Json file

I need to create 8-10 grids on a single panel, using accordion Layout. All grids would be created dynamically using the metaData object in JSON and metachange listener event on my store and reconfigure my grid accordingly (Pretty standard process) . But is there a way to use a single JSON file containing metaData and Data of more than one grid. So that I can use multiple stores to read a single JSON.
Something Like this would be good:
"grid1" :
{
"metaData" : {---"root":"data1"-----------}
},
"grid2" :
{
"metaData" : {----"root":"data2"----------}
},
"data1" : {------------------},
"data2" : {-----------------}
I already tried using metaProperty tag in my store, but that approach doesn't seem to work for me(ExtJs 4.1.3) .
Store Proxy:
proxy: {
type: 'ajax',
url: 'MultiData.json',
reader: {
type: 'json'
// metaProperty : 'grid1', //Doesn't work, hence commented
}
Store Listener:
'metachange' :function (store, meta) {
Grid.reconfigure(store, meta.columns);
}
NOTE: The above code works perfectly when I have only one metaData and data tag in JSON
How about this :
Get all the data you need using a single Ext.Ajax Call
Split the data into parts as you need.
use store.loadData() to load directly to store. This should also trigger the metachange listener and configure the grid accordingly. If it doesn't you can use the configure() property of the grid : grid.reconfigure(store,columns)
http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.data.Store-method-loadData
http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.grid.Panel-method-reconfigure

I can't find an elegant way to add a Database Source to a dgrid

For now I have
require([
"dojo/on", "dgrid/OnDemandGrid","dgrid/Tree","dgrid/Editor", "dgrid/Keyboard", "dojo/_base/declare",
"dgrid/data/createHierarchicalStore", "data/projects_data",
"dojo/domReady!"
], function(
on, Grid, Tree, Editor, Keyboard, declare, createHierarchicalStore, hierarchicalCountryData
){
var count = 0; // for incrementing edits from button under 1st grid
function nbspFormatter(value){
// returns " " for blank content, to prevent cell collapsing
return value === undefined || value === "" ? " " : value;
}
var StandardGrid = declare([Grid, Keyboard, Editor, Tree]);
window.grid = new StandardGrid({
collection: createHierarchicalStore({ data: hierarchicalCountryData }, true),
columns: [
{renderExpando: true, label: "Name", field:"variant_name", sortable: false, editor: "text", editOn: "dblclick"},
{label: "Visited", field: "bool", sortable: false, editor: "checkbox"},
{label:"Project", field:"project", sortable: false, editor: "text", editOn: "dblclick"},
{label:"locked", field:"locked", editor: "text", editOn: "dblclick"},
{label:"modified", field:"modified", editor: "text", editOn: "dblclick"},
{label:"summary", field:"summary", editor: "text", editOn: "dblclick"}
]
}, "treeGrid2");
grid.on("dgrid-datachange", function(evt){
console.log("data changed: ", evt.oldValue, " -> ", evt.value);
console.log("cell: ", evt.cell.row.id, evt.cell.column.field);
});
grid.on("dgrid-editor-show", function(evt){
console.log("show editOn editor: ", evt);
});
grid.on("dgrid-editor-hide", function(evt){
console.log("hide editOn editor: ", evt);
});
});
data/projects is a js file containing the data. but how to connect this dGrid now to a MySQL database? Can't find any good information in the docs. I think might be something with JSON rest but not sure about this.
Addition:
I can show the db in an HTML Table. is there a suitable possibilty to populate dGrid from a HTML Table?
I am still missing something. Have connections from
Database -> PHP
but can't get result in a proper JS to load into dStore.
The simplest path forward is to write a service in your server-side language of choice (sounds like PHP in this case) that produces JSON output based on the data in your MySQL database. Depending on the potential size of your data, you can potentially design your data to work with one of two out-of-the-box stores in dstore: Request (and Rest if write operations are also involved), or RequestMemory.
The simpler of the two is RequestMemory, which simply combines the features of the Memory store with an up-front server request (via Request). This store will expect the service to respond with one complete data payload: an array of objects where each object is a record in your database. Something like this:
[
{
"id": 1,
"foo": "bar"
},
{
"id": 2,
"foo": "baz"
}
]
The Rest store expects data in the same format, but also expects the service to handle filtering, sorting, and ranges. Filtering and sorting are represented via query string parameters (e.g. foo=bar&baz=bim in the simplest case for filter, and sort(+foo) or sort(-foo) for sort), while ranges are typically represented via the HTTP Range header (e.g. Range: Items 0-9 for the first 10 items).
Implementing a service for the Rest store is obviously more work, but would be preferable if you're expecting your data source to potentially have thousands of items, since RequestMemory would have no choice but to request all of the items up-front.
With either of these stores, once you have a service that outputs JSON as appropriate, you can create an instance of the store with its target pointing to the service endpoint, then pass it to a grid via the collection property.
If your data is intended to represent a hierarchical structure, it should still be possible to mix dstore/Tree into dstore/RequestMemory or dstore/Request, provided that your hierarchy is represented via parent ID references. By default, Tree filters children via a parent property on each item, and reports mayHaveChildren results by inspecting a hasChildren property on each item.

Select2 - create ajax with pre-loaded options

I have a fairly simple requirement set, but cannot for the life of me figure out how to achieve it with Select2...
I would like to have an input on the page
Which the user can type into to trigger an AJAX call
Which also displays a pre-loaded list of options that the user can click on instead of typing to trigger the AJAX.
If you close (blur) the input and then reopen it again then the previously loaded AJAX responses should still be displayed (instead of the options being blank and you having to start typing to load them again).
I can do #1 and #2 (or #1 and #3 of course!), but I cannot get all three requirements in one input field. I've not found any way to do #4.
Effectively, to achieve #3, I guess I'm looking for a way to inject my shortlist into what are normally the ajax-returned options and use something like #4 to make sure these are not cleared when the field is opened.
Is there a way to initialise the (normally Ajax loaded) options for a Select2 field? I've tried passing in data but it doesn't work, I tried using initSelection until I realised that wasn't relevant, I've tried all sorts of things, but to no avail...
Hopefully this is possible and I've just missed an option somewhere!
P.S. I've read several threads on Stack with similar titles to this but none of them seem to answer this question. If I've missed the vital one just let me know!
I think you can do this if you use Select2's query option, rather than the ajax option. That way you can make the ajax request if any characters have been typed, but show the default list if no characters have been typed.
If your default options are defined like this:
var DEFAULT_OPTIONS = [
{ id: 'def1', text: 'Default Choice 1' },
{ id: 'def2', text: 'Default Choice 2' },
{ id: 'def3', text: 'Default Choice 3' }
];
You could do the following:
var lastOptions = DEFAULT_OPTIONS;
$('#select').select2({
minimumInputLength: 0,
query: function(options) {
if (options.term) {
$.ajax({
type: 'post', // Or 'get' if appropriate
url: 'your_ajax_url',
dataType: 'json',
data: {
term: options.term // Change name to what is expected
},
success: function(data) {
lastOptions = data;
options.callback({ results: data });
}
});
} else {
options.callback({ results: lastOptions });
}
}
});
jsfiddle

Multiple datatables per page

I have multiple data tables per page, ranging from 4 to 8 ish.
All the tables have different settings. All the data is gotten via sAjaxSource (a javascript array).
My question boils down to:
Solution 1)
Should I have one seperate URL for each table? This seems to work, but means a full page load takes a lot longer.
Solution 2)
Have one same link for all the tables (and have seperate array name), so its only 1 download.
My questions are as follows:
Is there any recommmended solution for multiple data tables per page, that's best practice in terms of 1 or multiple links to get the javascript arrays.
If you provide the same ajax link to multiple datatables the browser seems to download them once per table instead of 1 time for all tables. Is this per "design" or a fault in my code?
Side note: I have checked http://www.datatables.net/examples/basic_init/multiple_tables.html and search the documentation but did not learn anything about the above questions.
In the case you described above, I would not rely on browser cashing, instead I would get data with my own single Ajax request. Store it in a local variable and for different tables use 'aaData' option.
var mydata;
$.ready(function(){
$.get("source/file.php", function(data){
mydata = data;
$('#table1').dataTable({ "aaData": mydata[0] });
$('#table1').dataTable({ "aaData": mydata[1] });
}, 'json');
});
but in the end solution depends on your needs, maybe you'll need lots of data, maybe it ll require paging and would be better off with multiple 'source' files with differed loading options etc.
The fact that the browser download the file only the first time when you provide the same link is, I think, due to the browser caching capabilities and has nothing to do with DataTables or your code. The browser put the content in its cache the first time and then serves it from there.
You can use this fact to your advantage by using the sAjaxDataProp option. I'm thinking something along these lines :
$('#table1').dataTable( {
"sAjaxSource": "sources/data.txt",
"sAjaxDataProp": "table1"
} );
$('#table2').dataTable( {
"sAjaxSource": "sources/data.txt",
"sAjaxDataProp": "table2"
} );
[ ... ]
$('#tableN').dataTable( {
"sAjaxSource": "sources/data.txt",
"sAjaxDataProp": "tableN"
} );
This will tell DataTable to look for a specific javascript array in the loaded content. Obviously, the data.txt file must contain the declaration of each table.
If you want to be sure that the browser do only one request, you could also load the data by an other means, a jQuery AJAX function for example, and then initialize the DataTables with an javascript array :
$('#table1').dataTable( { "aaData": array1 } );
$('#table2').dataTable( { "aaData": array2 } );
$('#tableN').dataTable( { "aaData": arrayN } );
I hope this will help :)

Categories