MDL-59828 autocomplete: Sizing issues on themes

We want to avoid page jumps wherever possible. This change uses the original select element as a "proxy" to reserve the space
in the DOM for the enhanced auto-complete when the JS runs.

It uses visibility: hidden to make the select not rendered - but still take up space.

The exact sizing for the CSS was determined by testing and reverse engineering the bootstrap calculations.

The size of user pictures in selectors was reduced to avoid flicker when switching between no selection and a selected user. I
could have reserved a larger amount of space, but it looks worse for pickers with no pictures.
This commit is contained in:
Damyon Wiese 2017-08-17 15:48:59 +08:00
parent f3625f47c5
commit d8e57f02a7
11 changed files with 67 additions and 15 deletions

View File

@ -49,7 +49,7 @@
}
}}
<span>
<img height="18" src="{{profileimageurlsmall}}" alt="" role="presentation">
<img height="12" src="{{profileimageurlsmall}}" alt="" role="presentation">
<span>{{fullname}}</span>
{{#hasidentity}}
<span><small>{{identity}}</small></span>

View File

@ -49,7 +49,7 @@
}
}}
<span>
<img height="18" src="{{profileimageurlsmall}}" alt="" role="presentation">
<img height="12" src="{{profileimageurlsmall}}" alt="" role="presentation">
<span>{{fullname}}</span>
{{#hasidentity}}
<span><small>{{identity}}</small></span>

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config","core/url","core/form-autocomplete"],function(a,b,c,d,e,f,g,h){return a("body").on("click keypress","[data-inplaceeditable] [data-inplaceeditablelink]",function(i){if("keypress"!==i.type||13===i.keyCode){i.stopImmediatePropagation(),i.preventDefault();var j=a(this),k=j.closest("[data-inplaceeditable]"),l=function(b){b.addClass("updating");var c=b.find("img.spinner");c.length?c.show():(c=a("<img/>").attr("src",g.imageUrl("i/loading_small")).addClass("spinner").addClass("smallicon"),b.append(c))},m=function(a){a.removeClass("updating"),a.find("img.spinner").hide()},n=function(e,f){l(e),b.call([{methodname:"core_update_inplace_editable",args:{itemid:e.attr("data-itemid"),component:e.attr("data-component"),itemtype:e.attr("data-itemtype"),value:f},done:function(b){var d=e.attr("data-value");c.render("core/inplace_editable",b).done(function(f,g){var h=a(f);c.replaceNode(e,h,g),h.find("[data-inplaceeditablelink]").focus(),h.trigger({type:"updated",ajaxreturn:b,oldvalue:d})})},fail:function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});m(e),e.trigger(c),c.isDefaultPrevented()||d.exception(b)}}],!0)},o=function(a){a.find("input").off(),a.find("select").off(),a.html(a.attr("data-oldcontent")),a.removeAttr("data-oldcontent"),a.removeClass("inplaceeditingon"),a.find("[data-inplaceeditablelink]").focus()},p=function(){a("span.inplaceeditable.inplaceeditingon").each(function(){o(a(this))})},q=function(b,c){var d,e=b;for(d=0;d<c;d++)e+=String(Math.floor(10*Math.random()));return 0===a("#"+e).length?e:q(b,c)},r=function(b){e.get_string("edittitleinstructions").done(function(c){var d=a('<span class="editinstructions">'+c+"</span>").attr("id",q("id_editinstructions_",20)),e=a('<input type="text"/>').attr("id",q("id_inplacevalue_",20)).attr("value",b.attr("data-value")).attr("aria-describedby",d.attr("id")).addClass("ignoredirty").addClass("form-control"),g=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));b.html("").append(d).append(g).append(e),e.focus(),e.select(),e.on("keyup keypress focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("keypress"===a.type&&13===a.keyCode){var c=e.val();o(b),n(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}})})},s=function(a,b){o(a),n(a,b)},t=function(b,c){var d,e=a("<select></select>").attr("id",q("id_inplacevalue_",20)).addClass("custom-select"),g=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));for(d in c)e.append(a("<option>").attr("value",c[d].key).html(c[d].value));e.val(b.attr("data-value")),b.html("").append(g).append(e),e.focus(),e.select(),e.on("keyup change focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("change"===a.type){var c=e.val();o(b),n(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}})},u=function(b,f){var g,i=a("<select></select>").attr("id",q("id_inplacevalue_",20)).addClass("custom-select"),j=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",i.attr("id")),l=f.options,m=f.attributes,p=a('<a href="#"></a>'),r=a('<a href="#"></a>');for(g in l)i.append(a("<option>").attr("value",l[g].key).html(l[g].value));m.multiple&&i.attr("multiple","true"),i.val(JSON.parse(b.attr("data-value"))),e.get_string("savechanges","core").then(function(a){return c.renderPix("e/save","core",a)}).then(function(a){p.append(a)}).fail(d.exception),e.get_string("cancel","core").then(function(a){return c.renderPix("e/cancel","core",a)}).then(function(a){r.append(a)}).fail(d.exception),b.html("").append(j).append(i).append(p).append(r),i.focus(),i.select(),h.enhance(i,m.tags,m.ajax,m.placeholder,m.caseSensitive,m.showSuggestions,m.noSelectionString).then(function(){b.find("[role=combobox]").focus()}).fail(d.exception),i.on("keyup",function(a){("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}),p.on("click",function(a){var c=JSON.stringify(i.val());o(b),n(b,c),a.preventDefault()}),r.on("click",function(a){o(b),a.preventDefault()})},v=function(b){b.addClass("inplaceeditingon"),b.attr("data-oldcontent",b.html());var c=b.attr("data-type"),d=b.attr("data-options");"toggle"===c?s(b,d):"select"===c?t(b,a.parseJSON(d)):"autocomplete"===c?u(b,a.parseJSON(d)):r(b)};p(),v(k)}}),{}});
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config","core/url","core/form-autocomplete"],function(a,b,c,d,e,f,g,h){return a("body").on("click keypress","[data-inplaceeditable] [data-inplaceeditablelink]",function(i){if("keypress"!==i.type||13===i.keyCode){i.stopImmediatePropagation(),i.preventDefault();var j=a(this),k=j.closest("[data-inplaceeditable]"),l=function(b){b.addClass("updating");var c=b.find("img.spinner");c.length?c.show():(c=a("<img/>").attr("src",g.imageUrl("i/loading_small")).addClass("spinner").addClass("smallicon"),b.append(c))},m=function(a){a.removeClass("updating"),a.find("img.spinner").hide()},n=function(e,f){l(e),b.call([{methodname:"core_update_inplace_editable",args:{itemid:e.attr("data-itemid"),component:e.attr("data-component"),itemtype:e.attr("data-itemtype"),value:f},done:function(b){var d=e.attr("data-value");c.render("core/inplace_editable",b).done(function(f,g){var h=a(f);c.replaceNode(e,h,g),h.find("[data-inplaceeditablelink]").focus(),h.trigger({type:"updated",ajaxreturn:b,oldvalue:d})})},fail:function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});m(e),e.trigger(c),c.isDefaultPrevented()||d.exception(b)}}],!0)},o=function(a){a.find("input").off(),a.find("select").off(),a.html(a.attr("data-oldcontent")),a.removeAttr("data-oldcontent"),a.removeClass("inplaceeditingon"),a.find("[data-inplaceeditablelink]").focus()},p=function(){a("span.inplaceeditable.inplaceeditingon").each(function(){o(a(this))})},q=function(b,c){var d,e=b;for(d=0;d<c;d++)e+=String(Math.floor(10*Math.random()));return 0===a("#"+e).length?e:q(b,c)},r=function(b){e.get_string("edittitleinstructions").done(function(c){var d=a('<span class="editinstructions">'+c+"</span>").attr("id",q("id_editinstructions_",20)),e=a('<input type="text"/>').attr("id",q("id_inplacevalue_",20)).attr("value",b.attr("data-value")).attr("aria-describedby",d.attr("id")).addClass("ignoredirty").addClass("form-control"),g=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));b.html("").append(d).append(g).append(e),e.focus(),e.select(),e.on("keyup keypress focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("keypress"===a.type&&13===a.keyCode){var c=e.val();o(b),n(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}})})},s=function(a,b){o(a),n(a,b)},t=function(b,c){var d,e=a('<select class="form-autocomplete-original-select"></select>').attr("id",q("id_inplacevalue_",20)).addClass("custom-select"),g=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));for(d in c)e.append(a("<option>").attr("value",c[d].key).html(c[d].value));e.val(b.attr("data-value")),b.html("").append(g).append(e),e.focus(),e.select(),e.on("keyup change focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("change"===a.type){var c=e.val();o(b),n(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}})},u=function(b,f){var g,i=a("<select></select>").attr("id",q("id_inplacevalue_",20)).addClass("custom-select"),j=a('<label class="accesshide">'+k.attr("data-editlabel")+"</label>").attr("for",i.attr("id")),l=f.options,m=f.attributes,p=a('<a href="#"></a>'),r=a('<a href="#"></a>');for(g in l)i.append(a("<option>").attr("value",l[g].key).html(l[g].value));m.multiple&&i.attr("multiple","true"),i.val(JSON.parse(b.attr("data-value"))),e.get_string("savechanges","core").then(function(a){return c.renderPix("e/save","core",a)}).then(function(a){p.append(a)}).fail(d.exception),e.get_string("cancel","core").then(function(a){return c.renderPix("e/cancel","core",a)}).then(function(a){r.append(a)}).fail(d.exception),b.html("").append(j).append(i).append(p).append(r),i.focus(),i.select(),h.enhance(i,m.tags,m.ajax,m.placeholder,m.caseSensitive,m.showSuggestions,m.noSelectionString).then(function(){b.find("[role=combobox]").focus()}).fail(d.exception),i.on("keyup",function(a){("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&o(b)}),p.on("click",function(a){var c=JSON.stringify(i.val());o(b),n(b,c),a.preventDefault()}),r.on("click",function(a){o(b),a.preventDefault()})},v=function(b){b.addClass("inplaceeditingon"),b.attr("data-oldcontent",b.html());var c=b.attr("data-type"),d=b.attr("data-options");"toggle"===c?s(b,d):"select"===c?t(b,a.parseJSON(d)):"autocomplete"===c?u(b,a.parseJSON(d)):r(b)};p(),v(k)}}),{}});

View File

@ -758,8 +758,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
return false;
}
originalSelect.css('visibility', 'hidden').attr('aria-hidden', true);
// Hide the original select.
originalSelect.hide().attr('aria-hidden', true);
// Find or generate some ids.
var state = {
@ -795,10 +796,11 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
var renderSelection = templates.render('core/form_autocomplete_selection', context);
return $.when(renderInput, renderDatalist, renderSelection).then(function(input, suggestions, selection) {
// Add our new UI elements to the page.
originalSelect.hide();
originalSelect.after(suggestions);
originalSelect.after(input);
originalSelect.after(selection);
// Update the form label to point to the text input.
originalLabel.attr('for', state.inputId);
// Add the event handlers.

View File

@ -171,7 +171,7 @@ define(['jquery',
var turnEditingOnSelect = function(el, options) {
var i,
inputelement = $('<select></select>').
inputelement = $('<select class="form-autocomplete-original-select"></select>').
attr('id', uniqueId('id_inplacevalue_', 20)).
addClass('custom-select'),
lbl = $('<label class="accesshide">' + mainelement.attr('data-editlabel') + '</label>')

View File

@ -241,9 +241,24 @@ fieldset.coursesearchbox label {
}
/* Custom styles for autocomplete form element */
/* These styles reserve a standard amount of space in the DOM to avoid flicker when the original select element is replaced */
[data-fieldtype=autocomplete] select,
[data-fieldtype=tags] select,
.form-autocomplete-original-select {
visibility: hidden;
overflow: hidden;
width: 15rem;
height: 44px;
margin: 0;
padding: 0;
border: 0;
margin-top: $font-size-base * $line-height-base + $tag-padding-y;
vertical-align: bottom;
}
.form-autocomplete-selection {
margin: 0.2em;
min-height: 21px;
margin: $tag-padding-y;
// Padding top and bottom, plus m-b-1 and the 100% lineheight.
min-height: 2 * $tag-padding-y + 2 * $font-size-base;
}
.form-autocomplete-multiple [role=listitem] {

View File

@ -40,11 +40,11 @@
<div class="form-autocomplete-selection {{#multiple}}form-autocomplete-multiple{{/multiple}}" id="{{selectionId}}" role="list" aria-atomic="true" {{#multiple}}tabindex="0" aria-multiselectable="true"{{/multiple}}>
<span class="accesshide">{{#str}}selecteditems, form{{/str}}</span>
{{#items}}
<span role="listitem" data-value="{{value}}" aria-selected="true" class="tag tag-info m-b-1 m-r-1" style="font-size: larger">
<span role="listitem" data-value="{{value}}" aria-selected="true" class="tag tag-info m-b-1 m-r-1" style="font-size: 100%">
{{#multiple}}<span aria-hidden="true">× </span>{{/multiple}}{{{label}}}
</span>
{{/items}}
{{^items}}
<span>{{noSelectionString}}</span>
<span class="m-b-1 m-r-1">{{noSelectionString}}</span>
{{/items}}
</div>

View File

@ -445,9 +445,27 @@ input[size] {
}
/* Custom styles for autocomplete form element */
[data-fieldtype=autocomplete] select,
[data-fieldtype=tags] select,
select.form-autocomplete-original-select {
visibility: hidden;
overflow: hidden;
width: 15rem;
height: 3 * @baseLineHeight + @baseFontSize / 2;
margin: 0;
margin-bottom: 0.2em;
padding: 0;
border: 0;
vertical-align: top;
}
.form-autocomplete-container {
display: inline-block;
min-height: 4.2rem;
}
.form-autocomplete-selection {
margin: 0.2em;
min-height: 21px;
min-height: @baseLineHeight + @baseFontSize / 2;
}
.form-autocomplete-multiple [role=listitem] {
cursor: pointer;

View File

@ -16902,9 +16902,26 @@ input[size] {
width: auto;
}
/* Custom styles for autocomplete form element */
[data-fieldtype=autocomplete] select,
[data-fieldtype=tags] select,
select.form-autocomplete-original-select {
visibility: hidden;
overflow: hidden;
width: 15rem;
height: 67px;
margin: 0;
margin-bottom: 0.2em;
padding: 0;
border: 0;
vertical-align: top;
}
.form-autocomplete-container {
display: inline-block;
min-height: 4.2rem;
}
.form-autocomplete-selection {
margin: 0.2em;
min-height: 21px;
min-height: 27px;
}
.form-autocomplete-multiple [role=listitem] {
cursor: pointer;

View File

@ -51,9 +51,9 @@
]
}
}}
<form method="post" action="{{action}}" class="form-inline m-b-2" role="search">
<form method="post" action="{{action}}" class="m-b-1" role="search">
<label for="unified-filters" class="sr-only">{{#str}}filters{{/str}}</label>
<select name="unified-filters[]" id="unified-filters" multiple="multiple" data-originaloptionsjson="{{originaloptionsjson}}">
<select name="unified-filters[]" id="unified-filters" multiple="multiple" data-originaloptionsjson="{{originaloptionsjson}}" class="form-autocomplete-original-select">
{{#filteroptions}}
<option value="{{value}}" {{#selected}}selected="selected"{{/selected}}>{{{label}}}</option>
{{/filteroptions}}