In some cases users have to insert special characters, for example polish alphabet contains some extra letters or umlauts of german alphabet or symbols like a celsius sign “°C”. I have developed this functionality in form of plugin. It inserts a trigger to field which popups the panel with special symbols. The plugin is implmented in two files, the plugin and popup window.
Ext.define('app.ux.form.field.VirtualKeyboard', { extend: 'Ext.plugin.Abstract', alias: 'plugin.virtualkeyboard', requires: [ 'app.ux.form.field.VirtualKeyboardPanel' ], triggerTooltip: "Additional Symbols", triggerGlyph: 'xf1ab@FontAwesome', pickerTitle: "Symbols", pickerHeight: 200, numberOfColumns: 5, symbols: [], init: function (field) { this.field = field; var triggers = field.getTriggers(); triggers.virtualKeyboard = { glyph: this.triggerGlyph, tooltip: this.triggerTooltip, handler: this.openPicker, scope: this }; field.setTriggers(triggers); }, openPicker: function () { this.getPicker().show(); }, getPicker: function () { if (!this.picker) { this.picker = this.createPicker(); } return this.picker; }, createPicker: function () { var picker, pickerCfg; pickerCfg = Ext.apply({ xtype: 'window', id: this.field.id + '-symbolContainer', title: this.pickerTitle, pickerField: this, height: this.pickerHeight, layout: 'fit', closeAction: 'hide', items: [{ xtype: 'app_ux_form_field_VirtualKeyboardPanel', numberOfColumns: this.numberOfColumns, symbols: this.symbols, listeners: { 'SymbolClick': { fn: this.onSymbolClick, scope: this } } }] }); picker = Ext.widget(pickerCfg); return picker; }, onSymbolClick: function (symbol) { var fieldValue = this.field.getValue(); fieldValue += symbol; this.field.setValue(fieldValue); this.getPicker().hide(); }, onEsc: function () { this.getPicker().hide(); } });
and the popup:
Ext.define('app.ux.form.field.VirtualKeyboardPanel', { extend: 'Ext.view.View', alias: 'widget.app_ux_form_field_VirtualKeyboardPanel', scrollable: true, border: false, symbols: [], cls: Ext.baseCSSPrefix + 'panel-body-default', itemSelector: 'div.thumb-wrap', initComponent: function() { this.tpl = this.createXTempalte(); this.store = this.createStore(); this.initEvents(); this.callParent(); }, initEvents: function() { this.on('itemclick', this.onSymbolClick, this); this.on('blur', this.onBlur, this); }, onSymbolClick: function(dataView, record, item, index, e, eOpt) { this.fireEvent('SymbolClick', record.get('symbol')); e.stopEvent(); }, onBlur: function(cmp, e, eOpt) { this.hide(); }, getSymbols: function() { var symbols = []; if(Ext.isArray(this.symbols)) { symbols = this.symbols; } else if(Ext.isFunction(this.symbols)) { symbols = this.symbols() } return symbols; }, createXTempalte: function() { var me = this; var xTemplate = new Ext.XTemplate( '<table>', '<tpl for=".">', '<tpl if="this.showOpenTr(xindex)">', '<tr>', '</tpl>', '<td style="background-color: #cccccc; text-align: center;" >', '<div style="cursor: pointer;" class="thumb-wrap">', '<span style="font-size: 40px;">{symbol}</span>', '</div>', '</td>', '<tpl if="this.showCloseTr(xindex, xcount)">', '</tr>', '</tpl>', '</tpl>', '</table>', { showOpenTr: function(xIndex) { return xIndex === 0 && xIndex % me.numberOfColumns === 0; }, showCloseTr: function(xIndex, xCount) { return xIndex === xCount || xIndex % me.numberOfColumns === 0; } } ); return xTemplate; }, createStore: function () { var store = Ext.create('Ext.data.Store', { fields: [ 'symbol' ] }); Ext.Array.each(this.getSymbols(), function(symbol) { store.add({ 'symbol': symbol }) }, this); return store; } });
The symbols can be listed in as an array or function.
plugins: { virtualkeyboard: { pickerTitle: "Polish chars", symbols: ['Ą', 'Ć', 'Ę', 'Ł', 'Ń', 'Ó', 'Ś', 'Ź', 'Ż'], numberOfColumns: 3 } }
plugins: { virtualkeyboard: { pickerTitle: "Chinese Сharacters", symbols: function() { var cJKUnifiedIdeographs = []; for(var i=19968; i<20000; i++) { cJKUnifiedIdeographs.push(String.fromCharCode(i)); } return cJKUnifiedIdeographs; } } }
Fiddle: