Display full names in Allowed Users autocomplete
This commit is contained in:
parent
5341906767
commit
31ed09e607
|
@ -0,0 +1,289 @@
|
||||||
|
/* An auto-complete module for select and input elements that can pull in
|
||||||
|
* a list of terms from an API endpoint (provided using data-module-source).
|
||||||
|
*
|
||||||
|
* source - A url pointing to an API autocomplete endpoint.
|
||||||
|
* interval - The interval between requests in milliseconds (default: 300).
|
||||||
|
* items - The max number of items to display (default: 10)
|
||||||
|
* tags - Boolean attribute if true will create a tag input.
|
||||||
|
* key - A string of the key you want to be the form value to end up on
|
||||||
|
* from the ajax returned results
|
||||||
|
* label - A string of the label you want to appear within the dropdown for
|
||||||
|
* returned results
|
||||||
|
* tokensep - A string that contains characters which will be interpreted
|
||||||
|
* as separators for tags when typed or pasted (default ",").
|
||||||
|
* Examples
|
||||||
|
*
|
||||||
|
* // <input name="tags" data-module="autocomplete" data-module-source="http://" />
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
this.ckan.module('privatedatasets_autocomplete', function (jQuery) {
|
||||||
|
return {
|
||||||
|
/* Options for the module */
|
||||||
|
options: {
|
||||||
|
tags: false,
|
||||||
|
key: false,
|
||||||
|
label: false,
|
||||||
|
items: 10,
|
||||||
|
source: null,
|
||||||
|
tokensep: ',',
|
||||||
|
interval: 300,
|
||||||
|
dropdownClass: '',
|
||||||
|
containerClass: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Sets up the module, binding methods, creating elements etc. Called
|
||||||
|
* internally by ckan.module.initialize();
|
||||||
|
*
|
||||||
|
* Returns nothing.
|
||||||
|
*/
|
||||||
|
initialize: function () {
|
||||||
|
jQuery.proxyAll(this, /_on/, /format/);
|
||||||
|
this.setupAutoComplete();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Sets up the auto complete plugin.
|
||||||
|
*
|
||||||
|
* Returns nothing.
|
||||||
|
*/
|
||||||
|
setupAutoComplete: function () {
|
||||||
|
var settings = {
|
||||||
|
width: 'resolve',
|
||||||
|
formatResult: this.formatResult,
|
||||||
|
formatNoMatches: this.formatNoMatches,
|
||||||
|
formatInputTooShort: this.formatInputTooShort,
|
||||||
|
dropdownCssClass: this.options.dropdownClass,
|
||||||
|
containerCssClass: this.options.containerClass,
|
||||||
|
tokenSeparators: this.options.tokensep.split('')
|
||||||
|
};
|
||||||
|
|
||||||
|
// Different keys are required depending on whether the select is
|
||||||
|
// tags or generic completion.
|
||||||
|
if (!this.el.is('select')) {
|
||||||
|
if (this.options.tags) {
|
||||||
|
settings.tags = this._onQuery;
|
||||||
|
} else {
|
||||||
|
settings.query = this._onQuery;
|
||||||
|
settings.createSearchChoice = this.formatTerm;
|
||||||
|
}
|
||||||
|
settings.initSelection = this.formatInitialValue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
|
||||||
|
var ieversion=new Number(RegExp.$1);
|
||||||
|
if (ieversion<=7) {return}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var select2 = this.el.select2(settings).data('select2');
|
||||||
|
|
||||||
|
if (this.options.tags && select2 && select2.search) {
|
||||||
|
// find the "fake" input created by select2 and add the keypress event.
|
||||||
|
// This is not part of the plugins API and so may break at any time.
|
||||||
|
select2.search.on('keydown', this._onKeydown);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This prevents Internet Explorer from causing a window.onbeforeunload
|
||||||
|
// even from firing unnecessarily
|
||||||
|
$('.select2-choice', select2.container).on('click', function() {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._select2 = select2;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Looks up the completions for the current search term and passes them
|
||||||
|
* into the provided callback function.
|
||||||
|
*
|
||||||
|
* The results are formatted for use in the select2 autocomplete plugin.
|
||||||
|
*
|
||||||
|
* string - The term to search for.
|
||||||
|
* fn - A callback function.
|
||||||
|
*
|
||||||
|
* Examples
|
||||||
|
*
|
||||||
|
* module.getCompletions('cake', function (results) {
|
||||||
|
* results === {results: []}
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Returns a jqXHR promise.
|
||||||
|
*/
|
||||||
|
getCompletions: function (string, fn) {
|
||||||
|
var parts = this.options.source.split('?');
|
||||||
|
var end = parts.pop();
|
||||||
|
var source = parts.join('?') + encodeURIComponent(string) + end;
|
||||||
|
var client = this.sandbox.client;
|
||||||
|
var options = {
|
||||||
|
format: function(data) {
|
||||||
|
var completion_options = jQuery.extend(options, {objects: true});
|
||||||
|
return {
|
||||||
|
results: client.parseCompletions(data, completion_options)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
key: this.options.key,
|
||||||
|
label: this.options.label
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.getCompletions(source, options, fn);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Looks up the completions for the provided text but also provides a few
|
||||||
|
* optimisations. If there is no search term it will automatically set
|
||||||
|
* an empty array. Ajax requests will also be debounced to ensure that
|
||||||
|
* the server is not overloaded.
|
||||||
|
*
|
||||||
|
* string - The term to search for.
|
||||||
|
* fn - A callback function.
|
||||||
|
*
|
||||||
|
* Returns nothing.
|
||||||
|
*/
|
||||||
|
lookup: function (string, fn) {
|
||||||
|
var module = this;
|
||||||
|
|
||||||
|
// Cache the last searched term otherwise we'll end up searching for
|
||||||
|
// old data.
|
||||||
|
this._lastTerm = string;
|
||||||
|
|
||||||
|
// Kills previous timeout
|
||||||
|
clearTimeout(this._debounced);
|
||||||
|
|
||||||
|
// OK, wipe the dropdown before we start ajaxing the completions
|
||||||
|
fn({results:[]});
|
||||||
|
|
||||||
|
if (string) {
|
||||||
|
// Set a timer to prevent the search lookup occurring too often.
|
||||||
|
this._debounced = setTimeout(function () {
|
||||||
|
var term = module._lastTerm;
|
||||||
|
|
||||||
|
// Cancel the previous request if it hasn't yet completed.
|
||||||
|
if (module._last && typeof module._last.abort == 'function') {
|
||||||
|
module._last.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
module._last = module.getCompletions(term, fn);
|
||||||
|
|
||||||
|
}, this.options.interval);
|
||||||
|
|
||||||
|
// This forces the ajax throbber to appear, because we've called the
|
||||||
|
// callback already and that hides the throbber
|
||||||
|
$('.select2-search input', this._select2.dropdown).addClass('select2-active');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Formatter for the select2 plugin that returns a string for use in the
|
||||||
|
* results list with the current term emboldened.
|
||||||
|
*
|
||||||
|
* state - The current object that is being rendered.
|
||||||
|
* container - The element the content will be added to (added in 3.0)
|
||||||
|
* query - The query object (added in select2 3.0).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns a text string.
|
||||||
|
*/
|
||||||
|
formatResult: function (state, container, query) {
|
||||||
|
var term = this._lastTerm || null; // same as query.term
|
||||||
|
|
||||||
|
if (container) {
|
||||||
|
// Append the select id to the element for styling.
|
||||||
|
container.attr('data-value', state.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the current string is the actual query, just format that
|
||||||
|
if (state.text === term && state.id === term){
|
||||||
|
var ret = state.text;
|
||||||
|
}
|
||||||
|
// if we're formatting a suggestion, concatenate the full name and
|
||||||
|
// username of the suggestion
|
||||||
|
else {
|
||||||
|
var ret = state.text + " (" + state.id + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.split(term).join(term && term.bold());
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Formatter for the select2 plugin that returns a string used when
|
||||||
|
* the filter has no matches.
|
||||||
|
*
|
||||||
|
* Returns a text string.
|
||||||
|
*/
|
||||||
|
formatNoMatches: function (term) {
|
||||||
|
return !term ? this._('Start typing…') : this._('No matches found');
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Formatter used by the select2 plugin that returns a string when the
|
||||||
|
* input is too short.
|
||||||
|
*
|
||||||
|
* Returns a string.
|
||||||
|
*/
|
||||||
|
formatInputTooShort: function (term, min) {
|
||||||
|
return this.ngettext(
|
||||||
|
'Input is too short, must be at least one character',
|
||||||
|
'Input is too short, must be at least %(num)d characters',
|
||||||
|
min
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Takes a string and converts it into an object used by the select2 plugin.
|
||||||
|
*
|
||||||
|
* term - The term to convert.
|
||||||
|
*
|
||||||
|
* Returns an object for use in select2.
|
||||||
|
*/
|
||||||
|
formatTerm: function (term) {
|
||||||
|
term = jQuery.trim(term || '');
|
||||||
|
|
||||||
|
// Need to replace comma with a unicode character to trick the plugin
|
||||||
|
// as it won't split this into multiple items.
|
||||||
|
return {id: term.replace(/,/g, '\u002C'), text: term};
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Callback function that parses the initial field value.
|
||||||
|
*
|
||||||
|
* element - The initialized input element wrapped in jQuery.
|
||||||
|
* callback - A callback to run once the formatting is complete.
|
||||||
|
*
|
||||||
|
* Returns a term object or an array depending on the type.
|
||||||
|
*/
|
||||||
|
formatInitialValue: function (element, callback) {
|
||||||
|
var value = jQuery.trim(element.val() || '');
|
||||||
|
var formatted;
|
||||||
|
|
||||||
|
if (this.options.tags) {
|
||||||
|
formatted = jQuery.map(value.split(","), this.formatTerm);
|
||||||
|
} else {
|
||||||
|
formatted = this.formatTerm(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select2 v3.0 supports a callback for async calls.
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Callback triggered when the select2 plugin needs to make a request.
|
||||||
|
*
|
||||||
|
* Returns nothing.
|
||||||
|
*/
|
||||||
|
_onQuery: function (options) {
|
||||||
|
if (options) {
|
||||||
|
this.lookup(options.term, options.callback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Called when a key is pressed. If the key is a comma we block it and
|
||||||
|
* then simulate pressing return.
|
||||||
|
*
|
||||||
|
* Returns nothing.
|
||||||
|
*/
|
||||||
|
_onKeydown: function (event) {
|
||||||
|
if (typeof event.key !== 'undefined' ? event.key === ',' : event.which === 188) {
|
||||||
|
event.preventDefault();
|
||||||
|
setTimeout(function () {
|
||||||
|
var e = jQuery.Event("keydown", { which: 13 });
|
||||||
|
jQuery(event.target).trigger(e);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -51,7 +51,7 @@
|
||||||
<span class="info-block info-inline">
|
<span class="info-block info-inline">
|
||||||
<i class="icon-info-sign fa fa-info-circle"></i>
|
<i class="icon-info-sign fa fa-info-circle"></i>
|
||||||
{% trans %}
|
{% trans %}
|
||||||
Private datasets can only be accessed by certain users, while public datasets can be accessed by anyone.
|
Private datasets can only be accessed by certain users, while public datasets can be accessed by anyone.
|
||||||
{% endtrans %}
|
{% endtrans %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,10 +82,12 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set users_attrs = {'data-module': 'autocomplete', 'data-module-tags': '', 'data-module-source': '/api/2/util/user/autocomplete?q=?'} %}
|
{% resource 'privatedatasets/privatedatasets_autocomplete.js' %}
|
||||||
|
|
||||||
|
{% set users_attrs = {'data-module': 'privatedatasets_autocomplete', 'data-module-tags': '', 'data-module-label': 'fullname', 'data-module-source': '/api/2/util/user/autocomplete?q=?'} %}
|
||||||
{{ form.input('allowed_users_str', label=_('Allowed Users'), id='field-allowed_users_str', placeholder=_('Allowed Users'), value=h.get_allowed_users_str(data.allowed_users), error=errors.custom_text, classes=['control-full'], attrs=users_attrs) }}
|
{{ form.input('allowed_users_str', label=_('Allowed Users'), id='field-allowed_users_str', placeholder=_('Allowed Users'), value=h.get_allowed_users_str(data.allowed_users), error=errors.custom_text, classes=['control-full'], attrs=users_attrs) }}
|
||||||
|
|
||||||
|
|
||||||
{% if editing and h.show_acquire_url_on_edit() or not editing and h.show_acquire_url_on_create() %}
|
{% if editing and h.show_acquire_url_on_edit() or not editing and h.show_acquire_url_on_create() %}
|
||||||
{{ form.input('acquire_url', label=_('Acquire URL'), id='field-acquire_url', placeholder=_('http://example.com/acquire/'), value=data.acquire_url, error=errors.custom_text, classes=['control-medium']) }}
|
{{ form.input('acquire_url', label=_('Acquire URL'), id='field-acquire_url', placeholder=_('http://example.com/acquire/'), value=data.acquire_url, error=errors.custom_text, classes=['control-medium']) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
Loading…
Reference in New Issue