From 741318e60bfd6baa9e5e2411fe968a22663eb82d Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Sun, 11 Oct 2020 09:52:44 -0400 Subject: [PATCH 01/10] Make the goldenlayout layout work with Evennia options --- .../webclient/js/plugins/goldenlayout.js | 204 ++++++++++++------ .../static/webclient/js/plugins/hotbuttons.js | 84 ++------ .../static/webclient/js/plugins/options.js | 178 --------------- .../static/webclient/js/plugins/options2.js | 72 +++---- 4 files changed, 196 insertions(+), 342 deletions(-) delete mode 100644 evennia/web/webclient/static/webclient/js/plugins/options.js diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index 36862272aa..4e21265f42 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -275,8 +275,18 @@ let goldenlayout = (function () { component.container.extendState({ "types": types, "updateMethod": updateMethod }); }); + // update the layout options when the stat changes from our previous stored state. var state = JSON.stringify( myLayout.toConfig() ); - localStorage.setItem( "evenniaGoldenLayoutSavedState", state ); + + if( state !== window.options["webclientLayout"] ) { + localStorage.setItem( "evenniaGoldenLayoutSavedState", state ); + + // Also update the server-side options, if the connection is ready to go. + if( Evennia.isConnected() && myLayout.isInitialised ) { + window.options["webclientLayout"] = state; + Evennia.msg("webclient_options", [], window.options); + } + } } @@ -347,22 +357,6 @@ let goldenlayout = (function () { } - // - // - var routeMsg = function (textDiv, txt, updateMethod) { - if ( updateMethod === "replace" ) { - textDiv.html(txt); - } else if ( updateMethod === "append" ) { - textDiv.append(txt); - } else { // line feed - textDiv.append("
" + txt + "
"); - } - let scrollHeight = textDiv.prop("scrollHeight"); - let clientHeight = textDiv.prop("clientHeight"); - textDiv.scrollTop( scrollHeight - clientHeight ); - } - - // // var initComponent = function (div, container, state, defaultTypes, updateMethod) { @@ -379,6 +373,51 @@ let goldenlayout = (function () { } + // + // + var registerComponents = function (myLayout) { + + // register our component and replace the default messagewindow with the Main component + myLayout.registerComponent( "Main", function (container, componentState) { + let main = $("#messagewindow").addClass("content"); + initComponent(main, container, componentState, "untagged", "newlines" ); + }); + + // register our input component + myLayout.registerComponent( "input", function (container, componentState) { + var promptfield = $("
"); + var formcontrol = $(""); + var button = $(""); + + var inputfield = $("
") + .append( button ) + .append( formcontrol ); + + $("
") + .append( promptfield ) + .append( inputfield ) + .appendTo( container.getElement() ); + + button.bind("click", function (evnt) { + // focus our textarea + $( $(evnt.target).siblings(".inputfield")[0] ).focus(); + // fake a carriage return event + var e = $.Event("keydown"); + e.which = 13; + $( $(evnt.target).siblings(".inputfield")[0] ).trigger(e); + }); + + container.on("tab", onInputCreate); + }); + + // register the generic "evennia" component + myLayout.registerComponent( "evennia", function (container, componentState) { + let div = $("
"); + initComponent(div, container, componentState, "all", "newlines"); + container.on("destroy", calculateUntaggedTypes); + }); + } + // // Public // @@ -403,6 +442,42 @@ let goldenlayout = (function () { } + // + // Add new HTML message to an existing Div pane, while + // honoring the pane's updateMethod and scroll state, etc. + // + var addMessageToPaneDiv = function (textDiv, message) { + let atBottom = false; + let updateMethod = textDiv.attr("updateMethod"); + + if ( updateMethod === "replace" ) { + textDiv.html(message); + } else if ( updateMethod === "append" ) { + textDiv.append(message); + } else { // line feed + textDiv.append("
" + message + "
"); + } + + // Calculate the scrollback state. + // + // This check helps us avoid scrolling to the bottom when someone is + // manually scrolled back, trying to read their backlog. + // Auto-scrolling would force them to re-scroll to their previous scroll position. + // Which, on fast updating games, destroys the utility of scrolling entirely. + // + //if( textDiv.scrollTop === (textDiv.scrollHeight - textDiv.offsetHeight) ) { + atBottom = true; + //} + + // if we are at the bottom of the window already, scroll to display the new content + if( atBottom ) { + let scrollHeight = textDiv.prop("scrollHeight"); + let clientHeight = textDiv.prop("clientHeight"); + textDiv.scrollTop( scrollHeight - clientHeight ); + } + } + + // // returns an array of pane divs that the given message should be sent to // @@ -445,6 +520,49 @@ let goldenlayout = (function () { } + // + // + var onGotOptions = function (args, kwargs) { + // Reset the UI if the JSON layout sent from the server doesn't match the client's current JSON + if( ("webclientLayout" in kwargs) && (kwargs["webclientLayout"] !== window.options["webclientLayout"]) ) { + var mainsub = document.getElementById("main-sub"); + + // rebuild the original HTML stacking + var messageDiv = $("#messagewindow").detach(); + messageDiv.prependTo( mainsub ); + + // out with the old + myLayout.destroy(); + + // in with the new + myLayout = new GoldenLayout( JSON.parse( kwargs["webclientLayout"] ), mainsub ); + + // re-register our main, input and generic evennia components. + registerComponents( myLayout ); + + // call all other plugins to give them a chance to registerComponents. + for( let plugin in window.plugins ) { + if( "onLayoutChange" in window.plugins[plugin] ) { + window.plugins[plugin].onLayoutChange(); + } + } + + // finish the setup and actually start GoldenLayout + myLayout.init(); + + // work out which types are untagged based on our pre-configured layout + calculateUntaggedTypes(); + + // Set the Event handler for when the client window changes size + $(window).bind("resize", scrollAll); + + // Set Save State callback + myLayout.on( "stateChanged", onStateChanged ); + + return true; + } + } + // // var onText = function (args, kwargs) { @@ -453,11 +571,9 @@ let goldenlayout = (function () { var msgHandled = false; divs.forEach( function (div) { - let updateMethod = div.attr("updateMethod"); let txt = args[0]; - // yes, so add this text message to the target div - routeMsg( div, txt, updateMethod ); + addMessageToPaneDiv( div, txt ); msgHandled = true; }); @@ -483,14 +599,16 @@ let goldenlayout = (function () { // - // required Init me + // required Init var init = function (options) { // Set up our GoldenLayout instance built off of the default main-sub div var savedState = localStorage.getItem( "evenniaGoldenLayoutSavedState" ); var mainsub = document.getElementById("main-sub"); if( savedState !== null ) { - // Overwrite the global-variable configuration with the version from localstorage + // Overwrite the global-variable configuration from + // webclient/js/plugins/goldenlayout_default_config.js + // with the version from localstorage window.goldenlayout_config = JSON.parse( savedState ); } @@ -499,56 +617,20 @@ let goldenlayout = (function () { $("#prompt").remove(); // remove the HTML-defined prompt div $("#inputcontrol").remove(); // remove the cluttered, HTML-defined input divs - // register our component and replace the default messagewindow with the Main component - myLayout.registerComponent( "Main", function (container, componentState) { - let main = $("#messagewindow").addClass("content"); - initComponent(main, container, componentState, "untagged", "newlines" ); - }); - - // register our new input component - myLayout.registerComponent( "input", function (container, componentState) { - var promptfield = $("
"); - var formcontrol = $(""); - var button = $(""); - - var inputfield = $("
") - .append( button ) - .append( formcontrol ); - - $("
") - .append( promptfield ) - .append( inputfield ) - .appendTo( container.getElement() ); - - button.bind("click", function (evnt) { - // focus our textarea - $( $(evnt.target).siblings(".inputfield")[0] ).focus(); - // fake a carriage return event - var e = $.Event("keydown"); - e.which = 13; - $( $(evnt.target).siblings(".inputfield")[0] ).trigger(e); - }); - - container.on("tab", onInputCreate); - }); - - myLayout.registerComponent( "evennia", function (container, componentState) { - let div = $("
"); - initComponent(div, container, componentState, "all", "newlines"); - container.on("destroy", calculateUntaggedTypes); - }); + registerComponents( myLayout ); } - return { init: init, postInit: postInit, onKeydown: onKeydown, + onGotOptions: onGotOptions, onText: onText, getGL: function () { return myLayout; }, addKnownType: addKnownType, onTabCreate: onTabCreate, routeMessage: routeMessage, + addMessageToPaneDiv: addMessageToPaneDiv, } }()); window.plugin_handler.add("goldenlayout", goldenlayout); diff --git a/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js b/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js index 023db7eb5e..6b7af9b2af 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js +++ b/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js @@ -17,16 +17,16 @@ * Copy evennia/web/webclient/templates/webclient/base.html to * mygame/web/template_overrides/webclient/base.html * - * Edit mygame/web/template_overrides/webclient/base.html to add: + * Edit mygame/web/template_overrides/webclient/base.html and before the goldenlayout.js plugin, add: * - * before the goldenlayout.js plugin tags or after the splithandler.js plugin tags * - * If you are using goldenlayout.js, uncomment the hotbuttons component in goldenlayout_default_config.js + * Then uncomment the hotbuttons component in goldenlayout_default_config.js * * Run: evennia collectstatic (say "yes" to the overwrite prompt) + * * Start Evennia * - * REQUIRES: goldenlayout.js OR splithandler.js + * REQUIRES: goldenlayout.js */ let hotbuttons = (function () { var dependenciesMet = false; @@ -95,47 +95,22 @@ let hotbuttons = (function () { } + // Public + // - // Add Buttons UI for SplitHandler - var addButtonsUI = function () { - var buttons = $( [ - "
", - "
", - "
", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "
", - "
", - "
", - ].join("\n") ); - - // Add buttons in front of the existing #inputform - $("#input").prev().replaceWith(buttons); - - Split(["#main","#buttons","#input"], { - sizes: [85,5,10], - direction: "vertical", - gutterSize: 4, - minSize: [150,20,50], - }); - - for( var n=0; nDon\'t echo prompts to the main text area', - '
', - '', - '
', - '
', - '', - '
', - '', - '
', - ].join("\n"); - - // Create a new options Dialog - plugins['popups'].createDialog( 'optionsdialog', 'Options', content ); - } - - // - // addHelpUI - var addHelpUI = function () { - // Create a new Help Dialog - plugins['popups'].createDialog( 'helpdialog', 'Help', "" ); - } - - // addToolbarButton - var addToolbarButton = function () { - var optionsbutton = $( [ - '', - ].join("") ); - $('#toolbar').append( optionsbutton ); - } - - // - // Opens the options dialog - var doOpenOptions = function () { - if (!Evennia.isConnected()) { - alert("You need to be connected."); - return; - } - - plugins['popups'].togglePopup("#optionsdialog"); - } - - // - // When the user changes a setting from the interface - var onOptionCheckboxChanged = function () { - var name = $(this).data("setting"); - var value = this.checked; - - var changedoptions = {}; - changedoptions[name] = value; - Evennia.msg("webclient_options", [], changedoptions); - - options[name] = value; - } - - // Public functions - - // - // onKeydown check for 'ESC' key. - var onKeydown = function (event) { - var code = event.which; - - if (code === 27) { // Escape key - if ($('#helpdialog').is(':visible')) { - plugins['popups'].closePopup("#helpdialog"); - return true; - } - if ($('#optionsdialog').is(':visible')) { - plugins['popups'].closePopup("#optionsdialog"); - return true; - } - } - return false; - } - - // - // Called when options settings are sent from server - var onGotOptions = function (args, kwargs) { - options = kwargs; - - $.each(kwargs, function(key, value) { - var elem = $("[data-setting='" + key + "']"); - if (elem.length === 0) { - console.log("Could not find option: " + key); - console.log(args); - console.log(kwargs); - } else { - elem.prop('checked', value); - }; - }); - } - - // - // Called when the user logged in - var onLoggedIn = function (args, kwargs) { - $('#optionsbutton').removeClass('hidden'); - Evennia.msg("webclient_options", [], {}); - } - - // - // Display a "prompt" command from the server - var onPrompt = function (args, kwargs) { - // also display the prompt in the output window if gagging is disabled - if (("gagprompt" in options) && (!options["gagprompt"])) { - plugin_handler.onText(args, kwargs); - } - - // don't claim this Prompt as completed. - return false; - } - - // - // Make sure to close any dialogs on connection lost - var onConnectionClose = function () { - $('#optionsbutton').addClass('hidden'); - plugins['popups'].closePopup("#optionsdialog"); - plugins['popups'].closePopup("#helpdialog"); - } - - // - // Make sure to close any dialogs on connection lost - var onText = function (args, kwargs) { - // is helppopup set? and if so, does this Text have type 'help'? - if ('helppopup' in options && options['helppopup'] ) { - if (kwargs && ('type' in kwargs) && (kwargs['type'] == 'help') ) { - $('#helpdialogcontent').prepend('
'+ args + '
'); - plugins['popups'].togglePopup("#helpdialog"); - return true; - } - } - - return false; - } - - // - // Register and init plugin - var init = function () { - // Add GUI components - addOptionsUI(); - addHelpUI(); - - // Add Options toolbar button. - addToolbarButton(); - - // Pressing the settings button - $("#optionsbutton").bind("click", doOpenOptions); - - // Checking a checkbox in the settings dialog - $("[data-setting]").bind("change", onOptionCheckboxChanged); - - console.log('Options Plugin Initialized.'); - } - - return { - init: init, - onKeydown: onKeydown, - onLoggedIn: onLoggedIn, - onGotOptions: onGotOptions, - onPrompt: onPrompt, - onConnectionClose: onConnectionClose, - onText: onText, - } -})() -plugin_handler.add('options', options_plugin); diff --git a/evennia/web/webclient/static/webclient/js/plugins/options2.js b/evennia/web/webclient/static/webclient/js/plugins/options2.js index 2e5ff4a410..14063c7c85 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/options2.js +++ b/evennia/web/webclient/static/webclient/js/plugins/options2.js @@ -4,7 +4,7 @@ */ let options2 = (function () { - var options_container = null ; + var optionsContainer = null ; // // When the user changes a setting from the interface @@ -51,35 +51,6 @@ let options2 = (function () { } - // - // Create and register the "options" golden-layout component - var createOptionsComponent = function () { - var myLayout = window.plugins["goldenlayout"].getGL(); - - myLayout.registerComponent( "options", function (container, componentState) { - var plugins = window.plugins; - options_container = container.getElement(); - - // build the buttons - var div = $("
"); - - for( let plugin in plugins ) { - if( "onOptionsUI" in plugins[plugin] ) { - var card = $("
"); - var body = $("
"); - - plugins[plugin].onOptionsUI( body ); - - card.append(body); - card.appendTo( div ); - } - } - - div.appendTo( options_container ); - }); - } - - // handler for the "Options" button var onOpenCloseOptions = function () { var optionsComponent = { @@ -92,7 +63,7 @@ let options2 = (function () { // Create a new GoldenLayout tab filled with the optionsComponent above var myLayout = window.plugins["goldenlayout"].getGL(); - if( ! options_container ) { + if( ! optionsContainer ) { // open new optionsComponent var main = myLayout.root.getItemsByType("stack")[0].getActiveContentItem(); @@ -102,16 +73,16 @@ let options2 = (function () { .closeElement .off("click") .click( function () { - options_container = null; + optionsContainer = null; tab.contentItem.remove(); }); - options_container = tab.contentItem; + optionsContainer = tab.contentItem; } }); main.parent.addChild( optionsComponent ); } else { - options_container.remove(); - options_container = null; + optionsContainer.remove(); + optionsContainer = null; } } @@ -132,6 +103,34 @@ let options2 = (function () { }); } + // + // Create and register the "options" golden-layout component + var onLayoutChanged = function () { + var myLayout = window.plugins["goldenlayout"].getGL(); + + myLayout.registerComponent( "options", function (container, componentState) { + var plugins = window.plugins; + optionsContainer = container.getElement(); + + // build the buttons + var div = $("
"); + + for( let plugin in plugins ) { + if( "onOptionsUI" in plugins[plugin] ) { + var card = $("
"); + var body = $("
"); + + plugins[plugin].onOptionsUI( body ); + + card.append(body); + card.appendTo( div ); + } + } + + div.appendTo( optionsContainer ); + }); + } + // // Called when the user logged in var onLoggedIn = function (args, kwargs) { @@ -165,7 +164,7 @@ let options2 = (function () { var postInit = function() { // Are we using GoldenLayout? if( window.plugins["goldenlayout"] ) { - createOptionsComponent(); + onLayoutChanged(); $("#optionsbutton").bind("click", onOpenCloseOptions); } @@ -176,6 +175,7 @@ let options2 = (function () { init: init, postInit: postInit, onGotOptions: onGotOptions, + onLayoutChanged: onLayoutChanged, onLoggedIn: onLoggedIn, onOptionsUI: onOptionsUI, onPrompt: onPrompt, From 7755777f322c703f140718000c21a973e744ce17 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Sun, 11 Oct 2020 21:30:34 -0400 Subject: [PATCH 02/10] Add settings pane Options and improved focus handling --- .../static/webclient/js/plugins/default_in.js | 33 ++- .../webclient/js/plugins/goldenlayout.js | 204 ++++++++++++------ .../webclient/js/plugins/message_routing.js | 15 +- .../static/webclient/js/plugins/options2.js | 3 + 4 files changed, 170 insertions(+), 85 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/default_in.js b/evennia/web/webclient/static/webclient/js/plugins/default_in.js index 044e4e7ec8..d5996685cb 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/default_in.js +++ b/evennia/web/webclient/static/webclient/js/plugins/default_in.js @@ -3,7 +3,9 @@ * Evennia Webclient default "send-text-on-enter-key" IO plugin * */ -let defaultin_plugin = (function () { +let defaultInPlugin = (function () { + + var focusOnKeydown = true; // // handle the default key triggering onSend() @@ -50,14 +52,17 @@ let defaultin_plugin = (function () { // Anything else, focus() a textarea if needed, and allow the default event default: - // is an inputfield actually focused? - if( inputfield.length < 1 ) { - // Nope, focus the last .inputfield found in the DOM (or #inputfield) - // :last only matters if multi-input plugins are in use - inputfield = $(".inputfield:last"); - inputfield.focus(); - if( inputfield.length < 1 ) { // non-goldenlayout backwards compatibility - $("#inputfield").focus(); + // has some other UI element turned off this behavior temporarily? + if( focusOnKeydown ) { + // is an inputfield actually focused? + if( inputfield.length < 1 ) { + // Nope, focus the last .inputfield found in the DOM (or #inputfield) + // :last only matters if multi-input plugins are in use + inputfield = $(".inputfield:last"); + inputfield.focus(); + if( inputfield.length < 1 ) { // non-goldenlayout backwards compatibility + $("#inputfield").focus(); + } } } } @@ -65,6 +70,13 @@ let defaultin_plugin = (function () { return true; } + // + // allow other UI elements to toggle this focus behavior on/off + var setKeydownFocus = function (bool) { + console.log("Focus = " + bool); + focusOnKeydown = bool; + } + // // Mandatory plugin init function var init = function () { @@ -81,6 +93,7 @@ let defaultin_plugin = (function () { return { init: init, onKeydown: onKeydown, + setKeydownFocus: setKeydownFocus, } })(); -window.plugin_handler.add("defaultin", defaultin_plugin); +window.plugin_handler.add("default_in", defaultInPlugin); diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index 4e21265f42..29dd136b77 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -5,7 +5,11 @@ */ let goldenlayout = (function () { - var myLayout; + var myLayout; // The actively used GoldenLayout API object. + + var evenniaGoldenLayouts = {}; // key/value storage Object for each selectable layout. + var activeLayoutName = "default"; // The object key of the active evenniaGoldenLayout + var knownTypes = ["all", "untagged", "testing"]; var untagged = []; @@ -80,6 +84,7 @@ let goldenlayout = (function () { myLayout.emit("stateChanged"); $("#renamebox").remove(); + window.plugins["default_in"].setKeydownFocus(true); } @@ -137,6 +142,7 @@ let goldenlayout = (function () { renamebox = $("
"); renamebox.append(""); renamebox.insertBefore( content ); + window.plugins["default_in"].setKeydownFocus(false); } else { closeRenameDropdown(); } @@ -262,6 +268,94 @@ let goldenlayout = (function () { } + // + // + var resetUI = function (newLayout) { + var mainsub = document.getElementById("main-sub"); + + // rebuild the original HTML stacking + var messageDiv = $("#messagewindow").detach(); + messageDiv.prependTo( mainsub ); + + // out with the old + myLayout.destroy(); + + // in with the new + myLayout = new GoldenLayout( newLayout, mainsub ); + + // re-register our main, input and generic evennia components. + registerComponents( myLayout ); + + // call all other plugins to give them a chance to registerComponents. + for( let plugin in window.plugins ) { + if( "onLayoutChanged" in window.plugins[plugin] ) { + window.plugins[plugin].onLayoutChanged(); + } + } + + // finish the setup and actually start GoldenLayout + myLayout.init(); + + // work out which types are untagged based on our pre-configured layout + calculateUntaggedTypes(); + + // Set the Event handler for when the client window changes size + $(window).bind("resize", scrollAll); + + // Set Save State callback + myLayout.on( "stateChanged", onStateChanged ); + } + + + // + // + var onSwitchLayout = function (evnt) { + // get the new layout name from the select box + var name = $('#layoutInput').val(); + + // check to see if the layout is in the list of known layouts + if( name in evenniaGoldenLayouts ) { + console.log( evenniaGoldenLayouts ); + + var newLayout = evenniaGoldenLayouts[name]; + activeLayoutName = name; + + // pull the trigger + resetUI( newLayout ); + } + } + + + // + // + var onSaveLayout = function (evnt) { + // get the name from the select box + var name = $('#layoutName').val(); + var input = $('#layoutInput'); + + if( name === "" ) { return; } // Can't save without a valid name + + // Is this name new or pre-existing? + if( !(name in evenniaGoldenLayouts) ) { + // add the new evenniaGoldenLayout to the listed dropdown options + var option = $(''); + input.append(option); + } + + // store the current layout to the local list of layouts + evenniaGoldenLayouts[ name ] = myLayout.toConfig(); + activeLayoutName = name; + + // upload it to the server + if( Evennia.isConnected() && myLayout.isInitialised ) { + window.options["webclientActiveLayout"] = name; + window.options["webclientLayouts"] = JSON.stringify( evenniaGoldenLayouts ); + console.log("Saving layout to server..."); + Evennia.msg("webclient_options", [], window.options); + } + } + + // // Save the GoldenLayout state to localstorage whenever it changes. var onStateChanged = function () { @@ -275,18 +369,9 @@ let goldenlayout = (function () { component.container.extendState({ "types": types, "updateMethod": updateMethod }); }); - // update the layout options when the stat changes from our previous stored state. - var state = JSON.stringify( myLayout.toConfig() ); - - if( state !== window.options["webclientLayout"] ) { - localStorage.setItem( "evenniaGoldenLayoutSavedState", state ); - - // Also update the server-side options, if the connection is ready to go. - if( Evennia.isConnected() && myLayout.isInitialised ) { - window.options["webclientLayout"] = state; - Evennia.msg("webclient_options", [], window.options); - } - } + // update localstorage + localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify(myLayout.toConfig()) ); + localStorage.getItem( "evenniaGoldenLayoutSavedStateName", JSON.stringify( activeLayoutName ) ); } @@ -418,6 +503,7 @@ let goldenlayout = (function () { }); } + // // Public // @@ -431,17 +517,6 @@ let goldenlayout = (function () { } - // - // - var onKeydown = function(evnt) { - var renamebox = document.getElementById("renamebox"); - if( renamebox ) { - return true; - } - return false; - } - - // // Add new HTML message to an existing Div pane, while // honoring the pane's updateMethod and scroll state, etc. @@ -524,45 +599,42 @@ let goldenlayout = (function () { // var onGotOptions = function (args, kwargs) { // Reset the UI if the JSON layout sent from the server doesn't match the client's current JSON - if( ("webclientLayout" in kwargs) && (kwargs["webclientLayout"] !== window.options["webclientLayout"]) ) { - var mainsub = document.getElementById("main-sub"); + if( "webclientLayouts" in kwargs ) { + console.log("Got evennia GoldenLayouts"); - // rebuild the original HTML stacking - var messageDiv = $("#messagewindow").detach(); - messageDiv.prependTo( mainsub ); - - // out with the old - myLayout.destroy(); - - // in with the new - myLayout = new GoldenLayout( JSON.parse( kwargs["webclientLayout"] ), mainsub ); - - // re-register our main, input and generic evennia components. - registerComponents( myLayout ); - - // call all other plugins to give them a chance to registerComponents. - for( let plugin in window.plugins ) { - if( "onLayoutChange" in window.plugins[plugin] ) { - window.plugins[plugin].onLayoutChange(); - } - } - - // finish the setup and actually start GoldenLayout - myLayout.init(); - - // work out which types are untagged based on our pre-configured layout - calculateUntaggedTypes(); - - // Set the Event handler for when the client window changes size - $(window).bind("resize", scrollAll); - - // Set Save State callback - myLayout.on( "stateChanged", onStateChanged ); - - return true; + evenniaGoldenLayouts = JSON.parse( kwargs["webclientLayouts"] ); } } + + // + // + var onOptionsUI = function (parentdiv) { + var layoutInput = $(''); + var saveButton = $(''); + + var layouts = Object.keys( evenniaGoldenLayouts ); + for (var x = 0; x < layouts.length; x++) { + var option = $(''); + layoutInput.append(option); + } + + layoutInput.val( activeLayoutName ); // current selection + layoutName.val( activeLayoutName ); + + // Layout selection on-change callback + layoutInput.on('change', onSwitchLayout); + saveButton.on('click', onSaveLayout); + + // add the selection dialog control to our parentdiv + parentdiv.append('
UI Layout Selection (This list may be longer after login):
'); + parentdiv.append(layoutInput); + parentdiv.append(layoutName); + parentdiv.append(saveButton); + } + + // // var onText = function (args, kwargs) { @@ -603,16 +675,24 @@ let goldenlayout = (function () { var init = function (options) { // Set up our GoldenLayout instance built off of the default main-sub div var savedState = localStorage.getItem( "evenniaGoldenLayoutSavedState" ); + var activeName = localStorage.getItem( "evenniaGoldenLayoutSavedStateName" ); var mainsub = document.getElementById("main-sub"); + // pre-load the evenniaGoldenLayouts with the hard-coded default + evenniaGoldenLayouts[ "default" ] = window.goldenlayout_config; + + if( activeName !== null ) { + activeLayoutName = activeName; + } + if( savedState !== null ) { // Overwrite the global-variable configuration from // webclient/js/plugins/goldenlayout_default_config.js // with the version from localstorage - window.goldenlayout_config = JSON.parse( savedState ); + evenniaGoldenLayouts[ activeLayoutName ] = JSON.parse( savedState ); } - myLayout = new GoldenLayout( window.goldenlayout_config, mainsub ); + myLayout = new GoldenLayout( evenniaGoldenLayouts[activeLayoutName], mainsub ); $("#prompt").remove(); // remove the HTML-defined prompt div $("#inputcontrol").remove(); // remove the cluttered, HTML-defined input divs @@ -623,8 +703,8 @@ let goldenlayout = (function () { return { init: init, postInit: postInit, - onKeydown: onKeydown, onGotOptions: onGotOptions, + onOptionsUI: onOptionsUI, onText: onText, getGL: function () { return myLayout; }, addKnownType: addKnownType, diff --git a/evennia/web/webclient/static/webclient/js/plugins/message_routing.js b/evennia/web/webclient/static/webclient/js/plugins/message_routing.js index 1279126b39..e051c12fae 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/message_routing.js +++ b/evennia/web/webclient/static/webclient/js/plugins/message_routing.js @@ -4,8 +4,6 @@ */ let spawns = (function () { - var ignoreDefaultKeydown = false; - var spawnmap = {}; // { id1: { r:regex, t:tag } } pseudo-array of regex-tag pairs // @@ -42,12 +40,12 @@ let spawns = (function () { // var onFocusIn = function (evnt) { - ignoreDefaultKeydown = true; + window.plugins["default_in"].setKeydownFocus(false); } // var onFocusOut = function (evnt) { - ignoreDefaultKeydown = false; + window.plugins["default_in"].setKeydownFocus(true); onAlterTag(evnt); // percolate event so closing the pane, etc saves any last changes. } @@ -121,14 +119,6 @@ let spawns = (function () { } - // - // OnKeydown -- if the Options window is open, capture focus - // - var onKeydown = function(evnt) { - return ignoreDefaultKeydown; - } - - // // init // @@ -148,7 +138,6 @@ let spawns = (function () { init: init, onOptionsUI: onOptionsUI, onText: onText, - onKeydown: onKeydown, } })(); window.plugin_handler.add("spawns", spawns); diff --git a/evennia/web/webclient/static/webclient/js/plugins/options2.js b/evennia/web/webclient/static/webclient/js/plugins/options2.js index 14063c7c85..01eba285c8 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/options2.js +++ b/evennia/web/webclient/static/webclient/js/plugins/options2.js @@ -75,11 +75,14 @@ let options2 = (function () { .click( function () { optionsContainer = null; tab.contentItem.remove(); + window.plugins["default_in"].setKeydownFocus(true); }); optionsContainer = tab.contentItem; } }); main.parent.addChild( optionsComponent ); + + window.plugins["default_in"].setKeydownFocus(false); } else { optionsContainer.remove(); optionsContainer = null; From 4c77211fa3744213ac62a008ef0b37e38a896d04 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Sun, 11 Oct 2020 22:20:09 -0400 Subject: [PATCH 03/10] persist font settings to localstorage --- .../static/webclient/js/plugins/font.js | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/font.js b/evennia/web/webclient/static/webclient/js/plugins/font.js index cf940fab40..9b691f6f66 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/font.js +++ b/evennia/web/webclient/static/webclient/js/plugins/font.js @@ -21,6 +21,8 @@ let font_plugin = (function () { // // var onOptionsUI = function (parentdiv) { + var fontfamily = localStorage.getItem('evenniaFontFamily'); + var fontsize = localStorage.getItem('evenniaFontSize'); var fontselect = $(''); @@ -36,17 +38,27 @@ let font_plugin = (function () { sizeselect.append(option); } - fontselect.val('DejaVu Sans Mono'); // default value - sizeselect.val('0.9'); // default scaling factor + if( fontfamily != null ) { + fontselect.val( fontfamily ); + } else { + fontselect.val('DejaVu Sans Mono'); // default value + } - // font-family change callback + if( fontsize != null ) { + sizeselect.val( fontsize ); + } else { + sizeselect.val('0.9'); // default scaling factor + } + + // font change callbacks fontselect.on('change', function () { $(document.body).css('font-family', $(this).val()); + localStorage.setItem('evenniaFontFamily', $(this).val() ); }); - - // font size change callback + sizeselect.on('change', function () { $(document.body).css('font-size', $(this).val()+"em"); + localStorage.setItem('evenniaFontSize', $(this).val() ); }); // add the font selection dialog control to our parentdiv @@ -59,6 +71,8 @@ let font_plugin = (function () { // Font plugin init function (adds the urls for the webfonts to the page) // var init = function () { + var fontfamily = localStorage.getItem('evenniaFontFamily'); + var fontsize = localStorage.getItem('evenniaFontSize'); var head = $(document.head); var fonts = Object.keys(font_urls); @@ -69,6 +83,14 @@ let font_plugin = (function () { head.append( link ); } } + + if( !fontfamily ) { + $(document.body).css('font-family', fontfamily); + } + + if( !fontsize ) { + $(document.body).css('font-size', fontsize+"em"); + } } return { From 5047fd0b41fe7dee025470def550da2082b5661e Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Mon, 12 Oct 2020 00:06:44 -0400 Subject: [PATCH 04/10] Codacy updates --- .../static/webclient/js/plugins/default_in.js | 1 - .../static/webclient/js/plugins/font.js | 99 +++++++----- .../webclient/js/plugins/goldenlayout.js | 146 +++++++++--------- .../static/webclient/js/plugins/hotbuttons.js | 2 +- 4 files changed, 133 insertions(+), 115 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/default_in.js b/evennia/web/webclient/static/webclient/js/plugins/default_in.js index d5996685cb..51b200f707 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/default_in.js +++ b/evennia/web/webclient/static/webclient/js/plugins/default_in.js @@ -73,7 +73,6 @@ let defaultInPlugin = (function () { // // allow other UI elements to toggle this focus behavior on/off var setKeydownFocus = function (bool) { - console.log("Focus = " + bool); focusOnKeydown = bool; } diff --git a/evennia/web/webclient/static/webclient/js/plugins/font.js b/evennia/web/webclient/static/webclient/js/plugins/font.js index 9b691f6f66..82008b4930 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/font.js +++ b/evennia/web/webclient/static/webclient/js/plugins/font.js @@ -18,51 +18,84 @@ let font_plugin = (function () { }; // + // + var setStartingFont = function () { + var fontfamily = localStorage.getItem("evenniaFontFamily"); + if( !fontfamily ) { + $(document.body).css("font-family", fontfamily); + } + + var fontsize = localStorage.getItem("evenniaFontSize"); + if( !fontsize ) { + $(document.body).css("font-size", fontsize+"em"); + } + } + + // + // + var getActiveFontFamily = function () { + var family = "DejaVu Sans Mono"; + var fontfamily = localStorage.getItem("evenniaFontFamily"); + if( fontfamily != null ) { + family = fontfamily; + } + return family; + } + + // + // + var getActiveFontSize = function () { + var size = "0.9"; + var fontsize = localStorage.getItem("evenniaFontSize"); + if( fontsize != null ) { + size = fontsize; + } + return size; + } + + // + // + var onFontFamily = function (evnt) { + var family = $(evnt.target).val(); + $(document.body).css('font-family', family); + localStorage.setItem('evenniaFontFamily', family); + } + + // + // + var onFontSize = function (evnt) { + var size = $(evnt.target).val(); + $(document.body).css("font-size", size+"em"); + localStorage.setItem("evenniaFontSize", size); + } + // // var onOptionsUI = function (parentdiv) { - var fontfamily = localStorage.getItem('evenniaFontFamily'); - var fontsize = localStorage.getItem('evenniaFontSize'); - var fontselect = $(''); + var fontselect = $(""); var fonts = Object.keys(font_urls); for (var x = 0; x < fonts.length; x++) { - var option = $(''); + var option = $(""); fontselect.append(option); } for (var x = 4; x < 21; x++) { var val = (x/10.0); - var option = $(''); + var option = $(""); sizeselect.append(option); } - if( fontfamily != null ) { - fontselect.val( fontfamily ); - } else { - fontselect.val('DejaVu Sans Mono'); // default value - } - - if( fontsize != null ) { - sizeselect.val( fontsize ); - } else { - sizeselect.val('0.9'); // default scaling factor - } + fontselect.val( getActiveFontFamily() ); + sizeselect.val( getActiveFontSize() ); // font change callbacks - fontselect.on('change', function () { - $(document.body).css('font-family', $(this).val()); - localStorage.setItem('evenniaFontFamily', $(this).val() ); - }); - - sizeselect.on('change', function () { - $(document.body).css('font-size', $(this).val()+"em"); - localStorage.setItem('evenniaFontSize', $(this).val() ); - }); + fontselect.on("change", onFontFamily); + sizeselect.on("change", onFontSize); // add the font selection dialog control to our parentdiv - parentdiv.append('
Font Selection:
'); + parentdiv.append("
Font Selection:
"); parentdiv.append(fontselect); parentdiv.append(sizeselect); } @@ -71,26 +104,18 @@ let font_plugin = (function () { // Font plugin init function (adds the urls for the webfonts to the page) // var init = function () { - var fontfamily = localStorage.getItem('evenniaFontFamily'); - var fontsize = localStorage.getItem('evenniaFontSize'); var head = $(document.head); var fonts = Object.keys(font_urls); for (var x = 0; x < fonts.length; x++) { if ( fonts[x] != "Monospace" ) { var url = font_urls[ fonts[x] ]; - var link = $(''); + var link = $(""); head.append( link ); } } - if( !fontfamily ) { - $(document.body).css('font-family', fontfamily); - } - - if( !fontsize ) { - $(document.body).css('font-size', fontsize+"em"); - } + setStartingFont(); } return { diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index 29dd136b77..d0037f27d5 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -267,56 +267,14 @@ let goldenlayout = (function () { } } - - // - // - var resetUI = function (newLayout) { - var mainsub = document.getElementById("main-sub"); - - // rebuild the original HTML stacking - var messageDiv = $("#messagewindow").detach(); - messageDiv.prependTo( mainsub ); - - // out with the old - myLayout.destroy(); - - // in with the new - myLayout = new GoldenLayout( newLayout, mainsub ); - - // re-register our main, input and generic evennia components. - registerComponents( myLayout ); - - // call all other plugins to give them a chance to registerComponents. - for( let plugin in window.plugins ) { - if( "onLayoutChanged" in window.plugins[plugin] ) { - window.plugins[plugin].onLayoutChanged(); - } - } - - // finish the setup and actually start GoldenLayout - myLayout.init(); - - // work out which types are untagged based on our pre-configured layout - calculateUntaggedTypes(); - - // Set the Event handler for when the client window changes size - $(window).bind("resize", scrollAll); - - // Set Save State callback - myLayout.on( "stateChanged", onStateChanged ); - } - - // // var onSwitchLayout = function (evnt) { // get the new layout name from the select box - var name = $('#layoutInput').val(); + var name = $("#layoutInput").val(); // check to see if the layout is in the list of known layouts if( name in evenniaGoldenLayouts ) { - console.log( evenniaGoldenLayouts ); - var newLayout = evenniaGoldenLayouts[name]; activeLayoutName = name; @@ -330,28 +288,27 @@ let goldenlayout = (function () { // var onSaveLayout = function (evnt) { // get the name from the select box - var name = $('#layoutName').val(); - var input = $('#layoutInput'); + var name = $("#layoutName").val(); + var input = $("#layoutInput"); if( name === "" ) { return; } // Can't save without a valid name // Is this name new or pre-existing? if( !(name in evenniaGoldenLayouts) ) { // add the new evenniaGoldenLayout to the listed dropdown options - var option = $(''); + var option = $(""); input.append(option); } // store the current layout to the local list of layouts - evenniaGoldenLayouts[ name ] = myLayout.toConfig(); + Object.assign( evenniaGoldenLayouts, { [name] : myLayout.toConfig() }); activeLayoutName = name; // upload it to the server - if( Evennia.isConnected() && myLayout.isInitialised ) { + if( window.Evennia.isConnected() && myLayout.isInitialised ) { window.options["webclientActiveLayout"] = name; window.options["webclientLayouts"] = JSON.stringify( evenniaGoldenLayouts ); - console.log("Saving layout to server..."); - Evennia.msg("webclient_options", [], window.options); + window.Evennia.msg("webclient_options", [], window.options); } } @@ -426,22 +383,6 @@ let goldenlayout = (function () { tab.header.parent.on( "activeContentItemChanged", onActiveTabChange ); } - // - // - var scrollAll = function () { - let components = myLayout.root.getItemsByType("component"); - components.forEach( function (component) { - if( component.hasId("inputComponent") ) { return; } // ignore input components - - let textDiv = component.container.getElement().children(".content"); - let scrollHeight = textDiv.prop("scrollHeight"); - let clientHeight = textDiv.prop("clientHeight"); - textDiv.scrollTop( scrollHeight - clientHeight ); - }); - myLayout.updateSize(); - } - - // // var initComponent = function (div, container, state, defaultTypes, updateMethod) { @@ -504,6 +445,61 @@ let goldenlayout = (function () { } + // + // + var scrollAll = function () { + let components = myLayout.root.getItemsByType("component"); + components.forEach( function (component) { + if( component.hasId("inputComponent") ) { return; } // ignore input components + + let textDiv = component.container.getElement().children(".content"); + let scrollHeight = textDiv.prop("scrollHeight"); + let clientHeight = textDiv.prop("clientHeight"); + textDiv.scrollTop( scrollHeight - clientHeight ); + }); + myLayout.updateSize(); + } + + + // + // + var resetUI = function (newLayout) { + var mainsub = document.getElementById("main-sub"); + + // rebuild the original HTML stacking + var messageDiv = $("#messagewindow").detach(); + messageDiv.prependTo( mainsub ); + + // out with the old + myLayout.destroy(); + + // in with the new + myLayout = new window.GoldenLayout( newLayout, mainsub ); + + // re-register our main, input and generic evennia components. + registerComponents( myLayout ); + + // call all other plugins to give them a chance to registerComponents. + for( let plugin in window.plugins ) { + if( "onLayoutChanged" in window.plugins[plugin] ) { + window.plugins[plugin].onLayoutChanged(); + } + } + + // finish the setup and actually start GoldenLayout + myLayout.init(); + + // work out which types are untagged based on our pre-configured layout + calculateUntaggedTypes(); + + // Set the Event handler for when the client window changes size + $(window).bind("resize", scrollAll); + + // Set Save State callback + myLayout.on( "stateChanged", onStateChanged ); + } + + // // Public // @@ -600,8 +596,6 @@ let goldenlayout = (function () { var onGotOptions = function (args, kwargs) { // Reset the UI if the JSON layout sent from the server doesn't match the client's current JSON if( "webclientLayouts" in kwargs ) { - console.log("Got evennia GoldenLayouts"); - evenniaGoldenLayouts = JSON.parse( kwargs["webclientLayouts"] ); } } @@ -610,13 +604,13 @@ let goldenlayout = (function () { // // var onOptionsUI = function (parentdiv) { - var layoutInput = $(''); - var saveButton = $(''); + var layoutInput = $(""); + var saveButton = $(""); var layouts = Object.keys( evenniaGoldenLayouts ); for (var x = 0; x < layouts.length; x++) { - var option = $(''); + var option = $(""); layoutInput.append(option); } @@ -628,7 +622,7 @@ let goldenlayout = (function () { saveButton.on('click', onSaveLayout); // add the selection dialog control to our parentdiv - parentdiv.append('
UI Layout Selection (This list may be longer after login):
'); + parentdiv.append("
UI Layout Selection (This list may be longer after login):
"); parentdiv.append(layoutInput); parentdiv.append(layoutName); parentdiv.append(saveButton); @@ -679,7 +673,7 @@ let goldenlayout = (function () { var mainsub = document.getElementById("main-sub"); // pre-load the evenniaGoldenLayouts with the hard-coded default - evenniaGoldenLayouts[ "default" ] = window.goldenlayout_config; + Object.assign( evenniaGoldenLayouts, { "default" : window.goldenlayout_config } ); if( activeName !== null ) { activeLayoutName = activeName; @@ -689,10 +683,10 @@ let goldenlayout = (function () { // Overwrite the global-variable configuration from // webclient/js/plugins/goldenlayout_default_config.js // with the version from localstorage - evenniaGoldenLayouts[ activeLayoutName ] = JSON.parse( savedState ); + Object.assign( evenniaGoldenLayouts, { activeLayoutName : JSON.parse(savedState) } ); } - myLayout = new GoldenLayout( evenniaGoldenLayouts[activeLayoutName], mainsub ); + myLayout = new window.GoldenLayout( evenniaGoldenLayouts[activeLayoutName], mainsub ); $("#prompt").remove(); // remove the HTML-defined prompt div $("#inputcontrol").remove(); // remove the cluttered, HTML-defined input divs diff --git a/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js b/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js index 6b7af9b2af..c486663aea 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js +++ b/evennia/web/webclient/static/webclient/js/plugins/hotbuttons.js @@ -144,7 +144,7 @@ let hotbuttons = (function () { } return { - init: function() {}, + init: function() {}, postInit: postInit, onGotOptions: onGotOptions, onLayoutChanged: onLayoutChanged, From 37884c9abcd7a62c0cdc983764a93cc5b0da4441 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Mon, 12 Oct 2020 08:54:23 -0400 Subject: [PATCH 05/10] Add a clear layout button to the webclient --- .../static/webclient/js/plugins/goldenlayout.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index d0037f27d5..e141b47b96 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -267,6 +267,17 @@ let goldenlayout = (function () { } } + + // + // + var onClearLocalstorage = function (evnt) { + myLayout.off( "stateChanged", onStateChanged ); + localStorage.removeItem( "evenniaGoldenLayoutSavedState" ); + localStorage.removeItem( "evenniaGoldenLayoutSavedStateName" ); + location.reload(); + } + + // // var onSwitchLayout = function (evnt) { @@ -328,7 +339,7 @@ let goldenlayout = (function () { // update localstorage localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify(myLayout.toConfig()) ); - localStorage.getItem( "evenniaGoldenLayoutSavedStateName", JSON.stringify( activeLayoutName ) ); + localStorage.setItem( "evenniaGoldenLayoutSavedStateName", JSON.stringify( activeLayoutName ) ); } @@ -607,6 +618,7 @@ let goldenlayout = (function () { var layoutInput = $(""); var saveButton = $(""); + var clearButton = $(""); var layouts = Object.keys( evenniaGoldenLayouts ); for (var x = 0; x < layouts.length; x++) { @@ -620,12 +632,15 @@ let goldenlayout = (function () { // Layout selection on-change callback layoutInput.on('change', onSwitchLayout); saveButton.on('click', onSaveLayout); + clearButton.on('click', onClearLocalstorage); // add the selection dialog control to our parentdiv + parentdiv.addClass("goldenlayout-ui"); parentdiv.append("
UI Layout Selection (This list may be longer after login):
"); parentdiv.append(layoutInput); parentdiv.append(layoutName); parentdiv.append(saveButton); + parentdiv.append(clearButton); } From d09575980c0cb9aa9a0d2e19f8b7fa03a01f11f1 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Mon, 12 Oct 2020 15:36:47 -0400 Subject: [PATCH 06/10] Hack in default-modified layout type --- .../web/webclient/static/webclient/js/plugins/goldenlayout.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index e141b47b96..0d80f33595 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -8,7 +8,7 @@ let goldenlayout = (function () { var myLayout; // The actively used GoldenLayout API object. var evenniaGoldenLayouts = {}; // key/value storage Object for each selectable layout. - var activeLayoutName = "default"; // The object key of the active evenniaGoldenLayout + var activeLayoutName = "default-modified"; // The object key of the active evenniaGoldenLayout var knownTypes = ["all", "untagged", "testing"]; var untagged = []; @@ -689,6 +689,7 @@ let goldenlayout = (function () { // pre-load the evenniaGoldenLayouts with the hard-coded default Object.assign( evenniaGoldenLayouts, { "default" : window.goldenlayout_config } ); + Object.assign( evenniaGoldenLayouts, { "default-modified" : window.goldenlayout_config } ); if( activeName !== null ) { activeLayoutName = activeName; From d1799badeac50591e9ace0911d5a1ef4162d04a0 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Mon, 12 Oct 2020 15:54:54 -0400 Subject: [PATCH 07/10] Grey out the save to default button and remove the Clear Layout button --- .../static/webclient/js/plugins/goldenlayout.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index 0d80f33595..e0122951bb 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -284,11 +284,19 @@ let goldenlayout = (function () { // get the new layout name from the select box var name = $("#layoutInput").val(); + var saveButton = $(".savelayout"); + // check to see if the layout is in the list of known layouts if( name in evenniaGoldenLayouts ) { var newLayout = evenniaGoldenLayouts[name]; activeLayoutName = name; + if( activeLayoutName === "default" ) { + saveButton.prop( "disabled", true ); + } else { + saveButton.prop( "disabled", false ); + } + // pull the trigger resetUI( newLayout ); } @@ -618,7 +626,10 @@ let goldenlayout = (function () { var layoutInput = $(""); var saveButton = $(""); - var clearButton = $(""); + + if( activeLayoutName === "default" ) { + saveButton.prop( "disabled", true ); + } var layouts = Object.keys( evenniaGoldenLayouts ); for (var x = 0; x < layouts.length; x++) { @@ -632,7 +643,6 @@ let goldenlayout = (function () { // Layout selection on-change callback layoutInput.on('change', onSwitchLayout); saveButton.on('click', onSaveLayout); - clearButton.on('click', onClearLocalstorage); // add the selection dialog control to our parentdiv parentdiv.addClass("goldenlayout-ui"); @@ -640,7 +650,6 @@ let goldenlayout = (function () { parentdiv.append(layoutInput); parentdiv.append(layoutName); parentdiv.append(saveButton); - parentdiv.append(clearButton); } From 27345f068b582235dcaede51079047191229e7b8 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Wed, 14 Oct 2020 13:35:03 -0400 Subject: [PATCH 08/10] fix localstorage "blank-page" bug --- .../static/webclient/js/plugins/goldenlayout.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index e0122951bb..13a8adf5cf 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -320,7 +320,7 @@ let goldenlayout = (function () { } // store the current layout to the local list of layouts - Object.assign( evenniaGoldenLayouts, { [name] : myLayout.toConfig() }); + evenniaGoldenLayouts[name] = myLayout.toConfig(); activeLayoutName = name; // upload it to the server @@ -347,7 +347,7 @@ let goldenlayout = (function () { // update localstorage localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify(myLayout.toConfig()) ); - localStorage.setItem( "evenniaGoldenLayoutSavedStateName", JSON.stringify( activeLayoutName ) ); + localStorage.setItem( "evenniaGoldenLayoutSavedStateName", activeLayoutName ); } @@ -708,7 +708,10 @@ let goldenlayout = (function () { // Overwrite the global-variable configuration from // webclient/js/plugins/goldenlayout_default_config.js // with the version from localstorage - Object.assign( evenniaGoldenLayouts, { activeLayoutName : JSON.parse(savedState) } ); + evenniaGoldenLayouts[activeLayoutName] = JSON.parse(savedState); + } else { + localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify( window.goldenlayout_config ) ); + localStorage.setItem( "evenniaGoldenLayoutSavedStateName", "default-modified" ); } myLayout = new window.GoldenLayout( evenniaGoldenLayouts[activeLayoutName], mainsub ); From 12f4bde1a929179ea10faacd770f1982a7b3e885 Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Tue, 27 Oct 2020 20:54:33 -0400 Subject: [PATCH 09/10] Remove -modified behavior in favor of explicit saves --- .../static/webclient/js/plugins/font.js | 12 +- .../webclient/js/plugins/goldenlayout.js | 273 +++++++++++------- .../static/webclient/js/plugins/options2.js | 1 + 3 files changed, 176 insertions(+), 110 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/font.js b/evennia/web/webclient/static/webclient/js/plugins/font.js index 82008b4930..8b2bb80caa 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/font.js +++ b/evennia/web/webclient/static/webclient/js/plugins/font.js @@ -57,8 +57,8 @@ let font_plugin = (function () { // var onFontFamily = function (evnt) { var family = $(evnt.target).val(); - $(document.body).css('font-family', family); - localStorage.setItem('evenniaFontFamily', family); + $(document.body).css("font-family", family); + localStorage.setItem("evenniaFontFamily", family); } // @@ -76,15 +76,13 @@ let font_plugin = (function () { var sizeselect = $(""); + option.on("click", onSwitchLayout); + div.append(option); + + if( name !== "default" && name !== activeLayoutName ) { + var remove = $(""); + remove.on("click", onRemoveLayout); + div.append(remove); + } + + layoutDiv.append(div); + } + + + // + // + var onSaveLayout = function () { + // get the name from the select box + var name = $("#layoutName").val(); + var layouts = $("#goldenlayouts"); + + // make sure we have a valid name + if( name !== "" ) { + // Is this name new or pre-existing? + if( !evenniaGoldenLayouts.has(name) ) { + // this is a new name, so add a new UI item for it. + addLayoutUI( layouts, name ); + } + + // Force Close the Options Menu so that it isn't part of the saved layout. + window.plugins["options2"].onOpenCloseOptions(); + + // store the current layout to the local list of layouts + evenniaGoldenLayouts.set( name, myLayout.toConfig() ); + activeLayoutName = name; + activeLayoutModified = false; + + // store the newly requested layout into localStorage. + localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify( evenniaGoldenLayouts.get(name) ) ); + localStorage.setItem( "evenniaGoldenLayoutSavedStateName", activeLayoutName ); + + // upload it to the server + if( window.Evennia.isConnected() && myLayout.isInitialised ) { + window.options["webclientActiveLayout"] = name; + window.options["webclientLayouts"] = JSON.stringify( evenniaGoldenLayouts ); + window.Evennia.msg("webclient_options", [], window.options); + } + + resetUI( evenniaGoldenLayouts.get(name) ); + } + } + + // // Public // @@ -615,7 +669,11 @@ let goldenlayout = (function () { var onGotOptions = function (args, kwargs) { // Reset the UI if the JSON layout sent from the server doesn't match the client's current JSON if( "webclientLayouts" in kwargs ) { - evenniaGoldenLayouts = JSON.parse( kwargs["webclientLayouts"] ); + let mapping = JSON.parse( kwargs["webclientLayouts"] ); + evenniaGoldenLayouts = new Map(); + for( var layout in mapping ) { + evenniaGoldenLayouts.set( layout, mapping[layout] ); + } } } @@ -623,33 +681,43 @@ let goldenlayout = (function () { // // var onOptionsUI = function (parentdiv) { - var layoutInput = $(""); - var saveButton = $(""); + var layoutName = $(""); + var saveButton = $(""); + var layoutDiv = $("
"); if( activeLayoutName === "default" ) { saveButton.prop( "disabled", true ); } - var layouts = Object.keys( evenniaGoldenLayouts ); - for (var x = 0; x < layouts.length; x++) { - var option = $(""); - layoutInput.append(option); + for (const name of evenniaGoldenLayouts.keys() ) { + addLayoutUI(layoutDiv, name); } - layoutInput.val( activeLayoutName ); // current selection + // currently active layout layoutName.val( activeLayoutName ); + layoutName.on("keydown", function (evnt) { + var name = $(evnt.target).val(); + if( name === "default" || name === "" ) { + saveButton.prop( "disabled", true ); + } else { + saveButton.prop( "disabled", false ); + } + }); // Layout selection on-change callback - layoutInput.on('change', onSwitchLayout); - saveButton.on('click', onSaveLayout); + saveButton.on("click", onSaveLayout); + + var saveDiv = $("
"); + saveDiv.append(layoutName); + saveDiv.append(saveButton); // add the selection dialog control to our parentdiv - parentdiv.addClass("goldenlayout-ui"); - parentdiv.append("
UI Layout Selection (This list may be longer after login):
"); - parentdiv.append(layoutInput); - parentdiv.append(layoutName); - parentdiv.append(saveButton); + parentdiv.addClass("goldenlayout-options-ui"); + parentdiv.append("
GoldenLayout Options:
"); + parentdiv.append("
Activate a new layout:
"); + parentdiv.append(layoutDiv); + parentdiv.append("
Save current layout as (best if used when logged in):
"); + parentdiv.append(saveDiv); } @@ -697,8 +765,7 @@ let goldenlayout = (function () { var mainsub = document.getElementById("main-sub"); // pre-load the evenniaGoldenLayouts with the hard-coded default - Object.assign( evenniaGoldenLayouts, { "default" : window.goldenlayout_config } ); - Object.assign( evenniaGoldenLayouts, { "default-modified" : window.goldenlayout_config } ); + evenniaGoldenLayouts.set( "default", window.goldenlayout_config ); if( activeName !== null ) { activeLayoutName = activeName; @@ -708,13 +775,13 @@ let goldenlayout = (function () { // Overwrite the global-variable configuration from // webclient/js/plugins/goldenlayout_default_config.js // with the version from localstorage - evenniaGoldenLayouts[activeLayoutName] = JSON.parse(savedState); + evenniaGoldenLayouts.set( activeLayoutName, JSON.parse(savedState) ); } else { localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify( window.goldenlayout_config ) ); - localStorage.setItem( "evenniaGoldenLayoutSavedStateName", "default-modified" ); + localStorage.setItem( "evenniaGoldenLayoutSavedStateName", "default" ); } - myLayout = new window.GoldenLayout( evenniaGoldenLayouts[activeLayoutName], mainsub ); + myLayout = new window.GoldenLayout( evenniaGoldenLayouts.get(activeLayoutName), mainsub ); $("#prompt").remove(); // remove the HTML-defined prompt div $("#inputcontrol").remove(); // remove the cluttered, HTML-defined input divs diff --git a/evennia/web/webclient/static/webclient/js/plugins/options2.js b/evennia/web/webclient/static/webclient/js/plugins/options2.js index 01eba285c8..24acd4b314 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/options2.js +++ b/evennia/web/webclient/static/webclient/js/plugins/options2.js @@ -183,6 +183,7 @@ let options2 = (function () { onOptionsUI: onOptionsUI, onPrompt: onPrompt, onOptionCheckboxChanged: onOptionCheckboxChanged, + onOpenCloseOptions: onOpenCloseOptions, } })(); window.plugin_handler.add("options2", options2); From dae9a79c5d06725beb84cb1db6003383aee775ad Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Thu, 29 Oct 2020 00:16:58 -0400 Subject: [PATCH 10/10] Fix codacy-fixes induced store/retrieve bug --- .../webclient/js/plugins/goldenlayout.js | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js index 5ba2b383e5..57c509c179 100644 --- a/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js +++ b/evennia/web/webclient/static/webclient/js/plugins/goldenlayout.js @@ -498,6 +498,28 @@ let goldenlayout = (function () { } + // + // upload the named layout to the Evennia server as an option + var uploadLayouts = function () { + if( window.Evennia.isConnected() && myLayout.isInitialised ) { + var obj = {}; + + // iterate over each layout, storing the json for each into our temp obj + for( const key of evenniaGoldenLayouts.keys() ) { + if( key !== "default" ) { + obj[key] = JSON.stringify( evenniaGoldenLayouts.get(key) ); + } + } + + // store our temp object as json out to window.options.webclientLayouts + window.options["webclientActiveLayout"] = activeLayoutName; + window.options["webclientLayouts"] = JSON.stringify( obj ); + window.Evennia.msg("webclient_options", [], window.options); + } + } + + + // // var onRemoveLayout = function (evnt) { @@ -507,11 +529,7 @@ let goldenlayout = (function () { evenniaGoldenLayouts.delete(name); layout.remove(); - if( window.Evennia.isConnected() && myLayout.isInitialised ) { - window.options["webclientActiveLayout"] = activeLayoutName; - window.options["webclientLayouts"] = JSON.stringify( evenniaGoldenLayouts ); - window.Evennia.msg("webclient_options", [], window.options); - } + uploadLayouts(); } @@ -561,12 +579,7 @@ let goldenlayout = (function () { localStorage.setItem( "evenniaGoldenLayoutSavedState", JSON.stringify( evenniaGoldenLayouts.get(name) ) ); localStorage.setItem( "evenniaGoldenLayoutSavedStateName", activeLayoutName ); - // upload it to the server - if( window.Evennia.isConnected() && myLayout.isInitialised ) { - window.options["webclientActiveLayout"] = name; - window.options["webclientLayouts"] = JSON.stringify( evenniaGoldenLayouts ); - window.Evennia.msg("webclient_options", [], window.options); - } + uploadLayouts(); resetUI( evenniaGoldenLayouts.get(name) ); } @@ -669,10 +682,13 @@ let goldenlayout = (function () { var onGotOptions = function (args, kwargs) { // Reset the UI if the JSON layout sent from the server doesn't match the client's current JSON if( "webclientLayouts" in kwargs ) { - let mapping = JSON.parse( kwargs["webclientLayouts"] ); - evenniaGoldenLayouts = new Map(); - for( var layout in mapping ) { - evenniaGoldenLayouts.set( layout, mapping[layout] ); + var layouts = JSON.parse( kwargs["webclientLayouts"] ); + + // deserialize key/layout pairs into evenniaGoldenLayouts + for( var key in layouts ) { + if( key !== "default" && layouts.hasOwnProperty(key) ) { // codacy.com guard-rail + evenniaGoldenLayouts.set( key, JSON.parse(layouts[key]) ); + } } } }