mirror of
https://github.com/evennia/evennia.git
synced 2026-03-24 16:56:32 +01:00
Fix the popup close bugs and expand functionality to allow dual inputs
This commit is contained in:
parent
2d1e9768ff
commit
43244b53b3
5 changed files with 256 additions and 165 deletions
|
|
@ -88,15 +88,26 @@ label {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#inputsend {
|
||||
.inputsend {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
height: inherit;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
#inputfield {
|
||||
.inputfield {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: inherit;
|
||||
width: calc(100% - 30px);
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.inputfield:focus {
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.glbutton {
|
||||
|
|
|
|||
|
|
@ -8,17 +8,38 @@ let defaultin_plugin = (function () {
|
|||
//
|
||||
// handle the default <enter> key triggering onSend()
|
||||
var onKeydown = function (event) {
|
||||
var inputfield = $("#inputfield");
|
||||
|
||||
// Enter Key without shift
|
||||
if ( inputfield.is(":focus") && (event.which === 13) && (!event.shiftKey) ) {
|
||||
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();
|
||||
// find where the key comes from
|
||||
var inputfield = $(".inputfield:focus");
|
||||
|
||||
// check for important keys
|
||||
switch (event.which) {
|
||||
case 16: // ignore shift
|
||||
case 17: // ignore alt
|
||||
case 18: // ignore control
|
||||
case 20: // ignore caps lock
|
||||
case 144: // ignore num lock
|
||||
break;
|
||||
|
||||
case 13: // Enter key
|
||||
var outtext = inputfield.val();
|
||||
if ( outtext && !event.shiftKey ) { // Enter Key without shift --> send Mesg
|
||||
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();
|
||||
}
|
||||
inputfield.blur();
|
||||
break;
|
||||
|
||||
// Anything else, focus() a textarea if needed, and allow the default event
|
||||
default:
|
||||
// is anything actually focused? if not, focus the first .inputfield found in the DOM
|
||||
if( !inputfield.hasClass('inputfield') ) {
|
||||
// :first only matters if dual_input or similar multi-input plugins are in use
|
||||
$('.inputfield:last').focus();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -29,10 +50,11 @@ let defaultin_plugin = (function () {
|
|||
var init = function () {
|
||||
// Handle pressing the send button
|
||||
$("#inputsend")
|
||||
.bind("click", function (event) {
|
||||
.bind("click", function (evnt) {
|
||||
// simulate a carriage return
|
||||
var e = $.Event( "keydown" );
|
||||
e.which = 13;
|
||||
$('#inputfield').trigger(e);
|
||||
$('.inputfield:last').trigger(e);
|
||||
});
|
||||
|
||||
console.log('DefaultIn initialized');
|
||||
|
|
|
|||
|
|
@ -14,25 +14,36 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
content: [{
|
||||
type: 'column',
|
||||
content: [{
|
||||
type: 'component',
|
||||
componentName: 'Main',
|
||||
isClosable: false,
|
||||
componentState: {
|
||||
types: 'untagged',
|
||||
update_method: 'newlines',
|
||||
}
|
||||
type: 'row',
|
||||
content: [{
|
||||
type: 'column',
|
||||
content: [{
|
||||
type: 'component',
|
||||
componentName: 'Main',
|
||||
isClosable: false,
|
||||
componentState: {
|
||||
types: 'untagged',
|
||||
update_method: 'newlines',
|
||||
},
|
||||
}]
|
||||
}],
|
||||
}, {
|
||||
type: 'component',
|
||||
componentName: 'input',
|
||||
id: 'inputComponent',
|
||||
height: 15,
|
||||
height: 12,
|
||||
}, {
|
||||
type: 'component',
|
||||
componentName: 'input',
|
||||
id: 'inputComponent',
|
||||
height: 12,
|
||||
isClosable: false,
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
|
||||
var newDragConfig = {
|
||||
var newTabConfig = {
|
||||
title: 'Untitled',
|
||||
type: 'component',
|
||||
componentName: 'evennia',
|
||||
|
|
@ -97,16 +108,26 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
let content = element.find('.content');
|
||||
let title = evnt.data.contentItem.config.title;
|
||||
let renamebox = document.getElementById('renamebox');
|
||||
|
||||
// check that no other popup is open
|
||||
if( document.getElementById('typelist') || document.getElementById('updatelist') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( !renamebox ) {
|
||||
renamebox = $('<div id="renamebox">');
|
||||
renamebox.append('<input type="textbox" id="renameboxin" value="'+title+'">');
|
||||
renamebox.insertBefore( content );
|
||||
} else {
|
||||
let title = $('#renameboxin').val();
|
||||
evnt.data.setTitle( title );
|
||||
evnt.data.contentItem.setTitle( title );
|
||||
myLayout.emit('stateChanged');
|
||||
$('#renamebox').remove();
|
||||
|
||||
// check that the renamebox that is open is for this contentItem
|
||||
if( $('#renamebox').parent()[0] === content.parent()[0] ) {
|
||||
evnt.data.setTitle( title );
|
||||
evnt.data.contentItem.setTitle( title );
|
||||
myLayout.emit('stateChanged');
|
||||
$('#renamebox').remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,9 +161,7 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
|
||||
//
|
||||
//
|
||||
var commitCheckboxes = function (evnt) {
|
||||
let element = $(evnt.data.contentItem.element);
|
||||
let content = element.find('.content');
|
||||
var commitCheckboxes = function (evnt, content) {
|
||||
let checkboxes = $('#typelist :input');
|
||||
let types = [];
|
||||
for (i=0; i<checkboxes.length; i++ ) {
|
||||
|
|
@ -160,12 +179,23 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
// Handle the typePopup
|
||||
var typePopup = function (evnt) {
|
||||
let typelist = document.getElementById('typelist');
|
||||
|
||||
// check that no other popup is open
|
||||
if( document.getElementById('renamebox') || document.getElementById('updatelist') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( !typelist ) {
|
||||
onSelectTypesClicked(evnt);
|
||||
} else {
|
||||
commitCheckboxes(evnt);
|
||||
calculate_untagged_types();
|
||||
$('#typelist').remove();
|
||||
let element = $(evnt.data.contentItem.element);
|
||||
let content = element.find('.content');
|
||||
if( $('#typelist').parent().children('.lm_content')[0] === content.parent()[0] ) {
|
||||
// check that the typelist that is open is for this contentItem
|
||||
commitCheckboxes(evnt, content);
|
||||
calculate_untagged_types();
|
||||
$('#typelist').remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,14 +231,24 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
// Handle the updatePopup
|
||||
var updatePopup = function (evnt) {
|
||||
let updatelist = document.getElementById('updatelist');
|
||||
|
||||
// check that no other popup is open
|
||||
if( document.getElementById('renamebox') || document.getElementById('typelist') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( !updatelist ) {
|
||||
onUpdateMethodClicked(evnt);
|
||||
} else {
|
||||
let element = $(evnt.data.contentItem.element);
|
||||
let content = element.find('.content');
|
||||
content.attr('update_method', $('input[name=update_method]:checked').val() );
|
||||
myLayout.emit('stateChanged');
|
||||
$('#updatelist').remove();
|
||||
|
||||
// check that the updatelist that is open is for this contentItem
|
||||
if( $('#updatelist').parent().children('.lm_content')[0] === content.parent()[0] ) {
|
||||
content.attr('update_method', $('input[name=update_method]:checked').val() );
|
||||
myLayout.emit('stateChanged');
|
||||
$('#updatelist').remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +270,7 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
updatePopupControl.click( tab, updatePopup );
|
||||
|
||||
splitControl.click( tab, function (evnt) {
|
||||
evnt.data.header.parent.addChild( newDragConfig );
|
||||
evnt.data.header.parent.addChild( newTabConfig );
|
||||
});
|
||||
|
||||
// Add the typeDropdown to the header
|
||||
|
|
@ -277,11 +317,6 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
var initComponent = function (div, container, state, default_types, update_method) {
|
||||
|
|
@ -298,6 +333,22 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
var onKeydown = function(evnt) {
|
||||
var renamebox = document.getElementById('renamebox');
|
||||
if( renamebox ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
var onText = function (args, kwargs) {
|
||||
|
|
@ -350,42 +401,12 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
|
||||
|
||||
//
|
||||
// required Init me
|
||||
var init = function (options) {
|
||||
// Set up our GoldenLayout instance built off of the default main-sub div
|
||||
var savedState = localStorage.getItem( 'evenniaGoldenLayoutSavedState' );
|
||||
var mainsub = document.getElementById('main-sub');
|
||||
|
||||
if( savedState !== null ) {
|
||||
myLayout = new GoldenLayout( JSON.parse( savedState ), mainsub );
|
||||
} else {
|
||||
myLayout = new GoldenLayout( config, mainsub );
|
||||
}
|
||||
|
||||
// register our component and replace the default messagewindow with the Main component element
|
||||
myLayout.registerComponent( 'Main', function (container, componentState) {
|
||||
let main = $('#messagewindow').addClass('content');
|
||||
initComponent(main, container, componentState, 'untagged', 'newlines' );
|
||||
});
|
||||
|
||||
myLayout.registerComponent( 'input', function (container, componentState) {
|
||||
$('#inputcontrol').remove(); // remove the cluttered, HTML-defined input divs
|
||||
$('<div id="inputcontrol">')
|
||||
.append( '<div class="inputwrap"><button id="inputsend" type="button"">></button></div>' )
|
||||
.append( '<textarea id="inputfield" type="text" class="form-control"></textarea>' )
|
||||
.appendTo( container.getElement() );
|
||||
});
|
||||
|
||||
myLayout.registerComponent( 'evennia', function (container, componentState) {
|
||||
let div = $('<div class="content"></div>');
|
||||
initComponent(div, container, componentState, 'all', 'newlines');
|
||||
container.on('destroy', calculate_untagged_types);
|
||||
});
|
||||
|
||||
// Make it go.
|
||||
//
|
||||
var postInit = function () {
|
||||
// finish the setup and actually start GoldenLayout
|
||||
myLayout.init();
|
||||
|
||||
// Event when client window changes
|
||||
// Set the Event handler for when the client window changes size
|
||||
$(window).bind("resize", scrollAll);
|
||||
|
||||
// Set Save State callback
|
||||
|
|
@ -394,10 +415,64 @@ plugin_handler.add('goldenlayout', (function () {
|
|||
console.log('Golden Layout Plugin Initialized.');
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// required Init me
|
||||
var init = function (options) {
|
||||
// Set up our GoldenLayout instance built off of the default main-sub div
|
||||
var savedState = localStorage.getItem( 'evenniaGoldenLayoutSavedState' );
|
||||
var mainsub = document.getElementById('main-sub');
|
||||
|
||||
if( savedState !== null ) {
|
||||
config = JSON.parse( savedState );
|
||||
}
|
||||
|
||||
myLayout = new GoldenLayout( config, mainsub );
|
||||
|
||||
$('#inputcontrol').remove(); // remove the cluttered, HTML-defined input divs
|
||||
|
||||
// register our component and replace the default messagewindow with the Main component
|
||||
myLayout.registerComponent( 'Main', function (container, componentState) {
|
||||
let main = $('#messagewindow').addClass('content');
|
||||
initComponent(main, container, componentState, 'untagged', 'newlines' );
|
||||
});
|
||||
|
||||
// register our new input component
|
||||
myLayout.registerComponent( 'input', function (container, componentState) {
|
||||
var inputfield = $('<textarea type="text" class="inputfield form-control"></textarea>');
|
||||
var button = $('<button type="button" class="inputsend">></button>');
|
||||
|
||||
$('<div class="inputwrap">')
|
||||
.append( button )
|
||||
.append( inputfield )
|
||||
.appendTo( container.getElement() );
|
||||
|
||||
button.bind('click', function (evnt) {
|
||||
// focus our textarea
|
||||
$( $(evnt.target).siblings('.inputfield')[0] ).focus();
|
||||
// fake a carriage return event
|
||||
var e = $.Event('keydown');
|
||||
e.which = 13;
|
||||
$( $(evnt.target).siblings('.inputfield')[0] ).trigger(e);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
myLayout.registerComponent( 'evennia', function (container, componentState) {
|
||||
let div = $('<div class="content"></div>');
|
||||
initComponent(div, container, componentState, 'all', 'newlines');
|
||||
container.on('destroy', calculate_untagged_types);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
postInit: postInit,
|
||||
onKeydown: onKeydown,
|
||||
onText: onText,
|
||||
getGL: function () { return myLayout },
|
||||
initComponent: initComponent,
|
||||
getConfig: function () { return config },
|
||||
setConfig: function (newconfig) { config = newconfig },
|
||||
}
|
||||
})());
|
||||
|
|
|
|||
|
|
@ -6,72 +6,49 @@
|
|||
let history_plugin = (function () {
|
||||
|
||||
// Manage history for input line
|
||||
var history_max = 20;
|
||||
var history = {};
|
||||
var history_pos = {};
|
||||
var history_max = 21;
|
||||
var history = new Array();
|
||||
var history_pos = 0;
|
||||
|
||||
history[0] = ''; // the very latest input is empty for new entry.
|
||||
|
||||
//
|
||||
// Add a new textarea to track history for.
|
||||
var track_history_for_id = function(id) {
|
||||
if( ! history.hasOwnProperty( id ) ) {
|
||||
history[id] = new Array;
|
||||
history_pos[id] = -1;
|
||||
} else {
|
||||
console.log('IGNORED -- already tracking history for that DOM element!');
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
|
||||
//
|
||||
// Return whichever inputfield (if any) is focused, out of the set we are tracking
|
||||
var get_focused_input = function () {
|
||||
let inputfield = $( document.activeElement );
|
||||
|
||||
// is the focused element one of the ones we are tracking history for?
|
||||
if( history.hasOwnProperty( inputfield.attr('id') ) ) {
|
||||
return inputfield;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// move back from the history (to newer elements)
|
||||
var back = function (id) {
|
||||
// step back in history queue, to the most recently stored entry.
|
||||
if( history_pos[id] >= 0 ) {
|
||||
history_pos[id]--;
|
||||
|
||||
// if we've stepped "before" the first element of our queue, return new, empty string
|
||||
if( history_pos[id] == -1 ) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return history[id][ history_pos[id] ];
|
||||
}
|
||||
|
||||
//
|
||||
// move forward into the history (to older elements)
|
||||
var fwd = function (id) {
|
||||
// step forward in history queue, restricted by bounds checking
|
||||
if( history_pos[id] < Math.min( history[id].length - 1, history_max - 1 ) ) {
|
||||
history_pos[id]++;
|
||||
}
|
||||
return history[id][ history_pos[id] ];
|
||||
// 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 (id, input) {
|
||||
var add = function (input) {
|
||||
// add a new entry to history, don't repeat latest
|
||||
if (input && input != history[id][0]) {
|
||||
// make sure to trim the history queue length to 'history_max'
|
||||
if (history[id].length + 1 >= history_max) {
|
||||
history[id].pop(); // remove oldest entry from queue
|
||||
if (input && input != history[history.length-2]) {
|
||||
if (history.length >= history_max) {
|
||||
history.shift(); // kill oldest entry
|
||||
}
|
||||
history[id].unshift(input); // add newest entry to beginning of queue
|
||||
history[history.length-1] = input;
|
||||
history[history.length] = '';
|
||||
}
|
||||
// reset the position to the beginning of the queue
|
||||
history_pos[id] = -1;
|
||||
history_pos = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
|
|
@ -79,52 +56,40 @@ let history_plugin = (function () {
|
|||
//
|
||||
// Handle up arrow and down arrow events.
|
||||
var onKeydown = function(event) {
|
||||
var keycode = event.which;
|
||||
var code = event.which;
|
||||
var history_entry = null;
|
||||
var inputfield = $('.inputfield:focus');
|
||||
|
||||
// Is one of the two input fields focused?
|
||||
let inputfield = get_focused_input();
|
||||
if( inputfield != null ) {
|
||||
let id = inputfield.attr('id')
|
||||
let history_entry = null; // check the keycode for up/down arrows
|
||||
if (keycode === 40) { // Arrow down
|
||||
history_entry = back(id);
|
||||
}
|
||||
else if (keycode === 38) { // Arrow up
|
||||
history_entry = fwd(id);
|
||||
}
|
||||
|
||||
if (history_entry !== null) {
|
||||
// Performing a history navigation
|
||||
// replace the text in the input and move the cursor to the end of the new value
|
||||
inputfield.blur().focus().val(history_entry);
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
// Only process up/down arrow if cursor is at the end of the line.
|
||||
if (code === 38 && event.shiftKey) { // Arrow up
|
||||
history_entry = back();
|
||||
}
|
||||
else if (code === 40 && event.shiftKey) { // Arrow down
|
||||
history_entry = fwd();
|
||||
}
|
||||
|
||||
// are we processing an up or down history event?
|
||||
if (history_entry !== null) {
|
||||
// Doing a history navigation; replace the text in the input and move the cursor to the end of the new value
|
||||
inputfield.val('');
|
||||
inputfield.blur().focus().val(history_entry);
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Listen for onSend lines to add to history
|
||||
var onSend = function (line) {
|
||||
let inputfield = get_focused_input();
|
||||
if( inputfield != null ) {
|
||||
add(inputfield.attr('id'), line);
|
||||
}
|
||||
return null; // we are not returning an altered input line
|
||||
add(line);
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// Init function
|
||||
var init = function () {
|
||||
track_history_for_id('inputfield'); // The default inputfield
|
||||
|
||||
// check to see if the dual_input plugin is enabled.
|
||||
if( !(typeof plugins['dual_input'] === "undefined") ) {
|
||||
console.log('configuring history tracking for dual_input plugin');
|
||||
track_history_for_id('inputfield2');
|
||||
}
|
||||
|
||||
console.log('History Plugin Initialized.');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,6 +228,20 @@ var plugin_handler = (function () {
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// normally init() is all that is needed, but some cases may require a second
|
||||
// pass to avoid chicken/egg dependencies between two plugins.
|
||||
var postInit = function () {
|
||||
// does this plugin need postInit() to be called?
|
||||
for( let n=0; n < ordered_plugins.length; n++ ) {
|
||||
let plugin = ordered_plugins[n];
|
||||
if( 'postInit' in plugin ) {
|
||||
plugin.postInit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
add: add,
|
||||
onKeydown: onKeydown,
|
||||
|
|
@ -241,6 +255,7 @@ var plugin_handler = (function () {
|
|||
onConnectionClose: onConnectionClose,
|
||||
onSend: onSend,
|
||||
init: init,
|
||||
postInit: postInit,
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
@ -285,5 +300,8 @@ $(document).ready(function() {
|
|||
// Initialize all plugins
|
||||
plugin_handler.init();
|
||||
|
||||
// Finish Initializing any plugins that need a second stage
|
||||
plugin_handler.postInit();
|
||||
|
||||
console.log("Completed Webclient setup");
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue