diff --git a/README.md b/README.md index 4924c7a5e5b..3aa81231f74 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,7 @@ a number of read-only getters are available in order to access state information * `getTheme()` - returns the name of the current theme. * `getFontSize()` - returns the current font size as a string (e.g., `"12px"`). * `getWordWrap()` - returns the current word wrap setting as a `Boolean` (i.e., enabled or disabled). +* `getAutoCloseTags()` - returns the current close tags setting as an `Object` with three properties: `whenOpening` a boolean that determines whether opening tags are closed upon typing ">", `whenClosing` a boolean that determines whether closing tags are closed upon typing "/", and an array of tags `indentTags`, that when opened, has a blank line. These values default to, respectively: `true`, `true`, and an empty array. * `getTutorialExists()` - returns `true` or `false` depending on whether or not there is a tutorial in the project (i.e., if `tutorial.html` is present) * `getTutorialVisible()` - returns `true` or `false` depending on whether or not the preview browser is showing a tutorial or not. * `getAutoUpdate()` - returns `true` or `false` depending on whether or not the auto update preference is enabled or not. @@ -355,6 +356,7 @@ to be notified when the action completes: * `disableInspector([callback])` - turns off the preview inspector (default) * `enableWordWrap([callback])` - turns on word wrap for the editor (default) * `disableWordWrap([callback])` - turns off word wrap for the editor +* `configureAutoCloseTags(options, [callback])` - enables/disables close tags for the editor using the provided options which consists of an `Object` that includes three properties: `whenOpening` a boolean, `whenClosing` a boolean, and an array `indentTags`. * `showTutorial([callback])` - shows tutorial (i.e., tutorial.html) vs editor contents in preview * `hideTutorial([callback])` - stops showing tutorial (i.e., tutorial.html) and uses editor contents in preview * `showUploadFilesDialog([callback])` - shows the Upload Files dialog, allowing users to drag-and-drop, upload a file, or take a selfie. @@ -375,6 +377,7 @@ the following events: * `"themeChange"` - triggered whenever the theme changes. It inclues an `Object` with a `theme` property that indicates the new theme * `"fontSizeChange"` - triggered whenever the font size changes. It includes an `Object` with a `fontSize` property that indicates the new size (e.g., `"12px"`). * `"wordWrapChange"` - triggered whenever the word wrap value changes. It includes an `Object` with a `wordWrap` property that indicates the new value (e.g., `true` or `false`). +* `"autoCloseTagsChange"` - triggered whenever the close tag value changes. It includes an `Object` with a `autoCloseTags` property that indicates the new value * `"tutorialAdded"` - triggered when a new tutorial is added to the project * `"tutorialRemoved"` - triggered when an existing tutorial for the project is removed * `"tutorialVisibilityChange"` - triggered when the tutorial preview is turned on or off. It includes an `Object` with a `visibility` property that indicates whether the tutorial is visible. diff --git a/src/bramble/client/StateManager.js b/src/bramble/client/StateManager.js index aab3e315010..97189ffce3b 100644 --- a/src/bramble/client/StateManager.js +++ b/src/bramble/client/StateManager.js @@ -51,6 +51,35 @@ define(function() { return str|0; } + function getObject(storage, property) { + var objStr = getString(storage, property); + var obj = {}; + + try { + obj = JSON.parse(objStr); + } catch(e) { + console.error("Failed to parse object from localStorage item " + prefix(property) + " with: ", e); + } + + return obj; + } + + function setObject(storage, property, obj) { + if(!obj) { + return; + } + + var objStr; + property = prefix(property); + + try { + objStr = JSON.stringify(obj); + storage.setItem(property, objStr); + } catch(e) { + console.error("Failed to stringify object to write to localStorage for item " + property + " with: ", e); + } + } + function StateManager(disableStorage) { var storage; if(disableStorage) { @@ -102,6 +131,10 @@ define(function() { get: function() { return getBool(storage, "wordWrap"); }, set: function(v) { storage.setItem(prefix("wordWrap"), v); } }, + autoCloseTags: { + get: function() { return getObject(storage, "closeTags"); }, + set: function(v) { setObject(storage, "closeTags", v); } + }, allowJavaScript: { get: function() { return getBool(storage, "allowJavaScript"); }, set: function(v) { storage.setItem(prefix("allowJavaScript"), v); } diff --git a/src/bramble/client/main.js b/src/bramble/client/main.js index bf06a7c20fa..eb68d09c34e 100644 --- a/src/bramble/client/main.js +++ b/src/bramble/client/main.js @@ -204,6 +204,7 @@ define([ self.getSidebarVisible = function() { return _state.sidebarVisible; }; self.getRootDir = function() { return _root; }; self.getWordWrap = function() { return _state.wordWrap; }; + self.getAutoCloseTags = function() { return _state.autoCloseTags; }; self.getAllowJavaScript = function() { return _state.allowJavaScript; }; self.getAutoUpdate = function() { return _state.autoUpdate; }; self.getTutorialExists = function() { return _tutorialExists; }; @@ -264,6 +265,7 @@ define([ _state.previewMode = data.previewMode; _state.theme = data.theme; _state.wordWrap = data.wordWrap; + _state.autoCloseTags = data.autoCloseTags; _state.allowJavaScript = data.allowJavaScript; _state.autoUpdate = data.autoUpdate; @@ -301,6 +303,8 @@ define([ _state.sidebarVisible = data.visible; } else if (eventName === "wordWrapChange") { _state.wordWrap = data.wordWrap; + } else if (eventName === "autoCloseTagsChange") { + _state.autoCloseTags = data.autoCloseTags; } else if (eventName === "allowJavaScriptChange") { _state.allowJavaScript = data.allowJavaScript; } else if (eventName === "tutorialVisibilityChange") { @@ -422,6 +426,7 @@ define([ previewMode: _state.previewMode, wordWrap: _state.wordWrap, allowJavaScript: _state.allowJavaScript, + autoCloseTags: _state.autoCloseTags, autoUpdate: _state.autoUpdate } }; @@ -920,6 +925,10 @@ define([ this._executeRemoteCommand({commandCategory: "bramble", command: "BRAMBLE_DISABLE_WORD_WRAP"}, callback); }; + BrambleProxy.prototype.configureAutoCloseTags = function(options, callback) { + this._executeRemoteCommand({commandCategory: "bramble", command: "BRAMBLE_CONFIGURE_AUTO_CLOSE_TAGS", args: [ options ]}, callback); + }; + BrambleProxy.prototype.showTutorial = function(callback) { this._executeRemoteCommand({commandCategory: "bramble", command: "BRAMBLE_SHOW_TUTORIAL"}, callback); }; @@ -953,7 +962,7 @@ define([ BrambleProxy.prototype.export = function(callback) { this._executeRemoteCommand({commandCategory: "bramble", command: "BRAMBLE_EXPORT"}, callback); }; - + BrambleProxy.prototype.addCodeSnippet = function(options, callback) { this._executeRemoteCommand({ commandCategory: "bramble", diff --git a/src/extensions/default/bramble/lib/RemoteCommandHandler.js b/src/extensions/default/bramble/lib/RemoteCommandHandler.js index 01a0e2694d9..3771c0b9e71 100644 --- a/src/extensions/default/bramble/lib/RemoteCommandHandler.js +++ b/src/extensions/default/bramble/lib/RemoteCommandHandler.js @@ -130,6 +130,9 @@ define(function (require, exports, module) { case "BRAMBLE_DISABLE_WORD_WRAP": PreferencesManager.set("wordWrap", false); break; + case "BRAMBLE_CONFIGURE_AUTO_CLOSE_TAGS": + PreferencesManager.set("closeTags", args[0]); + break; case "BRAMBLE_SHOW_TUTORIAL": Tutorial.setOverride(true); break; diff --git a/src/extensions/default/bramble/lib/RemoteEvents.js b/src/extensions/default/bramble/lib/RemoteEvents.js index a155b9468ad..462ab32c01b 100644 --- a/src/extensions/default/bramble/lib/RemoteEvents.js +++ b/src/extensions/default/bramble/lib/RemoteEvents.js @@ -140,7 +140,15 @@ define(function (require, exports, module) { wordWrap: PreferencesManager.get("wordWrap") }); }); - + + // Listen for changes to close tags + PreferencesManager.on("change", "closeTags", function () { + sendEvent({ + type: "bramble:autoCloseTagsChange", + autoCloseTags: PreferencesManager.get("closeTags") + }); + }); + // Listen for changes to allow javascript PreferencesManager.on("change", "allowJavaScript", function () { sendEvent({ @@ -189,6 +197,7 @@ define(function (require, exports, module) { theme: Theme.getTheme(), wordWrap: PreferencesManager.get("wordWrap"), allowJavaScript: PreferencesManager.get("allowJavaScript"), + autoCloseTags: PreferencesManager.get("closeTags"), autoUpdate: PreferencesManager.get("autoUpdate") }); } diff --git a/src/extensions/default/bramble/lib/UI.js b/src/extensions/default/bramble/lib/UI.js index 8fc47bd1f4e..2368fc456df 100644 --- a/src/extensions/default/bramble/lib/UI.js +++ b/src/extensions/default/bramble/lib/UI.js @@ -90,6 +90,9 @@ define(function (require, exports, module) { PreferencesManager.set("wordWrap", wordWrap); } + var autoCloseTags = BrambleStartupState.ui("autoCloseTags") || { whenOpening: true, whenClosing: true, indentTags: [] }; + PreferencesManager.set("closeTags", autoCloseTags); + var allowJavaScript = BrambleStartupState.ui("allowJavaScript"); if(typeof allowJavaScript === "boolean") { PreferencesManager.set("allowJavaScript", allowJavaScript); @@ -116,11 +119,11 @@ define(function (require, exports, module) { var secondPaneWidth = BrambleStartupState.ui("secondPaneWidth"); var firstPaneWidth = BrambleStartupState.ui("firstPaneWidth"); - + firstPaneWidth = firstPaneWidth * 100 / ( ((firstPaneWidth)? firstPaneWidth : 0) + ((secondPaneWidth)? secondPaneWidth : 0)); // calculate width in % - + if(firstPaneWidth) { $("#first-pane").width((firstPaneWidth + "%")); } diff --git a/src/extensions/default/bramble/main.js b/src/extensions/default/bramble/main.js index 0f44c4b73f2..54e0a8cd345 100644 --- a/src/extensions/default/bramble/main.js +++ b/src/extensions/default/bramble/main.js @@ -100,8 +100,6 @@ define(function (require, exports, module) { // Make the spaceUnits and tabSize consistent PreferencesManager.set("spaceUnits", 2); PreferencesManager.set("tabSize", 2); - // Allows the closeTags to indent consistently - PreferencesManager.set("closeTags", true); // Don't warn about opening file in split view (we steal second view for iframe) PreferencesManager.setViewState("splitview.multipane-info", true); @@ -156,7 +154,7 @@ define(function (require, exports, module) { // Setup the iframe browser and Blob URL live dev servers and // load the initial document into the preview. startLiveDev(); - + BrambleCodeSnippets.init(); UI.initUI(finishStartup); @@ -192,6 +190,7 @@ define(function (require, exports, module) { previewMode: data.state.previewMode, wordWrap: data.state.wordWrap, allowJavaScript: data.state.allowJavaScript, + autoCloseTags: data.state.autoCloseTags, autoUpdate: data.state.autoUpdate });