tips 0.0.2 → 0.0.4

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: 9684df1fded8d68ca41ee1ce6f427df5af471b34
4
- data.tar.gz: dfbf087e71d2d7d8d9553bf560e00e1254b45081
3
+ metadata.gz: 88eefb61e9358a7277d98c91dab830c502ac3032
4
+ data.tar.gz: 921e3580b09209f64afd35b78beb38ba3f55488d
5
5
  SHA512:
6
- metadata.gz: 405cd0a5dcb1b15ee664b066a23149bb893dc4aff4d18c3b6e5635c20c2911a3339b6d7fe1a588a520af4f19443dfcb293a1d501e32c0fcdb013bd176e8204d3
7
- data.tar.gz: a1f9c2b17f0230b56b385db8d3a756689eb4cc819688405fd86d51f4efbdd63143ac1ee771ee5f6ad9b90274b1e4ba6d4a55c3adc5b875b47a3fed0dddcf052d
6
+ metadata.gz: f8ffee509e78bd2b222e7eaee4faf725feab0936743474ff94361b62c118374b6925f26eb26c9dc2e7b637c26c72cad1f70f25e3cfd3a37350de116dc652a48c
7
+ data.tar.gz: 8f4a860f9dcb5120c707ba75481896c590c83bb96207968ad933d42e72f91cb5fdd9d8f6a5a800537ddb6e2f65095b2774f82b8835c9b9207ca1bfb035172f8f
data/README.markdown ADDED
@@ -0,0 +1,307 @@
1
+ # Tips (beta)
2
+
3
+ Slack inspired onboarding tips.
4
+
5
+ Note: Tips is currently in Beta. Left, much work there is. To see a backlog of features and work currently in progress <a href='https://huboard.com/rguerrettaz/tips-rails/' target='_blank'>checkout the HuBoard.</a>
6
+
7
+ <a href="http://codepen.io/rguerrettaz/pen/eNNXKB" target='_blank'><img src="http://i.imgur.com/EQuPxuh.gif"></a>
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'tips'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install tips
22
+
23
+ ## Examples
24
+
25
+ * <a href="http://codepen.io/rguerrettaz/pen/LVVVzR" target='_blank'>Single Tip</a>
26
+ * <a href="http://codepen.io/rguerrettaz/pen/doorJm" target='_blank'>Single Tip, multiple pages of content</a>
27
+ * <a href="http://codepen.io/rguerrettaz/pen/KppEop" target='_blank'>Multiple Tips</a>
28
+ * <a href="http://codepen.io/rguerrettaz/pen/eNNXKB" target='_blank'>Multiple Tips, multiple pages of content</a>
29
+
30
+ ## Usage
31
+
32
+ Tips uses HTML data-attributes to pass the majority of its configuration.
33
+
34
+ #### Creating a tip
35
+
36
+ Creating a tip is easy. Just add the necessary data-attributes to your target
37
+ element and call `Tips.init()`. For example, if you want to target a div on your
38
+ page you'd add the following data-attributes to the div:
39
+
40
+ ```html
41
+ <div data-tips-id='my-unique-tip-name'
42
+ data-tips-content='{"page1Header" : "This is my header",
43
+ "page1Body" : "This is the body of my tip",
44
+ }'
45
+ data-tips-hot-spot-position='top-right'
46
+ data-tips-card-position='right'
47
+ data-tips-priority='1'
48
+ data-tips-pages='1'>
49
+ </div>
50
+ ```
51
+
52
+ Once the data attributes have been added add this line to your javascript
53
+ ```javascript
54
+ Tips.init()
55
+ ```
56
+
57
+ #### Creating multiple tips on a single page
58
+
59
+ Use the same data-attributes as a single tip just make sure `data-tips-id` is
60
+ unique for each tip and set the `data-tips-priority` appropriately.
61
+
62
+ ```html
63
+ <div data-tips-id='my-unique-tip-name'
64
+ data-tips-content='{"page1Header" : "This is my header",
65
+ "page1Body" : "This is the body of my tip",
66
+ }'
67
+ data-tips-hot-spot-position='top-right'
68
+ data-tips-card-position='right'
69
+ data-tips-priority='1'
70
+ data-tips-pages='1'>
71
+ <button>My 1st Button</button>
72
+ </div>
73
+
74
+ <div data-tips-id='my-unique-tip-name-number-two'
75
+ data-tips-content='{"page1Header" : "This is my header no. 2",
76
+ "page1Body" : "This is the body of my tip no. 2",
77
+ }'
78
+ data-tips-hot-spot-position='top-right'
79
+ data-tips-card-position='right'
80
+ data-tips-priority='2'
81
+ data-tips-pages='1'>
82
+ <button>My 2nd Button</button>
83
+ </div>
84
+
85
+ ```
86
+
87
+ Once the data attributes have been added add this line to your javascript
88
+ ```javascript
89
+ Tips.init()
90
+ ```
91
+
92
+ #### Creating tips with multiple pages of content
93
+
94
+ To do this just add the extra pages to `data-tips-content`
95
+ ```html
96
+ <div data-tips-id='my-unique-tip-name'
97
+ data-tips-content='{"page1Header" : "This is my header",
98
+ "page1Body" : "This is the body of my tip",
99
+ "page2Header" : "A second header?",
100
+ "page2Body" : "Yes! If you so choose, you can have
101
+ tips with multiple pages."
102
+ }'
103
+ data-tips-hot-spot-position='top-right'
104
+ data-tips-card-position='right'
105
+ data-tips-priority='1'
106
+ data-tips-pages='1'>
107
+ <button>My 1st Button</button>
108
+ </div>
109
+ ```
110
+
111
+ Once the data attributes have been added add this line to your javascript
112
+ ```javascript
113
+ Tips.init()
114
+ ```
115
+
116
+ ## Attributes overview
117
+
118
+ #### data-tips-id
119
+ `data-tips-id` should be unique for each tip you have on your website.
120
+ These are used as references when we check if a user has previously seen a tip.
121
+
122
+ ```
123
+ data-tips-id='some-unique-name-for-this-tip'
124
+ ```
125
+
126
+ #### data-tips-content
127
+ `data-tips-content` is a JSON string representation of the content for your tip.
128
+ To allow Tips to support multiple pages of content we use keys in the form of
129
+ `page1Header` and `page1Body`. Pages should be sequential. Shit will fail
130
+ otherwise.
131
+
132
+ ```
133
+ data-tips-content='{"page1Header":"The header for the first page of this tip",
134
+ "page1Boy":"The body for the first page of this tip",
135
+ "page2Header":"The header for the second page of this tip",
136
+ "page2Body":"The body for the second page of this tip"
137
+ }
138
+ ```
139
+
140
+ #### data-tips-hot-spot-position
141
+ `data-tips-hot-spot-position` controls the position of the throbbing hot spot
142
+ icon in relation to the element you're targeting.
143
+
144
+
145
+ ```html
146
+ <!-- Default value: 'right' -->
147
+ data-tips-hot-spot-position='bottom-left'
148
+ ```
149
+
150
+ Acceptable values:
151
+ ```
152
+ top-right
153
+ top-left
154
+ top
155
+ bottom-right
156
+ bottom-left
157
+ bottom
158
+ left
159
+ right
160
+ middle
161
+ ```
162
+
163
+ #### data-tips-card-position
164
+ `data-tips-card-position` controls the side your tip modal will show up on.
165
+
166
+ ```
167
+ <!-- Default value: 'right' -->
168
+ data-tips-card-position='left'
169
+ ```
170
+
171
+ Acceptable values:
172
+ ```
173
+ top
174
+ bottom
175
+ left
176
+ right
177
+ ```
178
+
179
+ #### data-tips-priority
180
+ `data-tips-priority` is used when you have multiple tips on a given page.
181
+ Priority 1 will be shown first.
182
+ ```
183
+ data-tips-priority='1'
184
+ ```
185
+
186
+ #### data-tips-pages
187
+ `data-tips-pages` tells Tips how many pages you want on a given tip. Required
188
+ attribute. There is no default set at this point.
189
+ ```
190
+ data-tips-priority='1'
191
+ ```
192
+
193
+ ## Storage
194
+ #### Default Storage (localStorage)
195
+ By default Tips will use `localStorage` to store which tips have been seen.
196
+ This works, however, it's sub-optimal. Using `localStorage` means tips may be
197
+ seen twice. When using localStorage the following scenarios may show tips twice:
198
+ * User opens pages in incognito mode
199
+ * User opens pages in multiple browsers
200
+ * User opens pages from multiple devices
201
+
202
+ Because the lack of persistence with `localStorage`, Tips comes with the ability
203
+ to [define your own](#custom-storage-device) `customStorageDevice`.
204
+
205
+ Here's the `defaultStorageDevice`:
206
+ ```javascript
207
+ var defaultStorageDevice = {
208
+ optOutKey: 'tips-opted-out',
209
+
210
+ addTip: function(tipName){
211
+ localStorage.setItem(tipName, true);
212
+ },
213
+
214
+ tipHasBeenSeen: function(tipName){
215
+ return !!localStorage.getItem(tipName);
216
+ },
217
+
218
+ optOut: function(){
219
+ localStorage.setItem(this.optOutKey, true);
220
+ },
221
+
222
+ userHasOptedOut: function(){
223
+ return !!localStorage.getItem(this.optOutKey);
224
+ },
225
+
226
+ removeAll: function(tipNames){
227
+ tipNames.push(this.optOutKey);
228
+ tipNames.forEach(function(key){
229
+ localStorage.removeItem(key);
230
+ });
231
+ }
232
+ };
233
+ ```
234
+
235
+ #### Custom Storage Device
236
+ You can define your own custom storage device and pass it in as an argument when
237
+ you initialize with `Tips.init(myCustomStorageDevice)`. Example using `jQuery`:
238
+ ```javascript
239
+ (function initTipsWithCustomStorage() {
240
+
241
+ // Make an ajax call for a list of seen tips and if the user has opted out
242
+ // On success, init tips with out customStorageDevice
243
+ (function(){
244
+ $.ajax('/tips/data', {
245
+ method: 'GET'
246
+ })
247
+ .success(function(data){
248
+ var userHasOptedOut = data.optedOut;
249
+ var seenTips = data.seenTips;
250
+ var storageDevice = {
251
+ seenTips: seenTips,
252
+
253
+ addTip: function(tipName){
254
+ $.ajax('/tips/tip_seen', {
255
+ method: 'POST',
256
+ data: {name: tipName}
257
+ });
258
+
259
+ // Add tip to list of seenTips so it doesn't show again in the same
260
+ // window session
261
+ seenTips.push(tipName);
262
+ },
263
+
264
+ tipHasBeenSeen: function(tipName){
265
+ return seenTips.indexOf(tipName) != -1;
266
+ },
267
+
268
+ optOut: function(){
269
+ $.ajax('/tips/opted_out', {
270
+ method: 'POST',
271
+ data: {name: 'opt-out'}
272
+ })
273
+ },
274
+
275
+ userHasOptedOut: function(){
276
+ return !!userHasOptedOut;
277
+ },
278
+ };
279
+
280
+ // Begin the magic
281
+ Tips.init(storageDevice);
282
+ })
283
+ .fail(function(jqXHR, textStatus){
284
+ console.log('Failure? Yes, failure with status: ' + textStatus)
285
+ });
286
+ })();
287
+ })();
288
+
289
+ ```
290
+
291
+ Important things to note here
292
+ * You're passing an object with public methods, not a function
293
+ * You must have the following methods defined
294
+ ```javascript
295
+ storageDevice.addTip()
296
+ storageDevice.tipHasBeenSeen()
297
+ storageDevice.optOut()
298
+ storageDevice.userHasOptedOut()
299
+ ```
300
+
301
+ ## Contributing
302
+
303
+ 1. Fork it ( http://github.com/<my-github-username>/tips/fork )
304
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
305
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
306
+ 4. Push to the branch (`git push origin my-new-feature`)
307
+ 5. Create new Pull Request
@@ -1,6 +1,13 @@
1
1
  ;(function setup(window){
2
2
 
3
3
  function initTips(){
4
+
5
+ //
6
+ //
7
+ // Validation
8
+ // TODO: add validation to tip data-attributes config
9
+ //
10
+ //
4
11
  function Validation(config, settableAttrs, acceptableValues) {
5
12
 
6
13
  function logInvalidKeyError(key){
@@ -25,42 +32,19 @@
25
32
  })
26
33
  }
27
34
 
28
- //
29
- //
30
- // STORAGE DEVICE
31
- //
32
- //
33
- var tipsCustomStorageDevice;
34
- var storageDevice;
35
- var defaultStorageDevice = {
36
- optOutKey: 'tips-opted-out',
37
-
38
- addTip: function(tipName){
39
- localStorage.setItem(tipName, true);
40
- },
41
-
42
- tipHasBeenSeen: function(tipName){
43
- return !!localStorage.getItem(tipName);
44
- },
45
-
46
- optOut: function(){
47
- localStorage.setItem(this.optOutKey, true);
48
- },
49
-
50
- userHasOptedOut: function(){
51
- return !!localStorage.getItem(this.optOutKey);
52
- },
35
+ function createTips(){
36
+ var tipNodes = document.querySelectorAll('[data-tips-id]');
53
37
 
54
- removeAll: function(tipNames){
55
- tipNames.push(this.optOutKey)
56
- tipNames.forEach(function(key){
57
- localStorage.removeItem(key)
58
- })
38
+ for(i = 0; i < tipNodes.length; ++i) {
39
+ var tip = new Tip(tipNodes[i])
40
+ Tips.list.push(tip)
59
41
  }
60
42
  };
61
43
 
62
- if (tipsCustomStorageDevice == undefined) storageDevice = defaultStorageDevice;
63
- else storageDevice = tipsCustomStorageDevice();
44
+ // Sort list to make TipCard showing easier
45
+ function sortTipsList(list){
46
+ Tips.list.sort(function(a,b) {return a.priority - b.priority})
47
+ }
64
48
 
65
49
  //
66
50
  //
@@ -68,11 +52,52 @@
68
52
  //
69
53
  //
70
54
  var Tips = {
55
+ init: function(customStorageDevice){
56
+
57
+ // Allow user to define their own storageDevice
58
+ if(customStorageDevice != undefined) {
59
+ this.storageDevice = customStorageDevice;
60
+ }
61
+
62
+ createTips();
63
+ sortTipsList();
64
+ this.showNextTip();
65
+ },
66
+
71
67
  list: [],
72
68
 
73
- userOptedOut: function(){ return storageDevice.userHasOptedOut() },
69
+ storageDevice: {
70
+ optOutKey: 'tips-opted-out',
71
+
72
+ addTip: function(tipName){
73
+ localStorage.setItem(tipName, true);
74
+ },
75
+
76
+ tipHasBeenSeen: function(tipName){
77
+ console.log(" I GET CALLED BEFORE I GET OVERWRITTEN")
78
+ console.log(tipName)
79
+ return !!localStorage.getItem(tipName);
80
+ },
81
+
82
+ optOut: function(){
83
+ localStorage.setItem(this.optOutKey, true);
84
+ },
74
85
 
75
- reset: function(){ storageDevice.removeAll(this.tipNames()) },
86
+ userHasOptedOut: function(){
87
+ return !!localStorage.getItem(this.optOutKey);
88
+ },
89
+
90
+ removeAll: function(tipNames){
91
+ tipNames.push(this.optOutKey)
92
+ tipNames.forEach(function(key){
93
+ localStorage.removeItem(key)
94
+ })
95
+ }
96
+ },
97
+
98
+ userOptedOut: function(){ return this.storageDevice.userHasOptedOut() },
99
+
100
+ reset: function(){ this.storageDevice.removeAll(this.tipNames()) },
76
101
 
77
102
  tipNames: function(){
78
103
  var names = [];
@@ -102,7 +127,7 @@
102
127
  //
103
128
  //
104
129
  function Tip(el) {
105
- this.name = 'tips:' + el.getAttribute('data-tips-name');
130
+ this.name = 'tips:' + el.getAttribute('data-tips-id');
106
131
  this.priority = el.getAttribute('data-tips-priority') || 1;
107
132
  this.pages = el.getAttribute('data-tips-pages') || 1;
108
133
  this.tipNode = el;
@@ -116,7 +141,7 @@
116
141
 
117
142
  Tip.prototype.hasBeenSeen = function() {
118
143
  //Look in storage device for tip seen
119
- return !!storageDevice.tipHasBeenSeen(this.name)
144
+ return !!Tips.storageDevice.tipHasBeenSeen(this.name)
120
145
  }
121
146
 
122
147
  //
@@ -217,7 +242,7 @@
217
242
  }
218
243
 
219
244
  function storeThatTipHasBeenSeen(){
220
- storageDevice.addTip(hotSpot.tipName);
245
+ Tips.storageDevice.addTip(hotSpot.tipName);
221
246
  }
222
247
 
223
248
  function showTipCard(){
@@ -248,7 +273,8 @@
248
273
  // Highlight the tip node
249
274
  // For z-index to work the tipNode must have a positon in the following:
250
275
  // ['absolute', 'relative', 'fixed']
251
- this.tipNode.style.zIndex = 9999;
276
+ // TODO: only hightlight the element if user sets it in config
277
+ // this.tipNode.style.zIndex = 9999;
252
278
  };
253
279
 
254
280
  tipCard.hide = function(){
@@ -459,7 +485,7 @@
459
485
  function addOptOutListener(optOutLink) {
460
486
  optOutLink.addEventListener('click', function(e){
461
487
  e.preventDefault();
462
- storageDevice.optOut();
488
+ Tips.storageDevice.optOut();
463
489
  tipCard.hide();
464
490
  })
465
491
  };
@@ -553,24 +579,6 @@
553
579
  return this.charAt(0).toUpperCase() + this.slice(1);
554
580
  }
555
581
 
556
- function createTips(){
557
- var tipNodes = document.querySelectorAll('[data-tips-single-item]');
558
-
559
- for(i = 0; i < tipNodes.length; ++i) {
560
- var tip = new Tip(tipNodes[i])
561
- Tips.list.push(tip)
562
- }
563
- };
564
-
565
- // Sort list to make TipCard showing easier
566
- function sortTipsList(list){
567
- Tips.list.sort(function(a,b) {return a.priority - b.priority})
568
- }
569
-
570
- createTips();
571
- sortTipsList();
572
- Tips.showNextTip();
573
-
574
582
  return Tips;
575
583
  }
576
584
 
data/lib/tips/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tips
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tips
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Guerrettaz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-24 00:00:00.000000000 Z
11
+ date: 2015-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.5'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description: ''
@@ -45,10 +45,10 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - .gitignore
48
+ - ".gitignore"
49
49
  - Gemfile
50
50
  - LICENSE.txt
51
- - README.md
51
+ - README.markdown
52
52
  - Rakefile
53
53
  - app/assets/images/tip_throbber.png
54
54
  - app/assets/javascripts/tips.js
@@ -67,17 +67,17 @@ require_paths:
67
67
  - lib
68
68
  required_ruby_version: !ruby/object:Gem::Requirement
69
69
  requirements:
70
- - - '>='
70
+ - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: '0'
73
73
  required_rubygems_version: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - '>='
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  requirements: []
79
79
  rubyforge_project:
80
- rubygems_version: 2.4.1
80
+ rubygems_version: 2.2.3
81
81
  signing_key:
82
82
  specification_version: 4
83
83
  summary: Slack inspired onboarding tips
data/README.md DELETED
@@ -1,29 +0,0 @@
1
- # Tips
2
-
3
- TODO: Write a gem description
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'tips'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install tips
18
-
19
- ## Usage
20
-
21
- TODO: Write usage instructions here
22
-
23
- ## Contributing
24
-
25
- 1. Fork it ( http://github.com/<my-github-username>/tips/fork )
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request