298 lines
7.7 KiB
JavaScript
298 lines
7.7 KiB
JavaScript
webshims.register('form-datalist', function($, webshims, window, document, undefined, options){
|
|
"use strict";
|
|
var lazyLoad = function(name){
|
|
if(!name || typeof name != 'string'){
|
|
name = 'DOM';
|
|
}
|
|
if(!lazyLoad[name+'Loaded']){
|
|
lazyLoad[name+'Loaded'] = true;
|
|
webshims.ready(name, function(){
|
|
webshims.loader.loadList(['form-datalist-lazy']);
|
|
});
|
|
}
|
|
};
|
|
var noDatalistSupport = {
|
|
submit: 1,
|
|
button: 1,
|
|
reset: 1,
|
|
hidden: 1,
|
|
|
|
range: 1,
|
|
date: 1,
|
|
month: 1
|
|
};
|
|
if(webshims.modules["form-number-date-ui"].loaded){
|
|
$.extend(noDatalistSupport, {
|
|
number: 1,
|
|
time: 1
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* implement propType "element" currently only used for list-attribute (will be moved to dom-extend, if needed)
|
|
*/
|
|
webshims.propTypes.element = function(descs, name){
|
|
webshims.createPropDefault(descs, 'attr');
|
|
if(descs.prop){return;}
|
|
descs.prop = {
|
|
get: function(){
|
|
var elem = $.attr(this, name);
|
|
if(elem){
|
|
elem = document.getElementById(elem);
|
|
if(elem && descs.propNodeName && !$.nodeName(elem, descs.propNodeName)){
|
|
elem = null;
|
|
}
|
|
}
|
|
return elem || null;
|
|
},
|
|
writeable: false
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
* Implements datalist element and list attribute
|
|
*/
|
|
|
|
(function(){
|
|
var formsCFG = webshims.cfg.forms;
|
|
var listSupport = webshims.support.datalist;
|
|
if(listSupport && !formsCFG.customDatalist){return;}
|
|
|
|
var initializeDatalist = function(){
|
|
|
|
var updateDatlistAndOptions = function(){
|
|
var id;
|
|
if(!$.data(this, 'datalistWidgetData') && (id = $.prop(this, 'id'))){
|
|
$('input[list="'+ id +'"], input[data-wslist="'+ id +'"]').eq(0).attr('list', id);
|
|
} else {
|
|
$(this).triggerHandler('updateDatalist');
|
|
}
|
|
};
|
|
|
|
var inputListProto = {
|
|
//override autocomplete
|
|
autocomplete: {
|
|
attr: {
|
|
get: function(){
|
|
var elem = this;
|
|
var data = $.data(elem, 'datalistWidget');
|
|
if(data){
|
|
return data._autocomplete;
|
|
}
|
|
return ('autocomplete' in elem) ? elem.autocomplete : elem.getAttribute('autocomplete');
|
|
},
|
|
set: function(value){
|
|
var elem = this;
|
|
var data = $.data(elem, 'datalistWidget');
|
|
if(data){
|
|
data._autocomplete = value;
|
|
if(value == 'off'){
|
|
data.hideList();
|
|
}
|
|
} else {
|
|
if('autocomplete' in elem){
|
|
elem.autocomplete = value;
|
|
} else {
|
|
elem.setAttribute('autocomplete', value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if(listSupport){
|
|
//options only return options, if option-elements are rooted: but this makes this part of HTML5 less backwards compatible
|
|
if(!($('<datalist><select><option></option></select></datalist>').prop('options') || []).length ){
|
|
webshims.defineNodeNameProperty('datalist', 'options', {
|
|
prop: {
|
|
writeable: false,
|
|
get: function(){
|
|
var options = this.options || [];
|
|
if(!options.length){
|
|
var elem = this;
|
|
var select = $('select', elem);
|
|
if(select[0] && select[0].options && select[0].options.length){
|
|
options = select[0].options;
|
|
}
|
|
}
|
|
return options;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
inputListProto.list = {
|
|
attr: {
|
|
get: function(){
|
|
var val = webshims.contentAttr(this, 'list');
|
|
if(val != null){
|
|
$.data(this, 'datalistListAttr', val);
|
|
if(!noDatalistSupport[$.prop(this, 'type')] && !noDatalistSupport[$.attr(this, 'type')]){
|
|
this.removeAttribute('list');
|
|
}
|
|
} else {
|
|
val = $.data(this, 'datalistListAttr');
|
|
}
|
|
|
|
return (val == null) ? undefined : val;
|
|
},
|
|
set: function(value){
|
|
var elem = this;
|
|
$.data(elem, 'datalistListAttr', value);
|
|
if (!noDatalistSupport[$.prop(this, 'type')] && !noDatalistSupport[$.attr(this, 'type')]) {
|
|
webshims.objectCreate(shadowListProto, undefined, {
|
|
input: elem,
|
|
id: value,
|
|
datalist: $.prop(elem, 'list')
|
|
});
|
|
elem.setAttribute('data-wslist', value);
|
|
} else {
|
|
elem.setAttribute('list', value);
|
|
}
|
|
$(elem).triggerHandler('listdatalistchange');
|
|
}
|
|
},
|
|
initAttr: true,
|
|
reflect: true,
|
|
propType: 'element',
|
|
propNodeName: 'datalist'
|
|
};
|
|
} else {
|
|
webshims.defineNodeNameProperties('input', {
|
|
list: {
|
|
attr: {
|
|
get: function(){
|
|
var val = webshims.contentAttr(this, 'list');
|
|
return (val == null) ? undefined : val;
|
|
},
|
|
set: function(value){
|
|
var elem = this;
|
|
webshims.contentAttr(elem, 'list', value);
|
|
webshims.objectCreate(options.shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')});
|
|
$(elem).triggerHandler('listdatalistchange');
|
|
}
|
|
},
|
|
initAttr: true,
|
|
reflect: true,
|
|
propType: 'element',
|
|
propNodeName: 'datalist'
|
|
}
|
|
});
|
|
}
|
|
|
|
webshims.defineNodeNameProperties('input', inputListProto);
|
|
|
|
webshims.addReady(function(context, contextElem){
|
|
contextElem
|
|
.filter('datalist > select, datalist, datalist > option, datalist > select > option')
|
|
.closest('datalist')
|
|
.each(updateDatlistAndOptions)
|
|
;
|
|
});
|
|
};
|
|
|
|
|
|
/*
|
|
* ShadowList
|
|
*/
|
|
|
|
var shadowListProto = {
|
|
_create: function(opts){
|
|
|
|
if(noDatalistSupport[$.prop(opts.input, 'type')] || noDatalistSupport[$.attr(opts.input, 'type')]){return;}
|
|
var datalist = opts.datalist;
|
|
var data = $.data(opts.input, 'datalistWidget');
|
|
var that = this;
|
|
if(datalist && data && data.datalist !== datalist){
|
|
data.datalist = datalist;
|
|
data.id = opts.id;
|
|
|
|
|
|
$(data.datalist)
|
|
.off('updateDatalist.datalistWidget')
|
|
.on('updateDatalist.datalistWidget', $.proxy(data, '_resetListCached'))
|
|
;
|
|
|
|
data._resetListCached();
|
|
return;
|
|
} else if(!datalist){
|
|
if(data){
|
|
data.destroy();
|
|
}
|
|
return;
|
|
} else if(data && data.datalist === datalist){
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
this.datalist = datalist;
|
|
this.id = opts.id;
|
|
this.hasViewableData = true;
|
|
this._autocomplete = $.attr(opts.input, 'autocomplete');
|
|
$.data(opts.input, 'datalistWidget', this);
|
|
$.data(datalist, 'datalistWidgetData', this);
|
|
|
|
lazyLoad('WINDOWLOAD');
|
|
|
|
if(webshims.isReady('form-datalist-lazy')){
|
|
if(window.QUnit){
|
|
that._lazyCreate(opts);
|
|
} else {
|
|
setTimeout(function(){
|
|
that._lazyCreate(opts);
|
|
}, 9);
|
|
}
|
|
} else {
|
|
$(opts.input).one('focus', lazyLoad);
|
|
webshims.ready('form-datalist-lazy', function(){
|
|
if(!that._destroyed){
|
|
that._lazyCreate(opts);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
destroy: function(e){
|
|
var input;
|
|
var autocomplete = $.attr(this.input, 'autocomplete');
|
|
$(this.input)
|
|
.off('.datalistWidget')
|
|
.removeData('datalistWidget')
|
|
;
|
|
this.shadowList.remove();
|
|
$(document).off('.datalist'+this.id);
|
|
$(window).off('.datalist'+this.id);
|
|
if(this.input.form && this.input.id){
|
|
$(this.input.form).off('submit.datalistWidget'+this.input.id);
|
|
}
|
|
this.input.removeAttribute('aria-haspopup');
|
|
if(autocomplete === undefined){
|
|
this.input.removeAttribute('autocomplete');
|
|
} else {
|
|
$(this.input).attr('autocomplete', autocomplete);
|
|
}
|
|
if(e && e.type == 'beforeunload'){
|
|
input = this.input;
|
|
setTimeout(function(){
|
|
$.attr(input, 'list', $.attr(input, 'list'));
|
|
}, 9);
|
|
}
|
|
this._destroyed = true;
|
|
}
|
|
};
|
|
|
|
webshims.loader.addModule('form-datalist-lazy', {
|
|
noAutoCallback: true,
|
|
options: $.extend(options, {shadowListProto: shadowListProto})
|
|
});
|
|
if(!options.list){
|
|
options.list = {};
|
|
}
|
|
//init datalist update
|
|
initializeDatalist();
|
|
})();
|
|
|
|
});
|