diff --git a/editor/css/editor.css b/editor/css/editor.css index 025c03832bf43ef5c4161b78cdbb0d22acaadd22..393db7dd4071cb737f12941ad825627614d9e2cc 100644 --- a/editor/css/editor.css +++ b/editor/css/editor.css @@ -58,6 +58,6 @@ div#ks-editor img.preview-image { height: auto; } -div#ks-editor #toolbar-settings { +div#ks-editor #toolbar-settings, div#ks-editor #toolbar-save { float: right; } diff --git a/editor/editor.php b/editor/editor.php index 659acdfa07e470f761f24a808b7f1653b0977887..f9b65cc70e6df7456f9d85c34bc78bc4b0532e36 100644 --- a/editor/editor.php +++ b/editor/editor.php @@ -90,5 +90,4 @@ </input> </div> </section> - <button id="save" type="submit" class="primary">Save and publish</button> </div> \ No newline at end of file diff --git a/editor/js/interactions.js b/editor/js/interactions.js index 2c34de8152189f8640282ca6ff1b087430022e32..d24fec2652d2f9940210fa5f13021cf0fe201f6e 100644 --- a/editor/js/interactions.js +++ b/editor/js/interactions.js @@ -1,6 +1,6 @@ import jQuery from "jquery"; -import { state, graph } from "./editor"; -import { listAllSpaces, saveGraphJson } from "../../datasets/datasets"; +import { state } from "./editor"; +import { listAllSpaces } from "../../datasets/datasets"; import { SPACE } from "../../config"; /** @@ -10,10 +10,6 @@ export function initInteractions() { jQuery("button#clear-collection").on("click", () => { state.clearSelectedItems(); }); - jQuery("button#save").on("click", () => { - saveGraphJson(SPACE, graph.getCleanData()); // space_id defined globaly through knowledge-space.php - graph.saveChanges(); - }); // Fill space dropdown var selectContainer = jQuery("#space-id-select"); diff --git a/editor/js/manageddata.js b/editor/js/manageddata.js index a289ea46553fb4009eee11660786f4e5bf837d18..c35a2bb1b7890bb234404855f241d7f031a7aa14 100644 --- a/editor/js/manageddata.js +++ b/editor/js/manageddata.js @@ -1,34 +1,41 @@ +import jQuery from "jquery"; + +const SAVE_BUTTON_ID = "div#ks-editor #toolbar-save"; + export default class ManagedData { constructor(data) { this.data = data; this.history = []; // Newest state is always at 0 this.historyPosition = 0; - this.unsavedChanges = false; + this.savedHistoryId = 0; this.storeCurrentData("Initial state", false); } updateUnsavedChangesHandler() { if (this.hasUnsavedChanges()) { + jQuery(SAVE_BUTTON_ID).removeClass("hidden"); window.addEventListener("beforeunload", this.handleBeforeUnload); } else { + jQuery(SAVE_BUTTON_ID).addClass("hidden"); window.removeEventListener("beforeunload", this.handleBeforeUnload); } } handleBeforeUnload(e) { - var confirmationMessage = 'If you leave before saving, unsaved changes will be lost.'; - + var confirmationMessage = + "If you leave before saving, unsaved changes will be lost."; + (e || window.event).returnValue = confirmationMessage; //Gecko + IE return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc. } hasUnsavedChanges() { - return this.unsavedChanges; + return this.history[this.historyPosition].id !== this.savedHistoryId; } saveChanges() { - this.unsavedChanges = false; + this.savedHistoryId = this.history[this.historyPosition].id; this.updateUnsavedChangesHandler(); } @@ -37,6 +44,7 @@ export default class ManagedData { undo() { if (this.step(1)) { + this.updateUnsavedChangesHandler(); this.onUndo(); return true; } else { @@ -46,6 +54,7 @@ export default class ManagedData { redo() { if (this.step(-1)) { + this.updateUnsavedChangesHandler(); this.onRedo(); return true; } else { @@ -76,18 +85,27 @@ export default class ManagedData { storeCurrentData(description, relevantChanges = true) { var formattedData = this.storableData(this.data); - this.history.unshift({ - description: description, - data: JSON.stringify(formattedData), // Creating a deep copy - }); + var nextId = 0; + if (this.history.length > 0) { + nextId = this.history[0].id; + + // Keep same as previous id, if nothing relevant changed + // Otherwise, increase by one + if (relevantChanges) { + nextId++; + } + } // Forget about the currently stored potential future this.history.splice(0, this.historyPosition); this.historyPosition = 0; - if (!this.hasUnsavedChanges() && relevantChanges) { - this.unsavedChanges = true; - this.updateUnsavedChangesHandler(); - } + this.history.unshift({ + description: description, + data: JSON.stringify(formattedData), // Creating a deep copy + id: nextId, + }); + + this.updateUnsavedChangesHandler(); } } diff --git a/editor/js/state.js b/editor/js/state.js index 831043d7a58ed9e3af2ed8d4ba823176f742b279..490d3b6bf8ce310679d010123b9089d12c0f977a 100644 --- a/editor/js/state.js +++ b/editor/js/state.js @@ -7,6 +7,7 @@ import DeleteTool from "./tools/deletetool"; import AddNodeTool from "./tools/addnodetool"; import ConnectTool from "./tools/connecttool"; import SettingsTool from "./tools/settingstool"; +import SaveTool from "./tools/savetool"; import { graph } from "./editor"; import Toolbar from "./toolbar"; import * as Graph from "./graph"; @@ -20,6 +21,7 @@ export const TOOLS = { addnode: new AddNodeTool("addnode"), connect: new ConnectTool("connect"), settings: new SettingsTool("settings"), + save: new SaveTool("save"), }; export const CONTEXT = { diff --git a/editor/js/toolbar.js b/editor/js/toolbar.js index 795628b92177c0f4d447a838a67a266f6ce3986b..658553f133d0904caa8ce40eefea2e3515734c26 100644 --- a/editor/js/toolbar.js +++ b/editor/js/toolbar.js @@ -3,6 +3,7 @@ import { PLUGIN_PATH } from "../../config"; import { state } from "./editor"; const ID_TOOLBAR = "#toolbar"; +const SAVE_BUTTON_ID = "div#ks-editor #toolbar-save"; const TOOL_ICON_SRC = PLUGIN_PATH + "editor/images/tools/"; const TOOL_ICON_FORMAT = ".png"; @@ -14,6 +15,9 @@ export default class Toolbar { this.previousTool = undefined; this.renderToolbar(this.tools); + + // Special, intial treatment + jQuery(SAVE_BUTTON_ID).addClass("hidden"); } setSelectedTool(tool) { diff --git a/editor/js/tools/savetool.js b/editor/js/tools/savetool.js new file mode 100644 index 0000000000000000000000000000000000000000..5bbb1137dca3c5b437c4dfe03ad5d3a4edeab677 --- /dev/null +++ b/editor/js/tools/savetool.js @@ -0,0 +1,16 @@ +import Tool from "./tool"; +import { saveGraphJson } from "../../../datasets/datasets"; +import { state, graph } from "../editor"; +import { SPACE } from "../../../config"; + +export default class SaveTool extends Tool { + constructor(key) { + super("Save", "save", key); + } + + onToolActivate() { + saveGraphJson(SPACE, graph.getCleanData()); // space_id defined globaly through knowledge-space.php + graph.saveChanges(); + state.setTool(state.previousTool); + } +}