pinball_wizard 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c1ee29d61b4dac1dcb1965542c1ebacabe46852
4
- data.tar.gz: fa374257a6cae189d1b258efdcdd9ff04f48f80e
3
+ metadata.gz: f19047c410651760d4ba3fd40d003fc556b0f11b
4
+ data.tar.gz: 8967150c6eb2a68f737e2074760bae4df60afa8b
5
5
  SHA512:
6
- metadata.gz: 026f8a5fb150903a6e0d955e063c83444cf54faae6ff9c76b58f944db841ac1768d0e8caabc1dc07379ceca83fdd4484c7e2f07a54dcf33a39271dc0c12045a1
7
- data.tar.gz: 6fa133b85bfbbb4a65ddaaf0577106e5893f4c7bf95b1e0848b7d6fabe831be154f339725a9cb36bc686ce8d17aa36615bd22b733676bea71fb93f11c9c38aa8
6
+ metadata.gz: 0cd56ac8890deaf4e58b14b78ca7f61e539aac0720d40154d387e1060f661a553b86cc20c728a113d917f2fc786fa6400ce4da4c90850ccfe53595b8049570e6
7
+ data.tar.gz: 35548375bf420d5ffd22abf171d535b40aeef3f6344efd9a686c7d6ba0173d4a6e21fc5316d839150445598ed5de95a1db97804a3b26abd07f70f059dec5e643
@@ -1,3 +1,6 @@
1
+ # v1.0.0
2
+ * [feature] Now adds`without-` classes to inactive features to support better CSS partitioning between features and production code.
3
+
1
4
  # v0.4.2
2
5
  * [feature] `#activatePermanently` now supports multiple features: `('feature1', 'feature2'...)`
3
6
 
data/README.md CHANGED
@@ -67,9 +67,11 @@ If the feature is not active immediately, it's recommended to hide the HTML with
67
67
 
68
68
  ## CSS
69
69
 
70
- PinballWizard automatically adds and removes a CSS class named `.use-{feature-name}` to the `<html>` tag. This allows you to write CSS when features are active.
70
+ PinballWizard automatically adds and removes CSS classes named `.use-{feature-name}` and `without-{feature-name}` to the `<html>` tag.
71
71
 
72
- It is also recommended to organize your CSS similar to Ruby:
72
+ This supports keeping the global and feature-flipped CSS styles separated.
73
+
74
+ It is recommended to organize your CSS like so:
73
75
 
74
76
  ```scss
75
77
  // app/assets/stylesheets/features/_example.scss
@@ -81,6 +83,17 @@ It is also recommended to organize your CSS similar to Ruby:
81
83
 
82
84
  Then include it on the main file with `@import 'features/example'`
83
85
 
86
+ In your main SCSS file, wrap all CSS rules for the inactive state in the `without-{feature-name}` class, like so:
87
+
88
+ ```scss
89
+ .without-example {
90
+ // CSS when the 'example' feature is inactive;
91
+ // i.e. current production code.
92
+ }
93
+ ```
94
+
95
+ When your feature is published (made part of the permanent codebase), you can simply delete the entire `.without-example` section and remove the `.use-example` class wrapper.
96
+
84
97
 
85
98
  ## JavaScript
86
99
 
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinball_wizard",
3
- "version": "0.4.2",
3
+ "version": "1.0.0",
4
4
  "main": "dist/pinball_wizard.js",
5
5
  "dependencies": {
6
6
  },
@@ -1,13 +1,46 @@
1
1
  (function() {
2
2
  define(function() {
3
3
  return function(ele, pinballQueue, searchQuery) {
4
- var add, classNames, entry, feature, featureNames, i, j, k, len, len1, len2, matches, ref, ref1, state, storage;
4
+ var add, addWithout, classNames, entry, feature, featureNames, i, isAdded, j, k, kebabify, len, len1, len2, matches, ref, ref1, state, storage;
5
5
  classNames = [];
6
6
  add = function(name) {
7
- return classNames.push('use-' + name.split('_').join('-'));
7
+ var classToAdd;
8
+ classToAdd = 'use-' + kebabify(name);
9
+ if (!isAdded(name)) {
10
+ return classNames.push(classToAdd);
11
+ }
12
+ };
13
+ isAdded = function(name) {
14
+ var classToCheck;
15
+ classToCheck = 'use-' + kebabify(name);
16
+ return classNames.indexOf(classToCheck) !== -1;
17
+ };
18
+ addWithout = function(name) {
19
+ if (!isAdded(name)) {
20
+ return classNames.push('without-' + kebabify(name));
21
+ }
22
+ };
23
+ kebabify = function(name) {
24
+ return name.split('_').join('-');
25
+ };
26
+ matches = searchQuery.match(/pinball=([a-z-_,]+)/i);
27
+ if (matches && matches.length > 1) {
28
+ featureNames = (matches[1] + '').split(',');
29
+ for (i = 0, len = featureNames.length; i < len; i++) {
30
+ feature = featureNames[i];
31
+ add(feature);
32
+ }
33
+ }
34
+ storage = window.localStorage || {
35
+ setItem: function() {}
8
36
  };
9
- for (i = 0, len = pinballQueue.length; i < len; i++) {
10
- entry = pinballQueue[i];
37
+ ref = JSON.parse(storage.getItem('pinball_wizard')) || [];
38
+ for (j = 0, len1 = ref.length; j < len1; j++) {
39
+ feature = ref[j];
40
+ add(feature);
41
+ }
42
+ for (k = 0, len2 = pinballQueue.length; k < len2; k++) {
43
+ entry = pinballQueue[k];
11
44
  if (!entry.length) {
12
45
  continue;
13
46
  }
@@ -16,33 +49,19 @@
16
49
  add(entry[1]);
17
50
  break;
18
51
  case 'add':
19
- ref = entry[1];
20
- for (feature in ref) {
21
- state = ref[feature];
52
+ ref1 = entry[1];
53
+ for (feature in ref1) {
54
+ state = ref1[feature];
22
55
  if (state === 'active') {
23
56
  add(feature);
57
+ } else {
58
+ addWithout(feature);
24
59
  }
25
60
  }
26
61
  }
27
62
  }
28
- matches = searchQuery.match(/pinball=([a-z-_,]+)/i);
29
- if (matches && matches.length > 1) {
30
- featureNames = (matches[1] + '').split(',');
31
- for (j = 0, len1 = featureNames.length; j < len1; j++) {
32
- feature = featureNames[j];
33
- add(feature);
34
- }
35
- }
36
- storage = window.localStorage || {
37
- setItem: function() {}
38
- };
39
- ref1 = JSON.parse(storage.getItem('pinball_wizard')) || [];
40
- for (k = 0, len2 = ref1.length; k < len2; k++) {
41
- feature = ref1[k];
42
- add(feature);
43
- }
44
63
  if (ele) {
45
- ele.className += ' ' + classNames.join(' ');
64
+ ele.className += ' ' + classNames.sort().join(' ');
46
65
  }
47
66
  };
48
67
  });
@@ -1,3 +1 @@
1
- // Minified on http://closure-compiler.appspot.com/ using Advanced settings
2
-
3
- (function(h,c,f){var g,k,e,b,d,l,m;k=[];g=function(b){k.push("use-"+b.split("_").join("-"))};d=0;for(l=c.length;d<l;d++)if(e=c[d],e.length)switch(e[0]){case "activate":g(e[1]);break;case "add":for(b in e=e[1],e)m=e[b],"active"===m&&g(b)}if((b=f.match(/pinball=([a-z-_,]+)/i))&&1<b.length)for(c=(b[1]+"").split(","),f=0,d=c.length;f<d;f++)b=c[f],g(b);d=JSON.parse((window.localStorage||{setItem:function(){}}).getItem("pinball_wizard"))||[];c=0;for(f=d.length;c<f;c++)b=d[c],g(b);h&&(h.className+=" "+k.join(" "))})(document.documentElement,window.pinball,window.location.search);
1
+ (function(h,l,a){var e,m,f,b,c,d,k,g,n;f=[];e=function(a){var b;b="use-"+g(a);k(a)||f.push(b)};k=function(a){return-1!==f.indexOf("use-"+g(a))};m=function(a){k(a)||f.push("without-"+g(a))};g=function(a){return a.split("_").join("-")};if((a=a.match(/pinball=([a-z-_,]+)/i))&&1<a.length)for(a=(a[1]+"").split(","),d=0,b=a.length;d<b;d++)c=a[d],e(c);b=JSON.parse((window.localStorage||{setItem:function(){}}).getItem("pinball_wizard"))||[];a=0;for(d=b.length;a<d;a++)c=b[a],e(c);a=0;for(d=l.length;a<d;a++)if(b=l[a],b.length)switch(b[0]){case "activate":e(b[1]);break;case "add":for(c in b=b[1],b)n=b[c],"active"===n?e(c):m(c)}h&&(h.className+=""+f.sort().join(" "))})(document.documentElement,window.pinball,window.location.search);
@@ -78,22 +78,18 @@
78
78
  }
79
79
  return prefix + name.split('_').join('-');
80
80
  };
81
- addCSSClassName = function(name, ele) {
82
- var cN;
81
+ addCSSClassName = function(cN, ele) {
83
82
  if (ele == null) {
84
83
  ele = document.documentElement;
85
84
  }
86
- cN = cssClassName(name);
87
85
  if (ele.className.indexOf(cN) < 0) {
88
86
  return ele.className += ' ' + cN;
89
87
  }
90
88
  };
91
- removeCSSClassName = function(name, ele) {
92
- var cN;
89
+ removeCSSClassName = function(cN, ele) {
93
90
  if (ele == null) {
94
91
  ele = document.documentElement;
95
92
  }
96
- cN = cssClassName(name);
97
93
  if (ele.className.indexOf(cN) >= 0) {
98
94
  return ele.className = ele.className.replace(cN, '');
99
95
  }
@@ -134,7 +130,8 @@
134
130
  case 'inactive':
135
131
  _log("Activate %s%s.", name, source);
136
132
  update(name, 'active');
137
- addCSSClassName(name);
133
+ addCSSClassName(cssClassName(name, 'use-'));
134
+ removeCSSClassName(cssClassName(name, 'without-'));
138
135
  return _notifySubscribersOnActivate(name);
139
136
  case 'active':
140
137
  return _log("Attempted to activate %s, but it is already active%s.", name, source);
@@ -155,7 +152,8 @@
155
152
  case 'active':
156
153
  _log("Dectivate %s%s.", name, source);
157
154
  update(name, 'inactive');
158
- removeCSSClassName(name);
155
+ removeCSSClassName(cssClassName(name, 'use-'));
156
+ addCSSClassName(cssClassName(name, 'without-'));
159
157
  return _notifySubscribersOnDeactivate(name);
160
158
  default:
161
159
  return _log("Attempted to deactivate %s, but it is %s%s.", name, state, source);
@@ -1,3 +1,3 @@
1
1
  module PinballWizard
2
- VERSION = '0.4.2'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinball_wizard",
3
- "version": "0.4.2",
3
+ "version": "1.0.0",
4
4
  "description": "pinball_wizard",
5
5
  "homepage": "https://github.com/primedia/pinball_wizard",
6
6
  "license": "MIT",
@@ -19,19 +19,20 @@ define ->
19
19
  classNames = []
20
20
 
21
21
  add = (name) ->
22
- classNames.push 'use-' + name.split('_').join('-')
22
+ classToAdd = 'use-' + kebabify(name)
23
+ if !isAdded(name)
24
+ classNames.push classToAdd
23
25
 
24
- # Activated by the queue
25
- for entry in pinballQueue
26
- continue unless entry.length
26
+ isAdded = (name) ->
27
+ classToCheck = 'use-' + kebabify(name)
28
+ classNames.indexOf(classToCheck) != -1
27
29
 
28
- switch entry[0]
29
- when 'activate'
30
- add entry[1]
30
+ addWithout = (name) ->
31
+ if !isAdded(name)
32
+ classNames.push 'without-' + kebabify(name)
31
33
 
32
- when 'add'
33
- for feature, state of entry[1]
34
- add feature if state == 'active'
34
+ kebabify = (name) ->
35
+ name.split('_').join('-')
35
36
 
36
37
  # Activated by the URL
37
38
  matches = searchQuery.match(/pinball=([a-z-_,]+)/i)
@@ -41,12 +42,26 @@ define ->
41
42
  for feature in featureNames
42
43
  add feature
43
44
 
44
-
45
45
  # Activated permanently
46
46
  storage = window.localStorage or { setItem: -> }
47
47
  for feature in (JSON.parse(storage.getItem('pinball_wizard')) or [])
48
48
  add feature
49
49
 
50
- ele.className += ' ' + classNames.join(' ') if ele
50
+ # Activated by the queue
51
+ for entry in pinballQueue
52
+ continue unless entry.length
53
+
54
+ switch entry[0]
55
+ when 'activate'
56
+ add entry[1]
57
+
58
+ when 'add'
59
+ for feature, state of entry[1]
60
+ if state == 'active'
61
+ add feature
62
+ else
63
+ addWithout feature
64
+
65
+ ele.className += ' ' + classNames.sort().join(' ') if ele
51
66
 
52
67
  return
@@ -45,13 +45,11 @@ define ->
45
45
  cssClassName = (name, prefix = 'use-') ->
46
46
  prefix + name.split('_').join('-')
47
47
 
48
- addCSSClassName = (name, ele = document.documentElement) ->
49
- cN = cssClassName(name)
48
+ addCSSClassName = (cN, ele = document.documentElement) ->
50
49
  if ele.className.indexOf(cN) < 0
51
50
  ele.className += ' ' + cN
52
51
 
53
- removeCSSClassName = (name, ele = document.documentElement) ->
54
- cN = cssClassName(name)
52
+ removeCSSClassName = (cN, ele = document.documentElement) ->
55
53
  if ele.className.indexOf(cN) >= 0
56
54
  ele.className = ele.className.replace cN, ''
57
55
 
@@ -80,7 +78,8 @@ define ->
80
78
  when 'inactive'
81
79
  _log "Activate %s%s.", name, source
82
80
  update(name, 'active')
83
- addCSSClassName(name)
81
+ addCSSClassName(cssClassName(name, 'use-'))
82
+ removeCSSClassName(cssClassName(name, 'without-'))
84
83
  _notifySubscribersOnActivate(name)
85
84
  when 'active'
86
85
  _log "Attempted to activate %s, but it is already active%s.", name, source
@@ -96,7 +95,8 @@ define ->
96
95
  when 'active'
97
96
  _log "Dectivate %s%s.", name, source
98
97
  update(name, 'inactive')
99
- removeCSSClassName(name)
98
+ removeCSSClassName(cssClassName(name, 'use-'))
99
+ addCSSClassName(cssClassName(name, 'without-'))
100
100
  _notifySubscribersOnDeactivate(name)
101
101
  else
102
102
  _log "Attempted to deactivate %s, but it is %s%s.", name, state, source
@@ -21,7 +21,7 @@ define ['css_tagger'], (tagger) ->
21
21
  tagger ele, [], '?pinball=feature_a,feature_b&other=param'
22
22
  expect(ele.className).toEqual 'foo-bar use-feature-a use-feature-b'
23
23
 
24
- it 'should add classes from added pinball features', ->
24
+ it 'should add classes from active and inactive pinball features', ->
25
25
  ele = document.createElement 'div'
26
26
  pinballQueue = [
27
27
  [
@@ -33,7 +33,20 @@ define ['css_tagger'], (tagger) ->
33
33
  ]
34
34
 
35
35
  tagger ele, pinballQueue, ''
36
- expect(ele.className).toEqual ' use-feature-a use-feature-c'
36
+ expect(ele.className).toEqual ' use-feature-a use-feature-c without-feature-b'
37
+
38
+ it 'should add without-feature classes for inactive and disabled pinball features', ->
39
+ ele = document.createElement 'div'
40
+ pinballQueue = [
41
+ [
42
+ 'add'
43
+ feature_a: 'inactive'
44
+ feature_b: 'disabled'
45
+ ]
46
+ ]
47
+
48
+ tagger ele, pinballQueue, ''
49
+ expect(ele.className).toEqual ' without-feature-a without-feature-b'
37
50
 
38
51
  it 'should add classes from queue and query params', ->
39
52
  ele = document.createElement 'div'
@@ -41,20 +54,28 @@ define ['css_tagger'], (tagger) ->
41
54
  [
42
55
  'add'
43
56
  feature_a: 'active'
57
+ feature_d: 'inactive'
44
58
  ],
45
59
  ['activate', 'feature_b'],
46
60
  ['something-odd']
47
61
  ]
48
62
 
49
63
  tagger ele, pinballQueue, '?pinball=feature_c'
50
- expect(ele.className).toEqual ' use-feature-a use-feature-b use-feature-c'
64
+ expect(ele.className).toEqual ' use-feature-a use-feature-b use-feature-c without-feature-d'
51
65
 
52
66
  it 'should add classes from the permanent storage', ->
53
67
  ele = document.createElement 'div'
54
68
  window.localStorage.setItem 'pinball_wizard', JSON.stringify(['feature_a','feature_b'])
69
+ pinballQueue = [
70
+ [
71
+ 'add'
72
+ feature_c: 'active'
73
+ feature_d: 'inactive'
74
+ ]
75
+ ]
55
76
 
56
- tagger ele, [], ''
57
- expect(ele.className).toEqual ' use-feature-a use-feature-b'
77
+ tagger ele, pinballQueue, ''
78
+ expect(ele.className).toEqual ' use-feature-a use-feature-b use-feature-c without-feature-d'
58
79
 
59
80
  # Cleanup
60
81
  window.localStorage.setItem 'pinball_wizard', null
@@ -2,6 +2,7 @@ define ['pinball_wizard'], (pinball) ->
2
2
 
3
3
  beforeEach ->
4
4
  pinball.reset()
5
+ document.documentElement.className = ''
5
6
 
6
7
  describe 'initialize', ->
7
8
  it 'is defined', ->
@@ -87,6 +88,19 @@ define ['pinball_wizard'], (pinball) ->
87
88
 
88
89
  expect(pinball.get('a')).toEqual('disabled')
89
90
 
91
+ it 'adds use-feature class to css', ->
92
+ pinball.add
93
+ feature_a: 'inactive'
94
+ pinball.activate 'feature_a'
95
+ expect(document.documentElement.className).toEqual(' use-feature-a')
96
+
97
+ it 'removes without-feature', ->
98
+ document.documentElement.className = 'foo without-feature-a bar'
99
+ pinball.add
100
+ feature_a: 'inactive'
101
+ pinball.activate 'feature_a'
102
+ expect(document.documentElement.className).toMatch(/foo\s+bar\s+use-feature-a/)
103
+
90
104
  describe '#deactivate', ->
91
105
  it 'makes an active feature inactive', ->
92
106
  pinball.add
@@ -95,6 +109,12 @@ define ['pinball_wizard'], (pinball) ->
95
109
 
96
110
  expect(pinball.get('a')).toEqual('inactive')
97
111
 
112
+ it 'adds without-feature class to css', ->
113
+ pinball.add
114
+ feature_a: 'active'
115
+ pinball.deactivate 'feature_a'
116
+ expect(document.documentElement.className).toEqual(' without-feature-a')
117
+
98
118
  describe '#isActive', ->
99
119
  beforeEach ->
100
120
  pinball.add
@@ -235,16 +255,19 @@ define ['pinball_wizard'], (pinball) ->
235
255
  it 'builds the name with the prefix', ->
236
256
  expect(pinball.cssClassName('my_feature')).toEqual 'use-my-feature'
237
257
 
258
+ it 'builds the name with a custom prefix', ->
259
+ expect(pinball.cssClassName('my_feature', 'without-')).toEqual 'without-my-feature'
260
+
238
261
  describe '#addCSSClassName', ->
239
262
  it 'appends', ->
240
263
  ele = document.createElement 'div'
241
- pinball.addCSSClassName('my_feature', ele)
264
+ pinball.addCSSClassName('use-my-feature', ele)
242
265
  expect(ele.className).toEqual ' use-my-feature'
243
266
 
244
267
  it 'does not append twice', ->
245
268
  ele = document.createElement 'div'
246
- pinball.addCSSClassName('my_feature', ele)
247
- pinball.addCSSClassName('my_feature', ele)
269
+ pinball.addCSSClassName('use-my-feature', ele)
270
+ pinball.addCSSClassName('use-my-feature', ele)
248
271
  expect(ele.className).toEqual ' use-my-feature'
249
272
 
250
273
  describe '#removeCSSClassName', ->
@@ -271,28 +294,28 @@ define ['pinball_wizard'], (pinball) ->
271
294
  beforeEach ->
272
295
  pinball.resetPermanent()
273
296
  pinball.add
274
- my_feature1: 'inactive'
297
+ my_feature_one: 'inactive'
275
298
 
276
299
  it 'accepts a single feature', ->
277
- pinball.activatePermanently('my_feature1')
278
- expect(pinball.permanent()).toEqual(['my_feature1'])
300
+ pinball.activatePermanently('my_feature_one')
301
+ expect(pinball.permanent()).toEqual(['my_feature_one'])
279
302
 
280
303
  it 'adds it to the list of permanent', ->
281
- pinball.activatePermanently('my_feature1')
282
- expect(pinball.permanent()).toEqual(['my_feature1'])
304
+ pinball.activatePermanently('my_feature_one')
305
+ expect(pinball.permanent()).toEqual(['my_feature_one'])
283
306
 
284
307
  it 'activates the feature', ->
285
- pinball.activatePermanently('my_feature1')
286
- expect(pinball.isActive('my_feature1')).toEqual(true)
308
+ pinball.activatePermanently('my_feature_one')
309
+ expect(pinball.isActive('my_feature_one')).toEqual(true)
287
310
 
288
- it 'accepts a comma-separated list of features', ->
311
+ it 'accepts multiple features', ->
289
312
  pinball.add
290
- my_feature1: 'inactive'
291
- my_feature2: 'inactive'
292
- pinball.activatePermanently('my_feature1', 'my_feature2')
293
- expect(pinball.permanent()).toEqual(['my_feature1','my_feature2'])
294
- expect(pinball.isActive('my_feature1')).toEqual(true)
295
- expect(pinball.isActive('my_feature2')).toEqual(true)
313
+ my_feature_one: 'inactive'
314
+ my_feature_two: 'inactive'
315
+ pinball.activatePermanently('my_feature_one', 'my_feature_two')
316
+ expect(pinball.permanent()).toEqual(['my_feature_one','my_feature_two'])
317
+ expect(pinball.isActive('my_feature_one')).toEqual(true)
318
+ expect(pinball.isActive('my_feature_two')).toEqual(true)
296
319
 
297
320
 
298
321
  describe '#permanent', ->
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinball_wizard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Caleb Wright
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-10-19 00:00:00.000000000 Z
14
+ date: 2015-10-22 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: Build flippable features.
17
17
  email: