From 8b0eb66ba6d5416e50234f3f78aee904943086aa Mon Sep 17 00:00:00 2001 From: friarzen Date: Sat, 17 Mar 2018 20:50:51 +0000 Subject: [PATCH 01/10] Alpha webclient split interface support --- .../static/webclient/css/webclient.css | 167 +++++++++------ .../static/webclient/js/splithandler.js | 77 +++++++ .../static/webclient/js/webclient_gui.js | 198 +++++++++++++----- .../webclient/templates/webclient/base.html | 113 +++++----- .../templates/webclient/webclient.html | 57 ++++- 5 files changed, 434 insertions(+), 178 deletions(-) create mode 100644 evennia/web/webclient/static/webclient/js/splithandler.js diff --git a/evennia/web/webclient/static/webclient/css/webclient.css b/evennia/web/webclient/static/webclient/css/webclient.css index 1c94a1f9fd..94344386a1 100644 --- a/evennia/web/webclient/static/webclient/css/webclient.css +++ b/evennia/web/webclient/static/webclient/css/webclient.css @@ -8,10 +8,11 @@ --- */ /* Overall element look */ -html, body, #clientwrapper { height: 100% } +html, body { + height: 100%; + width: 100%; +} body { - margin: 0; - padding: 0; background: #000; color: #ccc; font-size: .9em; @@ -19,6 +20,12 @@ body { line-height: 1.6em; overflow: hidden; } +@media screen and (max-width: 480px) { + body { + font-size: .5rem; + line-height: .7rem; + } +} a:link, a:visited { color: inherit; } @@ -74,93 +81,75 @@ div {margin:0px;} } /* Style specific classes corresponding to formatted, narative text. */ - +.wrapper { + height: 100%; +} /* Container surrounding entire client */ -#wrapper { - position: relative; - height: 100% +#clientwrapper { + height: 100%; } /* Main scrolling message area */ + #messagewindow { - position: absolute; - overflow: auto; - padding: 1em; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - top: 0; - left: 0; - right: 0; - bottom: 70px; + overflow-y: auto; + overflow-x: hidden; + overflow-wrap: break-word; } -/* Input area containing input field and button */ -#inputform { - position: absolute; - width: 100%; - padding: 0; - bottom: 0; - margin: 0; - padding-bottom: 10px; - border-top: 1px solid #555; -} - -#inputcontrol { - width: 100%; - padding: 0; +#messagewindow { + overflow-y: auto; + overflow-x: hidden; + overflow-wrap: break-word; } /* Input field */ -#inputfield, #inputsend, #inputsizer { - display: block; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: 50px; +#inputfield, #inputsizer { + height: 100%; background: #000; color: #fff; - padding: 0 .45em; - font-size: 1.1em; + padding: 0 .45rem; + font-size: 1.1rem; font-family: 'DejaVu Sans Mono', Consolas, Inconsolata, 'Lucida Console', monospace; -} - -#inputfield, #inputsizer { - float: left; - width: 95%; - border: 0; resize: none; - line-height: normal; +} +#inputsend { + height: 100%; +} +#inputcontrol { + height: 100%; } #inputfield:focus { - outline: 0; -} - -#inputsizer { - margin-left: -9999px; -} - -/* Input 'send' button */ -#inputsend { - float: right; - width: 3%; - max-width: 25px; - margin-right: 10px; - border: 0; - background: #555; } /* prompt area above input field */ -#prompt { - margin-top: 10px; - padding: 0 .45em; +.prompt { + max-height: 3rem; +} + +.splitbutton { + position: absolute; + right: 1%; + top: 1%; + z-index: 1; + width: 2rem; + height: 2rem; + font-size: 2rem; + color: #a6a6a6; + background-color: transparent; + border: 0px; +} + +.splitbutton:hover { + color: white; + cursor: pointer; } #optionsbutton { - width: 40px; - font-size: 20px; + width: 2rem; + font-size: 2rem; color: #a6a6a6; background-color: transparent; border: 0px; @@ -173,8 +162,8 @@ div {margin:0px;} #toolbar { position: fixed; - top: 0; - right: 5px; + top: .5rem; + right: .5rem; z-index: 1; } @@ -248,6 +237,48 @@ div {margin:0px;} text-decoration: none; cursor: pointer; } +.gutter.gutter-vertical { + cursor: row-resize; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=') +} + +.gutter.gutter-horizontal { + cursor: col-resize; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==') +} + +.split { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + overflow-y: auto; + overflow-x: hidden; +} + +.content { + border: 1px solid #C0C0C0; + box-shadow: inset 0 1px 2px #e4e4e4; + background-color: black; + padding: 1rem; +} +@media screen and (max-width: 480px) { + .content { + padding: .5rem; + } +} + +.gutter { + background-color: grey; + + background-repeat: no-repeat; + background-position: 50%; +} + +.split.split-horizontal, .gutter.gutter-horizontal { + height: 100%; + float: left; +} /* XTERM256 colors */ diff --git a/evennia/web/webclient/static/webclient/js/splithandler.js b/evennia/web/webclient/static/webclient/js/splithandler.js new file mode 100644 index 0000000000..56890009e5 --- /dev/null +++ b/evennia/web/webclient/static/webclient/js/splithandler.js @@ -0,0 +1,77 @@ +// Use split.js to create a basic ui +var SplitHandler = (function () { + var num_splits = 0; + var split_panes = {}; + + var set_pane_types = function(splitpane, types) { + split_panes[splitpane]['types'] = types; + } + + var dynamic_split = function(splitpane, direction, update_method1, update_method2) { + var first = ++num_splits; + var second = ++num_splits; + + var first_div = $( '
' ) + var first_sub = $( '
' ) + var second_div = $( '
' ) + var second_sub = $( '
' ) + + // check to see if this pane contains the primary message window. + contents = $('#'+splitpane).contents(); + if( contents ) { + // it does, so move it to the first new div (TODO -- selectable between first/second?) + contents.appendTo(first_sub); + } + + first_div.append( first_sub ); + second_div.append( second_sub ); + + // update the split_panes array to remove this split + delete( split_panes[splitpane] ); + + // now vaporize the current split_N-sub placeholder and create two new panes. + $('#'+splitpane).parent().append(first_div); + $('#'+splitpane).parent().append(second_div); + $('#'+splitpane).remove(); + + // And split + Split(['#split_'+first,'#split_'+second], { + direction: direction, + sizes: [50,50], + gutterSize: 4, + minSize: [50,50], + }); + + // store our new splits for future splits/uses by the main UI. + split_panes['split_'+first +'-sub'] = { 'types': [], 'update_method': update_method1 }; + split_panes['split_'+second+'-sub'] = { 'types': [], 'update_method': update_method2 }; + } + + + var init = function(settings) { + //change Mustache tags to ruby-style (Django gets mad otherwise) + var customTags = [ '<%', '%>' ]; + Mustache.tags = customTags; + + var input_template = $('#input-template').html(); + Mustache.parse(input_template); + + Split(['#main','#input'], { + direction: 'vertical', + sizes: [90,10], + gutterSize: 4, + minSize: [50,50], + }); + + var input_render = Mustache.render(input_template); + $('[data-role-input]').html(input_render); + console.log("SplitHandler initialized"); + } + + return { + init: init, + set_pane_types: set_pane_types, + dynamic_split: dynamic_split, + split_panes: split_panes, + } +})(); diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index 57d9b0b7c0..b4e5168769 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -17,6 +17,10 @@ var options = {}; + +var known_types = new Array(); + known_types.push('help'); + // // GUI Elements // @@ -106,6 +110,7 @@ function togglePopup(dialogname, content) { // Grab text from inputline and send to Evennia function doSendText() { + console.log("sending text"); if (!Evennia.isConnected()) { var reconnect = confirm("Not currently connected. Reconnect?"); if (reconnect) { @@ -158,6 +163,10 @@ function onKeydown (event) { var code = event.which; var history_entry = null; var inputfield = $("#inputfield"); + if (code === 9) { + return; + } + inputfield.focus(); if (code === 13) { // Enter key sends text @@ -205,64 +214,68 @@ function onKeyPress (event) { } var resizeInputField = function () { - var min_height = 50; - var max_height = 300; - var prev_text_len = 0; + return function() { + var wrapper = $("#inputform") + var input = $("#inputcontrol") + var prompt = $("#prompt") - // Check to see if we should change the height of the input area - return function () { - var inputfield = $("#inputfield"); - var scrollh = inputfield.prop("scrollHeight"); - var clienth = inputfield.prop("clientHeight"); - var newh = 0; - var curr_text_len = inputfield.val().length; - - if (scrollh > clienth && scrollh <= max_height) { - // Need to make it bigger - newh = scrollh; - } - else if (curr_text_len < prev_text_len) { - // There is less text in the field; try to make it smaller - // To avoid repaints, we draw the text in an offscreen element and - // determine its dimensions. - var sizer = $('#inputsizer') - .css("width", inputfield.prop("clientWidth")) - .text(inputfield.val()); - newh = sizer.prop("scrollHeight"); - } - - if (newh != 0) { - newh = Math.min(newh, max_height); - if (clienth != newh) { - inputfield.css("height", newh + "px"); - doWindowResize(); - } - } - prev_text_len = curr_text_len; + input.height(wrapper.height() - (input.offset().top - wrapper.offset().top)); } }(); // Handle resizing of client function doWindowResize() { - var formh = $('#inputform').outerHeight(true); - var message_scrollh = $("#messagewindow").prop("scrollHeight"); - $("#messagewindow") - .css({"bottom": formh}) // leave space for the input form - .scrollTop(message_scrollh); // keep the output window scrolled to the bottom + resizeInputField(); + var resizable = $("[data-update-append]"); + var parents = resizable.closest(".split") + parents.animate({ + scrollTop: parents.prop("scrollHeight") + }, 0); } // Handle text coming from the server function onText(args, kwargs) { - // append message to previous ones, then scroll so latest is at - // the bottom. Send 'cls' kwarg to modify the output class. - var renderto = "main"; - if (kwargs["type"] == "help") { - if (("helppopup" in options) && (options["helppopup"])) { - renderto = "#helpdialog"; + var use_default_pane = true; + + if ( kwargs && 'type' in kwargs ) { + var msgtype = kwargs['type']; + if ( ! known_types.includes(msgtype) ) { + // this is a new output type that can be mapped to panes + console.log('detected new output type: ' + msgtype) + known_types.push(msgtype); + } + + if ( msgtype == 'help' ) { + if (("helppopup" in options) && (options["helppopup"])) { + openPopup("#helpdialog", args[0]); + return; + } + // fall through to the default output + + } else { + // pass this message to each pane that has this msgtype mapped + if( SplitHandler ) { + for ( var key in SplitHandler.split_panes) { + var pane = SplitHandler.split_panes[key]; + console.log(pane); + // is this message type mapped to this pane? + if ( (pane['types'].length > 0) && pane['types'].includes(msgtype) ) { + // yes, so append/replace this pane's inner div with this message + if ( pane['update_method'] == 'replace' ) { + $('#'+key).html(args[0]) + } else { + $('#'+key).append(args[0]).animate({ scrollTop: document.getElementById("#"+key).scrollHeight }, 0); + } + // record sending this message to a pane, no need to update the default div + use_default_pane = false; + } + } + } } } - if (renderto == "main") { + // append message to default pane, then scroll so latest is at the bottom. + if(use_default_pane) { var mwin = $("#messagewindow"); var cls = kwargs == null ? 'out' : kwargs['cls']; mwin.append("
" + args[0] + "
"); @@ -271,8 +284,6 @@ function onText(args, kwargs) { }, 0); onNewLine(args[0], null); - } else { - openPopup(renderto, args[0]); } } @@ -377,7 +388,10 @@ function onNewLine(text, originator) { document.title = "(" + unread + ") " + originalTitle; if ("Notification" in window){ if (("notification_popup" in options) && (options["notification_popup"])) { - Notification.requestPermission().then(function(result) { + // There is a Promise-based API for this, but it’s not supported + // in Safari and some older browsers: + // https://developer.mozilla.org/en-US/docs/Web/API/Notification/requestPermission#Browser_compatibility + Notification.requestPermission(function(result) { if(result === "granted") { var title = originalTitle === "" ? "Evennia" : originalTitle; var options = { @@ -427,6 +441,81 @@ function doStartDragDialog(event) { $(document).bind("mouseup", undrag); } + +function onSplitDialogClose() { + var pane = $("input[name=pane]:checked").attr("value"); + var direction = $("input[name=direction]:checked").attr("value"); + var flow1 = $("input[name=flow1]:checked").attr("value"); + var flow2 = $("input[name=flow2]:checked").attr("value"); + + SplitHandler.dynamic_split( pane, direction, flow1, flow2 ); + + closePopup("#splitdialog"); +} + + +function onSplitDialog() { + var dialog = $("#splitdialogcontent"); + dialog.empty(); + + dialog.append("

