Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

receivers: implement autocomplete #3006

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions inspirehep/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,17 @@
field='abstracts.abstract_source_suggest'
)),
book_title=dict(completion=dict(
field='bookautocomplete'
))
field='book_suggest'
)),
book_series=dict(completion=dict(
field='book_series.book_series_suggest'
)),
collaboration_name=dict(completion=dict(
field='collaborations.collaboration_suggest'
)),
report_number=dict(completion=dict(
field='report_number_suggest'
)),
),
list_route='/literature/',
item_route=(
Expand Down Expand Up @@ -419,6 +428,11 @@
),
'application/vnd+inspire.ids+json': 'inspirehep.modules.api.v1.common_serializers:json_recids_response',
},
suggesters=dict(
author=dict(completion=dict(
field='author_suggest'
))
),
list_route='/authors/',
item_route='/authors/<pid(aut,record_class="inspirehep.modules.records.api:InspireRecord"):pid_value>',
default_media_type='application/json',
Expand Down Expand Up @@ -602,6 +616,11 @@
),
'application/vnd+inspire.ids+json': 'inspirehep.modules.api.v1.common_serializers:json_recids_response',
},
suggesters=dict(
conference=dict(completion=dict(
field='conference_suggest'
))
),
list_route='/conferences/',
item_route='/conferences/<pid(con,record_class="inspirehep.modules.records.api:InspireRecord"):pid_value>',
default_media_type='application/json',
Expand Down
1 change: 1 addition & 0 deletions inspirehep/modules/forms/field_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def post_process(self, form=None, formfields=[], extra_processors=[],
for p in (extra_processors or []):
p(form, self, submit=submit, fields=formfields)

# TODO: this obsolete way of autocompletion should be removed.
def perform_autocomplete(self, form, name, term, limit=50):
"""Run auto-complete method for field.

Expand Down
12 changes: 1 addition & 11 deletions inspirehep/modules/forms/fields/wtformsext.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,6 @@ def post_process(self, form=None, formfields=[], extra_processors=[],
self.form.post_process(form=self.form, formfields=formfields,
submit=submit)

def perform_autocomplete(self, form, name, term, limit=50):
"""Run auto-complete method for field.

This method should not be called directly, instead use
Form.autocomplete().
"""
if name.startswith(self.name + self.separator):
form = self.form_class(prefix=self.name + self.separator)
return form.autocomplete(name, term, limit=limit, _form=form)
return None

def get_flags(self, filter_func=None):
"""Get flags."""
flags = self.form.get_flags(filter_func=filter_func)
Expand Down Expand Up @@ -292,6 +281,7 @@ def post_process(self, form=None, formfields=[], extra_processors=[],
submit=submit
)

# TODO: this obsolete way of autocompletion should be removed.
def perform_autocomplete(self, form, name, term, limit=50):
"""Run auto-complete method for field.

Expand Down
63 changes: 0 additions & 63 deletions inspirehep/modules/forms/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,69 +139,6 @@ def post_process(self, form=None, formfields=[], submit=False):
field.post_process(form, formfields=formfields,
extra_processors=extra, submit=submit)

# def autocomplete(self, name, term, limit=50, _form=None):
# """
# Auto complete a form field.
# Example::
# form = FormClass()
# form.autocomplete('related_identifiers-1-scheme','do')
# Implementation notes:
# The form will first try a fast lookup by field name in the form, and
# delegate the auto-completion to the field. This will work for all but
# field enclosures (FieldList and FormField). If the first lookup fails,
# each field enclosure is checked if they can auto-complete the term,
# which usually involves parsing the field name and generating a
# stub-field (see further details in wtforms_field module).
# @param name: Name of field (e.g. title or related_identifiers-1-scheme)
# @param term: Term to return auto-complete results for
# @param limit: Maximum number of results to return
# @return: None in case field could not be found, otherwise a (possibly
# empty) list of results.
# """
# if name in self._fields:
# res = self._fields[name].perform_autocomplete(
# _form or self,
# name,
# term,
# limit=limit,
# )
# if res is not None:
# return res[:limit]
# else:
# for f in self._fields.values():
# Only check field enclosures which cannot be found with above
# method.
# if name.startswith(f.name):
# res = f.perform_autocomplete(
# _form or self,
# name,
# term,
# limit=limit,
# )
# if res is not None:
# return res[:limit]
# return None

# def get_flags(self, filter_func=filter_flags):
# """Return dictionary of fields and their set flags."""
# flags = {}

# for f in self._fields.values():
# if hasattr(f, 'get_flags'):
# flags.update(f.get_flags(filter_func=filter_func))
# else:
# flags.update({f.name: filter_func(f)})

# return flags

# def set_flags(self, flags):
# """Set flags on fields.
# @param flags: Dictionary of fields and their set flags (same structure
# as returned by get_flags).
# """
# for f in self._fields.values():
# f.set_flags(flags)

@property
def json_data(self):
"""Return form data in a format suitable for the standard JSON encoder.
Expand Down
30 changes: 17 additions & 13 deletions inspirehep/modules/forms/static/js/forms/affiliations_typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ define([
this.dataEngine = new Bloodhound({
name: 'affiliations',
remote: {
url: '/api/institutions?q=affautocomplete:%QUERY*',
url: '/api/institutions/_suggest?affiliation=%QUERY',
filter: function(response) {
return $.map(response.hits.hits, function(el) { return el });
return $.map(response.affiliation[0].options, function(el) { return el.payload });
}
},
datumTokenizer: function() {},
Expand All @@ -47,9 +47,10 @@ define([
var suggestionTemplate = Hogan.compile(
'<strong>{{ legacy_ICN }}</strong><br>' +
'<small>' +
'{{#ICN}}{{#show_future_name}}Alternative name: {{future_name}}<br>{{/show_future_name}}{{/ICN}}' +
'{{#department}}{{ department }}<br>{{/department}}' +
'{{#institution}}{{ institution }}{{/institution}}' +
'{{#ICN}}{{#show_future_name}}Alternative name: {{future_name}}<br>{{/show_future_name}}{{/ICN}}' +
'{{#department}}{{ department }}<br>{{/department}}' +
'{{#institution}}{{ institution }}{{/institution}}' +
'{{#institution_name}}{{ institution_name }}{{/institution_name}}' +
'</small>'
);

Expand All @@ -68,29 +69,32 @@ define([
}.bind(this));
}.bind(this),
displayKey: function(data) {
return data.metadata.legacy_ICN;
return data.legacy_ICN;
},
templates: {
empty: function(data) {
return 'Cannot find this affiliation in our database.';
},
suggestion: function(data) {
function _getICN() {
if (!data.metadata.ICN) {
if (!data.ICN) {
return;
}
for (let i=0; i<data.metadata.ICN.length; i++) {
if (data.metadata.ICN[i] !== data.metadata.legacy_ICN) {
return data.metadata.ICN[i];
for (let i=0; i<data.ICN.length; i++) {
if (data.ICN[i] !== data.legacy_ICN) {
return data.ICN[i];
}
}
}
let ICN = _getICN();
if (ICN) {
data.metadata.show_future_name = true;
data.metadata.future_name = ICN;
data.show_future_name = true;
data.future_name = ICN;
}
return suggestionTemplate.render.call(suggestionTemplate, data.metadata);
if (data.institution_names && data.institution_names.length > 0) {
data.institution_name = data.institution_names[0];
}
return suggestionTemplate.render.call(suggestionTemplate, data);
}.bind(this)
}
});
Expand Down
23 changes: 5 additions & 18 deletions inspirehep/modules/forms/static/js/forms/authors_typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ define([
this.dataEngine = new Bloodhound({
name: 'authors',
remote: {
url: '/api/authors?q=authorautocomplete:%QUERY*',
url: '/api/authors/_suggest?author=%QUERY',
filter: function(response) {
return $.map(response.hits.hits, function(el) { return el });
return response.author[0].options;
}
},
datumTokenizer: function() {},
Expand All @@ -44,10 +44,7 @@ define([
this.$element = $element;

var suggestionTemplate = Hogan.compile(
'<strong>{{ name.value }}</strong><br>' +
'<small>' +
'{{#affiliation}}{{ affiliation }}<br>{{/affiliation}}' +
'</small>'
'<strong>{{#text}} {{ text }} {{/text}}</strong>'
);

this.$element.typeahead({
Expand All @@ -65,24 +62,14 @@ define([
}.bind(this));
}.bind(this),
displayKey: function(data) {
return data.metadata.name.value;
return data.text;
},
templates: {
empty: function(data) {
return 'Cannot find this author in our database.';
},
suggestion: function(data) {
data.metadata.affiliation = null;
if (data.metadata.positions) {
var currentPosition = $.map(data.metadata.positions, function(item, idx) {
if ('status' in item && 'institution' in item) {
if (item.status.toLowerCase() === "current") {
data.metadata.affiliation = item.institution.name;
}
}
});
}
return suggestionTemplate.render.call(suggestionTemplate, data.metadata);
return suggestionTemplate.render.call(suggestionTemplate, data);
}.bind(this)
}
});
Expand Down
92 changes: 54 additions & 38 deletions inspirehep/modules/forms/static/js/forms/conferences_typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,68 @@
*/

define([
'js/forms/extended_typeahead'
], function(ExtendedTypeahead) {
'jquery',
'js/jquery_plugin',
], function($, jQueryPlugin) {

function conferencesTypeahead($element) {
$element.extendedTypeahead({
suggestionTemplate: Hogan.compile(
'<b>{{ title }}</b><br>' +
function ConferencesTypeahead($element) {
this.dataEngine = new Bloodhound({
name: 'conferences',
remote: {
url: '/api/conferences/_suggest?conference=%QUERY',
filter: function(response) {
return response.conference[0].options;
}
},
datumTokenizer: function() {},
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 100,
});

this.dataEngine.initialize();
this.$element = $element;

var suggestionTemplate = Hogan.compile(
'<strong>{{#text}} {{ text }} {{/text}}</strong><br>' +
'<small>' +
'{{ opening_date }}, {{ city }}, {{ country }}<br>' +
'{{ cnum }}' +
'{{#payload.opening_date}} {{ payload.opening_date }}, {{/payload.opening_date}}' +
'{{#payload.city}} {{ payload.city }}, {{/payload.city}} ' +
'{{#payload.country}} {{ payload.country }} {{/payload.country}}<br>' +
'{{#payload.cnum}} {{ payload.cnum }} {{/payload.cnum}}<br>' +
'</small>'
),
selectedValueTemplate: Hogan.compile(
'{{ title }}, {{ opening_date }}, {{ city }}, {{ country }}'
),
cannotFindMessage: 'Cannot find this conference in our database.',
extractRawValue: function(data) {
return data.cnum;
},
displayKey: null,
displayfn: function(obj) {
return obj;
);

this.$element.typeahead({
minLength: 3
}, {
// after typeahead upgrade to 0.11 can be substituted with:
// source: this.engine.ttAdapter(),
// https://github.com/twitter/typeahead.js/issues/166
source: function(query, callback) {
// trigger can be deleted after typeahead upgrade to 0.11
this.$element.trigger('typeahead:asyncrequest');
this.dataEngine.get(query, function(suggestions) {
this.$element.trigger('typeahead:asyncreceive');
callback(suggestions);
}.bind(this));
}.bind(this),
displayKey: function(data) {
return data.text;
},
dataEngine: new Bloodhound({
name: 'conferences',
remote: {
url: '/api/conferences?q=conferenceautocomplete:%QUERY*',
filter: function(response) {
return $.map(response.hits.hits, function(el) {
el.metadata.city = el.metadata.address[0].cities[0];
el.metadata.country = el.metadata.address[0].country_code;
el.metadata.title = el.metadata.titles[0].title;
return el.metadata
}).sort(function(x, y) {
return new Date(y.opening_date) - new Date(x.opening_date);
});
}
templates: {
empty: function(data) {
return 'Cannot find this conference in our database.';
},
datumTokenizer: function() {},
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 100,
})
suggestion: function(data) {
return suggestionTemplate.render.call(suggestionTemplate, data);
}.bind(this)
}
});

return $element;
}

return conferencesTypeahead;
$.fn.conferencesTypeahead = jQueryPlugin(ConferencesTypeahead, 'conference-typeahead');

return ConferencesTypeahead;
});
Loading