diff --git a/app/abr-menu.js b/app/abr-menu.js index 3c7dfbb..c25ebf1 100644 --- a/app/abr-menu.js +++ b/app/abr-menu.js @@ -55,6 +55,9 @@ function preprocessTemplate (abrApp, element, config, abrWin) { if (item.id === "spelling") { item.submenu = spellingMenuGenerator(item.submenu, config); } + if (item.id === "tasks") { + item.submenu = tasksMenuGenerator(item.submenu, config); + } if (item.id === "exportHtml") { item.submenu = assetsMenuGenerator(item.submenu, constants.path.templatesDir, "template.json", "exportHtml"); } @@ -147,6 +150,22 @@ function spellingMenuGenerator (submenu, config) { return submenu; } +// Generate tasks menu template (before preprocesssing) +function tasksMenuGenerator (submenu, config) { + var tasks = getConfig(config, "tasks") || []; + var submenu = tasks.reduce(function (res, task) { + if (task.name && task.exec) { + res.push({ + label: task.name, + command: "runTask", + parameters: task.exec + }); + } + return res; + }, []); + return submenu; +} + // Generate menu template (before preprocesssing) function assetsMenuGenerator (submenu, dirPath, jsonName, command, menuType, checkId) { // Get a menu item diff --git a/app/dialogs.js b/app/dialogs.js index 067abca..17d72aa 100644 --- a/app/dialogs.js +++ b/app/dialogs.js @@ -142,6 +142,29 @@ Dialogs.prototype = { return false; }, + taskDone: function (cmd, stdout) { + var options = { + title: this.localizer.get("task-done-title"), + message: this.localizer.get("task-done-message", [cmd]), + buttons: [this.localizer.get('button-ok')], + detail: stdout, + noLink: true + }; + dialog.showMessageBox(this.win, options); + }, + + taskError: function (cmd, errMsg) { + var options = { + type: "error", + title: this.localizer.get("task-error-title"), + message: this.localizer.get("task-error-message", [cmd]), + detail: errMsg, + buttons: [this.localizer.get('button-ok')], + noLink: true + }; + dialog.showMessageBox(this.win, options); + }, + fileAccessDenied: function (path, callback) { var userChoice = dialog.showMessageBox(this.win, { title: this.localizer.get("permission-denied"), diff --git a/app/menu-window.json b/app/menu-window.json index dbf0f7d..d2e5ab1 100644 --- a/app/menu-window.json +++ b/app/menu-window.json @@ -104,6 +104,14 @@ { "type": "separator" }, + { + "labelKey": "menu-tasks", + "id": "tasks", + "submenu": [] + }, + { + "type": "separator" + }, { "labelKey": "menu-close-document", "accelerator": "CmdOrCtrl+Shift+W", diff --git a/app/renderer/abr-document.js b/app/renderer/abr-document.js index d27bd71..70edfb3 100644 --- a/app/renderer/abr-document.js +++ b/app/renderer/abr-document.js @@ -712,6 +712,46 @@ AbrDocument.prototype = { that.getConfig("preview-template", doExport); // TODO: log error if template don't exist }, + // Run tasks + runTask: function (instruction) { + var that = this; + + // Ask for saving if not clean + if (instruction.indexOf("%inputFilepath%") !== -1 && (!this.path || !this.isClean())) { + that.dialogs.askNeedSave(this, main); + } else { + main(); + } + + function main () { + var args = { + inputFilepath: '"' + that.path.replace('"', '\"') + '"' + }; + + // Ask user for outputFilepath + if (instruction.indexOf("%outputFilepath%") !== -1) { + var path = that.dialogs.askSavePath(null, "document"); + if (!path) return; + args.outputFilepath = '"' + path.replace('"', '\"') + '"'; + } + + // Replace args in command + var re = /%(inputFilepath|outputFilepath)%/g; + var cmd = instruction.replace(re, function (str, p1) { + return args[p1] ? args[p1] : str; + }); + + // Run command + cp.exec(cmd, function (err, stdout) { + if (err) { + that.dialogs.taskError(cmd, err.toString()); + return; + } + that.dialogs.taskDone(cmd, stdout); + }); + } + }, + // Inline autopreview autopreview: function (types, lines) { var cm = this.cm; diff --git a/app/renderer/commands.js b/app/renderer/commands.js index 9b9c744..226325c 100644 --- a/app/renderer/commands.js +++ b/app/renderer/commands.js @@ -45,6 +45,10 @@ var commands = { }); }, + runTask: function(win, abrDoc, cm, param) { + abrDoc.runTask(param); + }, + close: function(win, abrDoc, cm) { abrDoc.close(); }, diff --git a/default/config.json b/default/config.json index 08c4775..a2662d8 100644 --- a/default/config.json +++ b/default/config.json @@ -40,6 +40,12 @@ "active": false, "language": "" }, + "tasks": [ + { + "name": "Pandoc", + "exec": "pandoc %inputFilepath% -o %outputFilepath%" + } + ], "theme": "default", "window": { "showMenuBar": true diff --git a/default/lang/en.json b/default/lang/en.json index b39e30c..75abff2 100644 --- a/default/lang/en.json +++ b/default/lang/en.json @@ -27,6 +27,7 @@ "menu-save-autosave": "Save on Focus Lost", "menu-export-html": "Export as HTML", "menu-copy-images-on-html-export": "Copy Images when Exporting", + "menu-tasks": "Run Task", "menu-close-document": "Close Document", "menu-close-window": "Close Window", @@ -160,6 +161,11 @@ "images-copied": "Images Copied", "images-copied-message": "Document images have been copied in the '%0' directory.", + "task-done-title": "Task Completed", + "task-done-message": "The task was successfully completed: \n%0", + "task-error-title": "Task Error", + "task-error-message": "An error occurred while running the task: \n%0", + "html-export-title": "Abricotine Document", "changed-file": "Changed File", diff --git a/default/lang/fr.json b/default/lang/fr.json index cfb2543..0c7b6f5 100644 --- a/default/lang/fr.json +++ b/default/lang/fr.json @@ -27,6 +27,7 @@ "menu-save-autosave": "Sauvegarde automatique", "menu-export-html": "Exporter en HTML", "menu-copy-images-on-html-export": "Copier les images lors de l'export", + "menu-tasks": "Exécuter une tâche", "menu-close-document": "Fermer le document", "menu-close-window": "Fermer la fenêtre", @@ -160,6 +161,11 @@ "images-copied": "Images copiées", "images-copied-message": "Les images du document ont été copiées dans le répertoire '%0'.", + "task-done-title": "Tâche terminée", + "task-done-message": "La tâche a été exécutée avec succès : \n%0", + "task-error-title": "Échec de la tâche", + "task-error-message": "Une erreur a été rencontrée lors de l'exécution de la tâche : \n%0", + "html-export-title": "Document Abricotine", "changed-file": "Modification détectée",