From 99b1ebbcf41d93a30b358c95671d9990d3d3c88b Mon Sep 17 00:00:00 2001 From: Chadwick Meyer Date: Wed, 3 Jun 2015 16:25:30 -0700 Subject: [PATCH 1/5] Suggested Ability to have PlaceHolder If you want your "input" area to have placeholder text, like a normal input text field allows, this allows for that. When the area is clicked or if there are bit tags, the placeholder is hidden, like a normal placeholder. NOTE: this is different from the placeholder for the autocomplete, which is a useful, but different feature. --- Source/TextboxList.js | 86 +++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/Source/TextboxList.js b/Source/TextboxList.js index 5f69556..2b26228 100644 --- a/Source/TextboxList.js +++ b/Source/TextboxList.js @@ -20,39 +20,40 @@ var TextboxList = new Class({ plugins: [], options: {/* - onFocus: $empty, - onBlur: $empty, - onBitFocus: $empty, - onBitBlur: $empty, - onBitAdd: $empty, - onBitRemove: $empty, - onBitBoxFocus: $empty, - onBitBoxBlur: $empty, - onBitBoxAdd: $empty, - onBitBoxRemove: $empty, - onBitEditableFocus: $empty, - onBitEditableBlue: $empty, - onBitEditableAdd: $empty, - onBitEditableRemove: $empty,*/ - prefix: 'textboxlist', - max: null, - unique: false, - uniqueInsensitive: true, - endEditableBit: true, - startEditableBit: true, - hideEditableBits: true, - inBetweenEditableBits: true, - keys: {previous: Event.Keys.left, next: Event.Keys.right}, - bitsOptions: {editable: {}, box: {}}, - plugins: {}, - check: function(s){ return s.clean().replace(/,/g, '') != ''; }, - encode: function(o){ - return o.map(function(v){ - v = ($chk(v[0]) ? v[0] : v[1]); - return $chk(v) ? v : null; - }).clean().join(','); - }, - decode: function(o){ return o.split(','); } + onFocus: $empty, + onBlur: $empty, + onBitFocus: $empty, + onBitBlur: $empty, + onBitAdd: $empty, + onBitRemove: $empty, + onBitBoxFocus: $empty, + onBitBoxBlur: $empty, + onBitBoxAdd: $empty, + onBitBoxRemove: $empty, + onBitEditableFocus: $empty, + onBitEditableBlue: $empty, + onBitEditableAdd: $empty, + onBitEditableRemove: $empty,*/ + prefix: 'textboxlist', + max: null, + unique: false, + uniqueInsensitive: true, + endEditableBit: true, + startEditableBit: true, + hideEditableBits: true, + inBetweenEditableBits: true, + inputPlaceholder: null, + keys: {previous: Event.Keys.left, next: Event.Keys.right}, + bitsOptions: {editable: {}, box: {}}, +plugins: {}, + check: function(s){ return s.clean().replace(/,/g, '') != ''; }, + encode: function(o){ + return o.map(function(v){ + v = ($chk(v[0]) ? v[0] : v[1]); + return $chk(v) ? v : null; + }).clean().join(','); + }, + decode: function(o){ return o.split(','); } }, initialize: function(element, options){ @@ -62,6 +63,13 @@ var TextboxList = new Class({ this.container.addEvent('click', function(e){ if ((e.target == this.list || e.target == this.container) && (!this.focused || $(this.current) != this.list.getLast())) this.focusLast(); }.bind(this)); + if(this.options.inputPlaceholder) { + this.inputPlaceholder = new Element('div', {'class': this.options.prefix + '-placeholder'}).inject(this.container, 'top'); + this.inputPlaceholder.set('html', this.options.inputPlaceholder); + this.inputPlaceholder.addEvent('click', function(e){ + this.focusLast(); + }.bind(this)); + } this.list = new Element('ul', {'class': this.options.prefix + '-bits'}).inject(this.container); for (var name in this.options.plugins) this.enablePlugin(name, this.options.plugins[name]); ['check', 'encode', 'decode'].each(function(i){ this.options[i] = this.options[i].bind(this); }, this); @@ -143,6 +151,7 @@ var TextboxList = new Class({ this.focused = true; this.fireEvent('focus', bit); } + this.toggleInputPlaceholder(); }, onBlur: function(bit, all){ @@ -168,6 +177,7 @@ var TextboxList = new Class({ var prior = this.getBit($(bit).getPrevious()); if (prior && prior.is('editable')) prior.remove(); this.focusRelative('next', bit); + this.toggleInputPlaceholder(); }, focusRelative: function(dir, to){ @@ -186,6 +196,7 @@ var TextboxList = new Class({ if (! this.focused) return this; if (this.current) this.current.blur(); this.focused = false; + this.toggleInputPlaceholder(); return this.fireEvent('blur'); }, @@ -219,7 +230,12 @@ var TextboxList = new Class({ update: function(){ this.original.set('value', this.options.encode(this.getValues())); - } + }, + + toggleInputPlaceholder: function() { + if(!this.options.inputPlaceholder) return false; + this.inputPlaceholder.setStyle('display', (this.focused || this.original.get('value') != '') ? 'none' : 'block') + }, }); @@ -433,4 +449,4 @@ TextboxListBit.Box = new Class({ this.bit.getChildren().addEvent('click', function(e){ e.stop(); }); } -}); \ No newline at end of file +}); From 98b198fe2a7bcd31513b9f4d690e1e6f9a7abd9c Mon Sep 17 00:00:00 2001 From: Chadwick Meyer Date: Wed, 3 Jun 2015 16:29:44 -0700 Subject: [PATCH 2/5] Merge Fix and Feature Additions This is a joint merge that includes: - Prevent page from scrolling when you click the delete button on a bit tag. - Add ability to specify a pseduo placeholder on the "input" area, which disappears when you click in the field or when there are bit tags present. --- Source/TextboxList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/TextboxList.js b/Source/TextboxList.js index 2b26228..c2f67ef 100644 --- a/Source/TextboxList.js +++ b/Source/TextboxList.js @@ -444,7 +444,7 @@ TextboxListBit.Box = new Class({ this.bit.addEvent('click', this.focus.bind(this)); if (this.options.deleteButton){ this.bit.addClass(this.typeprefix + '-deletable'); - this.close = new Element('a', {href: '#', 'class': this.typeprefix + '-deletebutton', events: {click: this.remove.bind(this)}}).inject(this.bit); + this.close = new Element('a', {href: 'javascript:void(0)', 'class': this.typeprefix + '-deletebutton', events: {click: this.remove.bind(this)}}).inject(this.bit); } this.bit.getChildren().addEvent('click', function(e){ e.stop(); }); } From 199ec9cfd88efcfd6cd53c0650fba688ce981918 Mon Sep 17 00:00:00 2001 From: Chadwick Meyer Date: Wed, 3 Jun 2015 17:07:12 -0700 Subject: [PATCH 3/5] Fix Keys for Mootools 1.4.5 They left, right, delete, and backspace keys were not working when used with Mootools 1.4.5. This upgrades the code to work with the changes to mootools. There may be a better way to do it, but it appeared that the old method for calling the code value for a specific key just didn't work anymore, e.g. `Event.Keys.left` didn't produce the right event.code, so I switched it to event.key and hard coded the values. --- Source/TextboxList.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/TextboxList.js b/Source/TextboxList.js index c2f67ef..b52322a 100644 --- a/Source/TextboxList.js +++ b/Source/TextboxList.js @@ -43,7 +43,7 @@ var TextboxList = new Class({ hideEditableBits: true, inBetweenEditableBits: true, inputPlaceholder: null, - keys: {previous: Event.Keys.left, next: Event.Keys.right}, + keys: {previous: 'left', next: 'right', delete: 'delete', backspace: 'backspace'}, bitsOptions: {editable: {}, box: {}}, plugins: {}, check: function(s){ return s.clean().replace(/,/g, '') != ''; }, @@ -101,28 +101,31 @@ plugins: {}, var value = this.current.getValue()[1]; var special = ['shift', 'alt', 'meta', 'ctrl'].some(function(e){ return ev[e]; }); var custom = special || (this.current.is('editable') && this.current.isSelected()); - switch (ev.code){ - case Event.Keys.backspace: - if (this.current.is('box')){ + switch (ev.key){ + case this.options.keys.backspace: + if (this.current.is('box')){ ev.stop(); - return this.current.remove(); + return this.current.remove(); } + break; case this.options.keys.previous: if (this.current.is('box') || ((caret == 0 || !value.length) && !custom)){ ev.stop(); this.focusRelative('previous'); } break; - case Event.Keys['delete']: - if (this.current.is('box')){ + case this.options.keys.delete: + if (this.current.is('box')){ ev.stop(); - return this.current.remove(); + return this.current.remove(); } - case this.options.keys.next: + break + case this.options.keys.next: if (this.current.is('box') || (caret == value.length && !custom)){ ev.stop(); this.focusRelative('next'); } + break; } }.bind(this) }); From 551ee108ca10a62123321e6c6ec2d25c288eba0d Mon Sep 17 00:00:00 2001 From: Chadwick Meyer Date: Wed, 3 Jun 2015 17:30:29 -0700 Subject: [PATCH 4/5] Update to Make Up/Down Keys work with Mootools 1.4.5 The old method used `Event.keys.up` to determine the correct `ev.code` for the key. But that doesn't work anymore evidently. So this fix hard codes the key name, and compares it with `ev.key` instead. NOTE: this may not be the most compatible method, but it was the quickest fix for my purposes and hopefully it will help someone else. --- Source/TextboxList.Autocomplete.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Source/TextboxList.Autocomplete.js b/Source/TextboxList.Autocomplete.js index edb6ed8..1d6e764 100644 --- a/Source/TextboxList.Autocomplete.js +++ b/Source/TextboxList.Autocomplete.js @@ -35,7 +35,8 @@ TextboxList.Autocomplete = new Class({ loadPlaceholder: 'Please wait...' }, method: 'standard', - placeholder: 'Type to receive suggestions' + placeholder: 'Type to See Suggestions', + keys: {up: 'up', down: 'down', enter: 'enter'} }, initialize: function(textboxlist, options){ @@ -194,20 +195,21 @@ TextboxList.Autocomplete = new Class({ }, navigate: function(ev){ - switch (ev.code){ - case Event.Keys.up: + switch (ev.key){ + case this.options.keys.up: ev.stop(); (!this.options.onlyFromValues && this.current && this.current == this.list.getFirst()) ? this.blur() : this.focusRelative('previous'); break; - case Event.Keys.down: + case this.options.keys.down: ev.stop(); this.current ? this.focusRelative('next') : this.focusFirst(); break; - case Event.Keys.enter: + case this.options.keys.enter: ev.stop(); - if (this.current) this.addCurrent(); - else if (!this.options.onlyFromValues){ - var value = this.currentInput.getValue(); + if (this.current) { + this.addCurrent(); + } else if (!this.options.onlyFromValues) { + var value = this.currentInput.getValue(); var b = this.textboxlist.create('box', value); if (b){ b.inject($(this.currentInput), 'before'); @@ -241,4 +243,4 @@ TextboxList.Autocomplete.Methods = { }; -})(); \ No newline at end of file +})(); From 52434cc2f7aef0c46bda1ed84310bd5fedc227c4 Mon Sep 17 00:00:00 2001 From: Chadwick Meyer Date: Wed, 3 Jun 2015 18:11:49 -0700 Subject: [PATCH 5/5] fix bug I introduced Remove the breaks in the switching case statement when checking the correct keys. Evidently only the 'previous' key should have a break for some reason. --- Source/TextboxList.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Source/TextboxList.js b/Source/TextboxList.js index b52322a..854a6d9 100644 --- a/Source/TextboxList.js +++ b/Source/TextboxList.js @@ -102,30 +102,23 @@ plugins: {}, var special = ['shift', 'alt', 'meta', 'ctrl'].some(function(e){ return ev[e]; }); var custom = special || (this.current.is('editable') && this.current.isSelected()); switch (ev.key){ + case this.options.keys.delete: case this.options.keys.backspace: if (this.current.is('box')){ ev.stop(); return this.current.remove(); } - break; case this.options.keys.previous: if (this.current.is('box') || ((caret == 0 || !value.length) && !custom)){ ev.stop(); this.focusRelative('previous'); } break; - case this.options.keys.delete: - if (this.current.is('box')){ - ev.stop(); - return this.current.remove(); - } - break case this.options.keys.next: if (this.current.is('box') || (caret == value.length && !custom)){ ev.stop(); this.focusRelative('next'); } - break; } }.bind(this) });