notifly 0.1.1 → 0.1.2

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: 65940f99d804f1a248f21de334ca2cfd2eb749c3
4
- data.tar.gz: d4b365df60e2712776ee90b72eed3feee96e0905
3
+ metadata.gz: 079f1db58c119ea5ec0aa5b487c0aa45f6b24d61
4
+ data.tar.gz: b1a215bc6e1d3caccafedd29e86c2ee5e90467df
5
5
  SHA512:
6
- metadata.gz: 231ce6dc564754be301b7e682e42e4c26bea55fa2bac4676a8dfe9fefb7469edd720565ccd22051ea3c8d645471b41372139e282c6bbf59a724695ab7671ccdd
7
- data.tar.gz: c6f8ae0734c6162cbcbe13c92ccfbe3fd91528294e89cdd088d2cfe3e0c598b8d93ef5387759f445db032698f6b8b14deede3b810fc1e2c0de230ac95efad179
6
+ metadata.gz: 3aa005a8e84945e9228599e91a3b791a8ff8a9923af1cc5cff9e043e5bcd0e8a47ad9c17586ba5002183e2a28032be4b32d83f4ed93cc7ad48044f96ab3a2991
7
+ data.tar.gz: a31efb84696178c8126b037f221a4e0cab4e5f4e3f4779eea11071fbcc5422c04be383b9b8820769726dc9ff8e71a83a3d695828e315ede74707f816d1fda7bb
data/README.md CHANGED
@@ -161,7 +161,8 @@ end
161
161
  | `template: :foo` | send email using `foo` mail template and a notification using notifly template |
162
162
 
163
163
  Notiflies with `mail: { only: true }` will persist notifications, but them won't
164
- be in receivers notifications views. If you use [delayed_job](https://github.com/collectiveidea/delayed_job)
164
+ be in receivers notifications views. If you use
165
+ [delayed_job](https://github.com/collectiveidea/delayed_job)
165
166
  or [sidekiq](https://github.com/mperham/sidekiq) mails will be sent async.
166
167
 
167
168
  ### Notifications access
@@ -181,15 +182,33 @@ You can access the notifications using the following methods:
181
182
 
182
183
  ## Front-end
183
184
 
184
- First, you need to have a `current_user` in `ApplicationController`, if you use
185
- [Devise](https://github.com/plataformatec/devise) it is already there.
185
+ First, you need to have a `current_user`, if you use
186
+ [Devise](https://github.com/plataformatec/devise) maybe it is already there. If you
187
+ haven't a `current_user`, just define a method in `ApplicationController` and
188
+ add it to the helpers methods. Your controller should look like this:
186
189
 
187
- After that you need our assets, add them to your `application.js`
190
+ ```ruby
191
+ class ApplicationController < ActionController::Base
192
+ def current_user
193
+ current_talker
194
+ end
195
+
196
+ ActiveSupport.on_load(:action_controller) do
197
+ helper_method :current_user
198
+ end
199
+ end
200
+ ``
201
+
202
+ After that you need our assets, add them to your `application.js` and `application.css`.
188
203
 
189
204
  ```javascript
190
205
  //= require notifly
191
206
  ```
192
207
 
208
+ The `notifly` contain the code to do all requests and notifications injection, if
209
+ you do not use [Twitter bootstrap](http://getbootstrap.com/) you will need
210
+ to add `//= notifly_dropdown` to the code above.
211
+
193
212
  ```css
194
213
  /*
195
214
  *= require notifly
@@ -206,11 +225,7 @@ This will inject our views and it will be like that
206
225
 
207
226
  ![image](http://upl.io/i/4i26o3.png)
208
227
 
209
- Notifications and Mails are rendered with their templates. They use a simple default
210
- template but if you want to change or create new ones run the generate below
211
- with the option that you want or create them in `app/views/notifly/templates/`.
212
- Remember that notifications templates should be in `notifications` folder and
213
- mails templates in `mails` folder.
228
+ If you want to change something just use the code below
214
229
 
215
230
  ```shell
216
231
  $ rails generate notifly:views
@@ -222,6 +237,12 @@ mails templates in `mails` folder.
222
237
  | `--layout` | generates layout files |
223
238
  | `--mail` | generates mail templates files |
224
239
 
240
+ Notifications and Mails are rendered with their templates. They use a simple default
241
+ template but if you want to change or create new ones run the generate above
242
+ with the option that you want or create them in `app/views/notifly/templates/`.
243
+ Remember that notifications templates should be in `notifications` folder and
244
+ mails templates in `mails` folder.
245
+
225
246
  If you already have a layout and just want add our features to it, take a look
226
247
  at [Adapting your layout](#adapting).
227
248
 
@@ -235,11 +256,11 @@ you can change it in `config/locales/notifly.en.yaml` or create your own.
235
256
  All partials that we insert in your layout are in the gem or if you generated them,
236
257
  they will be in `app/views/notifly/layouts/`
237
258
 
238
- Above are the elements that will loading the Notifly in your layout
259
+ Below are the elements that will loading the Notifly in your layout
239
260
 
240
261
  - **Counter**: this element will show how many notifications are not seen. It
241
- should have the id `#notifly-counter`, and the html rendered in will be
242
- the `_counter.html.erb`
262
+ should have the id `#notifly-counter`, and it will be replaced by the
263
+ `_counter.html.erb`
243
264
  - **Notifications icon**: this element is the trigger to load the notifications
244
265
  and you should have an icon to show when the user "have notifications" and
245
266
  "do not have notifications" this element should have the id `#notifly-icon`. The
@@ -261,6 +282,10 @@ Above are the elements that will loading the Notifly in your layout
261
282
  - **Toggle read**: this link will be rendered by `_actions.html.erb' in
262
283
  `_notification.html.erb`
263
284
 
285
+ Those elements should be inside an element with id `#notifly` and the dropdown
286
+ trigger should have the id `#notifly-trigger`. For more info and examples, just
287
+ take a look at `_notifly.html.erb`
288
+
264
289
  # Contributing
265
290
 
266
291
  Consider to use [zenhub](https://www.zenhub.io/), with it will know what issues
@@ -1,5 +1,6 @@
1
1
  //= require 'jquery'
2
2
  //= require 'jquery_ujs'
3
+ //= require 'tinycon'
3
4
  //= require 'notifly/get_notifications'
4
5
  //= require 'notifly/seen_notifications'
5
6
  //= require 'notifly/read_notifications'
@@ -9,4 +10,6 @@ $(document).ready(function() {
9
10
  $(document).on('click', '#notifly-notifications-panel.dropdown-menu', function (e) {
10
11
  $('#notifly').hasClass('keep_open') && e.stopPropagation();
11
12
  });
13
+
14
+ Tinycon.setBubble(0);
12
15
  });
@@ -1 +1 @@
1
- //= require 'twitter/bootstrap'
1
+ //= require 'twitter/bootstrap/dropdown'
@@ -40,7 +40,8 @@ module Notifly
40
40
  end
41
41
 
42
42
  def current_user_notifications
43
- current_user.notifly_notifications.not_only_mail
43
+ @user = current_user
44
+ @user.notifly_notifications.not_only_mail
44
45
  end
45
46
 
46
47
  def count_unseen
@@ -4,7 +4,7 @@ module Notifly
4
4
  belongs_to :sender, polymorphic: true
5
5
  belongs_to :receiver, polymorphic: true
6
6
 
7
- before_validation :convert_data, :set_template
7
+ before_validation :convert_data, :set_template, :set_mail
8
8
 
9
9
  scope :all_from, -> (receiver) { where(receiver: receiver) }
10
10
  scope :unseen, -> { where(seen: false) }
@@ -44,5 +44,9 @@ module Notifly
44
44
  def set_template
45
45
  self.template ||= :default
46
46
  end
47
+
48
+ def set_mail
49
+ self.mail ||= :never
50
+ end
47
51
  end
48
52
  end
@@ -0,0 +1,3 @@
1
+ <div class="notifly-empty">
2
+ You have no notifications
3
+ </div>
@@ -1,5 +1,3 @@
1
- <!-- This partial requires the locals: receiver -->
2
-
3
1
  <div id="notifly" class="dropdown keep_open">
4
2
 
5
3
  <a id="notifly-trigger" href="#" class="dropdown-toggle" data-toggle="dropdown">
@@ -18,7 +16,7 @@
18
16
  </div>
19
17
 
20
18
  <div id="notifly-notifications-content">
21
- <div class="loading">Loading notifications...</div>
19
+ <div class="notifly-loading">Loading notifications...</div>
22
20
  </div>
23
21
 
24
22
  <div id="notifly-notifications-footer">
@@ -3,8 +3,10 @@
3
3
  <% last_notification = @notifications.last.try(:id) %>
4
4
  <% first_notification = @notifications.first.try(:id) %>
5
5
 
6
+ $('#notifly-notifications-content .notifly-loading').remove();
7
+ $('#notifly-notifications-content .notifly-empty').remove();
8
+
6
9
  <% if @notifications.any? %>
7
- $('#notifly-notifications-content .loading').remove();
8
10
 
9
11
  <% if @scope_param == 'older' %>
10
12
  $('#notifly-notifications-content').append("<%= j rendered_notifications %>");
@@ -20,14 +22,17 @@
20
22
  <% end %>
21
23
 
22
24
  <% else %>
23
- if (notiflyLastNotification == undefined)
25
+ if (notiflyLastNotification == undefined) {
24
26
  $('#notifly-more-notifications-link').remove();
27
+ $('#notifly-notifications-content').append("<%= j(render 'notifly/layouts/empty')%>")
28
+ }
25
29
 
26
30
  <% end %>
27
31
 
28
- <% if @scope_param == 'older' and Notifly::Notification.older(than: last_notification).blank? %>
32
+ <% if @scope_param == 'older' and @user.notifly_notifications.older(than: last_notification).blank? %>
29
33
  $('#notifly-more-notifications-link').remove();
30
34
  <% end %>
31
35
 
32
36
  $('#notifly-counter').replaceWith("<%= j(render 'notifly/layouts/counter', counter: @counter)%>");
33
37
  $('#notifly-icon').replaceWith("<%= j notifly_icon(@counter > 0) %>")
38
+ Tinycon.setBubble(<%= @counter %>);
@@ -1,2 +1,3 @@
1
1
  $('#notifly-counter').replaceWith("<%= j(render 'notifly/layouts/counter', counter: @counter)%>");
2
- $('#notifly-icon').replaceWith("<%= j notifly_icon(@counter > 0) %>")
2
+ $('#notifly-icon').replaceWith("<%= j notifly_icon(@counter > 0) %>");
3
+ Tinycon.setBubble(<%= @counter %>);
@@ -0,0 +1,279 @@
1
+ /*!
2
+ * Tinycon - A small library for manipulating the Favicon
3
+ * Tom Moor, http://tommoor.com
4
+ * Copyright (c) 2012 Tom Moor
5
+ * @license MIT Licensed
6
+ * @version 0.6.3
7
+ */
8
+
9
+ (function(){
10
+
11
+ var Tinycon = {};
12
+ var currentFavicon = null;
13
+ var originalFavicon = null;
14
+ var faviconImage = null;
15
+ var canvas = null;
16
+ var options = {};
17
+ var r = window.devicePixelRatio || 1;
18
+ var size = 16 * r;
19
+ var defaults = {
20
+ width: 7,
21
+ height: 9,
22
+ font: 10 * r + 'px arial',
23
+ colour: '#ffffff',
24
+ background: '#F03D25',
25
+ fallback: true,
26
+ crossOrigin: true,
27
+ abbreviate: true
28
+ };
29
+
30
+ var ua = (function () {
31
+ var agent = navigator.userAgent.toLowerCase();
32
+ // New function has access to 'agent' via closure
33
+ return function (browser) {
34
+ return agent.indexOf(browser) !== -1;
35
+ };
36
+ }());
37
+
38
+ var browser = {
39
+ ie: ua('msie'),
40
+ chrome: ua('chrome'),
41
+ webkit: ua('chrome') || ua('safari'),
42
+ safari: ua('safari') && !ua('chrome'),
43
+ mozilla: ua('mozilla') && !ua('chrome') && !ua('safari')
44
+ };
45
+
46
+ // private methods
47
+ var getFaviconTag = function(){
48
+
49
+ var links = document.getElementsByTagName('link');
50
+
51
+ for(var i=0, len=links.length; i < len; i++) {
52
+ if ((links[i].getAttribute('rel') || '').match(/\bicon\b/)) {
53
+ return links[i];
54
+ }
55
+ }
56
+
57
+ return false;
58
+ };
59
+
60
+ var removeFaviconTag = function(){
61
+
62
+ var links = document.getElementsByTagName('link');
63
+ var head = document.getElementsByTagName('head')[0];
64
+
65
+ for(var i=0, len=links.length; i < len; i++) {
66
+ var exists = (typeof(links[i]) !== 'undefined');
67
+ if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/)) {
68
+ head.removeChild(links[i]);
69
+ }
70
+ }
71
+ };
72
+
73
+ var getCurrentFavicon = function(){
74
+
75
+ if (!originalFavicon || !currentFavicon) {
76
+ var tag = getFaviconTag();
77
+ originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico';
78
+ }
79
+
80
+ return currentFavicon;
81
+ };
82
+
83
+ var getCanvas = function (){
84
+
85
+ if (!canvas) {
86
+ canvas = document.createElement("canvas");
87
+ canvas.width = size;
88
+ canvas.height = size;
89
+ }
90
+
91
+ return canvas;
92
+ };
93
+
94
+ var setFaviconTag = function(url){
95
+ removeFaviconTag();
96
+
97
+ var link = document.createElement('link');
98
+ link.type = 'image/x-icon';
99
+ link.rel = 'icon';
100
+ link.href = url;
101
+ document.getElementsByTagName('head')[0].appendChild(link);
102
+ };
103
+
104
+ var log = function(message){
105
+ if (window.console) window.console.log(message);
106
+ };
107
+
108
+ var drawFavicon = function(label, colour) {
109
+
110
+ // fallback to updating the browser title if unsupported
111
+ if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === 'force') {
112
+ return updateTitle(label);
113
+ }
114
+
115
+ var context = getCanvas().getContext("2d");
116
+ var colour = colour || '#000000';
117
+ var src = getCurrentFavicon();
118
+
119
+ faviconImage = document.createElement('img');
120
+ faviconImage.onload = function() {
121
+
122
+ // clear canvas
123
+ context.clearRect(0, 0, size, size);
124
+
125
+ // draw the favicon
126
+ context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, size, size);
127
+
128
+ // draw bubble over the top
129
+ if ((label + '').length > 0) drawBubble(context, label, colour);
130
+
131
+ // refresh tag in page
132
+ refreshFavicon();
133
+ };
134
+
135
+ // allow cross origin resource requests if the image is not a data:uri
136
+ // as detailed here: https://github.com/mrdoob/three.js/issues/1305
137
+ if (!src.match(/^data/) && options.crossOrigin) {
138
+ faviconImage.crossOrigin = 'anonymous';
139
+ }
140
+
141
+ faviconImage.src = src;
142
+ };
143
+
144
+ var updateTitle = function(label) {
145
+
146
+ if (options.fallback) {
147
+ // Grab the current title that we can prefix with the label
148
+ var originalTitle = document.title;
149
+
150
+ // Strip out the old label if there is one
151
+ if (originalTitle[0] === '(') {
152
+ originalTitle = originalTitle.slice(originalTitle.indexOf(' '));
153
+ }
154
+
155
+ if ((label + '').length > 0) {
156
+ document.title = '(' + label + ') ' + originalTitle;
157
+ } else {
158
+ document.title = originalTitle;
159
+ }
160
+ }
161
+ };
162
+
163
+ var drawBubble = function(context, label, colour) {
164
+
165
+ // automatic abbreviation for long (>2 digits) numbers
166
+ if (typeof label == 'number' && label > 99 && options.abbreviate) {
167
+ label = abbreviateNumber(label);
168
+ }
169
+
170
+ // bubble needs to be larger for double digits
171
+ var len = (label + '').length-1;
172
+
173
+ var width = options.width * r + (6 * r * len),
174
+ height = options.height * r;
175
+
176
+ var top = size - height,
177
+ left = size - width - r,
178
+ bottom = 16 * r,
179
+ right = 16 * r,
180
+ radius = 2 * r;
181
+
182
+ // webkit seems to render fonts lighter than firefox
183
+ context.font = (browser.webkit ? 'bold ' : '') + options.font;
184
+ context.fillStyle = options.background;
185
+ context.strokeStyle = options.background;
186
+ context.lineWidth = r;
187
+
188
+ // bubble
189
+ context.beginPath();
190
+ context.moveTo(left + radius, top);
191
+ context.quadraticCurveTo(left, top, left, top + radius);
192
+ context.lineTo(left, bottom - radius);
193
+ context.quadraticCurveTo(left, bottom, left + radius, bottom);
194
+ context.lineTo(right - radius, bottom);
195
+ context.quadraticCurveTo(right, bottom, right, bottom - radius);
196
+ context.lineTo(right, top + radius);
197
+ context.quadraticCurveTo(right, top, right - radius, top);
198
+ context.closePath();
199
+ context.fill();
200
+
201
+ // bottom shadow
202
+ context.beginPath();
203
+ context.strokeStyle = "rgba(0,0,0,0.3)";
204
+ context.moveTo(left + radius / 2.0, bottom);
205
+ context.lineTo(right - radius / 2.0, bottom);
206
+ context.stroke();
207
+
208
+ // label
209
+ context.fillStyle = options.colour;
210
+ context.textAlign = "right";
211
+ context.textBaseline = "top";
212
+
213
+ // unfortunately webkit/mozilla are a pixel different in text positioning
214
+ context.fillText(label, r === 2 ? 29 : 15, browser.mozilla ? 7*r : 6*r);
215
+ };
216
+
217
+ var refreshFavicon = function(){
218
+ // check support
219
+ if (!getCanvas().getContext) return;
220
+
221
+ setFaviconTag(getCanvas().toDataURL());
222
+ };
223
+
224
+ var abbreviateNumber = function(label) {
225
+ var metricPrefixes = [
226
+ ['G', 1000000000],
227
+ ['M', 1000000],
228
+ ['k', 1000]
229
+ ];
230
+
231
+ for(var i = 0; i < metricPrefixes.length; ++i) {
232
+ if (label >= metricPrefixes[i][1]) {
233
+ label = round(label / metricPrefixes[i][1]) + metricPrefixes[i][0];
234
+ break;
235
+ }
236
+ }
237
+
238
+ return label;
239
+ };
240
+
241
+ var round = function (value, precision) {
242
+ var number = new Number(value);
243
+ return number.toFixed(precision);
244
+ };
245
+
246
+ // public methods
247
+ Tinycon.setOptions = function(custom){
248
+ options = {};
249
+
250
+ for(var key in defaults){
251
+ options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key];
252
+ }
253
+ return this;
254
+ };
255
+
256
+ Tinycon.setImage = function(url){
257
+ currentFavicon = url;
258
+ refreshFavicon();
259
+ return this;
260
+ };
261
+
262
+ Tinycon.setBubble = function(label, colour) {
263
+ label = label || '';
264
+ drawFavicon(label, colour);
265
+ return this;
266
+ };
267
+
268
+ Tinycon.reset = function(){
269
+ setFaviconTag(originalFavicon);
270
+ };
271
+
272
+ Tinycon.setOptions(defaults);
273
+ window.Tinycon = Tinycon;
274
+
275
+ if(typeof define === 'function' && define.amd) {
276
+ define(Tinycon);
277
+ }
278
+
279
+ })();
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: notifly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Passalini
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-12-09 00:00:00.000000000 Z
12
+ date: 2014-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -73,62 +73,6 @@ dependencies:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- - !ruby/object:Gem::Dependency
77
- name: rspec-rails
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 3.1.0
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 3.1.0
90
- - !ruby/object:Gem::Dependency
91
- name: capybara
92
- requirement: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 2.4.4
97
- type: :development
98
- prerelease: false
99
- version_requirements: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 2.4.4
104
- - !ruby/object:Gem::Dependency
105
- name: poltergeist
106
- requirement: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 1.5.1
111
- type: :development
112
- prerelease: false
113
- version_requirements: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 1.5.1
118
- - !ruby/object:Gem::Dependency
119
- name: shoulda-matchers
120
- requirement: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 2.7.0
125
- type: :development
126
- prerelease: false
127
- version_requirements: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 2.7.0
132
76
  - !ruby/object:Gem::Dependency
133
77
  name: pry-rails
134
78
  requirement: !ruby/object:Gem::Requirement
@@ -171,20 +115,6 @@ dependencies:
171
115
  - - ">="
172
116
  - !ruby/object:Gem::Version
173
117
  version: '0'
174
- - !ruby/object:Gem::Dependency
175
- name: launchy
176
- requirement: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
- type: :development
182
- prerelease: false
183
- version_requirements: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - ">="
186
- - !ruby/object:Gem::Version
187
- version: '0'
188
118
  - !ruby/object:Gem::Dependency
189
119
  name: better_errors
190
120
  requirement: !ruby/object:Gem::Requirement
@@ -255,6 +185,7 @@ files:
255
185
  - app/models/notifly/notification.rb
256
186
  - app/views/notifly/layouts/_actions.html.erb
257
187
  - app/views/notifly/layouts/_counter.html.erb
188
+ - app/views/notifly/layouts/_empty.html.erb
258
189
  - app/views/notifly/layouts/_index.html.erb
259
190
  - app/views/notifly/layouts/_notification.html.erb
260
191
  - app/views/notifly/layouts/_notifly.html.erb
@@ -284,7 +215,8 @@ files:
284
215
  - lib/notifly/models/options/fly.rb
285
216
  - lib/notifly/railtie.rb
286
217
  - lib/tasks/notifly_tasks.rake
287
- - vendor/assets/javascripts/twitter/bootstrap.js
218
+ - vendor/assets/javascripts/tinycon.js
219
+ - vendor/assets/javascripts/twitter/bootstrap/dropdown.js
288
220
  - vendor/assets/stylesheets/twitter/bootstrap.css
289
221
  homepage: https://github.com/algorich/notifly
290
222
  licenses: