pinball_wizard 0.4.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: