Skip to content

Commit

Permalink
Standardize formatting of annotation views
Browse files Browse the repository at this point in the history
Issues #1654
  • Loading branch information
robyngit committed Jan 24, 2024
1 parent ac0047f commit b156a78
Show file tree
Hide file tree
Showing 2 changed files with 755 additions and 699 deletions.
284 changes: 144 additions & 140 deletions src/js/views/filters/SemanticFilterView.js
Original file line number Diff line number Diff line change
@@ -1,143 +1,147 @@
/*global define */
define(['jquery',
'underscore',
'backbone',
'models/filters/Filter',
'views/filters/FilterView',
'views/searchSelect/AnnotationFilterView'],
function ($, _, Backbone, Filter, FilterView, AnnotationFilterView) {
'use strict';

/**
* @class SemanticFilterView
* @classdesc Render a specialized view of a single Filter model using the
* AnnotationFilterView.
* @classcategory Views/Filters
* @extends FilterView
* @screenshot views/filters/SemanticFilterView.png
* @since 2.22.0
*/
var SemanticFilterView = FilterView.extend(
/** @lends SemanticFilterView.prototype */{

/**
* @inheritdoc
*/
model: null,

/**
* @inheritdoc
*/
modelClass: Filter,

className: "filter semantic",

// Template is an empty function because this view delegates to the
// AnnotationFilterView. See render() method.
template: function () { },

/**
* Render an instance of a Semantic Filter View.
*
* Note that this View doesn't have a template and instead delegates to
* the AnnotationFilterView which renders a SearchableSelectView which
* renders an NCBOTree.
* @since 2.22.0
*/
render: function () {

try {
var templateVars = this.model.toJSON();
templateVars.id = this.model.cid;

// Renders the template and inserts the FilterEditorView if the mode is uiBuilder
FilterView.prototype.render.call(this, templateVars);

var viewOpts = {
"useSearchableSelect": true,
"placeholderText": templateVars.placeholder,
"inputLabel": null, // Hides label and uses FilterView label
"ontology": this.model.get("ontology"),
"startingRoot": this.model.get("startingRoot")
};

var subView = new AnnotationFilterView(viewOpts);

this.$el.append(subView.el);
subView.render();

var view = this;
subView.on("annotationSelected", function (event, item) {
// Get the value of the associated input
var term = (!item || !item.value) ? input.val() : item.value;
var label = (!item || !item.filterLabel) ? null : item.filterLabel;

// Set up a label mapping for the term so we can display a
// human-readable label for it in the UI
view.setLabelMapping(term, label);

// Set the value, supports multiple values
var currentValue = view.model.get("values");
var newValuesArray = _.flatten(new Array(currentValue, term));
view.model.set("values", newValuesArray);

view.defocus()
});
}
catch (error) {
console.log('There was an error rendering a SemanticFilterView.' +
' Error details: ' + error);
}
},

/**
* Helper function which defocuses the dropdown portion of the
* SearchableSelectView used by this View's AnnotationFilterView. When the
* user clicks an item in the NCBOTree widget, we want the
* SearchableSelectView's dropdown to go away and I couldn't find any API
* to do that so we have this code. See the render() method to see how it's
* called.
*
* Note: This isn't really a stable API and is really something we might
* remove in the future if we refactor the NCBOTree widget.
* @since 2.22.0
*/
defocus: function () {
this.$el.find("div.menu").removeClass("visible").addClass("hidden")
this.$el.find("div.fluid.ui.dropdown").removeClass("active").removeClass("visible")
this.$el.find("input").blur()
},

/**
* Set the human-readable label for a term URI.
*
* For most uses of the Filter model, the value(s) set on the model can
* be shown directly in the UI. But for Semantic searches, we need to
* be able to display a human-readable label for the value because the
* value is likely an opaque URI.
*
* Rather than fetch and/or store all the possible labels for all
* possible URIs, we store a label for whichever terms the user chooses
* and keep that around until we need it in the UI.
*
* @param {string} term The term URI to set a label for
* @param {string} label The label to set
* @since 2.22.0
*/
setLabelMapping: function (term, label) {
var newMappings;

if (this.model.get("valueLabels")) {
newMappings = _.clone(this.model.get("valueLabels"));
}
else {
newMappings = new Object();
}

newMappings[term] = label;
this.model.set("valueLabels", newMappings);
define([
"jquery",
"underscore",
"backbone",
"models/filters/Filter",
"views/filters/FilterView",
"views/searchSelect/AnnotationFilterView",
], function ($, _, Backbone, Filter, FilterView, AnnotationFilterView) {
"use strict";

/**
* @class SemanticFilterView
* @classdesc Render a specialized view of a single Filter model using the
* AnnotationFilterView.
* @classcategory Views/Filters
* @extends FilterView
* @screenshot views/filters/SemanticFilterView.png
* @since 2.22.0
*/
var SemanticFilterView = FilterView.extend(
/** @lends SemanticFilterView.prototype */ {
/**
* @inheritdoc
*/
model: null,

/**
* @inheritdoc
*/
modelClass: Filter,

className: "filter semantic",

// Template is an empty function because this view delegates to the
// AnnotationFilterView. See render() method.
template: function () {},

/**
* Render an instance of a Semantic Filter View.
*
* Note that this View doesn't have a template and instead delegates to
* the AnnotationFilterView which renders a SearchableSelectView which
* renders an NCBOTree.
* @since 2.22.0
*/
render: function () {
try {
var templateVars = this.model.toJSON();
templateVars.id = this.model.cid;

// Renders the template and inserts the FilterEditorView if the mode is uiBuilder
FilterView.prototype.render.call(this, templateVars);

var viewOpts = {
useSearchableSelect: true,
placeholderText: templateVars.placeholder,
inputLabel: null, // Hides label and uses FilterView label
ontology: this.model.get("ontology"),
startingRoot: this.model.get("startingRoot"),
};

var subView = new AnnotationFilterView(viewOpts);

this.$el.append(subView.el);
subView.render();

var view = this;
subView.on("annotationSelected", function (event, item) {
// Get the value of the associated input
var term = !item || !item.value ? input.val() : item.value;
var label = !item || !item.filterLabel ? null : item.filterLabel;

// Set up a label mapping for the term so we can display a
// human-readable label for it in the UI
view.setLabelMapping(term, label);

// Set the value, supports multiple values
var currentValue = view.model.get("values");
var newValuesArray = _.flatten(new Array(currentValue, term));
view.model.set("values", newValuesArray);

view.defocus();
});
} catch (error) {
console.log(
"There was an error rendering a SemanticFilterView." +
" Error details: " +
error
);
}
});
},

/**
* Helper function which defocuses the dropdown portion of the
* SearchableSelectView used by this View's AnnotationFilterView. When the
* user clicks an item in the NCBOTree widget, we want the
* SearchableSelectView's dropdown to go away and I couldn't find any API
* to do that so we have this code. See the render() method to see how it's
* called.
*
* Note: This isn't really a stable API and is really something we might
* remove in the future if we refactor the NCBOTree widget.
* @since 2.22.0
*/
defocus: function () {
this.$el.find("div.menu").removeClass("visible").addClass("hidden");
this.$el
.find("div.fluid.ui.dropdown")
.removeClass("active")
.removeClass("visible");
this.$el.find("input").blur();
},

/**
* Set the human-readable label for a term URI.
*
* For most uses of the Filter model, the value(s) set on the model can
* be shown directly in the UI. But for Semantic searches, we need to
* be able to display a human-readable label for the value because the
* value is likely an opaque URI.
*
* Rather than fetch and/or store all the possible labels for all
* possible URIs, we store a label for whichever terms the user chooses
* and keep that around until we need it in the UI.
*
* @param {string} term The term URI to set a label for
* @param {string} label The label to set
* @since 2.22.0
*/
setLabelMapping: function (term, label) {
var newMappings;

if (this.model.get("valueLabels")) {
newMappings = _.clone(this.model.get("valueLabels"));
} else {
newMappings = new Object();
}

newMappings[term] = label;
this.model.set("valueLabels", newMappings);
},
}
);

return SemanticFilterView;
});
return SemanticFilterView;
});
Loading

0 comments on commit b156a78

Please sign in to comment.