Split?

"); + dialog.append(' top/bottom
'); + dialog.append(' side-by-side
'); + + dialog.append("

Split Which Pane?

"); + for ( var pane in SplitHandler.split_panes ) { + dialog.append(''+ pane +'
'); + } + + dialog.append("

New First Pane Flow

"); + dialog.append('append
'); + dialog.append('replace
'); + + dialog.append("

New Second Pane Flow

"); + dialog.append('append
'); + dialog.append('replace
'); + + dialog.append('
Split It
'); + + $("#splitclose").bind("click", onSplitDialogClose); + + openPopup("#splitdialog"); +} + +function onPaneControlDialogClose() { + var pane = $("input[name=pane]:checked").attr("value"); + + var types = new Array; + $('#splitdialogcontent input[type=checkbox]:checked').each(function() { + types.push( $(this).attr('value') ); + }); + + SplitHandler.set_pane_types( pane, types ); + + closePopup("#splitdialog"); +} + +function onPaneControlDialog() { + var dialog = $("#splitdialogcontent"); + dialog.empty(); + + dialog.append("

Set Which Pane?

"); + for ( var pane in SplitHandler.split_panes ) { + dialog.append(''+ pane +'
'); + } + + dialog.append("

Which content types?

"); + for ( var type in known_types ) { + dialog.append(''+ known_types[type] +'
'); + } + + dialog.append('
Make It So
'); + + $("#paneclose").bind("click", onPaneControlDialogClose); + + openPopup("#splitdialog"); +} + // // Register Events // @@ -434,6 +523,16 @@ function doStartDragDialog(event) { // Event when client finishes loading $(document).ready(function() { + if( SplitHandler ) { + SplitHandler.init(); + SplitHandler.split_panes['main-sub'] = {'types': ['help'], 'update_method': 'replace'}; + $("#splitbutton").bind("click", onSplitDialog); + $("#panebutton").bind("click", onPaneControlDialog); + } else { + $("#splitbutton").hide(); + $("#panebutton").hide(); + } + if ("Notification" in window) { Notification.requestPermission(); } @@ -450,7 +549,7 @@ $(document).ready(function() { //$(document).on("visibilitychange", onVisibilityChange); - $("#inputfield").bind("resize", doWindowResize) + $("[data-role-input]").bind("resize", doWindowResize) .keypress(onKeyPress) .bind("paste", resizeInputField) .bind("cut", resizeInputField); @@ -503,6 +602,7 @@ $(document).ready(function() { }, 60000*3 ); + console.log("Completed GUI setup"); }); diff --git a/evennia/web/webclient/templates/webclient/base.html b/evennia/web/webclient/templates/webclient/base.html index f5f47b230f..f31e4c89f1 100644 --- a/evennia/web/webclient/templates/webclient/base.html +++ b/evennia/web/webclient/templates/webclient/base.html @@ -14,55 +14,16 @@ JQuery available. + + + + + - - - - {% block jquery_import %} - - {% endblock %} - - - - - - - - - {% block guilib_import %} - - {% endblock %} - - + @@ -79,17 +40,69 @@ JQuery available. web browser supporting javascript.

This error could also be due to not being able to access the online jQuery javascript library.

- -
-
+
{% block client %} {% endblock %}
+ + + {% block jquery_import %} + + {% endblock %} + + + + + + + + + + + + + + + + + + {% block guilib_import %} + + {% endblock %} + + + + + {% block scripts %} + {% endblock %} diff --git a/evennia/web/webclient/templates/webclient/webclient.html b/evennia/web/webclient/templates/webclient/webclient.html index 1c641bffb0..2b138cb8bd 100644 --- a/evennia/web/webclient/templates/webclient/webclient.html +++ b/evennia/web/webclient/templates/webclient/webclient.html @@ -8,20 +8,30 @@ {% block client %} +
+ + + +
-
-
- -
-
-
-
-
- - + +
+
+
+
+
+ + +
+
+ + +
+
Split Pane×
+
+
-
@@ -47,4 +57,29 @@
+ + + + + + +{% endblock %} +{% block scripts %} {% endblock %} From 8680708d52f8756aeb0bf5272ee309a02aee248e Mon Sep 17 00:00:00 2001 From: friarzen Date: Sat, 17 Mar 2018 21:50:11 +0000 Subject: [PATCH 02/10] Example of how to tag msg() with a type --- evennia/commands/default/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 2f4c51a227..aef5309d32 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -71,7 +71,7 @@ class CmdLook(COMMAND_DEFAULT_CLASS): target = caller.search(self.args) if not target: return - self.msg(caller.at_look(target)) + self.msg((caller.at_look(target), {'type':'look'}), options=None) class CmdNick(COMMAND_DEFAULT_CLASS): From 856c889e3f62dad7af489384fe5b212fd14d9d20 Mon Sep 17 00:00:00 2001 From: friarzen Date: Sun, 18 Mar 2018 00:33:08 +0000 Subject: [PATCH 03/10] move the initial settings for the main split where it belongs --- evennia/web/webclient/static/webclient/js/splithandler.js | 2 ++ evennia/web/webclient/static/webclient/js/webclient_gui.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/evennia/web/webclient/static/webclient/js/splithandler.js b/evennia/web/webclient/static/webclient/js/splithandler.js index 56890009e5..7ba8e45e17 100644 --- a/evennia/web/webclient/static/webclient/js/splithandler.js +++ b/evennia/web/webclient/static/webclient/js/splithandler.js @@ -63,6 +63,8 @@ var SplitHandler = (function () { minSize: [50,50], }); + split_panes['main-sub'] = {'types': [], 'update_method': 'append'}; + var input_render = Mustache.render(input_template); $('[data-role-input]').html(input_render); console.log("SplitHandler initialized"); diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index b4e5168769..d07239039f 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -525,7 +525,6 @@ $(document).ready(function() { if( SplitHandler ) { SplitHandler.init(); - SplitHandler.split_panes['main-sub'] = {'types': ['help'], 'update_method': 'replace'}; $("#splitbutton").bind("click", onSplitDialog); $("#panebutton").bind("click", onPaneControlDialog); } else { From 665ba8d0f42dfc3a5f004000fbd1944f398ac9be Mon Sep 17 00:00:00 2001 From: friarzen Date: Sun, 18 Mar 2018 00:45:23 +0000 Subject: [PATCH 04/10] Make the initial login 'look' match CmdLook --- evennia/objects/objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index f583570707..a588af0000 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1762,7 +1762,7 @@ class DefaultCharacter(DefaultObject): """ self.msg("\nYou become |c%s|n.\n" % self.name) - self.msg(self.at_look(self.location)) + self.msg((self.at_look(self.location), {'type':'look'}), options = None) def message(obj, from_obj): obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj) From 36e294a9d4ee3d4cefc028abf60662a2042a97e9 Mon Sep 17 00:00:00 2001 From: friarzen Date: Mon, 19 Mar 2018 00:59:28 +0000 Subject: [PATCH 05/10] Fix append scrolling -- needs more testing --- .../web/webclient/static/webclient/js/webclient_gui.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index d07239039f..4189e026fb 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -257,14 +257,15 @@ function onText(args, kwargs) { if( SplitHandler ) { for ( var key in SplitHandler.split_panes) { var pane = SplitHandler.split_panes[key]; - console.log(pane); // is this message type mapped to this pane? if ( (pane['types'].length > 0) && pane['types'].includes(msgtype) ) { // yes, so append/replace this pane's inner div with this message if ( pane['update_method'] == 'replace' ) { $('#'+key).html(args[0]) } else { - $('#'+key).append(args[0]).animate({ scrollTop: document.getElementById("#"+key).scrollHeight }, 0); + $('#'+key).append(args[0]); + var scrollHeight = $('#'+key).parent().prop("scrollHeight"); + $('#'+key).parent().animate({ scrollTop: scrollHeight }, 0); } // record sending this message to a pane, no need to update the default div use_default_pane = false; @@ -279,9 +280,8 @@ function onText(args, kwargs) { var mwin = $("#messagewindow"); var cls = kwargs == null ? 'out' : kwargs['cls']; mwin.append("
" + args[0] + "
"); - mwin.animate({ - scrollTop: document.getElementById("messagewindow").scrollHeight - }, 0); + var scrollHeight = mwin.parent().parent().prop("scrollHeight"); + mwin.parent().parent().animate({ scrollTop: scrollHeight }, 0); onNewLine(args[0], null); } From acc78186e34bfbf0f21aa7ed2d65803ff319673c Mon Sep 17 00:00:00 2001 From: Nicholas Matlaga Date: Mon, 19 Mar 2018 11:20:08 -0400 Subject: [PATCH 06/10] fix webclient/base.html (500 error) --- .../webclient/templates/webclient/base.html | 100 +++++++----------- 1 file changed, 37 insertions(+), 63 deletions(-) diff --git a/evennia/web/webclient/templates/webclient/base.html b/evennia/web/webclient/templates/webclient/base.html index 3852b45273..a5c65fad2c 100644 --- a/evennia/web/webclient/templates/webclient/base.html +++ b/evennia/web/webclient/templates/webclient/base.html @@ -13,16 +13,18 @@ JQuery available. - - + + + + {% block jquery_import %} - + {% endblock %} + + + - + + + + + + + + {% block guilib_import %} + + {% endblock %} + - - + + + + {% block scripts %} + {% endblock %} @@ -74,6 +101,10 @@ JQuery available. web browser supporting javascript.

This error could also be due to not being able to access the online jQuery javascript library.

+ +
@@ -81,62 +112,5 @@ JQuery available. {% block client %} {% endblock %}
- - - - {% block jquery_import %} - - {% endblock %} - - - - - - - - - - - - - - - - - - {% block guilib_import %} - - {% endblock %} - - - - - {% block scripts %} - {% endblock %} From 36c89799cddd39905d82b54fce926dc6d44e87be Mon Sep 17 00:00:00 2001 From: friarzen Date: Wed, 21 Mar 2018 18:35:48 +0000 Subject: [PATCH 07/10] Add user selected names to each new pane and some CSS --- .../static/webclient/css/webclient.css | 17 +++++ .../static/webclient/js/splithandler.js | 44 +++++------ .../static/webclient/js/webclient_gui.js | 73 ++++++++++++------- .../templates/webclient/webclient.html | 6 +- 4 files changed, 86 insertions(+), 54 deletions(-) diff --git a/evennia/web/webclient/static/webclient/css/webclient.css b/evennia/web/webclient/static/webclient/css/webclient.css index 94344386a1..1e9adb283b 100644 --- a/evennia/web/webclient/static/webclient/css/webclient.css +++ b/evennia/web/webclient/static/webclient/css/webclient.css @@ -147,6 +147,19 @@ div {margin:0px;} cursor: pointer; } +.button { + width: fit-content; + padding: 1em; + color: black; + border: 1px solid black; + background-color: darkgray; + margin: 0 auto; +} + +.splitbutton:hover { + cursor: pointer; +} + #optionsbutton { width: 2rem; font-size: 2rem; @@ -256,6 +269,10 @@ div {margin:0px;} overflow-x: hidden; } +.split-sub { + padding: .5rem; +} + .content { border: 1px solid #C0C0C0; box-shadow: inset 0 1px 2px #e4e4e4; diff --git a/evennia/web/webclient/static/webclient/js/splithandler.js b/evennia/web/webclient/static/webclient/js/splithandler.js index 7ba8e45e17..aa6ea4364a 100644 --- a/evennia/web/webclient/static/webclient/js/splithandler.js +++ b/evennia/web/webclient/static/webclient/js/splithandler.js @@ -1,50 +1,50 @@ // Use split.js to create a basic ui var SplitHandler = (function () { - var num_splits = 0; var split_panes = {}; var set_pane_types = function(splitpane, types) { split_panes[splitpane]['types'] = types; } - var dynamic_split = function(splitpane, direction, update_method1, update_method2) { - var first = ++num_splits; - var second = ++num_splits; - var first_div = $( '
' ) - var first_sub = $( '
' ) - var second_div = $( '
' ) - var second_sub = $( '
' ) + var dynamic_split = function(splitpane, direction, pane_name1, pane_name2, update_method1, update_method2, sizes) { + // find the sub-div of the pane we are being asked to split + splitpanesub = splitpane + '-sub'; - // check to see if this pane contains the primary message window. - contents = $('#'+splitpane).contents(); + // create the new div stack to replace the sub-div with. + var first_div = $( '
' ) + var first_sub = $( '
' ) + var second_div = $( '
' ) + var second_sub = $( '
' ) + + // check to see if this sub-pane contains anything + contents = $('#'+splitpanesub).contents(); if( contents ) { - // it does, so move it to the first new div (TODO -- selectable between first/second?) + // it does, so move it to the first new div-sub (TODO -- selectable between first/second?) contents.appendTo(first_sub); } - first_div.append( first_sub ); second_div.append( second_sub ); - // update the split_panes array to remove this split + // update the split_panes array to remove this pane name delete( split_panes[splitpane] ); // now vaporize the current split_N-sub placeholder and create two new panes. - $('#'+splitpane).parent().append(first_div); - $('#'+splitpane).parent().append(second_div); - $('#'+splitpane).remove(); + $('#'+splitpane).append(first_div); + $('#'+splitpane).append(second_div); + $('#'+splitpane+'-sub').remove(); // And split - Split(['#split_'+first,'#split_'+second], { + Split(['#'+pane_name1,'#'+pane_name2], { direction: direction, - sizes: [50,50], + sizes: sizes, gutterSize: 4, minSize: [50,50], }); - // store our new splits for future splits/uses by the main UI. - split_panes['split_'+first +'-sub'] = { 'types': [], 'update_method': update_method1 }; - split_panes['split_'+second+'-sub'] = { 'types': [], 'update_method': update_method2 }; + // store our new split sub-divs for future splits/uses by the main UI. + split_panes[pane_name1] = { 'types': [], 'update_method': update_method1 }; + split_panes[pane_name2] = { 'types': [], 'update_method': update_method2 }; } @@ -63,7 +63,7 @@ var SplitHandler = (function () { minSize: [50,50], }); - split_panes['main-sub'] = {'types': [], 'update_method': 'append'}; + split_panes['main'] = { 'types': [], 'update_method': 'append' }; var input_render = Mustache.render(input_template); $('[data-role-input]').html(input_render); diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index 4189e026fb..7a7c218921 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -15,6 +15,7 @@ (function () { "use strict" +var num_splits = 0; var options = {}; @@ -167,7 +168,7 @@ function onKeydown (event) { return; } - inputfield.focus(); + //inputfield.focus(); if (code === 13) { // Enter key sends text doSendText(); @@ -245,31 +246,23 @@ function onText(args, kwargs) { known_types.push(msgtype); } - if ( msgtype == 'help' ) { - if (("helppopup" in options) && (options["helppopup"])) { - openPopup("#helpdialog", args[0]); - return; - } - // fall through to the default output - - } else { - // pass this message to each pane that has this msgtype mapped - if( SplitHandler ) { - for ( var key in SplitHandler.split_panes) { - var pane = SplitHandler.split_panes[key]; - // is this message type mapped to this pane? - if ( (pane['types'].length > 0) && pane['types'].includes(msgtype) ) { - // yes, so append/replace this pane's inner div with this message - if ( pane['update_method'] == 'replace' ) { - $('#'+key).html(args[0]) - } else { - $('#'+key).append(args[0]); - var scrollHeight = $('#'+key).parent().prop("scrollHeight"); - $('#'+key).parent().animate({ scrollTop: scrollHeight }, 0); - } - // record sending this message to a pane, no need to update the default div - use_default_pane = false; + // pass this message to each pane that has this msgtype mapped + if( SplitHandler ) { + for ( var key in SplitHandler.split_panes) { + var pane = SplitHandler.split_panes[key]; + // is this message type mapped to this pane? + if ( (pane['types'].length > 0) && pane['types'].includes(msgtype) ) { + // yes, so append/replace this pane's inner div with this message + var text_div = $('#'+key+'-sub'); + if ( pane['update_method'] == 'replace' ) { + text_div.html(args[0]) + } else { + text_div.append(args[0]); + var scrollHeight = text_div.parent().prop("scrollHeight"); + text_div.parent().animate({ scrollTop: scrollHeight }, 0); } + // record sending this message to a pane, no need to update the default div + use_default_pane = false; } } } @@ -441,19 +434,39 @@ function doStartDragDialog(event) { $(document).bind("mouseup", undrag); } - function onSplitDialogClose() { var pane = $("input[name=pane]:checked").attr("value"); var direction = $("input[name=direction]:checked").attr("value"); + var new_pane1 = $("input[name=new_pane1]").val(); + var new_pane2 = $("input[name=new_pane2]").val(); var flow1 = $("input[name=flow1]:checked").attr("value"); var flow2 = $("input[name=flow2]:checked").attr("value"); - SplitHandler.dynamic_split( pane, direction, flow1, flow2 ); + if( new_pane1 == "" ) { + new_pane1 = 'pane_'+num_splits; + num_splits++; + } + + if( new_pane2 == "" ) { + new_pane2 = 'pane_'+num_splits; + num_splits++; + } + + if( document.getElementById(new_pane1) ) { + alert('An element: "' + new_pane1 + '" already exists'); + return; + } + + if( document.getElementById(new_pane2) ) { + alert('An element: "' + new_pane2 + '" already exists'); + return; + } + + SplitHandler.dynamic_split( pane, direction, new_pane1, new_pane2, flow1, flow2, [50,50] ); closePopup("#splitdialog"); } - function onSplitDialog() { var dialog = $("#splitdialogcontent"); dialog.empty(); @@ -467,6 +480,10 @@ function onSplitDialog() { dialog.append(''+ pane +'
'); } + dialog.append("

New Pane Names

"); + dialog.append(''); + dialog.append(''); + dialog.append("

New First Pane Flow

"); dialog.append('append
'); dialog.append('replace
'); diff --git a/evennia/web/webclient/templates/webclient/webclient.html b/evennia/web/webclient/templates/webclient/webclient.html index 2b138cb8bd..b750257048 100644 --- a/evennia/web/webclient/templates/webclient/webclient.html +++ b/evennia/web/webclient/templates/webclient/webclient.html @@ -16,14 +16,12 @@
-
+
- -
-
+
From 8bde43a3e34e99b58d980fda2ecd17dc2847dfcc Mon Sep 17 00:00:00 2001 From: friarzen Date: Thu, 22 Mar 2018 00:52:19 +0000 Subject: [PATCH 08/10] adjust css to match existing toolbar and toggle split/pane popup --- .../static/webclient/css/webclient.css | 22 +++++++++++++------ .../static/webclient/js/webclient_gui.js | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/evennia/web/webclient/static/webclient/css/webclient.css b/evennia/web/webclient/static/webclient/css/webclient.css index 1e9adb283b..75dd91ce2a 100644 --- a/evennia/web/webclient/static/webclient/css/webclient.css +++ b/evennia/web/webclient/static/webclient/css/webclient.css @@ -129,20 +129,28 @@ div {margin:0px;} max-height: 3rem; } -.splitbutton { - position: absolute; - right: 1%; - top: 1%; - z-index: 1; +#splitbutton { width: 2rem; - height: 2rem; font-size: 2rem; color: #a6a6a6; background-color: transparent; border: 0px; } -.splitbutton:hover { +#splitbutton:hover { + color: white; + cursor: pointer; +} + +#panebutton { + width: 2rem; + font-size: 2rem; + color: #a6a6a6; + background-color: transparent; + border: 0px; +} + +#panebutton:hover { color: white; cursor: pointer; } diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index 7a7c218921..b975ae7044 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -496,7 +496,7 @@ function onSplitDialog() { $("#splitclose").bind("click", onSplitDialogClose); - openPopup("#splitdialog"); + togglePopup("#splitdialog"); } function onPaneControlDialogClose() { @@ -530,7 +530,7 @@ function onPaneControlDialog() { $("#paneclose").bind("click", onPaneControlDialogClose); - openPopup("#splitdialog"); + togglePopup("#splitdialog"); } // From ab811c81c8a9bf7c1afac07bd931b886c9472b4a Mon Sep 17 00:00:00 2001 From: Brenden Tuck Date: Sun, 8 Apr 2018 12:33:38 -0400 Subject: [PATCH 09/10] Added an undo button for multi-level undo of splits --- .../static/webclient/css/webclient.css | 13 ++++ .../static/webclient/js/splithandler.js | 68 ++++++++++++++++++- .../static/webclient/js/webclient_gui.js | 5 +- .../templates/webclient/webclient.html | 1 + 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/evennia/web/webclient/static/webclient/css/webclient.css b/evennia/web/webclient/static/webclient/css/webclient.css index 75dd91ce2a..7a33cfa207 100644 --- a/evennia/web/webclient/static/webclient/css/webclient.css +++ b/evennia/web/webclient/static/webclient/css/webclient.css @@ -155,6 +155,19 @@ div {margin:0px;} cursor: pointer; } +#undobutton { + width: 2rem; + font-size: 2rem; + color: #a6a6a6; + background-color: transparent; + border: 0px; +} + +#undobutton:hover { + color: white; + cursor: pointer; +} + .button { width: fit-content; padding: 1em; diff --git a/evennia/web/webclient/static/webclient/js/splithandler.js b/evennia/web/webclient/static/webclient/js/splithandler.js index aa6ea4364a..81210df854 100644 --- a/evennia/web/webclient/static/webclient/js/splithandler.js +++ b/evennia/web/webclient/static/webclient/js/splithandler.js @@ -1,6 +1,7 @@ // Use split.js to create a basic ui var SplitHandler = (function () { var split_panes = {}; + var backout_list = new Array; var set_pane_types = function(splitpane, types) { split_panes[splitpane]['types'] = types; @@ -26,7 +27,8 @@ var SplitHandler = (function () { first_div.append( first_sub ); second_div.append( second_sub ); - // update the split_panes array to remove this pane name + // update the split_panes array to remove this pane name, but store it for the backout stack + var backout_settings = split_panes[splitpane]; delete( split_panes[splitpane] ); // now vaporize the current split_N-sub placeholder and create two new panes. @@ -45,6 +47,69 @@ var SplitHandler = (function () { // store our new split sub-divs for future splits/uses by the main UI. split_panes[pane_name1] = { 'types': [], 'update_method': update_method1 }; split_panes[pane_name2] = { 'types': [], 'update_method': update_method2 }; + + // add our new split to the backout stack + backout_list.push( {'pane1': pane_name1, 'pane2': pane_name2, 'undo': backout_settings} ); + } + + + var undo_split = function() { + // pop off the last split pair + var back = backout_list.pop(); + if( !back ) { + return; + } + + // Collect all the divs/subs in play + var pane1 = back['pane1']; + var pane2 = back['pane2']; + var pane1_sub = $('#'+pane1+'-sub'); + var pane2_sub = $('#'+pane2+'-sub'); + var pane1_parent = $('#'+pane1).parent(); + var pane2_parent = $('#'+pane2).parent(); + + if( pane1_parent.attr('id') != pane2_parent.attr('id') ) { + // sanity check failed...somebody did something weird...bail out + console.log( pane1 ); + console.log( pane2 ); + console.log( pane1_parent ); + console.log( pane2_parent ); + return; + } + + // create a new sub-pane in the panes parent + var parent_sub = $( '
' ) + + // check to see if the special #messagewindow is in either of our sub-panes. + var msgwindow = pane1_sub.find('#messagewindow') + if( !msgwindow ) { + //didn't find it in pane 1, try pane 2 + msgwindow = pane2_sub.find('#messagewindow') + } + if( msgwindow ) { + // It is, so collect all contents into it instead of our parent_sub div + // then move it to parent sub div, this allows future #messagewindow divs to flow properly + msgwindow.append( pane1_sub.contents() ); + msgwindow.append( pane2_sub.contents() ); + parent_sub.append( msgwindow ); + } else { + //didn't find it, so move the contents of the two panes' sub-panes into the new sub-pane + parent_sub.append( pane1_sub.contents() ); + parent_sub.append( pane2_sub.contents() ); + } + + // clear the parent + pane1_parent.empty(); + + // add the new sub-pane back to the parent div + pane1_parent.append(parent_sub); + + // pull the sub-div's from split_panes + delete split_panes[pane1]; + delete split_panes[pane2]; + + // add our parent pane back into the split_panes list for future splitting + split_panes[pane1_parent.attr('id')] = back['undo']; } @@ -75,5 +140,6 @@ var SplitHandler = (function () { set_pane_types: set_pane_types, dynamic_split: dynamic_split, split_panes: split_panes, + undo_split: undo_split, } })(); diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index b975ae7044..8929a7529c 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -15,7 +15,7 @@ (function () { "use strict" -var num_splits = 0; +var num_splits = 0; //unique id counter for default split-panel names var options = {}; @@ -544,9 +544,12 @@ $(document).ready(function() { SplitHandler.init(); $("#splitbutton").bind("click", onSplitDialog); $("#panebutton").bind("click", onPaneControlDialog); + $("#undobutton").bind("click", SplitHandler.undo_split); + $("#optionsbutton").hide(); } else { $("#splitbutton").hide(); $("#panebutton").hide(); + $("#undobutton").hide(); } if ("Notification" in window) { diff --git a/evennia/web/webclient/templates/webclient/webclient.html b/evennia/web/webclient/templates/webclient/webclient.html index b750257048..74bef631cf 100644 --- a/evennia/web/webclient/templates/webclient/webclient.html +++ b/evennia/web/webclient/templates/webclient/webclient.html @@ -12,6 +12,7 @@ +
From b580123b19564c3b8c5da42513c95b6aed35a1a6 Mon Sep 17 00:00:00 2001 From: friarzen Date: Sat, 21 Apr 2018 17:03:01 +0000 Subject: [PATCH 10/10] Attempt to make append/replace dialog text more clear --- .../webclient/static/webclient/js/webclient_gui.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index 8929a7529c..e1ed4d31fd 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -484,13 +484,13 @@ function onSplitDialog() { dialog.append(''); dialog.append(''); - dialog.append("

New First Pane Flow

"); - dialog.append('append
'); - dialog.append('replace
'); + dialog.append("

New First Pane

"); + dialog.append('append new incoming messages
'); + dialog.append('replace old messages with new ones
'); - dialog.append("

New Second Pane Flow

"); - dialog.append('append
'); - dialog.append('replace
'); + dialog.append("

New Second Pane

"); + dialog.append('append new incoming messages
'); + dialog.append('replace old messages with new ones
'); dialog.append('
Split It
');