mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 05:16:31 +01:00
Merge pull request #2008 from friarzen/webclient_options2
Extend the Webclient Options handling
This commit is contained in:
commit
de6ef73949
10 changed files with 537 additions and 2 deletions
|
|
@ -88,6 +88,10 @@ div {margin:0px;}
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
/* Container surrounding entire client */
|
||||
#clientwrapper {
|
||||
height: 100%;
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
@font-face {
|
||||
font-family: 'DejaVu Sans Mono';
|
||||
src: url('/static/webclient/fonts/DejaVuSansMono-webfont.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient help plugin
|
||||
*
|
||||
*/
|
||||
let clienthelp_plugin = (function () {
|
||||
//
|
||||
//
|
||||
//
|
||||
var onOptionsUI = function (parentdiv) {
|
||||
var help_text = $( [
|
||||
"<div style='font-weight: bold;'>",
|
||||
"<a href='http://evennia.com'>Evennia</a>",
|
||||
" Webclient Settings:",
|
||||
"</div>"
|
||||
].join(""));
|
||||
parentdiv.append(help_text);
|
||||
}
|
||||
|
||||
return {
|
||||
init: function () {},
|
||||
onOptionsUI: onOptionsUI,
|
||||
}
|
||||
})();
|
||||
window.plugin_handler.add("clienthelp", clienthelp_plugin);
|
||||
79
evennia/web/webclient/static/webclient/js/plugins/font.js
Normal file
79
evennia/web/webclient/static/webclient/js/plugins/font.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient default "send-text-on-enter-key" IO plugin
|
||||
*
|
||||
*/
|
||||
let font_plugin = (function () {
|
||||
|
||||
const font_urls = {
|
||||
'B612 Mono': 'https://fonts.googleapis.com/css?family=B612+Mono&display=swap',
|
||||
'Consolas': 'https://fonts.googleapis.com/css?family=Consolas&display=swap',
|
||||
'DejaVu Sans Mono': '/static/webclient/fonts/DejaVuSansMono.css',
|
||||
'Fira Mono': 'https://fonts.googleapis.com/css?family=Fira+Mono&display=swap',
|
||||
'Inconsolata': 'https://fonts.googleapis.com/css?family=Inconsolata&display=swap',
|
||||
'Monospace': '',
|
||||
'Roboto Mono': 'https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap',
|
||||
'Source Code Pro': 'https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap',
|
||||
'Ubuntu Mono': 'https://fonts.googleapis.com/css?family=Ubuntu+Mono&display=swap',
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
var onOptionsUI = function (parentdiv) {
|
||||
var fontselect = $('<select>');
|
||||
var sizeselect = $('<select>');
|
||||
|
||||
var fonts = Object.keys(font_urls);
|
||||
for (var x = 0; x < fonts.length; x++) {
|
||||
var option = $('<option value="'+fonts[x]+'">'+fonts[x]+'</option>');
|
||||
fontselect.append(option);
|
||||
}
|
||||
|
||||
for (var x = 4; x < 21; x++) {
|
||||
var val = (x/10.0);
|
||||
var option = $('<option value="'+val+'">'+x+'</option>');
|
||||
sizeselect.append(option);
|
||||
}
|
||||
|
||||
fontselect.val('DejaVu Sans Mono'); // default value
|
||||
sizeselect.val('0.9'); // default scaling factor
|
||||
|
||||
// font-family change callback
|
||||
fontselect.on('change', function () {
|
||||
$(document.body).css('font-family', $(this).val());
|
||||
});
|
||||
|
||||
// font size change callback
|
||||
sizeselect.on('change', function () {
|
||||
$(document.body).css('font-size', $(this).val()+"em");
|
||||
});
|
||||
|
||||
// add the font selection dialog control to our parentdiv
|
||||
parentdiv.append('<div style="font-weight: bold">Font Selection:</div>');
|
||||
parentdiv.append(fontselect);
|
||||
parentdiv.append(sizeselect);
|
||||
}
|
||||
|
||||
//
|
||||
// Font plugin init function (adds the urls for the webfonts to the page)
|
||||
//
|
||||
var init = function () {
|
||||
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 = $('<link href="'+url+'" rel="stylesheet">');
|
||||
head.append( link );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onOptionsUI: onOptionsUI,
|
||||
}
|
||||
})();
|
||||
window.plugin_handler.add("font", font_plugin);
|
||||
|
|
@ -383,6 +383,14 @@ let goldenlayout = (function () {
|
|||
// Public
|
||||
//
|
||||
|
||||
//
|
||||
// helper accessor for other plugins to add new known-message types
|
||||
var addKnownType = function (newtype) {
|
||||
if( knownTypes.includes(newtype) == false ) {
|
||||
knownTypes.push(newtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
|
|
@ -526,7 +534,7 @@ let goldenlayout = (function () {
|
|||
onKeydown: onKeydown,
|
||||
onText: onText,
|
||||
getGL: function () { return myLayout; },
|
||||
addKnownType: function (newtype) { knownTypes.push(newtype); },
|
||||
addKnownType: addKnownType,
|
||||
}
|
||||
}());
|
||||
window.plugin_handler.add("goldenlayout", goldenlayout);
|
||||
|
|
|
|||
68
evennia/web/webclient/static/webclient/js/plugins/iframe.js
Normal file
68
evennia/web/webclient/static/webclient/js/plugins/iframe.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* IFrame plugin
|
||||
* REQUIRES: goldenlayout.js
|
||||
*/
|
||||
let iframe = (function () {
|
||||
|
||||
var url = window.location.origin;
|
||||
|
||||
//
|
||||
// Create iframe component
|
||||
var createIframeComponent = function () {
|
||||
var myLayout = window.plugins["goldenlayout"].getGL();
|
||||
|
||||
myLayout.registerComponent( "iframe", function (container, componentState) {
|
||||
// build the iframe
|
||||
var div = $('<iframe src="' + url + '">');
|
||||
div.css("width", "100%");
|
||||
div.css("height", "inherit");
|
||||
div.appendTo( container.getElement() );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// handler for the "iframe" button
|
||||
var onOpenIframe = function () {
|
||||
var iframeComponent = {
|
||||
title: url,
|
||||
type: "component",
|
||||
componentName: "iframe",
|
||||
componentState: {
|
||||
},
|
||||
};
|
||||
|
||||
// Create a new GoldenLayout tab filled with the iframeComponent above
|
||||
var myLayout = window.plugins["goldenlayout"].getGL();
|
||||
var main = myLayout.root.getItemsByType("stack")[0].getActiveContentItem();
|
||||
main.parent.addChild( iframeComponent );
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
var onOptionsUI = function (parentdiv) {
|
||||
var iframebutton = $('<input type="button" value="Open Game Website" />');
|
||||
iframebutton.on('click', onOpenIframe);
|
||||
|
||||
parentdiv.append( '<div style="font-weight: bold">Restricted Browser-in-Browser:</div>' );
|
||||
parentdiv.append( iframebutton );
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
var postInit = function() {
|
||||
// Are we using GoldenLayout?
|
||||
if( window.plugins["goldenlayout"] ) {
|
||||
createIframeComponent();
|
||||
|
||||
$("#iframebutton").bind("click", onOpenIframe);
|
||||
}
|
||||
console.log('IFrame plugin Loaded');
|
||||
}
|
||||
|
||||
return {
|
||||
init: function () {},
|
||||
postInit: postInit,
|
||||
onOptionsUI: onOptionsUI,
|
||||
}
|
||||
})();
|
||||
window.plugin_handler.add("iframe", iframe);
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Spawns plugin
|
||||
* REQUIRES: goldenlayout.js
|
||||
*/
|
||||
let spawns = (function () {
|
||||
|
||||
var ignoreDefaultKeydown = false;
|
||||
|
||||
var spawnmap = {}; // { id1: { r:regex, t:tag } } pseudo-array of regex-tag pairs
|
||||
|
||||
//
|
||||
// changes the spawnmap row's contents to the new regex/tag provided,
|
||||
// this avoids leaving stale regex/tag definitions in the spawnmap
|
||||
var onAlterTag = function (evnt) {
|
||||
var adult = $(evnt.target).parent();
|
||||
var children = adult.children();
|
||||
var id = $(adult).data('id');
|
||||
var regex = $(children[0]).val();// spaces before/after are valid regex syntax, unfortunately
|
||||
var mytag = $(children[1]).val().trim();
|
||||
|
||||
if( mytag != "" && regex != "" ) {
|
||||
if( !(id in spawnmap) ) {
|
||||
spawnmap[id] = {};
|
||||
}
|
||||
spawnmap[id]["r"] = regex;
|
||||
spawnmap[id]["t"] = mytag;
|
||||
localStorage.setItem( "evenniaMessageRoutingSavedState", JSON.stringify(spawnmap) );
|
||||
window.plugins["goldenlayout"].addKnownType( mytag );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deletes the entire regex/tag/delete button row.
|
||||
var onDeleteTag = function (evnt) {
|
||||
var adult = $(evnt.target).parent();
|
||||
var children = adult.children();
|
||||
var id = $(adult).data('id');
|
||||
delete spawnmap[id];
|
||||
localStorage.setItem( "evenniaMessageRoutingSavedState", JSON.stringify(spawnmap) );
|
||||
adult.remove(); // remove this set of input boxes/etc from the DOM
|
||||
}
|
||||
|
||||
//
|
||||
var onFocusIn = function (evnt) {
|
||||
ignoreDefaultKeydown = true;
|
||||
}
|
||||
|
||||
//
|
||||
var onFocusOut = function (evnt) {
|
||||
ignoreDefaultKeydown = false;
|
||||
onAlterTag(evnt); // percolate event so closing the pane, etc saves any last changes.
|
||||
}
|
||||
|
||||
//
|
||||
// display a row with proper editting hooks
|
||||
var displayRow = function (formdiv, div, regexstring, tagstring) {
|
||||
var regex = $('<input class="regex" type=text value="'+regexstring+'"/>');
|
||||
var tag = $('<input class="tag" type=text value="'+tagstring+'"/>');
|
||||
var del = $('<input class="delete-regex" type=button value="X"/>');
|
||||
regex.on('change', onAlterTag );
|
||||
regex.on('focusin', onFocusIn );
|
||||
regex.on('focusout', onFocusOut );
|
||||
tag.on('change', onAlterTag );
|
||||
tag.on('focusin', onFocusIn );
|
||||
tag.on('focusout', onFocusOut );
|
||||
del.on('click', onDeleteTag );
|
||||
div.append(regex);
|
||||
div.append(tag);
|
||||
div.append(del);
|
||||
formdiv.append(div);
|
||||
}
|
||||
|
||||
//
|
||||
// generate a whole new regex/tag/delete button row
|
||||
var onNewRegexRow = function (formdiv) {
|
||||
var nextid = 1;
|
||||
while( nextid in spawnmap ) { // pseudo-index spawnmap with id reuse
|
||||
nextid++;
|
||||
}
|
||||
var div = $("<div data-id='"+nextid+"'>");
|
||||
displayRow(formdiv, div, "", "");
|
||||
}
|
||||
|
||||
|
||||
// Public
|
||||
|
||||
//
|
||||
// onOptionsUI -- display the existing spawnmap and a button to create more entries.
|
||||
//
|
||||
var onOptionsUI = function (parentdiv) {
|
||||
var formdiv = $('<div>');
|
||||
var button= $('<input type="button" value="New Regex/Tag Pair" />');
|
||||
button.on('click', function () { onNewRegexRow(formdiv) });
|
||||
formdiv.append(button);
|
||||
|
||||
// display the existing spawnmap
|
||||
for( var id in spawnmap ) {
|
||||
var div = $("<div data-id='"+id+"'>");
|
||||
displayRow(formdiv, div, spawnmap[id]["r"], spawnmap[id]["t"] );
|
||||
}
|
||||
|
||||
parentdiv.append('<div style="font-weight: bold">Message Routing:</div>');
|
||||
parentdiv.append(formdiv);
|
||||
}
|
||||
|
||||
//
|
||||
// onText -- catch Text before it is routed by the goldenlayout router
|
||||
// then test our list of regexes on the given text to see if it matches.
|
||||
// If it does, rewrite the Text Type to be our tag value instead.
|
||||
//
|
||||
var onText = function (args, kwargs) {
|
||||
var div = $("<div>" + args[0] + "</div>");
|
||||
var txt = div.text();
|
||||
for( var id in spawnmap ) {
|
||||
var regex = spawnmap[id]["r"];
|
||||
if ( txt.match(regex) != null ) {
|
||||
kwargs['type'] = spawnmap[id]["t"];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// OnKeydown -- if the Options window is open, capture focus
|
||||
//
|
||||
var onKeydown = function(evnt) {
|
||||
return ignoreDefaultKeydown;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// init
|
||||
//
|
||||
var init = function () {
|
||||
var ls_spawnmap = localStorage.getItem( "evenniaMessageRoutingSavedState" );
|
||||
if( ls_spawnmap ) {
|
||||
spawnmap = JSON.parse(ls_spawnmap);
|
||||
for( var id in spawnmap ) {
|
||||
window.plugins["goldenlayout"].addKnownType( spawnmap[id]["t"] );
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Client-Side Message Routing plugin initialized');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onOptionsUI: onOptionsUI,
|
||||
onText: onText,
|
||||
onKeydown: onKeydown,
|
||||
}
|
||||
})();
|
||||
window.plugin_handler.add("spawns", spawns);
|
||||
184
evennia/web/webclient/static/webclient/js/plugins/options2.js
Normal file
184
evennia/web/webclient/static/webclient/js/plugins/options2.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Options 2.0
|
||||
* REQUIRES: goldenlayout.js
|
||||
*/
|
||||
let options2 = (function () {
|
||||
|
||||
var options_container = null ;
|
||||
|
||||
//
|
||||
// When the user changes a setting from the interface
|
||||
var onOptionCheckboxChanged = function (evnt) {
|
||||
var name = $(evnt.target).data("setting");
|
||||
var value = $(evnt.target).is(":checked");
|
||||
options[name] = value;
|
||||
Evennia.msg("webclient_options", [], options);
|
||||
}
|
||||
|
||||
//
|
||||
// Callback to display our basic OptionsUI
|
||||
var onOptionsUI = function (parentdiv) {
|
||||
var checked;
|
||||
|
||||
checked = options["gagprompt"] ? "checked='checked'" : "";
|
||||
var gagprompt = $( [ "<label>",
|
||||
"<input type='checkbox' data-setting='gagprompt' " + checked + "'>",
|
||||
" Don't echo prompts to the main text area",
|
||||
"</label>"
|
||||
].join("") );
|
||||
|
||||
checked = options["notification_popup"] ? "checked='checked'" : "";
|
||||
var notifypopup = $( [ "<label>",
|
||||
"<input type='checkbox' data-setting='notification_popup' " + checked + "'>",
|
||||
" Popup notification",
|
||||
"</label>"
|
||||
].join("") );
|
||||
|
||||
checked = options["notification_sound"] ? "checked='checked'" : "";
|
||||
var notifysound = $( [ "<label>",
|
||||
"<input type='checkbox' data-setting='notification_sound' " + checked + "'>",
|
||||
" Play a sound",
|
||||
"</label>"
|
||||
].join("") );
|
||||
|
||||
gagprompt.on("change", onOptionCheckboxChanged);
|
||||
notifypopup.on("change", onOptionCheckboxChanged);
|
||||
notifysound.on("change", onOptionCheckboxChanged);
|
||||
|
||||
parentdiv.append(gagprompt);
|
||||
parentdiv.append(notifypopup);
|
||||
parentdiv.append(notifysound);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 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 = $("<div class='accordion' style='overflow-y:scroll; height:inherit;'>");
|
||||
|
||||
for( let plugin in plugins ) {
|
||||
if( "onOptionsUI" in plugins[plugin] ) {
|
||||
var card = $("<div class='card'>");
|
||||
var body = $("<div>");
|
||||
|
||||
plugins[plugin].onOptionsUI( body );
|
||||
|
||||
card.append(body);
|
||||
card.appendTo( div );
|
||||
}
|
||||
}
|
||||
|
||||
div.appendTo( options_container );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// handler for the "Options" button
|
||||
var onOpenCloseOptions = function () {
|
||||
var optionsComponent = {
|
||||
title: "Options",
|
||||
type: "component",
|
||||
componentName: "options",
|
||||
componentState: {
|
||||
},
|
||||
};
|
||||
|
||||
// Create a new GoldenLayout tab filled with the optionsComponent above
|
||||
var myLayout = window.plugins["goldenlayout"].getGL();
|
||||
if( ! options_container ) {
|
||||
// open new optionsComponent
|
||||
var main = myLayout.root.getItemsByType("stack")[0].getActiveContentItem();
|
||||
|
||||
myLayout.on( "tabCreated", function( tab ) {
|
||||
if( tab.contentItem.componentName == "options" ) {
|
||||
tab
|
||||
.closeElement
|
||||
.off("click")
|
||||
.click( function () {
|
||||
options_container = null;
|
||||
tab.contentItem.remove();
|
||||
});
|
||||
options_container = tab.contentItem;
|
||||
}
|
||||
});
|
||||
main.parent.addChild( optionsComponent );
|
||||
} else {
|
||||
options_container.remove();
|
||||
options_container = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
//
|
||||
// Called when options settings are sent from server
|
||||
var onGotOptions = function (args, kwargs) {
|
||||
var addKnownType = window.plugins["goldenlayout"].addKnownType;
|
||||
|
||||
$.each(kwargs, function(key, value) {
|
||||
options[key] = value;
|
||||
|
||||
// for "available_server_tags", addKnownType for each value ["tag1", "tag2", ... ]
|
||||
if( (key === "available_server_tags") && addKnownType ) {
|
||||
$.each( value, addKnownType );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Called when the user logged in
|
||||
var onLoggedIn = function (args, kwargs) {
|
||||
Evennia.msg("webclient_options", [], {});
|
||||
}
|
||||
|
||||
//
|
||||
// Display a "prompt" command from the server
|
||||
var onPrompt = function (args, kwargs) {
|
||||
// display the prompt in the output window if gagging is disabled
|
||||
if( options["gagprompt"] == false ) {
|
||||
plugin_handler.onText(args, kwargs);
|
||||
}
|
||||
|
||||
// don't claim this Prompt as completed.
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
var init = function() {
|
||||
var optionsbutton = $("<button id='optionsbutton'>⚙</button>");
|
||||
$("#toolbar").append( optionsbutton );
|
||||
options["gagprompt"] = true;
|
||||
options["notification_popup"] = true;
|
||||
options["notification_sound"] = true;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
var postInit = function() {
|
||||
// Are we using GoldenLayout?
|
||||
if( window.plugins["goldenlayout"] ) {
|
||||
createOptionsComponent();
|
||||
|
||||
$("#optionsbutton").bind("click", onOpenCloseOptions);
|
||||
}
|
||||
console.log("Options 2.0 Loaded");
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
postInit: postInit,
|
||||
onGotOptions: onGotOptions,
|
||||
onLoggedIn: onLoggedIn,
|
||||
onOptionsUI: onOptionsUI,
|
||||
onPrompt: onPrompt,
|
||||
}
|
||||
})();
|
||||
window.plugin_handler.add("options2", options2);
|
||||
|
|
@ -76,9 +76,16 @@ JQuery available.
|
|||
{% block guilib_import %}
|
||||
<script src={% static "webclient/js/webclient_gui.js" %} language="javascript" type="text/javascript" charset="utf-8"></script>
|
||||
<script src={% static "webclient/js/plugins/goldenlayout_default_config.js" %} type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/clienthelp.js" %} language="javascript" type="text/javascript" charset="utf-8"></script>
|
||||
<script src={% static "webclient/js/plugins/popups.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/options.js" %} language="javascript" type="text/javascript"></script>
|
||||
<!--
|
||||
<script src={% static "webclient/js/plugins/options.js" %} language="javascript" type="text/javascript"></script>
|
||||
-->
|
||||
<script src={% static "webclient/js/plugins/options2.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/iframe.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/message_routing.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/history.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/font.js" %} language="javascript" type="text/javascript" charset="utf-8"></script>
|
||||
<!--
|
||||
<script src={% static "webclient/js/plugins/splithandler.js" %} language="javascript" type="text/javascript"></script>
|
||||
-->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue