tips 0.0.2 → 0.0.4

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: 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