Skip to content

Instantly share code, notes, and snippets.

@hallvors
Last active October 21, 2015 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hallvors/9cdf228aeb72598b78eb to your computer and use it in GitHub Desktop.
Save hallvors/9cdf228aeb72598b78eb to your computer and use it in GitHub Desktop.
A label list implementation for webcompat.com
/**
* A LabelList is a list of labels. It takes care of all namespace
* prefixing and unprefixing, so that the rest of the app doesn't
* ever need to worry about those details. Just pass in a list
* of labels from the server or a URL.
*/
issues.LabelList = Backbone.Model.extend({
initialize: function() {
this.set('namespaceRegex', /(browser|closed|os|status)-(.+)/i);
this.set('allLabelsURL', '/api/issues/labels'); // see "need a complete list" below
// if we're initialized with {labels:array-of-objects}
var inputLabelData = this.get('labels');
this.set('labels', []);
if(inputLabelData) {
// If we have an array, process labels
this.parse(inputLabelData);
} else {
// We default to making a list of all labels if lacking other data
if(! this.get('url')) {
this.set('url', this.get('allLabelsURL'));
}
// If we have an URL, start a fetch
var headersBag = {headers: {'Accept': 'application/json'}};
this.fetch(headersBag); // This will trigger parse()
}
// We allow updating 'labels', but want to make sure
// other internal details are kept sync'ed..
this.on('change:labels', function(){
this.set('labelsArray', _.pluck(this.get('labels'), 'name'));
});
// We need a complete list of labels for certain operations,
// especially namespace mapping. If the list we're handling
// doesn't happen to contain all the labels initially, it
// can't get prefixing/unprefixing right when labels in previously
// unseen namespaces are added in their local name form.
if(this.get('url') === this.get('allLabelsURL')) {
this.set('allLabels', this);
} else {
this.set('allLabels', new issues.LabelList({url:this.get('allLabelsURL')}));
}
},
parse: function(labelsArray){
var list = [];
var namespaceMap = {"ns2local":{}, "local2ns":{}};
for(var i = 0, matches; i < labelsArray.length; i++){
matches = labelsArray[i].name.match(this.get('namespaceRegex'));
if(matches) {
namespaceMap.local2ns[matches[2]] = matches[1];
namespaceMap.ns2local[matches[0]] = matches[2];
list[i] = {
'name': matches[2],
'url': labelsArray[i].url,
'color': labelsArray[i].color,
};
}else {
list[i] = labelsArray[i];
}
};
this.set('labels', list);
this.set('namespaceMap', namespaceMap);
},
// toLocal takes a repository label name and maps it
// to the unprefixed local form. Also handles an array
// of label names (Note: not arrays of objects)
toLocal: function(input) {
var all = this.get('allLabels');
if (typeof input === 'string') {
return all.get('namespaceMap').ns2local[input] || input;
} else {
return input.map(function(label){return this.toLocal(label);}.bind(all));
}
},
// toNamespaced takes a local label name and maps it
// to the prefixed repository form. Also handles an array
// of label names (Note: not arrays of objects)
toNamespaced: function (input) {
var all = this.get('allLabels');
if (typeof input === 'string') {
return all.get('namespaceMap').local2ns[input] + '-' + input || input;
} else {
return input.map(function(label){return this.toNamespaced(label);}.bind(all));
}
},
url: function() {
return this.get('url');
},
// To save the model to the server, we need to make
// sure we apply the prefixes the server expects
save: function() {
var all = this.get('allLabels');
var labelsArray = this.get('labelsArray');
var saveLabels = all.toNamespaced(labelsArray);
var url = this.url();
// We create a new model with only the labels we
// want to send to the server to save
var saver = new (Backbone.Model.extend({
url:function(){return url;}
}))({labels:saveLabels});
saver.save();
}
});
@hallvors
Copy link
Author

toLocal() is perhaps not necessary. The parsing method doesn't use it and has no reason to. If not we can drop the ns2local object too.

@hallvors
Copy link
Author

toNamespaced might be better named "toPrefixed" and toLocal -> toUnprefixed ?
("Local name" and "namespace" terminology is XMLish)

toNamespaced() (by any name) should never apply a namespace to a label that has namespace prefix already - simply because there would be no match in the local2ns object. But this should be tested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment