Change code to satisfy new ESLint checks

Change-Id: I36926039fff61328626682f37eb229f58e27c928
This commit is contained in:
Vlad Okhrimenko 2015-07-07 15:43:11 +03:00 committed by Timur Sufiev
parent 6062444015
commit ac6336b5e2
8 changed files with 794 additions and 731 deletions

View File

@ -3,24 +3,56 @@
*/ */
(function() { (function() {
'use strict'; 'use strict';
angular
angular.module('merlin') .module('merlin')
/* /*
* Allows to edit field name in-place. * Allows to edit field name in-place.
* For example, you have a field named 'Input 1' and you want to replace this name with "Base input" value. * For example, you have a field named 'Input 1' and you want to replace this name with
* "Base input" value.
* If you add editable directive to such field, you will get a marker icon near this field, * If you add editable directive to such field, you will get a marker icon near this field,
* and with clicking on this icon you can type new name and save or discard changes. * and with clicking on this icon you can type new name and save or discard changes.
* */ * */
.directive('editable', function() { .directive('editable', editable)
/*
* this directive auto-sets the focus to an input field once it is shown.
* */
.directive('showFocus', showFocus)
/*
* tells Merlin to render this element as a panel.
* */
.directive('panel', panel)
/*
* tells Merlin to render this element as a group with ability to collapse.
* */
.directive('collapsibleGroup', collapsibleGroup)
/*
* sets up the DOM nodes related to validation of model being edited in this widget
* (and specifies the name of this model on scope).
* */
.directive('validatableWith', validatableWith)
/*
* retrieves a template by its name which is the same as model's type and renders it,
* recursive <typed-field></..>-s are possible.
* */
.directive('typedField', typedField);
typedField.$inject = ['$compile', 'merlin.templates'];
function editable() {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '/static/merlin/templates/editable.html', templateUrl: '/static/merlin/templates/editable.html',
require: 'ngModel', require: 'ngModel',
scope: true, scope: true,
link: function(scope, element, attrs, ngModelCtrl) { link: function(scope, element, attrs, ngModelCtrl) {
var hiddenSpan = element.find('span.width-detector'), var hiddenSpan = element.find('span.width-detector');
input = element.find('input'), var input = element.find('input');
maxWidth = 400; var maxWidth = 400;
function adjustWidth() { function adjustWidth() {
var width; var width;
@ -40,7 +72,10 @@
} }
scope.isEdited = false; scope.isEdited = false;
scope.$watch('editableValue', function() {
// Unused variable created here due to rule 'ng_on_watch': 2
// (see https://github.com/Gillespie59/eslint-plugin-angular)
var editableValueWatcher = scope.$watch('editableValue', function() {
adjustWidth(); adjustWidth();
}); });
input.on('keyup', function(e) { input.on('keyup', function(e) {
@ -63,23 +98,23 @@
scope.reject = reject; scope.reject = reject;
} }
}; };
})
/*
* this directive auto-sets the focus to an input field once it is shown.
* */
.directive('showFocus', function($timeout) {
return function(scope, element, attrs) {
scope.$watch(attrs.showFocus, function(newValue) {
$timeout(function() {
newValue && element.focus();
});
});
} }
})
/* function showFocus($timeout) {
* tells Merlin to render this element as a panel. return function(scope, element, attrs) {
* */ // Unused variable created here due to rule 'ng_on_watch': 2
.directive('panel', function($parse) { // (see https://github.com/Gillespie59/eslint-plugin-angular)
var showFocusWatcher = scope.$watch(attrs.showFocus, function(newValue) {
$timeout(function() {
if (newValue) {
element.focus();
}
});
});
};
}
function panel($parse) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '/static/merlin/templates/collapsible-panel.html', templateUrl: '/static/merlin/templates/collapsible-panel.html',
@ -91,12 +126,10 @@
scope.removable = $parse(attrs.removable)(); scope.removable = $parse(attrs.removable)();
scope.isCollapsed = false; scope.isCollapsed = false;
} }
};
} }
})
/* function collapsibleGroup() {
* tells Merlin to render this element as a group with ability to collapse.
* */
.directive('collapsibleGroup', function() {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '/static/merlin/templates/collapsible-group.html', templateUrl: '/static/merlin/templates/collapsible-group.html',
@ -115,12 +148,10 @@
scope.removable = true; scope.removable = true;
} }
} }
};
} }
})
/* function validatableWith($parse) {
* sets up the DOM nodes related to validation of model being edited in this widget (and specifies the name of this model on scope).
* */
.directive('validatableWith', function($parse) {
return { return {
restrict: 'A', restrict: 'A',
require: 'ngModel', require: 'ngModel',
@ -129,32 +160,33 @@
if ( attrs.validatableWith ) { if ( attrs.validatableWith ) {
model = $parse(attrs.validatableWith)(scope); model = $parse(attrs.validatableWith)(scope);
scope.error = ''; scope.error = '';
model.setValidatable && model.setValidatable(true); if (model.setValidatable) {
model.on && model.on('validation', function(result) { model.setValidatable(true);
var isValid = (result == 'succeeded'), }
baseMessage = ''; if (model.on) {
model.on('validation', function(result) {
var isValid = (result == 'succeeded');
var baseMessage = '';
// (FIXME): hack until Barricade supports validation of empty required entries // (FIXME): hack until Barricade supports validation of empty required entries
if ( !model.get() && model.isRequired() ) { if ( !model.get() && model.isRequired() ) {
isValid = false; isValid = false;
baseMessage = 'This field is required.' baseMessage = 'This field is required.';
} }
ctrl.$setValidity('barricade', isValid); ctrl.$setValidity('barricade', isValid);
scope.error = model.hasError() ? model.getError() : baseMessage; scope.error = model.hasError() ? model.getError() : baseMessage;
}); });
}
ctrl.$formatters.push(function(modelValue) { ctrl.$formatters.push(function(modelValue) {
return modelValue === undefined ? return angular.isUndefined(modelValue) ?
( ctrl.$isEmpty(ctrl.$viewValue) ? undefined : ctrl.$viewValue ) : ( ctrl.$isEmpty(ctrl.$viewValue) ? undefined : ctrl.$viewValue ) :
modelValue; modelValue;
}); });
} }
} }
};
} }
})
/* function typedField($compile, templates) {
* retrieves a template by its name which is the same as model's type and renders it, recursive <typed-field></..>-s are possible.
* */
.directive('typedField', ['$compile', 'merlin.templates',
function($compile, templates) {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
@ -164,9 +196,8 @@
link: function(scope, element) { link: function(scope, element) {
templates.templateReady(scope.type).then(function(template) { templates.templateReady(scope.type).then(function(template) {
element.replaceWith($compile(template)(scope)); element.replaceWith($compile(template)(scope));
}) });
} }
};
} }
}])
})(); })();

View File

@ -2,38 +2,43 @@
(function() { (function() {
'use strict'; 'use strict';
angular.module('merlin') angular
.factory('merlin.field.models', .module('merlin')
['merlin.utils', 'merlin.panel.models', '$http', function(utils, panels, $http) { .factory('merlin.field.models', merlinFieldModels);
merlinFieldModels.$inject = ['merlin.utils', 'merlin.panel.models', '$http'];
function merlinFieldModels(utils, panels, $http) {
var wildcardMixin = Barricade.Blueprint.create(function() { var wildcardMixin = Barricade.Blueprint.create(function() {
return this; return this;
}); });
var viewChoicesMixin = Barricade.Blueprint.create(function() { var viewChoicesMixin = Barricade.Blueprint.create(function() {
var self = this, var self = this;
dropDownLimit = this._dropDownLimit || 5, var dropDownLimit = this._dropDownLimit || 5;
values, labels, items, isDropDown; var values, labels, items, isDropDown;
function fillItems() { function fillItems() {
values = self.getEnumValues(); values = self.getEnumValues();
labels = self.getEnumLabels(); labels = self.getEnumLabels();
items = {}; items = {};
values && values.forEach(function (value, index) { if (values) {
values.forEach(function (value, index) {
items[value] = labels[index]; items[value] = labels[index];
}); });
} }
}
this.getLabel = function(value) { this.getLabel = function(value) {
if ( values === undefined ) { if ( angular.isUndefined(values) ) {
fillItems(); fillItems();
} }
return items[value]; return items[value];
}; };
this.getValues = function() { this.getValues = function() {
if ( values === undefined ) { if ( angular.isUndefined(values) ) {
fillItems(); fillItems();
} }
return values; return values;
@ -57,8 +62,8 @@
}); });
var modelMixin = Barricade.Blueprint.create(function(type) { var modelMixin = Barricade.Blueprint.create(function(type) {
var isValid = true, var isValid = true;
isValidatable = false; var isValidatable = false;
this.value = function() { this.value = function() {
if ( !arguments.length ) { if ( !arguments.length ) {
if ( isValidatable ) { if ( isValidatable ) {
@ -168,7 +173,7 @@
self._getContents = function() { self._getContents = function() {
return self.getKeys().map(function(key) { return self.getKeys().map(function(key) {
return self.get(key); return self.get(key);
}) });
}; };
meldGroup.call(self); meldGroup.call(self);
return self; return self;
@ -177,11 +182,11 @@
var dictionaryModel = Barricade.MutableObject.extend({ var dictionaryModel = Barricade.MutableObject.extend({
create: function(json, parameters) { create: function(json, parameters) {
var self = Barricade.MutableObject.create.call(this, json, parameters), var self = Barricade.MutableObject.create.call(this, json, parameters);
_items = [], var _items = [];
_elClass = self._elementClass, var _elClass = self._elementClass;
baseKey = utils.getMeta(_elClass, 'baseKey') || 'key', var baseKey = utils.getMeta(_elClass, 'baseKey') || 'key';
baseName = utils.getMeta(_elClass, 'baseName') || utils.makeTitle(baseKey); var baseName = utils.getMeta(_elClass, 'baseName') || utils.makeTitle(baseKey);
modelMixin.call(self, 'dictionary'); modelMixin.call(self, 'dictionary');
@ -198,8 +203,8 @@
} }
self.add = function(newID) { self.add = function(newID) {
var regexp = new RegExp('(' + baseKey + ')([0-9]+)'), var regexp = new RegExp('(' + baseKey + ')([0-9]+)');
newValue; var newValue;
newID = newID || baseKey + utils.getNextIDSuffix(self, regexp); newID = newID || baseKey + utils.getNextIDSuffix(self, regexp);
if ( _elClass.instanceof(Barricade.ImmutableObject) ) { if ( _elClass.instanceof(Barricade.ImmutableObject) ) {
if ( 'name' in _elClass._schema ) { if ( 'name' in _elClass._schema ) {
@ -251,8 +256,8 @@
var linkedCollectionModel = stringModel.extend({ var linkedCollectionModel = stringModel.extend({
create: function(json, parameters) { create: function(json, parameters) {
var self = stringModel.create.call(this, json, parameters), var self = stringModel.create.call(this, json, parameters);
collectionCls = Barricade.create({ var collectionCls = Barricade.create({
'@type': String, '@type': String,
'@ref': { '@ref': {
to: function() { to: function() {
@ -300,6 +305,5 @@
frozendict: frozendictModel, frozendict: frozendictModel,
wildcard: wildcardMixin // use for most general type-checks wildcard: wildcardMixin // use for most general type-checks
}; };
}]) }
})(); })();

View File

@ -14,9 +14,17 @@
under the License. under the License.
*/ */
(function() { (function() {
angular.module('merlin') angular
.module('merlin')
.filter('extractPanels', extractPanels)
.filter('extractRows', extractRows)
.filter('extractItems', extractItems);
.filter('extractPanels', ['merlin.utils', function(utils) { extractPanels.$inject = ['merlin.utils'];
extractRows.$inject = ['merlin.utils'];
extractItems.$inject = ['merlin.utils'];
function extractPanels(utils) {
var panelProto = { var panelProto = {
create: function(itemsOrContainer, id) { create: function(itemsOrContainer, id) {
if ( angular.isArray(itemsOrContainer) && !itemsOrContainer.length ) { if ( angular.isArray(itemsOrContainer) && !itemsOrContainer.length ) {
@ -52,8 +60,8 @@
} }
}, },
remove: function() { remove: function() {
var container = this._barricadeContainer, var container = this._barricadeContainer;
pos = container.getPosByID(this._barricadeId); var pos = container.getPosByID(this._barricadeId);
container.remove(pos); container.remove(pos);
} }
}; };
@ -73,8 +81,8 @@
} }
return _.memoize(function(container) { return _.memoize(function(container) {
var items = container._getContents(), var items = container._getContents();
panels = []; var panels = [];
utils.groupByMetaKey(items, 'panelIndex').forEach(function(items) { utils.groupByMetaKey(items, 'panelIndex').forEach(function(items) {
var panelsRoot = extractPanelsRoot(items); var panelsRoot = extractPanelsRoot(items);
if ( panelsRoot ) { if ( panelsRoot ) {
@ -85,7 +93,7 @@
panels.push(Object.create(panelProto).create(items)); panels.push(Object.create(panelProto).create(items));
} }
}); });
return panels.condense(); return utils.condense(panels);
}, function(container) { }, function(container) {
var hash = ''; var hash = '';
container.getKeys().map(function(key) { container.getKeys().map(function(key) {
@ -100,9 +108,9 @@
}); });
return hash; return hash;
}); });
}]) }
.filter('extractRows', ['merlin.utils', function(utils) { function extractRows(utils) {
function getItems(panelOrContainer) { function getItems(panelOrContainer) {
if ( panelOrContainer.items ) { if ( panelOrContainer.items ) {
return panelOrContainer.items; return panelOrContainer.items;
@ -136,10 +144,10 @@
hash += item.uid(); hash += item.uid();
}); });
return hash; return hash;
}) });
}]) }
.filter('extractItems', ['merlin.utils', function(utils) { function extractItems(utils) {
return _.memoize(function(row) { return _.memoize(function(row) {
return row.items.sort(function(item1, item2) { return row.items.sort(function(item1, item2) {
return utils.getMeta(item1, 'index') - utils.getMeta(item2, 'index'); return utils.getMeta(item1, 'index') - utils.getMeta(item2, 'index');
@ -150,7 +158,6 @@
hash += item.uid(); hash += item.uid();
}); });
return hash; return hash;
}) });
}]) }
})(); })();

View File

@ -4,20 +4,33 @@
(function() { (function() {
'use strict'; 'use strict';
angular.module('merlin', ['ui.bootstrap']) angular
.config(function($interpolateProvider) { .module('merlin', ['ui.bootstrap'])
.config(interpolateProvider)
// move these 2 values out of run section to change them in unit-tests
.value('fieldTemplatesUrl', '/static/merlin/templates/fields/')
// The false posititive on array constant here we're working around is caused
// by https://github.com/Gillespie59/eslint-plugin-angular/issues/99
.value('fieldTemplates', fieldTemplates())
.run(runTemplates);
runTemplates.$inject = ['merlin.templates', 'fieldTemplatesUrl', 'fieldTemplates'];
function fieldTemplates() {
return [
'dictionary', 'frozendict', 'list',
'string', 'text', 'group', 'number', 'choices'
];
}
function runTemplates(templates, rootUrl, fieldList) {
templates.prefetch(rootUrl, fieldList);
}
function interpolateProvider($interpolateProvider) {
// Replacing the default angular symbol // Replacing the default angular symbol
// allow us to mix angular with django templates // allow us to mix angular with django templates
$interpolateProvider.startSymbol('{$'); $interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}'); $interpolateProvider.endSymbol('$}');
}) }
// move these 2 values out of run section to change them in unit-tests
.value('fieldTemplatesUrl', '/static/merlin/templates/fields/')
.value('fieldTemplates', ['dictionary', 'frozendict', 'list',
'string', 'text', 'group', 'number', 'choices'])
.run(['merlin.templates', 'fieldTemplatesUrl', 'fieldTemplates',
function(templates, rootUrl, fieldList) {
templates.prefetch(rootUrl, fieldList);
}])
})(); })();

View File

@ -4,22 +4,26 @@
(function() { (function() {
'use strict'; 'use strict';
angular.module('merlin') angular
.factory('merlin.panel.models', ['merlin.utils', function(utils) { .module('merlin')
.factory('merlin.panel.models', merlinPanelModels);
merlinPanelModels.$inject = ['merlin.utils'];
function merlinPanelModels(utils) {
var groupMixin = Barricade.Blueprint.create(function() { var groupMixin = Barricade.Blueprint.create(function() {
var self = this, var self = this;
additive = utils.getMeta(self, 'additive'), var additive = utils.getMeta(self, 'additive');
removable = utils.getMeta(self, 'removable'); var removable = utils.getMeta(self, 'removable');
if ( additive === undefined ) { if ( angular.isUndefined(additive) ) {
additive = true; additive = true;
} }
self.isAdditive = function() { self.isAdditive = function() {
return additive; return additive;
}; };
if ( removable === undefined ) { if ( angular.isUndefined(removable) ) {
removable = false; removable = false;
} }
self.isRemovable = function() { self.isRemovable = function() {
@ -33,7 +37,7 @@
} else { } else {
return self.getID(); return self.getID();
} }
} };
} }
self.setType('group'); self.setType('group');
@ -43,7 +47,6 @@
return { return {
groupmixin: groupMixin groupmixin: groupMixin
};
} }
}])
})(); })();

View File

@ -1,7 +1,11 @@
(function() { (function() {
angular.module('merlin') angular
.factory('merlin.templates', [ .module('merlin')
'$http', '$q', function($http, $q) { .factory('merlin.templates', merlinTemplates);
merlinTemplates.$inject = ['$http', '$q'];
function merlinTemplates($http, $q) {
var promises = {}; var promises = {};
function makeEmptyPromise() { function makeEmptyPromise() {
@ -33,5 +37,5 @@
prefetch: prefetch, prefetch: prefetch,
templateReady: templateReady templateReady: templateReady
}; };
}]) }
})(); })();

View File

@ -1,30 +1,35 @@
/** /**
* Created by tsufiev on 2/24/15. * Created by tsufiev on 2/24/15.
*/ */
(function() { (function() {
'use strict'; 'use strict';
angular.module('merlin') angular
.factory('merlin.utils', function() { .module('merlin')
Array.prototype.condense = function() { .factory('merlin.utils', merlinUtils);
return this.filter(function(el) {
return el !== undefined && el != null;
});
};
var _id_counter = 0; function merlinUtils() {
function condense(array) {
return array.filter(function(el) {
return angular.isDefined(el) && el !== null;
});
}
var idCounter = 0;
function getNewId() { function getNewId() {
_id_counter++; idCounter++;
return 'id-' + _id_counter; return 'id-' + idCounter;
} }
function groupByMetaKey(sequence, metaKey, insertAtBeginning) { function groupByMetaKey(sequence, metaKey, insertAtBeginning) {
var newSequence = [], defaultBucket = [], var newSequence = [];
index; var defaultBucket = [];
var index;
sequence.forEach(function(item) { sequence.forEach(function(item) {
index = getMeta(item, metaKey); index = getMeta(item, metaKey);
if ( index !== undefined ) { if ( angular.isDefined(index) ) {
if ( !newSequence[index] ) { if ( !newSequence[index] ) {
newSequence[index] = []; newSequence[index] = [];
newSequence[index][metaKey] = index; newSequence[index][metaKey] = index;
@ -34,7 +39,7 @@
defaultBucket.push(item); defaultBucket.push(item);
} }
}); });
newSequence = newSequence.condense(); newSequence = condense(newSequence);
// insert default bucket at the beginning/end of sequence // insert default bucket at the beginning/end of sequence
if ( defaultBucket.length ) { if ( defaultBucket.length ) {
if ( insertAtBeginning ) { if ( insertAtBeginning ) {
@ -86,7 +91,7 @@
function extend(proto, extension) { function extend(proto, extension) {
var newObj; var newObj;
proto = (proto !== undefined ? proto : null); proto = (angular.isDefined(proto) ? proto : null);
newObj = Object.create(proto); newObj = Object.create(proto);
Object.keys(extension).forEach(function(key) { Object.keys(extension).forEach(function(key) {
newObj[key] = extension[key]; newObj[key] = extension[key];
@ -102,8 +107,9 @@
getNextIDSuffix: getNextIDSuffix, getNextIDSuffix: getNextIDSuffix,
enhanceItemWithID: enhanceItemWithID, enhanceItemWithID: enhanceItemWithID,
extend: extend, extend: extend,
pop: pop pop: pop,
condense: condense
};
} }
})
})(); })();

View File

@ -16,15 +16,10 @@ describe('merlin.utils', function() {
}); });
}); });
describe('condense Array method', function() { describe('condense function', function() {
it('Array prototype should have condense()', function() {
var array = [];
expect(array.condense).toBeDefined();
});
it('condense() should throw away undefined and null values', function() { it('condense() should throw away undefined and null values', function() {
var array = [1, 0, 15, undefined, 7, null, null, 8]; var array = [1, 0, 15, undefined, 7, null, null, 8];
expect(array.condense()).toEqual([1, 0, 15, 7, 8]); expect(utils.condense(array)).toEqual([1, 0, 15, 7, 8]);
}); });
}); });