mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Merge branch 'develop-plugin-based-webclient' of https://github.com/friarzen/evennia into friarzen-develop-plugin-based-webclient
This commit is contained in:
commit
c6fa04407c
14 changed files with 1230 additions and 759 deletions
|
|
@ -105,6 +105,13 @@ div {margin:0px;}
|
|||
}
|
||||
|
||||
/* Input field */
|
||||
#input {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#inputfield, #inputsizer {
|
||||
height: 100%;
|
||||
background: #000;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient default 'send-text-on-enter-key' IO plugin
|
||||
*
|
||||
*/
|
||||
let defaultin_plugin = (function () {
|
||||
|
||||
//
|
||||
// handle the default <enter> key triggering onSend()
|
||||
var onKeydown = function (event) {
|
||||
if ( (event.which === 13) && (!event.shiftKey) ) { // Enter Key without shift
|
||||
var inputfield = $("#inputfield");
|
||||
var outtext = inputfield.val();
|
||||
var lines = outtext.trim().replace(/[\r]+/,"\n").replace(/[\n]+/, "\n").split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
plugin_handler.onSend( lines[i].trim() );
|
||||
}
|
||||
inputfield.val('');
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Mandatory plugin init function
|
||||
var init = function () {
|
||||
// Handle pressing the send button
|
||||
$("#inputsend")
|
||||
.bind("click", function (event) {
|
||||
var e = $.Event( "keydown" );
|
||||
e.which = 13;
|
||||
$('#inputfield').trigger(e);
|
||||
});
|
||||
|
||||
console.log('DefaultIn initialized');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onKeydown: onKeydown,
|
||||
}
|
||||
})();
|
||||
plugin_handler.add('defaultin', defaultin_plugin);
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient default outputs plugin
|
||||
*
|
||||
*/
|
||||
let defaultout_plugin = (function () {
|
||||
|
||||
//
|
||||
// By default add all unclaimed onText messages to the #messagewindow <div> and scroll
|
||||
var onText = function (args, kwargs) {
|
||||
// append message to default pane, then scroll so latest is at the bottom.
|
||||
var mwin = $("#messagewindow");
|
||||
var cls = kwargs == null ? 'out' : kwargs['cls'];
|
||||
mwin.append("<div class='" + cls + "'>" + args[0] + "</div>");
|
||||
var scrollHeight = mwin.parent().parent().prop("scrollHeight");
|
||||
mwin.parent().parent().animate({ scrollTop: scrollHeight }, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// By default just show the prompt.
|
||||
var onPrompt = function (args, kwargs) {
|
||||
// show prompt
|
||||
$('#prompt')
|
||||
.addClass("out")
|
||||
.html(args[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// By default just show an error for the Unhandled Event.
|
||||
var onUnknownCmd = function (args, kwargs) {
|
||||
var mwin = $("#messagewindow");
|
||||
mwin.append(
|
||||
"<div class='msg err'>"
|
||||
+ "Error or Unhandled event:<br>"
|
||||
+ cmdname + ", "
|
||||
+ JSON.stringify(args) + ", "
|
||||
+ JSON.stringify(kwargs) + "<p></div>");
|
||||
mwin.scrollTop(mwin[0].scrollHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Mandatory plugin init function
|
||||
var init = function () {
|
||||
console.log('DefaultOut initialized');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onText: onText,
|
||||
onPrompt: onPrompt,
|
||||
onUnknownCmd: onUnknownCmd,
|
||||
}
|
||||
})();
|
||||
plugin_handler.add('defaultout', defaultout_plugin);
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient default unload plugin
|
||||
*
|
||||
*/
|
||||
let unload_plugin = (function () {
|
||||
|
||||
let onBeforeUnload = function () {
|
||||
return "You are about to leave the game. Please confirm.";
|
||||
}
|
||||
|
||||
return {
|
||||
init: function () {},
|
||||
onBeforeUnload: onBeforeUnload,
|
||||
}
|
||||
})();
|
||||
plugin_handler.add('unload', unload_plugin);
|
||||
116
evennia/web/webclient/static/webclient/js/plugins/history.js
Normal file
116
evennia/web/webclient/static/webclient/js/plugins/history.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Webclient Command History plugin
|
||||
*
|
||||
*/
|
||||
let history_plugin = (function () {
|
||||
|
||||
// Manage history for input line
|
||||
var history_max = 21;
|
||||
var history = new Array();
|
||||
var history_pos = 0;
|
||||
|
||||
history[0] = ''; // the very latest input is empty for new entry.
|
||||
|
||||
//
|
||||
// move back in the history
|
||||
var back = function () {
|
||||
// step backwards in history stack
|
||||
history_pos = Math.min(++history_pos, history.length - 1);
|
||||
return history[history.length - 1 - history_pos];
|
||||
}
|
||||
|
||||
//
|
||||
// move forward in the history
|
||||
var fwd = function () {
|
||||
// step forwards in history stack
|
||||
history_pos = Math.max(--history_pos, 0);
|
||||
return history[history.length - 1 - history_pos];
|
||||
}
|
||||
|
||||
//
|
||||
// add a new history line
|
||||
var add = function (input) {
|
||||
// add a new entry to history, don't repeat latest
|
||||
if (input && input != history[history.length-2]) {
|
||||
if (history.length >= history_max) {
|
||||
history.shift(); // kill oldest entry
|
||||
}
|
||||
history[history.length-1] = input;
|
||||
history[history.length] = '';
|
||||
}
|
||||
// reset the position to the last history entry
|
||||
history_pos = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Go to the last history line
|
||||
var end = function () {
|
||||
// move to the end of the history stack
|
||||
history_pos = 0;
|
||||
return history[history.length -1];
|
||||
}
|
||||
|
||||
//
|
||||
// Add input to the scratch line
|
||||
var scratch = function (input) {
|
||||
// Put the input into the last history entry (which is normally empty)
|
||||
// without making the array larger as with add.
|
||||
// Allows for in-progress editing to be saved.
|
||||
history[history.length-1] = input;
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
//
|
||||
// Handle up arrow and down arrow events.
|
||||
var onKeydown = function(event) {
|
||||
var code = event.which;
|
||||
var history_entry = null;
|
||||
var inputfield = $("#inputfield");
|
||||
|
||||
if (inputfield[0].selectionStart == inputfield.val().length) {
|
||||
// Only process up/down arrow if cursor is at the end of the line.
|
||||
if (code === 38) { // Arrow up
|
||||
history_entry = back();
|
||||
}
|
||||
else if (code === 40) { // Arrow down
|
||||
history_entry = fwd();
|
||||
}
|
||||
}
|
||||
|
||||
if (history_entry !== null) {
|
||||
// Doing a history navigation; replace the text in the input.
|
||||
inputfield.val(history_entry);
|
||||
}
|
||||
else {
|
||||
// Save the current contents of the input to the history scratch area.
|
||||
setTimeout(function () {
|
||||
// Need to wait until after the key-up to capture the value.
|
||||
scratch(inputfield.val());
|
||||
end();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Listen for onSend lines to add to history
|
||||
var onSend = function (line) {
|
||||
add(line);
|
||||
}
|
||||
|
||||
//
|
||||
// Init function
|
||||
var init = function () {
|
||||
console.log('History Plugin Initialized.');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onKeydown: onKeydown,
|
||||
onSend: onSend,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('history', history_plugin);
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
*
|
||||
* Desktop Notifications Plugin
|
||||
*
|
||||
*/
|
||||
let notifications_plugin = (function () {
|
||||
// Notifications
|
||||
var unread = 0;
|
||||
var originalTitle = document.title;
|
||||
var focused = true;
|
||||
var favico;
|
||||
|
||||
var onBlur = function (e) {
|
||||
focused = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Notifications for unfocused window
|
||||
var onFocus = function (e) {
|
||||
focused = true;
|
||||
document.title = originalTitle;
|
||||
unread = 0;
|
||||
favico.badge(0);
|
||||
}
|
||||
|
||||
//
|
||||
// on receiving new text from the server, if we are not focused, send a notification to the desktop
|
||||
var onText = function (args, kwargs) {
|
||||
if(!focused) {
|
||||
// Changes unfocused browser tab title to number of unread messages
|
||||
unread++;
|
||||
favico.badge(unread);
|
||||
document.title = "(" + unread + ") " + originalTitle;
|
||||
if ("Notification" in window) {
|
||||
if (("notification_popup" in options) && (options["notification_popup"])) {
|
||||
// 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 = {
|
||||
body: text.replace(/(<([^>]+)>)/ig,""),
|
||||
icon: "/static/website/images/evennia_logo.png"
|
||||
}
|
||||
|
||||
var n = new Notification(title, options);
|
||||
n.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
window.focus();
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (("notification_sound" in options) && (options["notification_sound"])) {
|
||||
var audio = new Audio("/static/webclient/media/notification.wav");
|
||||
audio.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// required init function
|
||||
var init = function () {
|
||||
if ("Notification" in window) {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
|
||||
favico = new Favico({
|
||||
animation: 'none'
|
||||
});
|
||||
|
||||
$(window).blur(onBlur);
|
||||
$(window).focus(onFocus);
|
||||
|
||||
console.log('Notifications Plugin Initialized.');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onText: onText,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('notifications', notifications_plugin);
|
||||
35
evennia/web/webclient/static/webclient/js/plugins/oob.js
Normal file
35
evennia/web/webclient/static/webclient/js/plugins/oob.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*
|
||||
* OOB Plugin
|
||||
* enables '##send { "command", [ args ], { kwargs } }' as a way to inject OOB instructions
|
||||
*
|
||||
*/
|
||||
let oob_plugin = (function () {
|
||||
|
||||
//
|
||||
// Check outgoing text for handtyped/injected JSON OOB instruction
|
||||
var onSend = function (line) {
|
||||
if (line.length > 7 && line.substr(0, 7) == "##send ") {
|
||||
// send a specific oob instruction ["cmdname",[args],{kwargs}]
|
||||
line = line.slice(7);
|
||||
var cmdarr = JSON.parse(line);
|
||||
var cmdname = cmdarr[0];
|
||||
var args = cmdarr[1];
|
||||
var kwargs = cmdarr[2];
|
||||
log(cmdname, args, kwargs);
|
||||
return (cmdname, args, kwargs);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// init function
|
||||
var init = function () {
|
||||
console.log('OOB Plugin Initialized.');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onSend: onSend,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('oob', oob_plugin);
|
||||
162
evennia/web/webclient/static/webclient/js/plugins/options.js
Normal file
162
evennia/web/webclient/static/webclient/js/plugins/options.js
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
*
|
||||
* Evennia Options GUI plugin
|
||||
*
|
||||
* This code deals with all of the UI and events related to Options.
|
||||
*
|
||||
*/
|
||||
let options_plugin = (function () {
|
||||
//
|
||||
// addOptionsUI
|
||||
var addOptionsUI = function () {
|
||||
var content = [ // TODO dynamically create this based on the options{} hash
|
||||
'<h3>Output display</h3>',
|
||||
'<label><input type="checkbox" data-setting="gagprompt" value="value">Don\'t echo prompts to the main text area</label>',
|
||||
'<br />',
|
||||
'<label><input type="checkbox" data-setting="helppopup" value="value">Open help in popup window</label>',
|
||||
'<br />',
|
||||
'<hr />',
|
||||
'<h3>Notifications</h3>',
|
||||
'<label><input type="checkbox" data-setting="notification_popup" value="value">Popup notification</label>',
|
||||
'<br />',
|
||||
'<label><input type="checkbox" data-setting="notification_sound" value="value">Play a sound</label>',
|
||||
'<br />',
|
||||
].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 = $( [
|
||||
'<button id="optionsbutton" type="button" aria-haspopup="true" aria-owns="#optionsdialog">',
|
||||
'⚙',
|
||||
'<span class="sr-only sr-only-focusable">Settings</span>',
|
||||
'</button>',
|
||||
].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");
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
//
|
||||
// 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,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('options', options_plugin);
|
||||
101
evennia/web/webclient/static/webclient/js/plugins/popups.js
Normal file
101
evennia/web/webclient/static/webclient/js/plugins/popups.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Popups GUI functions plugin
|
||||
*/
|
||||
let popups_plugin = (function () {
|
||||
|
||||
//
|
||||
// openPopup
|
||||
var openPopup = function (dialogname, content) {
|
||||
var dialog = $(dialogname);
|
||||
if (!dialog.length) {
|
||||
console.log("Dialog " + renderto + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (content) {
|
||||
var contentel = dialog.find(".dialogcontent");
|
||||
contentel.html(content);
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
//
|
||||
// closePopup
|
||||
var closePopup = function (dialogname) {
|
||||
var dialog = $(dialogname);
|
||||
dialog.hide();
|
||||
}
|
||||
|
||||
//
|
||||
// togglePopup
|
||||
var togglePopup = function (dialogname, content) {
|
||||
var dialog = $(dialogname);
|
||||
if (dialog.css('display') == 'none') {
|
||||
openPopup(dialogname, content);
|
||||
} else {
|
||||
closePopup(dialogname);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// createDialog
|
||||
var createDialog = function (dialogid, dialogtitle, content) {
|
||||
var dialog = $( [
|
||||
'<div id="'+ dialogid +'" class="dialog">',
|
||||
' <div class="dialogtitle">'+ dialogtitle +'<span class="dialogclose">×</span></div>',
|
||||
' <div class="dialogcontentparent">',
|
||||
' <div id="'+ dialogid +'content" class="dialogcontent">'+ content +'</div>',
|
||||
' </div>',
|
||||
' </div>',
|
||||
'</div>',
|
||||
].join("\n") );
|
||||
|
||||
$('body').append( dialog );
|
||||
|
||||
$('#'+ dialogid +' .dialogclose').bind('click', function (event) { $('#'+dialogid).hide(); });
|
||||
}
|
||||
|
||||
//
|
||||
// User clicked on a dialog to drag it
|
||||
var doStartDragDialog = function (event) {
|
||||
var dialog = $(event.target).closest(".dialog");
|
||||
dialog.css('cursor', 'move');
|
||||
|
||||
var position = dialog.offset();
|
||||
var diffx = event.pageX;
|
||||
var diffy = event.pageY;
|
||||
|
||||
var drag = function(event) {
|
||||
var y = position.top + event.pageY - diffy;
|
||||
var x = position.left + event.pageX - diffx;
|
||||
dialog.offset({top: y, left: x});
|
||||
};
|
||||
|
||||
var undrag = function() {
|
||||
$(document).unbind("mousemove", drag);
|
||||
$(document).unbind("mouseup", undrag);
|
||||
dialog.css('cursor', '');
|
||||
}
|
||||
|
||||
$(document).bind("mousemove", drag);
|
||||
$(document).bind("mouseup", undrag);
|
||||
}
|
||||
|
||||
//
|
||||
// required plugin function
|
||||
var init = function () {
|
||||
// Makes dialogs draggable
|
||||
$(".dialogtitle").bind("mousedown", doStartDragDialog);
|
||||
|
||||
console.log('Popups Plugin Initialized.');
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
openPopup: openPopup,
|
||||
closePopup: closePopup,
|
||||
togglePopup: togglePopup,
|
||||
createDialog: createDialog,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('popups', popups_plugin);
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
*
|
||||
* Plugin to use split.js to create a basic windowed ui
|
||||
*
|
||||
*/
|
||||
let splithandler_plugin = (function () {
|
||||
|
||||
var num_splits = 0;
|
||||
var split_panes = {};
|
||||
var backout_list = new Array;
|
||||
|
||||
var known_types = new Array();
|
||||
|
||||
// Exported Functions
|
||||
|
||||
//
|
||||
// function to assign "Text types to catch" to a pane
|
||||
var set_pane_types = function (splitpane, types) {
|
||||
split_panes[splitpane]['types'] = types;
|
||||
}
|
||||
|
||||
//
|
||||
// Add buttons to the Evennia webcilent toolbar
|
||||
function addToolbarButtons () {
|
||||
var toolbar = $('#toolbar');
|
||||
toolbar.append( $('<button id="splitbutton" type="button">⇹</button>') );
|
||||
toolbar.append( $('<button id="panebutton" type="button">⚙</button>') );
|
||||
toolbar.append( $('<button id="undobutton" type="button">↶</button>') );
|
||||
$('#undobutton').hide();
|
||||
}
|
||||
|
||||
function addSplitDialog () {
|
||||
plugins['popups'].createDialog('splitdialog', 'Split Dialog', '');
|
||||
}
|
||||
|
||||
function addPaneDialog () {
|
||||
plugins['popups'].createDialog('panedialog', 'Pane Dialog', '');
|
||||
}
|
||||
|
||||
//
|
||||
// Handle resizing the InputField after a client resize event so that the splits dont get too big.
|
||||
function resizeInputField () {
|
||||
var wrapper = $("#inputform")
|
||||
var input = $("#inputcontrol")
|
||||
var prompt = $("#prompt")
|
||||
|
||||
input.height( wrapper.height() - (input.offset().top - wrapper.offset().top) );
|
||||
}
|
||||
|
||||
//
|
||||
// Handle resizing of client
|
||||
function doWindowResize() {
|
||||
var resizable = $("[data-update-append]");
|
||||
var parents = resizable.closest(".split");
|
||||
|
||||
resizeInputField();
|
||||
|
||||
parents.animate({
|
||||
scrollTop: parents.prop("scrollHeight")
|
||||
}, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// create a new UI split
|
||||
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';
|
||||
|
||||
// create the new div stack to replace the sub-div with.
|
||||
var first_div = $( '<div id="'+pane_name1+'" class="split split-'+direction+'" />' )
|
||||
var first_sub = $( '<div id="'+pane_name1+'-sub" class="split-sub" />' )
|
||||
var second_div = $( '<div id="'+pane_name2+'" class="split split-'+direction+'" />' )
|
||||
var second_sub = $( '<div id="'+pane_name2+'-sub" class="split-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-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 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.
|
||||
$('#'+splitpane).append(first_div);
|
||||
$('#'+splitpane).append(second_div);
|
||||
$('#'+splitpane+'-sub').remove();
|
||||
|
||||
// And split
|
||||
Split(['#'+pane_name1,'#'+pane_name2], {
|
||||
direction: direction,
|
||||
sizes: sizes,
|
||||
gutterSize: 4,
|
||||
minSize: [50,50],
|
||||
});
|
||||
|
||||
// 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} );
|
||||
|
||||
$('#undobutton').show();
|
||||
}
|
||||
|
||||
//
|
||||
// Reverse the last UI split
|
||||
var undo_split = function () {
|
||||
// pop off the last split pair
|
||||
var back = backout_list.pop();
|
||||
if( !back ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( backout_list.length === 0 ) {
|
||||
$('#undobutton').hide();
|
||||
}
|
||||
|
||||
// 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 = $( '<div id="'+pane1_parent.attr('id')+'-sub" class="split-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'];
|
||||
}
|
||||
|
||||
//
|
||||
// UI elements
|
||||
//
|
||||
|
||||
//
|
||||
// Draw "Split Controls" Dialog
|
||||
var onSplitDialog = function () {
|
||||
var dialog = $("#splitdialogcontent");
|
||||
dialog.empty();
|
||||
|
||||
dialog.append("<h3>Split?</h3>");
|
||||
dialog.append('<input type="radio" name="direction" value="vertical" checked> top/bottom<br />');
|
||||
dialog.append('<input type="radio" name="direction" value="horizontal"> side-by-side<br />');
|
||||
|
||||
dialog.append("<h3>Split Which Pane?</h3>");
|
||||
for ( var pane in split_panes ) {
|
||||
dialog.append('<input type="radio" name="pane" value="'+ pane +'">'+ pane +'<br />');
|
||||
}
|
||||
|
||||
dialog.append("<h3>New Pane Names</h3>");
|
||||
dialog.append('<input type="text" name="new_pane1" value="" />');
|
||||
dialog.append('<input type="text" name="new_pane2" value="" />');
|
||||
|
||||
dialog.append("<h3>New First Pane Flow</h3>");
|
||||
dialog.append('<input type="radio" name="flow1" value="append" checked>append<br />');
|
||||
dialog.append('<input type="radio" name="flow1" value="replace">replace<br />');
|
||||
|
||||
dialog.append("<h3>New Second Pane Flow</h3>");
|
||||
dialog.append('<input type="radio" name="flow2" value="append" checked>append<br />');
|
||||
dialog.append('<input type="radio" name="flow2" value="replace">replace<br />');
|
||||
|
||||
dialog.append('<div id="splitclose" class="button">Split It</div>');
|
||||
|
||||
$("#splitclose").bind("click", onSplitDialogClose);
|
||||
|
||||
plugins['popups'].togglePopup("#splitdialog");
|
||||
}
|
||||
|
||||
//
|
||||
// Close "Split Controls" Dialog
|
||||
var onSplitDialogClose = function () {
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dynamic_split( pane, direction, new_pane1, new_pane2, flow1, flow2, [50,50] );
|
||||
|
||||
plugins['popups'].closePopup("#splitdialog");
|
||||
}
|
||||
|
||||
//
|
||||
// Draw "Pane Controls" dialog
|
||||
var onPaneControlDialog = function () {
|
||||
var dialog = $("#splitdialogcontent");
|
||||
dialog.empty();
|
||||
|
||||
dialog.append("<h3>Set Which Pane?</h3>");
|
||||
for ( var pane in split_panes ) {
|
||||
dialog.append('<input type="radio" name="pane" value="'+ pane +'">'+ pane +'<br />');
|
||||
}
|
||||
|
||||
dialog.append("<h3>Which content types?</h3>");
|
||||
for ( var type in known_types ) {
|
||||
dialog.append('<input type="checkbox" value="'+ known_types[type] +'">'+ known_types[type] +'<br />');
|
||||
}
|
||||
|
||||
dialog.append('<div id="paneclose" class="button">Make It So</div>');
|
||||
|
||||
$("#paneclose").bind("click", onPaneControlDialogClose);
|
||||
|
||||
plugins['popups'].togglePopup("#splitdialog");
|
||||
}
|
||||
|
||||
//
|
||||
// Close "Pane Controls" dialog
|
||||
var onPaneControlDialogClose = function () {
|
||||
var pane = $("input[name=pane]:checked").attr("value");
|
||||
|
||||
var types = new Array;
|
||||
$('#splitdialogcontent input[type=checkbox]:checked').each(function() {
|
||||
types.push( $(this).attr('value') );
|
||||
});
|
||||
|
||||
set_pane_types( pane, types );
|
||||
|
||||
plugins['popups'].closePopup("#splitdialog");
|
||||
}
|
||||
|
||||
//
|
||||
// plugin functions
|
||||
//
|
||||
|
||||
//
|
||||
// Accept plugin onText events
|
||||
var onText = function (args, kwargs) {
|
||||
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);
|
||||
}
|
||||
|
||||
for ( var key in split_panes) {
|
||||
var pane = 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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Required plugin "init" function
|
||||
var init = function(settings) {
|
||||
known_types.push('help');
|
||||
|
||||
Split(['#main','#input'], {
|
||||
direction: 'vertical',
|
||||
sizes: [90,10],
|
||||
gutterSize: 4,
|
||||
minSize: [50,50],
|
||||
});
|
||||
|
||||
split_panes['main'] = { 'types': [], 'update_method': 'append' };
|
||||
|
||||
// Create our UI
|
||||
addToolbarButtons();
|
||||
addSplitDialog();
|
||||
addPaneDialog();
|
||||
|
||||
// Register our utility button events
|
||||
$("#splitbutton").bind("click", onSplitDialog);
|
||||
$("#panebutton").bind("click", onPaneControlDialog);
|
||||
$("#undobutton").bind("click", undo_split);
|
||||
|
||||
// Event when client window changes
|
||||
$(window).bind("resize", doWindowResize);
|
||||
|
||||
$("[data-role-input]").bind("resize", doWindowResize)
|
||||
.bind("paste", resizeInputField)
|
||||
.bind("cut", resizeInputField);
|
||||
|
||||
// Event when any key is pressed
|
||||
$(document).keyup(resizeInputField);
|
||||
|
||||
console.log("Splithandler Plugin Initialized.");
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onText: onText,
|
||||
dynamic_split: dynamic_split,
|
||||
undo_split: undo_split,
|
||||
set_pane_types: set_pane_types,
|
||||
}
|
||||
})()
|
||||
plugin_handler.add('splithandler', splithandler_plugin);
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
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';
|
||||
|
||||
// create the new div stack to replace the sub-div with.
|
||||
var first_div = $( '<div id="'+pane_name1+'" class="split split-'+direction+'" />' )
|
||||
var first_sub = $( '<div id="'+pane_name1+'-sub" class="split-sub" />' )
|
||||
var second_div = $( '<div id="'+pane_name2+'" class="split split-'+direction+'" />' )
|
||||
var second_sub = $( '<div id="'+pane_name2+'-sub" class="split-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-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 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.
|
||||
$('#'+splitpane).append(first_div);
|
||||
$('#'+splitpane).append(second_div);
|
||||
$('#'+splitpane+'-sub').remove();
|
||||
|
||||
// And split
|
||||
Split(['#'+pane_name1,'#'+pane_name2], {
|
||||
direction: direction,
|
||||
sizes: sizes,
|
||||
gutterSize: 4,
|
||||
minSize: [50,50],
|
||||
});
|
||||
|
||||
// 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 = $( '<div id="'+pane1_parent.attr('id')+'-sub" class="split-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'];
|
||||
}
|
||||
|
||||
|
||||
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],
|
||||
});
|
||||
|
||||
split_panes['main'] = { 'types': [], 'update_method': 'append' };
|
||||
|
||||
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,
|
||||
undo_split: undo_split,
|
||||
}
|
||||
})();
|
||||
|
|
@ -5,625 +5,285 @@
|
|||
* This is used in conjunction with the main evennia.js library, which
|
||||
* handles all the communication with the Server.
|
||||
*
|
||||
* The job of this code is to create listeners to subscribe to evennia
|
||||
* messages, via Evennia.emitter.on(cmdname, listener) and to handle
|
||||
* input from the user and send it to
|
||||
* Evennia.msg(cmdname, args, kwargs, [callback]).
|
||||
* The job of this code is to coordinate between listeners subscribed to
|
||||
* evennia messages and any registered plugins that want to process those
|
||||
* messages and send data back to Evennia
|
||||
*
|
||||
* This is done via Evennia.emitter.on(cmdname, listener) and calling
|
||||
* each plugin's init() function to give each plugin a chance to register
|
||||
* input handlers or other events on startup.
|
||||
*
|
||||
* Once a plugin has determined it wants to send a message back to the
|
||||
* server, it generates an onSend() function event which allows all
|
||||
* other plugins a chance to modify the event and then uses
|
||||
* Evennia.msg(cmdname, args, kwargs, [callback]) to finally send the data.
|
||||
*
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict"
|
||||
|
||||
var num_splits = 0; //unique id counter for default split-panel names
|
||||
|
||||
var options = {};
|
||||
|
||||
var known_types = new Array();
|
||||
known_types.push('help');
|
||||
|
||||
//
|
||||
// GUI Elements
|
||||
// Global Plugins system
|
||||
//
|
||||
|
||||
var options = {}; // Global "settings" object that all plugins can use to
|
||||
// save/pass data to each other and the server.
|
||||
// format should match:
|
||||
// { 'plugin_name': { 'option_key': value, ... }, ... }
|
||||
|
||||
// Manage history for input line
|
||||
var input_history = function() {
|
||||
var history_max = 21;
|
||||
var history = new Array();
|
||||
var history_pos = 0;
|
||||
|
||||
history[0] = ''; // the very latest input is empty for new entry.
|
||||
|
||||
var back = function () {
|
||||
// step backwards in history stack
|
||||
history_pos = Math.min(++history_pos, history.length - 1);
|
||||
return history[history.length - 1 - history_pos];
|
||||
};
|
||||
var fwd = function () {
|
||||
// step forwards in history stack
|
||||
history_pos = Math.max(--history_pos, 0);
|
||||
return history[history.length - 1 - history_pos];
|
||||
};
|
||||
var add = function (input) {
|
||||
// add a new entry to history, don't repeat latest
|
||||
if (input && input != history[history.length-2]) {
|
||||
if (history.length >= history_max) {
|
||||
history.shift(); // kill oldest entry
|
||||
}
|
||||
history[history.length-1] = input;
|
||||
history[history.length] = '';
|
||||
};
|
||||
// reset the position to the last history entry
|
||||
history_pos = 0;
|
||||
};
|
||||
var end = function () {
|
||||
// move to the end of the history stack
|
||||
history_pos = 0;
|
||||
return history[history.length -1];
|
||||
}
|
||||
|
||||
var scratch = function (input) {
|
||||
// Put the input into the last history entry (which is normally empty)
|
||||
// without making the array larger as with add.
|
||||
// Allows for in-progress editing to be saved.
|
||||
history[history.length-1] = input;
|
||||
}
|
||||
|
||||
return {back: back,
|
||||
fwd: fwd,
|
||||
add: add,
|
||||
end: end,
|
||||
scratch: scratch}
|
||||
}();
|
||||
|
||||
function openPopup(dialogname, content) {
|
||||
var dialog = $(dialogname);
|
||||
if (!dialog.length) {
|
||||
console.log("Dialog " + renderto + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (content) {
|
||||
var contentel = dialog.find(".dialogcontent");
|
||||
contentel.html(content);
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
function closePopup(dialogname) {
|
||||
var dialog = $(dialogname);
|
||||
dialog.hide();
|
||||
}
|
||||
|
||||
function togglePopup(dialogname, content) {
|
||||
var dialog = $(dialogname);
|
||||
if (dialog.css('display') == 'none') {
|
||||
openPopup(dialogname, content);
|
||||
} else {
|
||||
closePopup(dialogname);
|
||||
}
|
||||
}
|
||||
var plugins = {}; // Global plugin objects by name.
|
||||
// Each must have an init() function.
|
||||
|
||||
//
|
||||
// GUI Event Handlers
|
||||
// Global plugin_handler
|
||||
//
|
||||
var plugin_handler = (function () {
|
||||
"use strict"
|
||||
|
||||
// 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) {
|
||||
onText(["Attempting to reconnnect..."], {cls: "sys"});
|
||||
Evennia.connect();
|
||||
}
|
||||
// Don't try to send anything until the connection is back.
|
||||
return;
|
||||
}
|
||||
var inputfield = $("#inputfield");
|
||||
var outtext = inputfield.val();
|
||||
var lines = outtext.trim().replace(/[\r]+/,"\n").replace(/[\n]+/, "\n").split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim();
|
||||
if (line.length > 7 && line.substr(0, 7) == "##send ") {
|
||||
// send a specific oob instruction ["cmdname",[args],{kwargs}]
|
||||
line = line.slice(7);
|
||||
var cmdarr = JSON.parse(line);
|
||||
var cmdname = cmdarr[0];
|
||||
var args = cmdarr[1];
|
||||
var kwargs = cmdarr[2];
|
||||
log(cmdname, args, kwargs);
|
||||
Evennia.msg(cmdname, args, kwargs);
|
||||
} else {
|
||||
input_history.add(line);
|
||||
inputfield.val("");
|
||||
Evennia.msg("text", [line], {});
|
||||
}
|
||||
}
|
||||
}
|
||||
var ordered_plugins = new Array; // plugins in <html> loaded order
|
||||
|
||||
// Opens the options dialog
|
||||
function doOpenOptions() {
|
||||
if (!Evennia.isConnected()) {
|
||||
alert("You need to be connected.");
|
||||
return;
|
||||
//
|
||||
// Plugin Support Functions
|
||||
//
|
||||
|
||||
// Add a new plugin
|
||||
var add = function (name, plugin) {
|
||||
plugins[name] = plugin;
|
||||
ordered_plugins.push( plugin );
|
||||
}
|
||||
|
||||
togglePopup("#optionsdialog");
|
||||
}
|
||||
|
||||
// Closes the currently open dialog
|
||||
function doCloseDialog(event) {
|
||||
var dialog = $(event.target).closest(".dialog");
|
||||
dialog.hide();
|
||||
}
|
||||
//
|
||||
// GUI Event Handlers
|
||||
//
|
||||
|
||||
// catch all keyboard input, handle special chars
|
||||
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
|
||||
doSendText();
|
||||
event.preventDefault();
|
||||
}
|
||||
else if (inputfield[0].selectionStart == inputfield.val().length) {
|
||||
// Only process up/down arrow if cursor is at the end of the line.
|
||||
if (code === 38) { // Arrow up
|
||||
history_entry = input_history.back();
|
||||
}
|
||||
else if (code === 40) { // Arrow down
|
||||
history_entry = input_history.fwd();
|
||||
}
|
||||
}
|
||||
|
||||
if (code === 27) { // Escape key
|
||||
if ($('#helpdialog').is(':visible')) {
|
||||
closePopup("#helpdialog");
|
||||
} else {
|
||||
closePopup("#optionsdialog");
|
||||
}
|
||||
}
|
||||
|
||||
if (history_entry !== null) {
|
||||
// Doing a history navigation; replace the text in the input.
|
||||
inputfield.val(history_entry);
|
||||
event.preventDefault();
|
||||
}
|
||||
else {
|
||||
// Save the current contents of the input to the history scratch area.
|
||||
setTimeout(function () {
|
||||
// Need to wait until after the key-up to capture the value.
|
||||
input_history.scratch(inputfield.val());
|
||||
input_history.end();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
function onKeyPress (event) {
|
||||
// Prevent carriage returns inside the input area.
|
||||
if (event.which === 13) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
var resizeInputField = function () {
|
||||
return function() {
|
||||
var wrapper = $("#inputform")
|
||||
var input = $("#inputcontrol")
|
||||
var prompt = $("#prompt")
|
||||
|
||||
input.height(wrapper.height() - (input.offset().top - wrapper.offset().top));
|
||||
}
|
||||
}();
|
||||
|
||||
// Handle resizing of client
|
||||
function doWindowResize() {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// catch all keyboard input, handle special chars
|
||||
var onKeydown = function (event) {
|
||||
// cycle through each plugin's keydown
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
// does this plugin handle keydown events?
|
||||
if( 'onKeydown' in plugin ) {
|
||||
// yes, does this plugin claim this event exclusively?
|
||||
if( plugin.onKeydown(event) ) {
|
||||
// 'true' claims this event has been handled
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('NO plugin handled this Keydown');
|
||||
}
|
||||
|
||||
// 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("<div class='" + cls + "'>" + args[0] + "</div>");
|
||||
var scrollHeight = mwin.parent().parent().prop("scrollHeight");
|
||||
mwin.parent().parent().animate({ scrollTop: scrollHeight }, 0);
|
||||
|
||||
onNewLine(args[0], null);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle prompt output from the server
|
||||
function onPrompt(args, kwargs) {
|
||||
// show prompt
|
||||
$('#prompt')
|
||||
.addClass("out")
|
||||
.html(args[0]);
|
||||
doWindowResize();
|
||||
|
||||
// also display the prompt in the output window if gagging is disabled
|
||||
if (("gagprompt" in options) && (!options["gagprompt"])) {
|
||||
onText(args, kwargs);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the user logged in
|
||||
function onLoggedIn() {
|
||||
$('#optionsbutton').removeClass('hidden');
|
||||
Evennia.msg("webclient_options", [], {});
|
||||
}
|
||||
|
||||
// Called when a setting changed
|
||||
function onGotOptions(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);
|
||||
} else {
|
||||
elem.prop('checked', value);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Called when the user changed a setting from the interface
|
||||
function onOptionCheckboxChanged() {
|
||||
var name = $(this).data("setting");
|
||||
var value = this.checked;
|
||||
|
||||
var changedoptions = {};
|
||||
changedoptions[name] = value;
|
||||
Evennia.msg("webclient_options", [], changedoptions);
|
||||
|
||||
options[name] = value;
|
||||
}
|
||||
|
||||
// Silences events we don't do anything with.
|
||||
function onSilence(cmdname, args, kwargs) {}
|
||||
|
||||
// Handle the server connection closing
|
||||
function onConnectionClose(conn_name, evt) {
|
||||
$('#optionsbutton').addClass('hidden');
|
||||
closePopup("#optionsdialog");
|
||||
onText(["The connection was closed or lost."], {'cls': 'err'});
|
||||
}
|
||||
|
||||
// Handle unrecognized commands from server
|
||||
function onDefault(cmdname, args, kwargs) {
|
||||
var mwin = $("#messagewindow");
|
||||
mwin.append(
|
||||
"<div class='msg err'>"
|
||||
+ "Error or Unhandled event:<br>"
|
||||
+ cmdname + ", "
|
||||
+ JSON.stringify(args) + ", "
|
||||
+ JSON.stringify(kwargs) + "<p></div>");
|
||||
mwin.scrollTop(mwin[0].scrollHeight);
|
||||
}
|
||||
|
||||
// Ask if user really wants to exit session when closing
|
||||
// the tab or reloading the page. Note: the message is not shown
|
||||
// in Firefox, there it's a standard error.
|
||||
function onBeforeUnload() {
|
||||
return "You are about to leave the game. Please confirm.";
|
||||
}
|
||||
|
||||
// Notifications
|
||||
var unread = 0;
|
||||
var originalTitle = document.title;
|
||||
var focused = true;
|
||||
var favico;
|
||||
|
||||
function onBlur(e) {
|
||||
focused = false;
|
||||
}
|
||||
|
||||
// Notifications for unfocused window
|
||||
function onFocus(e) {
|
||||
focused = true;
|
||||
document.title = originalTitle;
|
||||
unread = 0;
|
||||
favico.badge(0);
|
||||
}
|
||||
|
||||
function onNewLine(text, originator) {
|
||||
if(!focused) {
|
||||
// Changes unfocused browser tab title to number of unread messages
|
||||
unread++;
|
||||
favico.badge(unread);
|
||||
document.title = "(" + unread + ") " + originalTitle;
|
||||
if ("Notification" in window){
|
||||
if (("notification_popup" in options) && (options["notification_popup"])) {
|
||||
// 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 = {
|
||||
body: text.replace(/(<([^>]+)>)/ig,""),
|
||||
icon: "/static/website/images/evennia_logo.png"
|
||||
}
|
||||
|
||||
var n = new Notification(title, options);
|
||||
n.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
window.focus();
|
||||
this.close();
|
||||
}
|
||||
// Ask if user really wants to exit session when closing
|
||||
// the tab or reloading the page. Note: the message is not shown
|
||||
// in Firefox, there it's a standard error.
|
||||
var onBeforeUnload = function () {
|
||||
// cycle through each plugin to look for unload handlers
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onBeforeUnload' in plugin ) {
|
||||
plugin.onBeforeUnload();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (("notification_sound" in options) && (options["notification_sound"])) {
|
||||
var audio = new Audio("/static/webclient/media/notification.wav");
|
||||
audio.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User clicked on a dialog to drag it
|
||||
function doStartDragDialog(event) {
|
||||
var dialog = $(event.target).closest(".dialog");
|
||||
dialog.css('cursor', 'move');
|
||||
|
||||
var position = dialog.offset();
|
||||
var diffx = event.pageX;
|
||||
var diffy = event.pageY;
|
||||
|
||||
var drag = function(event) {
|
||||
var y = position.top + event.pageY - diffy;
|
||||
var x = position.left + event.pageX - diffx;
|
||||
dialog.offset({top: y, left: x});
|
||||
};
|
||||
|
||||
var undrag = function() {
|
||||
$(document).unbind("mousemove", drag);
|
||||
$(document).unbind("mouseup", undrag);
|
||||
dialog.css('cursor', '');
|
||||
}
|
||||
}
|
||||
|
||||
$(document).bind("mousemove", drag);
|
||||
$(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");
|
||||
//
|
||||
// Evennia Public Event Handlers
|
||||
//
|
||||
|
||||
if( new_pane1 == "" ) {
|
||||
new_pane1 = 'pane_'+num_splits;
|
||||
num_splits++;
|
||||
// Handle onLoggedIn from the server
|
||||
var onLoggedIn = function (args, kwargs) {
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onLoggedIn' in plugin ) {
|
||||
plugin.onLoggedIn(args, kwargs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( new_pane2 == "" ) {
|
||||
new_pane2 = 'pane_'+num_splits;
|
||||
num_splits++;
|
||||
|
||||
// Handle onGotOptions from the server
|
||||
var onGotOptions = function (args, kwargs) {
|
||||
// does any plugin handle Options?
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onGotOptions' in plugin ) {
|
||||
plugin.onGotOptions(args, kwargs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( document.getElementById(new_pane1) ) {
|
||||
alert('An element: "' + new_pane1 + '" already exists');
|
||||
return;
|
||||
|
||||
// Handle text coming from the server
|
||||
var onText = function (args, kwargs) {
|
||||
// does this plugin handle this onText event?
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onText' in plugin ) {
|
||||
if( plugin.onText(args, kwargs) ) {
|
||||
// True -- means this plugin claims this Text exclusively.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('NO plugin handled this Text');
|
||||
}
|
||||
|
||||
if( document.getElementById(new_pane2) ) {
|
||||
alert('An element: "' + new_pane2 + '" already exists');
|
||||
return;
|
||||
|
||||
// Handle prompt output from the server
|
||||
var onPrompt = function (args, kwargs) {
|
||||
// does this plugin handle this onPrompt event?
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onPrompt' in plugin ) {
|
||||
if( plugin.onPrompt(args, kwargs) ) {
|
||||
// True -- means this plugin claims this Prompt exclusively.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('NO plugin handled this Prompt');
|
||||
}
|
||||
|
||||
SplitHandler.dynamic_split( pane, direction, new_pane1, new_pane2, flow1, flow2, [50,50] );
|
||||
|
||||
closePopup("#splitdialog");
|
||||
}
|
||||
|
||||
function onSplitDialog() {
|
||||
var dialog = $("#splitdialogcontent");
|
||||
dialog.empty();
|
||||
|
||||
dialog.append("<h3>Split?</h3>");
|
||||
dialog.append('<input type="radio" name="direction" value="vertical" checked> top/bottom<br />');
|
||||
dialog.append('<input type="radio" name="direction" value="horizontal"> side-by-side<br />');
|
||||
|
||||
dialog.append("<h3>Split Which Pane?</h3>");
|
||||
for ( var pane in SplitHandler.split_panes ) {
|
||||
dialog.append('<input type="radio" name="pane" value="'+ pane +'">'+ pane +'<br />');
|
||||
// Handle unrecognized commands from server
|
||||
var onDefault = function (cmdname, args, kwargs) {
|
||||
// does this plugin handle this UnknownCmd?
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onUnknownCmd' in plugin ) {
|
||||
if( plugin.onUnknownCmd(args, kwargs) ) {
|
||||
// True -- means this plugin claims this UnknownCmd exclusively.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('NO plugin handled this Unknown Evennia Command');
|
||||
}
|
||||
|
||||
dialog.append("<h3>New Pane Names</h3>");
|
||||
dialog.append('<input type="text" name="new_pane1" value="" />');
|
||||
dialog.append('<input type="text" name="new_pane2" value="" />');
|
||||
|
||||
dialog.append("<h3>New First Pane</h3>");
|
||||
dialog.append('<input type="radio" name="flow1" value="append" checked>append new incoming messages<br />');
|
||||
dialog.append('<input type="radio" name="flow1" value="replace">replace old messages with new ones<br />');
|
||||
// Handle the server connection closing
|
||||
var onConnectionClose = function (args, kwargs) {
|
||||
// give every plugin a chance to do stuff onConnectionClose
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onConnectionClose' in plugin ) {
|
||||
plugin.onConnectionClose(args, kwargs);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.append("<h3>New Second Pane</h3>");
|
||||
dialog.append('<input type="radio" name="flow2" value="append" checked>append new incoming messages<br />');
|
||||
dialog.append('<input type="radio" name="flow2" value="replace">replace old messages with new ones<br />');
|
||||
|
||||
dialog.append('<div id="splitclose" class="button">Split It</div>');
|
||||
|
||||
$("#splitclose").bind("click", onSplitDialogClose);
|
||||
|
||||
togglePopup("#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("<h3>Set Which Pane?</h3>");
|
||||
for ( var pane in SplitHandler.split_panes ) {
|
||||
dialog.append('<input type="radio" name="pane" value="'+ pane +'">'+ pane +'<br />');
|
||||
onText(["The connection was closed or lost."], {'cls': 'err'});
|
||||
}
|
||||
|
||||
dialog.append("<h3>Which content types?</h3>");
|
||||
for ( var type in known_types ) {
|
||||
dialog.append('<input type="checkbox" value="'+ known_types[type] +'">'+ known_types[type] +'<br />');
|
||||
|
||||
// Silences events we don't do anything with.
|
||||
var onSilence = function (cmdname, args, kwargs) {}
|
||||
|
||||
|
||||
//
|
||||
// Global onSend() function to iterate through all plugins before sending text to the server.
|
||||
// This can be called by other plugins for "Triggers", <enter>, and other automated sends
|
||||
//
|
||||
var onSend = function (line) {
|
||||
if (!Evennia.isConnected()) {
|
||||
var reconnect = confirm("Not currently connected. Reconnect?");
|
||||
if (reconnect) {
|
||||
onText(["Attempting to reconnnect..."], {cls: "sys"});
|
||||
Evennia.connect();
|
||||
}
|
||||
// Don't try to send anything until the connection is back.
|
||||
return;
|
||||
}
|
||||
|
||||
// default output command
|
||||
var cmd = {
|
||||
command: "text",
|
||||
args: [ line ],
|
||||
kwargs: {}
|
||||
};
|
||||
|
||||
// Give each plugin a chance to use/modify the outgoing command for aliases/history/etc
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'onSend' in plugin ) {
|
||||
var outCmd = plugin.onSend(line);
|
||||
if( outCmd ) {
|
||||
cmd = outCmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('sending: ' + cmd.command + ', [' + cmd.args[0].toString() + '], ' + cmd.kwargs.toString() );
|
||||
Evennia.msg(cmd.command, cmd.args, cmd.kwargs);
|
||||
}
|
||||
|
||||
dialog.append('<div id="paneclose" class="button">Make It So</div>');
|
||||
|
||||
$("#paneclose").bind("click", onPaneControlDialogClose);
|
||||
//
|
||||
// call each plugins' init function (the only required function)
|
||||
//
|
||||
var init = function () {
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
ordered_plugins[n].init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
add: add,
|
||||
onKeydown: onKeydown,
|
||||
onBeforeUnload: onBeforeUnload,
|
||||
onLoggedIn: onLoggedIn,
|
||||
onText: onText,
|
||||
onGotOptions: onGotOptions,
|
||||
onPrompt: onPrompt,
|
||||
onDefault: onDefault,
|
||||
onSilence: onSilence,
|
||||
onConnectionClose: onConnectionClose,
|
||||
onSend: onSend,
|
||||
init: init,
|
||||
}
|
||||
})();
|
||||
|
||||
togglePopup("#splitdialog");
|
||||
}
|
||||
|
||||
//
|
||||
// Register Events
|
||||
// Webclient Initialization
|
||||
//
|
||||
|
||||
// Event when client finishes loading
|
||||
$(document).ready(function() {
|
||||
|
||||
if( SplitHandler ) {
|
||||
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) {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
|
||||
favico = new Favico({
|
||||
animation: 'none'
|
||||
});
|
||||
|
||||
// Event when client window changes
|
||||
$(window).bind("resize", doWindowResize);
|
||||
|
||||
$(window).blur(onBlur);
|
||||
$(window).focus(onFocus);
|
||||
|
||||
//$(document).on("visibilitychange", onVisibilityChange);
|
||||
|
||||
$("[data-role-input]").bind("resize", doWindowResize)
|
||||
.keypress(onKeyPress)
|
||||
.bind("paste", resizeInputField)
|
||||
.bind("cut", resizeInputField);
|
||||
|
||||
// Event when any key is pressed
|
||||
$(document).keydown(onKeydown)
|
||||
.keyup(resizeInputField);
|
||||
|
||||
// Pressing the send button
|
||||
$("#inputsend").bind("click", doSendText);
|
||||
|
||||
// Pressing the settings button
|
||||
$("#optionsbutton").bind("click", doOpenOptions);
|
||||
|
||||
// Checking a checkbox in the settings dialog
|
||||
$("[data-setting]").bind("change", onOptionCheckboxChanged);
|
||||
|
||||
// Pressing the close button on a dialog
|
||||
$(".dialogclose").bind("click", doCloseDialog);
|
||||
|
||||
// Makes dialogs draggable
|
||||
$(".dialogtitle").bind("mousedown", doStartDragDialog);
|
||||
|
||||
// This is safe to call, it will always only
|
||||
// initialize once.
|
||||
Evennia.init();
|
||||
// register listeners
|
||||
Evennia.emitter.on("text", onText);
|
||||
Evennia.emitter.on("prompt", onPrompt);
|
||||
Evennia.emitter.on("default", onDefault);
|
||||
Evennia.emitter.on("connection_close", onConnectionClose);
|
||||
Evennia.emitter.on("logged_in", onLoggedIn);
|
||||
Evennia.emitter.on("webclient_options", onGotOptions);
|
||||
// silence currently unused events
|
||||
Evennia.emitter.on("connection_open", onSilence);
|
||||
Evennia.emitter.on("connection_error", onSilence);
|
||||
|
||||
// Handle pressing the send button
|
||||
$("#inputsend").bind("click", doSendText);
|
||||
// register listeners
|
||||
Evennia.emitter.on("logged_in", plugin_handler.onLoggedIn);
|
||||
Evennia.emitter.on("text", plugin_handler.onText);
|
||||
Evennia.emitter.on("webclient_options", plugin_handler.onGotOptions);
|
||||
Evennia.emitter.on("prompt", plugin_handler.onPrompt);
|
||||
Evennia.emitter.on("default", plugin_handler.onDefault);
|
||||
Evennia.emitter.on("connection_close", plugin_handler.onConnectionClose);
|
||||
|
||||
// silence currently unused events
|
||||
Evennia.emitter.on("connection_open", plugin_handler.onSilence);
|
||||
Evennia.emitter.on("connection_error", plugin_handler.onSilence);
|
||||
|
||||
// Event when closing window (have to have Evennia initialized)
|
||||
$(window).bind("beforeunload", onBeforeUnload);
|
||||
$(window).bind("beforeunload", plugin_handler.onBeforeUnload);
|
||||
$(window).bind("unload", Evennia.connection.close);
|
||||
|
||||
doWindowResize();
|
||||
// Event when any key is pressed
|
||||
$(document).keydown(plugin_handler.onKeydown)
|
||||
|
||||
// set an idle timer to send idle every 3 minutes,
|
||||
// to avoid proxy servers timing out on us
|
||||
setInterval(function() {
|
||||
// Connect to server
|
||||
Evennia.msg("text", ["idle"], {});
|
||||
},
|
||||
60000*3
|
||||
setInterval( function() { // Connect to server
|
||||
Evennia.msg("text", ["idle"], {});
|
||||
},
|
||||
60000*3
|
||||
);
|
||||
console.log("Completed GUI setup");
|
||||
|
||||
// Initialize all plugins
|
||||
plugin_handler.init();
|
||||
|
||||
console.log("Completed Webclient setup");
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -63,15 +63,21 @@ JQuery available.
|
|||
</script>
|
||||
<script src={% static "webclient/js/evennia.js" %} language="javascript" type="text/javascript" charset="utf-8"/></script>
|
||||
|
||||
|
||||
<!-- set up splits before loading the GUI -->
|
||||
<script src="https://unpkg.com/split.js/split.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
|
||||
<script src={% static "webclient/js/splithandler.js" %} language="javascript"></script>
|
||||
|
||||
<!-- Load gui library -->
|
||||
{% 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/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/history.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/default_in.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/oob.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/notifications.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/splithandler.js" %} language="javascript" type="text/javascript"></script>
|
||||
<script src={% static "webclient/js/plugins/default_out.js" %} language="javascript" type="text/javascript"></script>
|
||||
{% endblock %}
|
||||
|
||||
<script src="https://cdn.rawgit.com/ejci/favico.js/master/favico-0.3.10.min.js" language="javascript" type="text/javascript" charset="utf-8"></script>
|
||||
|
|
|
|||
|
|
@ -6,67 +6,19 @@
|
|||
- guilib_import - for using your own gui lib
|
||||
-->
|
||||
|
||||
|
||||
{% block client %}
|
||||
<div id="toolbar">
|
||||
<button id="optionsbutton" type="button" aria-haspopup="true" aria-owns="#optionsdialog">⚙<span class="sr-only sr-only-focusable">Settings</span></button>
|
||||
<button id="splitbutton" type="button" aria-haspopup="true" aria-owns="#optionsdialog">⇹<span class="sr-only sr-only-focusable">Splits</span></button>
|
||||
<button id="panebutton" type="button" aria-haspopup="true" aria-owns="#optionsdialog">⚙<span class="sr-only sr-only-focusable">Splits</span></button>
|
||||
<button id="undobutton" type="button" aria-haspopup="true" aria-owns="#optionsdialog">↶<span class="sr-only sr-only-focusable">Splits</span></button>
|
||||
</div>
|
||||
|
||||
<!-- The "Main" Content -->
|
||||
<!-- Basic toolbar -->
|
||||
<div id="toolbar"></div>
|
||||
|
||||
<!-- "Main" Content -->
|
||||
<div id="main" class="split split-vertical" data-role-default>
|
||||
<div id="main-sub" class="split-sub">
|
||||
<div id="messagewindow"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The "Input" Pane -->
|
||||
<div id="input" class="split split-vertical" data-role-input data-update-append></div>
|
||||
|
||||
<!-- Basic UI Components -->
|
||||
<div id="splitdialog" class="dialog">
|
||||
<div class="dialogtitle">Split Pane<span class="dialogclose">×</span></div>
|
||||
<div class="dialogcontentparent">
|
||||
<div id="splitdialogcontent" class="dialogcontent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="optionsdialog" class="dialog">
|
||||
<div class="dialogtitle">Options<span class="dialogclose">×</span></div>
|
||||
<div class="dialogcontentparent">
|
||||
<div class="dialogcontent">
|
||||
<h3>Output display</h3>
|
||||
<label><input type="checkbox" data-setting="gagprompt" value="value">Don't echo prompts to the main text area</label><br />
|
||||
<label><input type="checkbox" data-setting="helppopup" value="value">Open help in popup window</label><br />
|
||||
<hr />
|
||||
<h3>Notifications</h3>
|
||||
<label><input type="checkbox" data-setting="notification_popup" value="value">Popup notification</label><br />
|
||||
<label><input type="checkbox" data-setting="notification_sound" value="value">Play a sound</label><br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="helpdialog" class="dialog">
|
||||
<div class="dialogtitle">Help<span class="dialogclose">×</span></div>
|
||||
<div class="dialogcontentparent">
|
||||
<div class="dialogcontent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="split-template">
|
||||
<div class="split content<%#horizontal%> split-horizontal<%/horizontal%>" id='<%id%>'>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="output-template">
|
||||
<div id="<%id%>" role="log" data-role-output data-update-append data-tags='[<%#tags%>"<%.%>", <%/tags%>]'></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="input-template">
|
||||
<!-- "Input" Pane -->
|
||||
<div id="input" class="split split-vertical" data-role-input data-update-append>
|
||||
<div id="inputform" class="wrapper">
|
||||
<div id="prompt" class="prompt">
|
||||
</div>
|
||||
|
|
@ -77,7 +29,7 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue