Files
Chamilo/app/Resources/public/assets/keyboard/js/jquery.keyboard.extension-autocomplete.js
2025-04-10 12:53:50 +02:00

231 lines
6.5 KiB
JavaScript

/*! jQuery UI Virtual Keyboard Autocomplete v1.11.4 *//*
* for Keyboard v1.18+ only (2018-01-10)
*
* By Rob Garrison (Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to get
* the jQuery UI Autocomplete widget to work seamlessly
*
* Requires:
* jQuery
* jQuery UI & css
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .autocomplete(options)
* .addAutoComplete();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .autocomplete(options) // jQuery UI autocomplete
* .addAutoComplete(); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.fn.addAutocomplete = function(options) {
var defaults = {
position : {
of : null,
my : 'right top',
at : 'left top',
collision: 'flip'
},
events: 'autocomplete',
data: ''
};
return this.each(function() {
// make sure a keyboard is attached
var o, namespace,
base = $(this).data('keyboard');
if (!base) { return; }
namespace = base.namespace + 'Autocomplete';
base.autocomplete_namespace = namespace;
base.extensionNamespace.push( namespace );
// Setup
base.autocomplete_init = function() {
// variables
o = base.autocomplete_options = $.extend( true, {}, defaults, options );
var events = o.events || o.data || 'autocomplete';
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.autocomplete_setup();
}
base.$el
.unbind(namespace)
.bind($.keyboard.events.kbVisible + namespace, function() {
base.autocomplete_setup();
})
.bind($.keyboard.events.kbHidden + namespace, function() {
base.$el[o.data || 'autocomplete']('close');
})
.bind($.keyboard.events.kbChange + namespace, function() {
if (base.hasAutocomplete && base.isVisible()) {
base.$el.val(base.$preview.val());
}
})
.bind(events + 'open' + namespace, function() {
if (base.hasAutocomplete) {
// default to $keyboard if no position.of defined
var position = $.extend( {}, o.position );
// refresh base.$keyboard (it gets destroyed after use); fixes #382
position.of = position.of || base.$keyboard;
// reposition autocomplete window next to the keyboard
base.$autocomplete.menu.element.position( position );
}
})
.bind(events + 'select' + namespace, function(e, ui) {
base.autocomplete_getVal(ui.item);
});
};
base.autocomplete_getVal = function(val) {
var v;
switch (typeof val) {
case 'string':
v = val || '';
break;
case 'object':
v = val.label || val.value || '';
break;
default:
v = base.preview && base.preview.value || base.el.value;
}
v = v.toString();
if (base.hasAutocomplete && v !== '') {
// fallback to original input if undefined, see #520
(base.$preview || base.$el)
.val( v )
.focus();
// see issue #95 - thanks banku!
base.last.start = v.length;
base.last.end = v.length;
base.last.val = v;
}
};
base.autocomplete_update = function(event) {
clearTimeout( base.$autocomplete.searching );
base.$autocomplete.searching = setTimeout(function() {
// only search if the value has changed
if ( base.$autocomplete.term !== base.$autocomplete.element.val() ) {
base.$autocomplete.selectedItem = null;
base.$autocomplete.search( null, event );
}
}, base.$autocomplete.options.delay );
};
base.autocomplete_navKeys = {
8: 'backSpace',
9: 'tab',
13: 'enter',
20: 'capsLock',
27: 'escape',
32: 'space',
33: 'pageup',
34: 'pagedown',
35: 'end',
36: 'home',
37: 'left',
38: 'up',
39: 'right',
40: 'down',
45: 'insert',
46: 'delete'
};
// set up after keyboard is visible
base.autocomplete_setup = function() {
var key;
// look for autocomplete
base.$autocomplete = base.$el.data(base.autocomplete_options.data) ||
// data changes based on jQuery UI version
base.$el.data('uiAutocomplete') ||
base.$el.data('ui-autocomplete') ||
base.$el.data('autocomplete');
base.hasAutocomplete = (typeof(base.$autocomplete) === 'undefined') ?
false : (base.$autocomplete.options.disabled) ? false : true;
// only bind to keydown once
if (base.hasAutocomplete) {
base.$preview.bind('keydown' + namespace + ' keypress' + namespace, function(event) {
// send keys to the autocomplete widget (arrow, pageup/down, etc)
if (base.$preview && event.namespace !== base.$autocomplete.eventNamespace) {
event.namespace = base.$autocomplete.eventNamespace.slice(1);
key = base.autocomplete_navKeys[event.which];
if (key) {
if (base.el !== base.preview) {
base.$el.triggerHandler(event);
if (key === 'enter') {
// update preview with the selected item
setTimeout(function(){
if (base.$autocomplete) {
base.$preview.val(base.$autocomplete.selectedItem.value);
base.$preview.focus();
}
}, 100);
}
}
} else {
// only search when a non-navigation key is pressed
base.autocomplete_update(event);
}
}
});
var events = 'mouseup mousedown mouseleave touchstart touchend touchcancel '
.split(' ')
.join(namespace + ' ');
base.bindButton(events, function(event) {
base.autocomplete_update(event);
});
}
if (!base.escCloseCallback.autocomplete) {
base.escCloseCallback.autocomplete = base.checkAutocompleteMenu;
}
};
base.checkAutocompleteMenu = function($target) {
// prevent selecting an item in autocomplete from closing keyboard
// return a "shouldStayOpen" boolean state for this extension
return base.hasAutocomplete &&
$target.closest('ul').hasClass('ui-autocomplete');
};
base.autocomplete_destroy = function() {
clearTimeout(base.$autocomplete.searching);
base.hasAutocomplete = false;
base.$el.unbind(namespace);
if (base.$preview) {
base.$preview.unbind(namespace);
base.unbindButton(namespace);
}
delete base.$autocomplete;
};
base.autocomplete_init();
});
};
}));