+
+
+
Code
+
+
+ var menus=[
+ {
+ name:"rename",
+ action:function(){
+ console.log("rename action ");
+ }
+ },
+ {
+ name:"delete",
+ action:function(){
+ console.log("delete action");
+ }
+ },
+ {
+ name:"download",
+ action:function(){
+ console.log("download action ");
+ }
+ },
+ {
+ name:"move to",
+ action:function(){
+ console.log("move action")
+ },
+ options:[
+ {name:"share",action:function(){console.log("move action to share")}},
+ {name:"test",action:function(){console.log("move action to test")}},
+ {name:"dev",action:function(){console.log("move action to dev")}}
+ ]
+ }
+ ];
+
+ $('demo').addRightClickMenu(menus);
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/content/src/controller.js b/content/src/controller.js
index 0f7d80c5..60a68347 100644
--- a/content/src/controller.js
+++ b/content/src/controller.js
@@ -14,7 +14,8 @@ var $ = require('jquery'),
pencilTracer = require('pencil-tracer'),
icedCoffeeScript = require('iced-coffee-script'),
drawProtractor = require('draw-protractor'),
- cache = require('cache');
+ cache = require('cache'),
+ contextMenu = require('contextMenu');
eval(see.scope('controller'));
@@ -1476,53 +1477,86 @@ function doneWithFile(filename) {
}
}
-view.on('rename', function(newname) {
- var pp = paneatpos('left');
- var mp = modelatpos('left');
- if (mp.filename === newname || nosaveowner()) {
- // Nothing to do
+view.on('delete', function (callback, filename, pane) {
+ var pp = pane ? pane : paneatpos('left');
+ var mp = modelatpos(posofpane(pp));
+ deleteFile((mp.filename ? mp.filename + '/' : '') + filename, callback);
+});
+
+function deleteFile (filename, callback) {
+ if (model.ownername) {
+ var userValidationError = false;
+ var validateUserLoginPopupCallback;
+ executeDeleteFile();
+
+ function executeDeleteFile () {
+ storage.deleteFile(model.ownername, filename, model.passkey, function (m) {
+ if (validateUserLoginPopupCallback) {
+ validateUserLoginPopupCallback(m)
+ }
+
+ if (m.needauth) {
+ /* Open the login popup only if it has closed
+ */
+ if (!validateUserLoginPopupCallback) {
+ requireLogin("Log in to delete " + filename, null, function (state, validateUserLoginPopup) {
+ validateUserLoginPopupCallback = validateUserLoginPopup;
+ executeDeleteFile(filename, callback);
+ });
+ }
+ } else if (m.error) {
+ callback(m);
+ } else {
+ // If there is a running on the right, bring it along
+ var rp = modelatpos('right');
+ if (rp.filename == filename) {
+ //Destroy the pane
+ view.closePane(paneatpos('right'));
+ }
+ callback(m);
+ }
+ });
+ }
+ }
+}
+
+view.on('rename', function (callback, newname, oldName, pane) {
+ var pp = pane ? pane : paneatpos('left');
+ var mp = modelatpos(posofpane(pp));
+ var oldFileName;
+ var newFileName;
+
+ if (!oldName) {
+ //Takes the currently opened filename as the old name if it has not provided
+ oldName = mp.filename;
+ oldFileName = mp.filename;
+ newFileName = newname;
+ } else {
+ oldFileName = (mp.filename ? mp.filename + '/' : '') + oldName;
+ newFileName = (mp.filename ? mp.filename + '/' : '') + newname;
+ }
+
+ var payload = {
+ mode: 'mv',
+ source: model.ownername + '/' + oldFileName
+ };
+
+ if (oldName === newname || nosaveowner()) {
+ callback({ processing: false, oldName: oldName });
return;
}
- var oldMimeType = filetype.mimeForFilename(mp.filename);
+
+ var oldMimeType = filetype.mimeForFilename(oldName);
+
// Error cases: go back to original name.
// Can't rename the root (for now).
// TODO: check for:
// - moving directory inside itself
// etc.
- if (!mp.filename) {
- view.setNameText(mp.filename);
+ if (!oldName) {
+ callback({ processing: false, oldName: oldName });
return;
}
- function completeRename(newfile) {
- view.flashNotification(
- (newfile ? 'Using name ' : 'Renamed to ') + newname + '.');
- // If there is a running on the right, bring it along
- var rp = modelatpos('right');
- if (rp.running && rp.filename == mp.filename) {
- rp.filename = newname;
- }
- mp.filename = newname;
- view.noteNewFilename(pp, newname);
- updateTopControls(false);
- view.setPrimaryFocus();
- var changed = view.isPaneEditorDirty(paneatpos('left')) ||
- oldMimeType != filetype.mimeForFilename(newname);
- if (changed && model.ownername && !nosaveowner() &&
- !view.isPaneEditorEmpty(paneatpos('left'))) {
- saveAction(true, 'Login to save', function() {
- if (modelatpos('right').running) {
- // After a change-rename-save, reset the run preview if any.
- // (Possible mime type change.)
- var doc = view.getPaneEditorData(paneatpos('left'));
- runCodeAtPosition('right', doc, modelatpos('left').filename, true);
- }
- });
- }
- }
- var payload = {
- source: model.ownername + '/' + mp.filename,
- mode: 'mv'
- };
if (model.passkey) {
payload.key = model.passkey;
}
@@ -1531,30 +1565,75 @@ view.on('rename', function(newname) {
// it exists on disk and so we first rename it on disk.
if (model.ownername && (mp.data.directory || mp.data.mtime)) {
if (mp.data.auth && !model.username) {
- view.setNameText(mp.filename);
- logInAndMove(mp.filename, newname, completeRename);
+ callback({ processing: true, oldName: oldName });
+ logInAndMove(oldFileName, newFileName, renameSuccess);
} else {
storage.moveFile(
- model.ownername, mp.filename, newname, model.passkey, false,
- function(m) {
+ model.ownername, oldFileName, newFileName, model.passkey, false,
+ function (m) {
if (m.needauth) {
- view.setNameText(mp.filename);
- logInAndMove(mp.filename, newname, completeRename);
+ callback({ processing: true, oldName: oldName });
+ logInAndMove(oldName, newname, callback);
return;
}
if (m.error) {
- // Abort if there is an error.
- view.flashNotification(m.error);
- view.setNameText(mp.filename);
+ callback({ oldName: oldName, processing: false, error: m.error });
} else {
- completeRename();
+ renameSuccess(m);
}
});
}
} else {
// No mtime means it's purely local - just rename in memory.
storage.deleteBackup(mp.filename);
- completeRename(true);
+ renameSuccess({});
+ }
+
+ function renameSuccess (m) {
+ callback({ oldName: oldName, newName: newname, processing: false, saved: m.saved, href: "/edit/" + newFileName });
+ }
+});
+
+view.on('renameOpenedFile', function (newname) {
+ var pp = paneatpos('left');
+ var mp = modelatpos('left');
+
+ view.fireEvent('rename', [completeRename, newname]);
+
+ function completeRename(data, error) {
+ if (error) {
+ // Abort if there is an error.
+ view.flashNotification(error);
+ view.setNameText(data.oldName);
+ return;
+ }
+ if (data.processing) {
+ view.setNameText(data.oldName);
+ return;
+ }
+ view.flashNotification('Renamed to ' + data.newName + '.');
+ // If there is a running on the right, bring it along
+ var rp = modelatpos('right');
+ if (rp.running && rp.filename == data.oldName) {
+ rp.filename = data.newName;
+ }
+ mp.filename = data.newName;
+ view.noteNewFilename(pp, data.newName);
+ updateTopControls(false);
+ view.setPrimaryFocus();
+ var changed = view.isPaneEditorDirty(paneatpos('left')) ||
+ oldMimeType != filetype.mimeForFilename(data.newName);
+ if (changed && model.ownername && !nosaveowner() &&
+ !view.isPaneEditorEmpty(paneatpos('left'))) {
+ saveAction(true, 'Login to save', function() {
+ if (modelatpos('right').running) {
+ // After a change-rename-save, reset the run preview if any.
+ // (Possible mime type change.)
+ var doc = view.getPaneEditorData(paneatpos('left'));
+ runCodeAtPosition('right', doc, modelatpos('left').filename, true);
+ }
+ });
+ }
}
});
@@ -1564,31 +1643,53 @@ function logInAndMove(filename, newfilename, completeRename) {
if (!filename || !newfilename) {
return;
}
+
+ requireLogin('Log in to rename.', null, function(state) {
+ state.update({info: 'Renaming....', disable: true});
+ storage.moveFile(
+ model.ownername, filename, newfilename, model.passkey, false,
+ function(m) {
+ if (m.needauth) {
+ state.update({info: 'Wrong password.', disable: false});
+ return;
+ }
+ state.update({cancel: true});
+ if (m.error) {
+ completeRename({ oldName: filename, newName: newfilename, processing: false, error: m.error });
+ } else {
+ saveLoginCookie();
+ if (!specialowner()) {
+ cookie('recent', window.location.href,
+ { expires: 7, path: '/', domain: window.pencilcode.domain });
+ }
+ completeRename(m);
+ }
+ });
+ });
+}
+
+function requireLogin (promptMessage, validateCB, doneCB) {
view.showLoginDialog({
- prompt: 'Log in to rename.',
+ prompt: promptMessage,
username: model.ownername,
- validate: function(state) { return {}; },
+ validate: function(state) {
+ validateCB && validateCB();
+ return {};
+ },
done: function(state) {
model.username = model.ownername;
model.passkey = keyFromPassword(model.username, state.password);
- state.update({info: 'Renaming....', disable: true});
- storage.moveFile(
- model.ownername, filename, newfilename, model.passkey, false,
- function(m) {
+
+ /* second callback is used to update the login popup
+ according to the user input for the password
+ */
+ doneCB && doneCB(state, function (m) {
if (m.needauth) {
state.update({info: 'Wrong password.', disable: false});
- return;
- }
- state.update({cancel: true});
- if (m.error) {
- view.flashNotification(m.error);
+ return false;
} else {
- saveLoginCookie();
- if (!specialowner()) {
- cookie('recent', window.location.href,
- { expires: 7, path: '/', domain: window.pencilcode.domain });
- }
- completeRename();
+ state.update({cancel: true});
+ return true;
}
});
}
@@ -2100,7 +2201,7 @@ function updateSearchResults(pane, search, cb) {
updateViewAndCache(results, getUpdatedLinksArray(pane), cache);
}
}
-
+
function updateViewAndCache(list, viewlist, cache) {
view.setPaneLinks(pane, viewlist);
cb && cb();
diff --git a/content/src/editor.less b/content/src/editor.less
index 5e60034c..9165ec4d 100644
--- a/content/src/editor.less
+++ b/content/src/editor.less
@@ -852,6 +852,7 @@ body#pencildoc #diigolet-csm {
color: #222;
cursor: pointer;
width: 154px;
+ position: relative;
div {
margin: 0px;
max-height: 154px;
@@ -876,13 +877,14 @@ body#pencildoc #diigolet-csm {
padding: 2px;
}
}
- &:hover {
+ &:hover, &.right-click-active {
text-decoration: underline;
color: blue;
div .thumbnail {
padding: 0px;
border-width: 2px;
border-color: #1679FF;
+ /*box-shadow: 1px 1px 1px 1px rgb(168, 168, 168);*/
}
span:not(.caption) {
display: table;
@@ -894,6 +896,33 @@ body#pencildoc #diigolet-csm {
}
}
+.directory .item-processing-animation {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(30, 144, 255, 0.54);
+ position: absolute;
+ z-index: 100;
+ text-align: center;
+ vertical-align: middle;
+ border-radius: 10px;
+ padding: 10px;
+ box-shadow: inset 0 0 10px 5px #fffde7;
+ color: #F5F5F5;
+ top: 0%;
+ i {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ }
+}
+
+.directory .item-div {
+ float: left;
+ clear: left;
+ width: 154px;
+ position: relative;
+}
+
.directory .create {
color: #1e90ff;
div .thumbnail {
@@ -1403,3 +1432,22 @@ body#pencildoc #diigolet-csm {
list-style: none;
display: inline-flex;
}
+
+.pencilcode-textfield {
+ position: relative;
+ color: #aaa;
+ font-size: 16px;
+ z-index: 3;
+}
+
+.pencilcode-textfield input[type="text"] {
+ width: 100%;
+ padding: 3px;
+ border-radius: 5px;
+ border-color: #1B78FE;
+ font-size: 20px;
+}
+
+.pencilcode-textfield input[type="text"]:focus {
+ color: dodgerblue;
+}
diff --git a/content/src/storage.js b/content/src/storage.js
index 6b5cf979..3fc835ed 100644
--- a/content/src/storage.js
+++ b/content/src/storage.js
@@ -355,6 +355,29 @@ window.pencilcode.storage = {
});
});
},
+ deleteFile: function(ownername, filename, key, callback) {
+ var payload = {
+ mode: 'rmtree',
+ key: key
+ };
+ $.post('//' + ownername + '.' + window.pencilcode.domain + '/save/' +
+ filename, payload, function(m) {
+ var check;
+ if (m.error) {
+ // Pass errors on to calback. Don't affect backup.
+ } else {
+ // On a successful move, just delete the backup of everything
+ // in the source area. TODO: move the backup tree instead.
+ //deleteBackupPrefix(sourcefile);
+ }
+ callback && callback(m);
+ }, 'json').error(function() {
+ callback && callback({
+ error: networkErrorMessage(ownername + '.' + window.pencilcode.domain),
+ offline:true
+ });
+ });
+ },
setPassKey: function(ownername, key, oldkey, callback) {
$.post('//' + ownername + '.' + window.pencilcode.domain + '/save/',
$.extend({ mode: 'setkey', data: key}, oldkey ? { key: oldkey } : {}),
diff --git a/content/src/view.js b/content/src/view.js
index 421a9c52..826fea0e 100644
--- a/content/src/view.js
+++ b/content/src/view.js
@@ -112,6 +112,10 @@ window.pencilcode.view = {
$('#' + pane + 'title_text').html(html);
},
clearPane: clearPane,
+ closePane: function (pane) {
+ clearPane(pane);
+ showMiddleButton(false);
+ },
setPaneEditorData: setPaneEditorData,
changePaneEditorText: function(pane, text) {
return changeEditorText(state.pane[pane], text);
@@ -533,7 +537,7 @@ $('#filename').on('blur', function() {
}
if (fixedtext != state.nameText) {
state.nameText = fixedtext;
- fireEvent('rename', [fixedtext]);
+ fireEvent('renameOpenedFile', [fixedtext]);
}
});
@@ -1389,18 +1393,61 @@ function updatePaneLinks(pane) {
}
list = paneState.links;
if (!list) { return; }
-
+
$('#' + pane).html('');
directory = $('', { class: "pencilcode-textfield" }).appendTo(itemContent))
+ .focus().select();
+ element.closeRightClickMenu();
+
+ function completeRenaming (data, callback) {
+ var isDir = item.name.indexOf('/');
+
+ item.name = data.newName + (isDir ? '/' : '');
+ item.link = data.newName;
+ item.href = data.href;
+
+ element.attr('href', item.href);
+ element.data('link', item.link);
+
+ callback && callback();
+ }
+
+ function closeItemRenameField () {
+ itemContent.find('.caption').remove();
+ itemContent.find('.item-rename-text-field').remove();
+ itemContent.append($('
', { text: item.name, class:"caption" }));
+ }
+ }
+
+ function deleteItem (item) {
+ setItemAsProcessing (true);
+ fireEvent('delete', [function (data) {
+ if (data.error) {
+ flashNotification(data.error);
+ setItemAsProcessing (false);
+ } else {
+ flashNotification('Deleted ' + item.name);
+
+ list.splice(index,1);
+ updatePaneLinks(pane);
+ }
+ }, item.name, pane]);
+ }
+
+ function setItemAsProcessing (status) {
+ console.log('setItemAsProcessing : '+status);
+ if (status) {
+ if (!element.hasClass('item-precessing')) {
+ itemDiv.addClass("item-precessing");
+ }
+ if (element.find('.item-processing-animation').length == 0) {
+ itemDiv.append('
');
+ }
+ } else {
+ itemDiv.removeClass("item-precessing");
+ itemDiv.find('.item-processing-animation').remove();
+ }
+ }
+
+ var menus=[
+ {
+ name: "rename",
+ action:function () {
+ console.log("rename action "+"["+item.name+"]");
+ showItemRenameField(item);
+ }
+ },
+ {
+ name: "delete",
+ action:function () {
+ console.log("delete action" + "[" + item.name + "]");
+ deleteItem(item);
+ }
+ }/*,
+ {
+ name:"download",
+ action:function(){
+ console.log("download action "+"["+item.name+"]");
+ //TODO
+ }
+ },
+ {
+ name:"move to",
+ action:function(){
+ console.log("move action"+"["+item.name+"]")
+ //TODO
+ },
+ //List of options TBD
+ options:[
+ {name:"share",action:function(){console.log("move action to share"+"["+item.name+"]")}},
+ {name:"test",action:function(){console.log("move action to test"+"["+item.name+"]")}},
+ {name:"dev",action:function(){console.log("move action to dev"+"["+item.name+"]")}}
+ ]
+ }*/
+ ];
+
+ element.addRightClickMenu(menus);
+ }
+
if (list[j].link) {
item.data('link', list[j].link);
}
}
- items = directory.find('.item');
+ items = directory.find('.item-div');
maxwidth = 0;
for (j = 0; j < items.length; j++) {
maxwidth = Math.max(maxwidth, Math.ceil(fwidth(items.get(j))));
@@ -1483,14 +1675,16 @@ function updatePaneLinks(pane) {
}
}, 600);
});
-
+
setVisibilityOfSearchTextField(pane);
}
(function($) {
- $.fn.hasScrollBar = function() {
+ $.fn.extend({
+ hasScrollBar : function() {
return this.get(0) ? this.get(0).scrollHeight > this.innerHeight() : false;
- }
+ }
+ });
})(jQuery);
function setVisibilityOfSearchTextField(pane) {
diff --git a/package.json b/package.json
index 13c918f1..28207020 100644
--- a/package.json
+++ b/package.json
@@ -76,7 +76,8 @@
"thumbnail": "./content/src/thumbnail.js",
"tooltipster": "./content/lib/tooltipster/js/jquery.tooltipster.js",
"view": "./content/src/view.js",
- "ZeroClipboard": "./content/lib/zeroclipboard/ZeroClipboard.js"
+ "ZeroClipboard": "./content/lib/zeroclipboard/ZeroClipboard.js",
+ "contextMenu": "./content/lib/pencilcode-contextmenu/src/dev/pencilcode-contextmenu.js"
},
"browserify": {
"transform": [ "browserify-shim" ]
@@ -95,6 +96,10 @@
"see": {
"exports": "see",
"depends": ["jquery:jQuery"]
+ },
+ "contextMenu": {
+ "exports": "$",
+ "depends": ["jquery"]
}
}
}