Fix the popup close bugs and expand functionality to allow dual inputs

This commit is contained in:
Brenden Tuck 2019-03-21 08:44:46 -04:00
parent 2d1e9768ff
commit 43244b53b3
5 changed files with 256 additions and 165 deletions

View file

@ -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 {

View file

@ -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');

View file

@ -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"">&gt;</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">&gt;</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 },
}
})());

View file

@ -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.');
}

View file

@ -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");
});