diff --git a/demo/scripts/directives.js b/demo/scripts/directives.js
index c7fe4cf..2c23c55 100644
--- a/demo/scripts/directives.js
+++ b/demo/scripts/directives.js
@@ -31,6 +31,7 @@ angular.module('my-app')
replace: true
};
})
- .run(function(featureFlags, $http) {
- featureFlags.set($http.get('../data/flags.json'));
+ .run(function($http, featureFlagConfig) {
+ featureFlagConfig.setAppName('myapp');
+ featureFlagConfig.setInitialFlags($http.get('../data/flags.json'));
});
diff --git a/dist/featureFlags.js b/dist/featureFlags.js
index a9b479a..bb1f173 100644
--- a/dist/featureFlags.js
+++ b/dist/featureFlags.js
@@ -76,10 +76,8 @@ angular.module('feature-flags').directive('featureFlagOverrides', ['featureFlags
};
}]);
-angular.module('feature-flags').service('featureFlagOverrides', ['$rootElement', function($rootElement) {
- var appName = $rootElement.attr('ng-app'),
- keyPrefix = 'featureFlags.' + appName + '.',
-
+angular.module('feature-flags').service('featureFlagOverrides', ['$rootElement', 'featureFlagConfig', function($rootElement, featureFlagConfig) {
+ var keyPrefix = 'featureFlags.',
localStorageAvailable = (function() {
try {
localStorage.setItem('featureFlags.availableTest', 'test');
@@ -116,6 +114,9 @@ angular.module('feature-flags').service('featureFlagOverrides', ['$rootElement',
}
};
+ if (featureFlagConfig.getAppName().length > 0) {
+ keyPrefix += featureFlagConfig.getAppName() + '.';
+ }
return {
isPresent: function(key) {
var value = get(key);
@@ -143,7 +144,7 @@ angular.module('feature-flags').service('featureFlagOverrides', ['$rootElement',
};
}]);
-function FeatureFlags($q, featureFlagOverrides, initialFlags) {
+angular.module('feature-flags').service('featureFlags', ['$q', 'featureFlagOverrides', 'featureFlagConfig', function($q, featureFlagOverrides, featureFlagConfig) {
var serverFlagCache = {},
flags = [],
@@ -205,8 +206,9 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) {
},
init = function() {
- if (initialFlags) {
- set(initialFlags);
+ var iniFlags = featureFlagConfig.getInitialFlags();
+ if (iniFlags) {
+ set(iniFlags);
}
};
init();
@@ -221,18 +223,56 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) {
isOnByDefault: isOnByDefault,
isOverridden: isOverridden
};
+}]);
+
+function FeatureFlagConfig(initialFlags, userAppName) {
+ var initFlags = [],
+ appName = '',
+
+ getInitialFlags = function() {
+ return initFlags;
+ },
+ setInitialFlags = function(value) {
+ initFlags = value;
+ },
+ getAppName = function() {
+ return appName;
+ },
+ setAppName = function(value) {
+ appName = value;
+ },
+ init = function() {
+ if (initialFlags) {
+ initFlags = initialFlags;
+ }
+ if (userAppName) {
+ appName = userAppName;
+ }
+ };
+ init();
+
+ return {
+ getInitialFlags: getInitialFlags,
+ setInitialFlags: setInitialFlags,
+ getAppName: getAppName,
+ setAppName: setAppName
+ };
}
-angular.module('feature-flags').provider('featureFlags', function() {
- var initialFlags = [];
+angular.module('feature-flags').provider('featureFlagConfig', function() {
+ var initialFlags = [],
+ appName = '';
this.setInitialFlags = function(flags) {
initialFlags = flags;
};
- this.$get = ['$q', 'featureFlagOverrides', function($q, featureFlagOverrides) {
- return new FeatureFlags($q, featureFlagOverrides, initialFlags);
- }];
+ this.setAppName = function(name) {
+ appName = name;
+ };
+ this.$get = function() {
+ return new FeatureFlagConfig(initialFlags, appName);
+ };
});
}());
\ No newline at end of file
diff --git a/dist/featureFlags.min.js b/dist/featureFlags.min.js
index 9b113d4..c25fdd5 100644
--- a/dist/featureFlags.min.js
+++ b/dist/featureFlags.min.js
@@ -1,2 +1,2 @@
/*! Angular Feature Flags v1.6.1 © 2017 Michael Taranto */
-!function(){function e(e,a,t){var r={},n=[],i=function(a){var t=e.defer();return t.resolve(a),t.promise},l=function(e){return a.isPresent(e)},f=function(e){return l(e)?"true"===a.get(e):r[e]},u=function(e){return r[e]},s=function(e){return e.forEach(function(e){r[e.key]=e.active,e.active=f(e.key)}),angular.copy(e,n),n},c=function(e){return e.then(function(e){return s(e.data||e)})},g=function(){return n},o=function(e){return angular.isArray(e)?i(s(e)):c(e)},d=function(e){e.active=!0,a.set(e.key,!0)},v=function(e){e.active=!1,a.set(e.key,!1)},y=function(e){e.active=r[e.key],a.remove(e.key)},m=function(){t&&o(t)};return m(),{set:o,get:g,enable:d,disable:v,reset:y,isOn:f,isOnByDefault:u,isOverridden:l}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,a){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(t,r){var n="featureFlagHide"in r;return t[0].textContent=" featureFlag: "+r.featureFlag+" is "+(n?"on":"off")+" ",function(t,r,i,l,f){var u,s;t.$watch(function(){var r=a(i.featureFlag)(t);return e.isOn(r)},function(e){var a=n?!e:e;a?(s=t.$new(),f(s,function(e){u=e,r.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(r).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(a){a.flags=e.get(),a.isOn=e.isOn,a.isOverridden=e.isOverridden,a.enable=e.enable,a.disable=e.disable,a.reset=e.reset,a.isOnByDefault=e.isOnByDefault},template:'
Feature Flags
{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement",function(e){var a=e.attr("ng-app"),t="featureFlags."+a+".",r=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),n=function(e){return t+e},i=function(e){return 0===e.indexOf(t)},l=function(e,a){r&&localStorage.setItem(n(a),e)},f=function(e){return r?localStorage.getItem(n(e)):void 0},u=function(e){r&&localStorage.removeItem(n(e))};return{isPresent:function(e){var a=f(e);return"undefined"!=typeof a&&null!==a},get:f,set:function(e,a){angular.isObject(e)?angular.forEach(e,l):l(a,e)},remove:u,reset:function(){var e;if(r)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").provider("featureFlags",function(){var a=[];this.setInitialFlags=function(e){a=e},this.$get=["$q","featureFlagOverrides",function(t,r){return new e(t,r,a)}]})}();
\ No newline at end of file
+!function(){function e(e,t){var a=[],n="",r=function(){return a},i=function(e){a=e},l=function(){return n},f=function(e){n=e},u=function(){e&&(a=e),t&&(n=t)};return u(),{getInitialFlags:r,setInitialFlags:i,getAppName:l,setAppName:f}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,t){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(a,n){var r="featureFlagHide"in n;return a[0].textContent=" featureFlag: "+n.featureFlag+" is "+(r?"on":"off")+" ",function(a,n,i,l,f){var u,s;a.$watch(function(){var n=t(i.featureFlag)(a);return e.isOn(n)},function(e){var t=r?!e:e;t?(s=a.$new(),f(s,function(e){u=e,n.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(n).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(t){t.flags=e.get(),t.isOn=e.isOn,t.isOverridden=e.isOverridden,t.enable=e.enable,t.disable=e.disable,t.reset=e.reset,t.isOnByDefault=e.isOnByDefault},template:' Feature Flags
{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement","featureFlagConfig",function(e,t){var a="featureFlags.",n=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),r=function(e){return a+e},i=function(e){return 0===e.indexOf(a)},l=function(e,t){n&&localStorage.setItem(r(t),e)},f=function(e){return n?localStorage.getItem(r(e)):void 0},u=function(e){n&&localStorage.removeItem(r(e))};return t.getAppName().length>0&&(a+=t.getAppName()+"."),{isPresent:function(e){var t=f(e);return"undefined"!=typeof t&&null!==t},get:f,set:function(e,t){angular.isObject(e)?angular.forEach(e,l):l(t,e)},remove:u,reset:function(){var e;if(n)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").service("featureFlags",["$q","featureFlagOverrides","featureFlagConfig",function(e,t,a){var n={},r=[],i=function(t){var a=e.defer();return a.resolve(t),a.promise},l=function(e){return t.isPresent(e)},f=function(e){return l(e)?"true"===t.get(e):n[e]},u=function(e){return n[e]},s=function(e){return e.forEach(function(e){n[e.key]=e.active,e.active=f(e.key)}),angular.copy(e,r),r},g=function(e){return e.then(function(e){return s(e.data||e)})},c=function(){return r},o=function(e){return angular.isArray(e)?i(s(e)):g(e)},v=function(e){e.active=!0,t.set(e.key,!0)},d=function(e){e.active=!1,t.set(e.key,!1)},m=function(e){e.active=n[e.key],t.remove(e.key)},F=function(){var e=a.getInitialFlags();e&&o(e)};return F(),{set:o,get:c,enable:v,disable:d,reset:m,isOn:f,isOnByDefault:u,isOverridden:l}}]),angular.module("feature-flags").provider("featureFlagConfig",function(){var t=[],a="";this.setInitialFlags=function(e){t=e},this.setAppName=function(e){a=e},this.$get=function(){return new e(t,a)}})}();
\ No newline at end of file
diff --git a/src/featureFlagOverrides.service.js b/src/featureFlagOverrides.service.js
index 14b8f96..1601adf 100644
--- a/src/featureFlagOverrides.service.js
+++ b/src/featureFlagOverrides.service.js
@@ -1,7 +1,5 @@
-angular.module('feature-flags').service('featureFlagOverrides', function($rootElement) {
- var appName = $rootElement.attr('ng-app'),
- keyPrefix = 'featureFlags.' + appName + '.',
-
+angular.module('feature-flags').service('featureFlagOverrides', function($rootElement, featureFlagConfig) {
+ var keyPrefix = 'featureFlags.',
localStorageAvailable = (function() {
try {
localStorage.setItem('featureFlags.availableTest', 'test');
@@ -38,6 +36,9 @@ angular.module('feature-flags').service('featureFlagOverrides', function($rootEl
}
};
+ if (featureFlagConfig.getAppName().length > 0) {
+ keyPrefix += featureFlagConfig.getAppName() + '.';
+ }
return {
isPresent: function(key) {
var value = get(key);
diff --git a/src/featureFlags.provider.js b/src/featureFlags.service.js
similarity index 80%
rename from src/featureFlags.provider.js
rename to src/featureFlags.service.js
index db7ac99..50acaf1 100644
--- a/src/featureFlags.provider.js
+++ b/src/featureFlags.service.js
@@ -1,4 +1,4 @@
-function FeatureFlags($q, featureFlagOverrides, initialFlags) {
+angular.module('feature-flags').service('featureFlags', function($q, featureFlagOverrides, featureFlagConfig) {
var serverFlagCache = {},
flags = [],
@@ -60,8 +60,9 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) {
},
init = function() {
- if (initialFlags) {
- set(initialFlags);
+ var iniFlags = featureFlagConfig.getInitialFlags();
+ if (iniFlags) {
+ set(iniFlags);
}
};
init();
@@ -76,16 +77,4 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) {
isOnByDefault: isOnByDefault,
isOverridden: isOverridden
};
-}
-
-angular.module('feature-flags').provider('featureFlags', function() {
- var initialFlags = [];
-
- this.setInitialFlags = function(flags) {
- initialFlags = flags;
- };
-
- this.$get = function($q, featureFlagOverrides) {
- return new FeatureFlags($q, featureFlagOverrides, initialFlags);
- };
});
diff --git a/src/featureFlagsConfig.provider.js b/src/featureFlagsConfig.provider.js
new file mode 100644
index 0000000..8cbaedd
--- /dev/null
+++ b/src/featureFlagsConfig.provider.js
@@ -0,0 +1,49 @@
+function FeatureFlagConfig(initialFlags, userAppName) {
+ var initFlags = [],
+ appName = '',
+
+ getInitialFlags = function() {
+ return initFlags;
+ },
+ setInitialFlags = function(value) {
+ initFlags = value;
+ },
+ getAppName = function() {
+ return appName;
+ },
+ setAppName = function(value) {
+ appName = value;
+ },
+ init = function() {
+ if (initialFlags) {
+ initFlags = initialFlags;
+ }
+ if (userAppName) {
+ appName = userAppName;
+ }
+ };
+ init();
+
+ return {
+ getInitialFlags: getInitialFlags,
+ setInitialFlags: setInitialFlags,
+ getAppName: getAppName,
+ setAppName: setAppName
+ };
+}
+
+angular.module('feature-flags').provider('featureFlagConfig', function() {
+ var initialFlags = [],
+ appName = '';
+
+ this.setInitialFlags = function(flags) {
+ initialFlags = flags;
+ };
+
+ this.setAppName = function(name) {
+ appName = name;
+ };
+ this.$get = function() {
+ return new FeatureFlagConfig(initialFlags, appName);
+ };
+});
diff --git a/test/featureFlagOverrides.service.spec.js b/test/featureFlagOverrides.service.spec.js
index 6291d26..f744c24 100644
--- a/test/featureFlagOverrides.service.spec.js
+++ b/test/featureFlagOverrides.service.spec.js
@@ -5,9 +5,21 @@
inject = angular.mock.inject;
describe('Service: featureFlagOverrides', function() {
- var service, appName = '';
-
- beforeEach(module('feature-flags'));
+ var service, appName = 'myapp';
+
+ beforeEach(module('feature-flags', function($provide) {
+ $provide.provider('featureFlagConfig', function() {
+ return {
+ $get: function() {
+ return {
+ getAppName: function() {
+ return appName;
+ }
+ };
+ }
+ };
+ });
+ }));
beforeEach(inject(function(featureFlagOverrides) {
service = featureFlagOverrides;
diff --git a/test/featureFlags.provider.spec.js b/test/featureFlags.service.spec.js
similarity index 92%
rename from test/featureFlags.provider.spec.js
rename to test/featureFlags.service.spec.js
index 99df006..e999a4e 100644
--- a/test/featureFlags.provider.spec.js
+++ b/test/featureFlags.service.spec.js
@@ -354,7 +354,7 @@
});
});
- describe('Provider: featureFlags', function() {
+ describe('Service with provider config: featureFlags', function() {
var featureFlags,
flags = [{
active: true,
@@ -362,11 +362,25 @@
}, {
active: false,
key: 'FLAG_KEY_2'
- }];
+ }],
+ appName = 'myapp';
describe('When no flags are set in the config phase', function() {
- beforeEach(module('feature-flags', function(featureFlagsProvider) {
- featureFlagsProvider.setInitialFlags(null);
+ beforeEach(module('feature-flags', function($provide) {
+ $provide.provider('featureFlagConfig', function() {
+ return {
+ $get: function() {
+ return {
+ getInitialFlags: function() {
+ return null;
+ },
+ getAppName: function() {
+ return appName;
+ }
+ };
+ }
+ };
+ });
}));
beforeEach(inject(function(_featureFlags_) {
@@ -379,8 +393,21 @@
});
describe('When flags are set in the config phase', function() {
- beforeEach(module('feature-flags', function(featureFlagsProvider) {
- featureFlagsProvider.setInitialFlags(flags);
+ beforeEach(module('feature-flags', function($provide) {
+ $provide.provider('featureFlagConfig', function() {
+ return {
+ $get: function() {
+ return {
+ getInitialFlags: function() {
+ return flags;
+ },
+ getAppName: function() {
+ return appName;
+ }
+ };
+ }
+ };
+ });
}));
beforeEach(inject(function(_featureFlags_) {
diff --git a/test/featureFlagsConfig.provider.spec.js b/test/featureFlagsConfig.provider.spec.js
new file mode 100644
index 0000000..1f675f1
--- /dev/null
+++ b/test/featureFlagsConfig.provider.spec.js
@@ -0,0 +1,69 @@
+(function(angular) {
+ 'use strict';
+
+ var module = angular.mock.module,
+ inject = angular.mock.inject;
+
+ describe('Provider: featureFlags', function() {
+ var appName = 'myapp',
+ featureFlagConfig,
+ flags = [{
+ active: true,
+ key: 'FLAG_KEY'
+ }, {
+ active: false,
+ key: 'FLAG_KEY_2'
+ }];
+
+ describe('When no flags are set in the config phase', function() {
+ beforeEach(module('feature-flags', function(featureFlagConfigProvider) {
+ featureFlagConfigProvider.setInitialFlags(null);
+ featureFlagConfigProvider.setAppName(null);
+ }));
+
+ beforeEach(inject(function(_featureFlagConfig_) {
+ featureFlagConfig = _featureFlagConfig_;
+ }));
+
+ it('should return an empty array for current feature flags', function() {
+ expect(featureFlagConfig).not.toBeUndefined();
+ expect(featureFlagConfig.getInitialFlags()).toEqual([]);
+ expect(featureFlagConfig.getAppName()).toEqual('');
+ });
+ });
+
+ describe('When flags are set in the config phase', function() {
+ beforeEach(module('feature-flags', function(featureFlagConfigProvider) {
+ featureFlagConfigProvider.setInitialFlags(flags);
+ featureFlagConfigProvider.setAppName(appName);
+ }));
+
+ beforeEach(inject(function(_featureFlagConfig_) {
+ featureFlagConfig = _featureFlagConfig_;
+ }));
+
+ it('should init the flags with the ones set in the config phase', function() {
+ expect(featureFlagConfig).not.toBeUndefined();
+ expect(featureFlagConfig.getInitialFlags()).toEqual(flags);
+ expect(featureFlagConfig.getAppName()).toEqual(appName);
+ });
+ });
+
+ describe('When flags are set in the run phase', function() {
+ beforeEach(module('feature-flags', function(featureFlagConfigProvider) {
+ featureFlagConfigProvider.setInitialFlags(null);
+ }));
+ beforeEach(inject(function(_featureFlagConfig_) {
+ featureFlagConfig = _featureFlagConfig_;
+ }));
+
+ it('should init the flags with the ones set in the run phase', function() {
+ expect(featureFlagConfig).not.toBeUndefined();
+ featureFlagConfig.setInitialFlags(flags);
+ featureFlagConfig.setAppName(appName);
+ expect(featureFlagConfig.getInitialFlags()).toEqual(flags);
+ expect(featureFlagConfig.getAppName()).toEqual(appName);
+ });
+ });
+ });
+}(window.angular));