the_notification 0.0.1
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/the_notification.js.coffee +40 -0
- data/app/assets/javascripts/the_notification/vendors/toastr.js +306 -0
- data/app/assets/stylesheets/the_notification.css.scss +37 -0
- data/app/assets/stylesheets/the_notification/vendors/toastr.css +183 -0
- data/app/helpers/the_notification_helper.rb +11 -0
- data/app/models/concerns/localized_errors.rb +21 -0
- data/app/views/the_notification/_flash.html.slim +18 -0
- data/app/views/the_notification/_form.html.slim +28 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/ru.yml +3 -0
- data/gem_version.rb +3 -0
- data/lib/the_notification.rb +13 -0
- data/lib/the_notification/config.rb +20 -0
- data/lib/the_notification/version.rb +1 -0
- data/the_notification.gemspec +25 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5bc2d717d5e0cc126b7c8dc93351f47fec2f1272
|
4
|
+
data.tar.gz: 6eb52510b458ed2aed7d0370b55820b8bf62bec6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 64b1389ee3867e58dfcb6403014c1a0b5e48b93fb35e4528ac55e40d5aa4d572800a75e4db8f054d45aec3a00b9e986d06225ce937a8b231009db86a140ee4e5
|
7
|
+
data.tar.gz: 37b5e61f3cbfa23aa3c365d9da9951dcad38cb4cde1ef51ed54e022ea17c71ca122c16f12723335076e63efeac726251a072e1f18fd3cd602e9cb704f482330c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ilya N. Zykin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
## TheNotification
|
2
|
+
|
3
|
+
Just add JSON on HTML notifications in your APP
|
4
|
+
|
5
|
+
Designed for Bootstrap 3 style of for toastr notifications
|
6
|
+
|
7
|
+
## How it works
|
8
|
+
|
9
|
+
Just remove
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
<%= form_for(@resource) do |f| %>
|
13
|
+
<% if @resource.errors.any? %>
|
14
|
+
<div id="error_explanation">
|
15
|
+
<h2><%= pluralize(@resource.errors.count, "error") %> prohibited this resource from being saved:</h2>
|
16
|
+
|
17
|
+
<ul>
|
18
|
+
<% @resource.errors.full_messages.each do |msg| %>
|
19
|
+
<li><%= msg %></li>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
22
|
+
</div>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
# ....
|
26
|
+
|
27
|
+
<% end %>
|
28
|
+
```
|
29
|
+
|
30
|
+
with
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
<%= form_for(@post) do |f| %>
|
34
|
+
<%= render partial: 'the_notification/form', locals: { object: @post } %>
|
35
|
+
|
36
|
+
# ....
|
37
|
+
|
38
|
+
<% end %>
|
39
|
+
```
|
40
|
+
|
41
|
+
and add to Layout
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
<body>
|
45
|
+
<%= render partial: 'the_notification/flash' %>
|
46
|
+
<%= yield %>
|
47
|
+
```
|
48
|
+
|
49
|
+
*application.js*
|
50
|
+
```js
|
51
|
+
//= require the_notification/vendors/toastr
|
52
|
+
//= require the_notification
|
53
|
+
```
|
54
|
+
|
55
|
+
*application.css*
|
56
|
+
```js
|
57
|
+
*= require bootstrap
|
58
|
+
*= require the_notification/vendors/toastr
|
59
|
+
```
|
60
|
+
|
61
|
+
### HTML or JSON
|
62
|
+
|
63
|
+
```erb
|
64
|
+
<%= render partial: 'the_notification/flash' locals: { format: :html } %>
|
65
|
+
<%= render partial: 'the_notification/form', locals: { object: @post, format: :html } %>
|
66
|
+
```
|
67
|
+
|
68
|
+
or
|
69
|
+
|
70
|
+
```erb
|
71
|
+
<%= render partial: 'the_notification/flash' locals: { format: :json } %>
|
72
|
+
<%= render partial: 'the_notification/form', locals: { object: @post, format: :json } %>
|
73
|
+
```
|
74
|
+
|
75
|
+
*initializers/the_notification.rb*
|
76
|
+
```ruby
|
77
|
+
TheNotification.configure do |config|
|
78
|
+
config.default_type = :json # :html
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
### Localized errors
|
83
|
+
|
84
|
+
*models/user.rb*
|
85
|
+
```ruby
|
86
|
+
class Post < ActiveRecord::Base
|
87
|
+
include TheNotification::LocalizedErrors
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
*config/locales/ru.yml*
|
92
|
+
```
|
93
|
+
activerecord:
|
94
|
+
models:
|
95
|
+
post: Публикация
|
96
|
+
attributes:
|
97
|
+
post:
|
98
|
+
title: "Загловок"
|
99
|
+
```
|
100
|
+
|
101
|
+
Now errors messages will looks like this:
|
102
|
+
|
103
|
+
```
|
104
|
+
Загловок: не может быть пустым
|
105
|
+
```
|
106
|
+
|
107
|
+
instead
|
108
|
+
|
109
|
+
```
|
110
|
+
Title: не может быть пустым
|
111
|
+
```
|
112
|
+
|
113
|
+
### Installation
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
gem 'the_notification'
|
117
|
+
```
|
118
|
+
|
119
|
+
```sh
|
120
|
+
$ bundle
|
121
|
+
```
|
122
|
+
|
123
|
+
### Usage
|
124
|
+
|
125
|
+
TODO: Write usage instructions here
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
@TheNotification = do ->
|
2
|
+
show_error: (error) ->
|
3
|
+
toastr.error(error) if error
|
4
|
+
|
5
|
+
show_errors: (errors) ->
|
6
|
+
for field, errs of errors
|
7
|
+
for err in errs
|
8
|
+
toastr.error "<b>#{ field }:</b> #{ err }"
|
9
|
+
|
10
|
+
show_flash: (flash) ->
|
11
|
+
fu =
|
12
|
+
notice: 'info'
|
13
|
+
errors: 'error'
|
14
|
+
error: 'error'
|
15
|
+
warning: 'warning'
|
16
|
+
alert: 'warning'
|
17
|
+
|
18
|
+
for level, msg of flash
|
19
|
+
method = fu[level] || 'info'
|
20
|
+
|
21
|
+
if msg instanceof Array
|
22
|
+
for _msg in msg
|
23
|
+
toastr[method] _msg
|
24
|
+
else
|
25
|
+
toastr[method] msg
|
26
|
+
|
27
|
+
show_notifications: ->
|
28
|
+
data = window.the_notifications
|
29
|
+
return false unless data
|
30
|
+
|
31
|
+
@show_errors errors if errors = data.errors
|
32
|
+
@show_flash flash if flash = data.flash
|
33
|
+
|
34
|
+
click_for_close_init: ->
|
35
|
+
$('.flash_msgs, .error_explanation').on 'click', ->
|
36
|
+
$(@).slideUp(500)
|
37
|
+
|
38
|
+
init: ->
|
39
|
+
do @click_for_close_init
|
40
|
+
do @show_notifications
|
@@ -0,0 +1,306 @@
|
|
1
|
+
/*
|
2
|
+
* Toastr
|
3
|
+
* Version 2.0.1
|
4
|
+
* Copyright 2012 John Papa and Hans Fjällemark.
|
5
|
+
* All Rights Reserved.
|
6
|
+
* Use, reproduction, distribution, and modification of this code is subject to the terms and
|
7
|
+
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
|
8
|
+
*
|
9
|
+
* Author: John Papa and Hans Fjällemark
|
10
|
+
* Project: https://github.com/CodeSeven/toastr
|
11
|
+
*/
|
12
|
+
; (function (define) {
|
13
|
+
define(['jquery'], function ($) {
|
14
|
+
return (function () {
|
15
|
+
var version = '2.0.1';
|
16
|
+
var $container;
|
17
|
+
var listener;
|
18
|
+
var toastId = 0;
|
19
|
+
var toastType = {
|
20
|
+
error: 'error',
|
21
|
+
info: 'info',
|
22
|
+
success: 'success',
|
23
|
+
warning: 'warning'
|
24
|
+
};
|
25
|
+
|
26
|
+
var toastr = {
|
27
|
+
clear: clear,
|
28
|
+
error: error,
|
29
|
+
getContainer: getContainer,
|
30
|
+
info: info,
|
31
|
+
options: {},
|
32
|
+
subscribe: subscribe,
|
33
|
+
success: success,
|
34
|
+
version: version,
|
35
|
+
warning: warning
|
36
|
+
};
|
37
|
+
|
38
|
+
return toastr;
|
39
|
+
|
40
|
+
//#region Accessible Methods
|
41
|
+
function error(message, title, optionsOverride) {
|
42
|
+
return notify({
|
43
|
+
type: toastType.error,
|
44
|
+
iconClass: getOptions().iconClasses.error,
|
45
|
+
message: message,
|
46
|
+
optionsOverride: optionsOverride,
|
47
|
+
title: title
|
48
|
+
});
|
49
|
+
}
|
50
|
+
|
51
|
+
function info(message, title, optionsOverride) {
|
52
|
+
return notify({
|
53
|
+
type: toastType.info,
|
54
|
+
iconClass: getOptions().iconClasses.info,
|
55
|
+
message: message,
|
56
|
+
optionsOverride: optionsOverride,
|
57
|
+
title: title
|
58
|
+
});
|
59
|
+
}
|
60
|
+
|
61
|
+
function subscribe(callback) {
|
62
|
+
listener = callback;
|
63
|
+
}
|
64
|
+
|
65
|
+
function success(message, title, optionsOverride) {
|
66
|
+
return notify({
|
67
|
+
type: toastType.success,
|
68
|
+
iconClass: getOptions().iconClasses.success,
|
69
|
+
message: message,
|
70
|
+
optionsOverride: optionsOverride,
|
71
|
+
title: title
|
72
|
+
});
|
73
|
+
}
|
74
|
+
|
75
|
+
function warning(message, title, optionsOverride) {
|
76
|
+
return notify({
|
77
|
+
type: toastType.warning,
|
78
|
+
iconClass: getOptions().iconClasses.warning,
|
79
|
+
message: message,
|
80
|
+
optionsOverride: optionsOverride,
|
81
|
+
title: title
|
82
|
+
});
|
83
|
+
}
|
84
|
+
|
85
|
+
function clear($toastElement) {
|
86
|
+
var options = getOptions();
|
87
|
+
if (!$container) { getContainer(options); }
|
88
|
+
if ($toastElement && $(':focus', $toastElement).length === 0) {
|
89
|
+
$toastElement[options.hideMethod]({
|
90
|
+
duration: options.hideDuration,
|
91
|
+
easing: options.hideEasing,
|
92
|
+
complete: function () { removeToast($toastElement); }
|
93
|
+
});
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
if ($container.children().length) {
|
97
|
+
$container[options.hideMethod]({
|
98
|
+
duration: options.hideDuration,
|
99
|
+
easing: options.hideEasing,
|
100
|
+
complete: function () { $container.remove(); }
|
101
|
+
});
|
102
|
+
}
|
103
|
+
}
|
104
|
+
//#endregion
|
105
|
+
|
106
|
+
//#region Internal Methods
|
107
|
+
|
108
|
+
function getDefaults() {
|
109
|
+
return {
|
110
|
+
tapToDismiss: true,
|
111
|
+
toastClass: 'toast',
|
112
|
+
containerId: 'toast-container',
|
113
|
+
debug: false,
|
114
|
+
|
115
|
+
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
|
116
|
+
showDuration: 300,
|
117
|
+
showEasing: 'swing', //swing and linear are built into jQuery
|
118
|
+
onShown: undefined,
|
119
|
+
hideMethod: 'fadeOut',
|
120
|
+
hideDuration: 1000,
|
121
|
+
hideEasing: 'swing',
|
122
|
+
onHidden: undefined,
|
123
|
+
|
124
|
+
extendedTimeOut: 1000,
|
125
|
+
iconClasses: {
|
126
|
+
error: 'toast-error',
|
127
|
+
info: 'toast-info',
|
128
|
+
success: 'toast-success',
|
129
|
+
warning: 'toast-warning'
|
130
|
+
},
|
131
|
+
iconClass: 'toast-info',
|
132
|
+
positionClass: 'toast-top-right',
|
133
|
+
timeOut: 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
|
134
|
+
titleClass: 'toast-title',
|
135
|
+
messageClass: 'toast-message',
|
136
|
+
target: 'body',
|
137
|
+
closeHtml: '<button>×</button>',
|
138
|
+
newestOnTop: true
|
139
|
+
};
|
140
|
+
}
|
141
|
+
|
142
|
+
function publish(args) {
|
143
|
+
if (!listener) {
|
144
|
+
return;
|
145
|
+
}
|
146
|
+
listener(args);
|
147
|
+
}
|
148
|
+
|
149
|
+
function notify(map) {
|
150
|
+
var
|
151
|
+
options = getOptions(),
|
152
|
+
iconClass = map.iconClass || options.iconClass;
|
153
|
+
|
154
|
+
if (typeof (map.optionsOverride) !== 'undefined') {
|
155
|
+
options = $.extend(options, map.optionsOverride);
|
156
|
+
iconClass = map.optionsOverride.iconClass || iconClass;
|
157
|
+
}
|
158
|
+
|
159
|
+
toastId++;
|
160
|
+
|
161
|
+
$container = getContainer(options);
|
162
|
+
var
|
163
|
+
intervalId = null,
|
164
|
+
$toastElement = $('<div/>'),
|
165
|
+
$titleElement = $('<div/>'),
|
166
|
+
$messageElement = $('<div/>'),
|
167
|
+
$closeElement = $(options.closeHtml),
|
168
|
+
response = {
|
169
|
+
toastId: toastId,
|
170
|
+
state: 'visible',
|
171
|
+
startTime: new Date(),
|
172
|
+
options: options,
|
173
|
+
map: map
|
174
|
+
};
|
175
|
+
|
176
|
+
if (map.iconClass) {
|
177
|
+
$toastElement.addClass(options.toastClass).addClass(iconClass);
|
178
|
+
}
|
179
|
+
|
180
|
+
if (map.title) {
|
181
|
+
$titleElement.append(map.title).addClass(options.titleClass);
|
182
|
+
$toastElement.append($titleElement);
|
183
|
+
}
|
184
|
+
|
185
|
+
if (map.message) {
|
186
|
+
$messageElement.append(map.message).addClass(options.messageClass);
|
187
|
+
$toastElement.append($messageElement);
|
188
|
+
}
|
189
|
+
|
190
|
+
if (options.closeButton) {
|
191
|
+
$closeElement.addClass('toast-close-button');
|
192
|
+
$toastElement.prepend($closeElement);
|
193
|
+
}
|
194
|
+
|
195
|
+
$toastElement.hide();
|
196
|
+
if (options.newestOnTop) {
|
197
|
+
$container.prepend($toastElement);
|
198
|
+
} else {
|
199
|
+
$container.append($toastElement);
|
200
|
+
}
|
201
|
+
|
202
|
+
|
203
|
+
$toastElement[options.showMethod](
|
204
|
+
{ duration: options.showDuration, easing: options.showEasing, complete: options.onShown }
|
205
|
+
);
|
206
|
+
if (options.timeOut > 0) {
|
207
|
+
intervalId = setTimeout(hideToast, options.timeOut);
|
208
|
+
}
|
209
|
+
|
210
|
+
$toastElement.hover(stickAround, delayedhideToast);
|
211
|
+
if (!options.onclick && options.tapToDismiss) {
|
212
|
+
$toastElement.click(hideToast);
|
213
|
+
}
|
214
|
+
if (options.closeButton && $closeElement) {
|
215
|
+
$closeElement.click(function (event) {
|
216
|
+
event.stopPropagation();
|
217
|
+
hideToast(true);
|
218
|
+
});
|
219
|
+
}
|
220
|
+
|
221
|
+
if (options.onclick) {
|
222
|
+
$toastElement.click(function () {
|
223
|
+
options.onclick();
|
224
|
+
hideToast();
|
225
|
+
});
|
226
|
+
}
|
227
|
+
|
228
|
+
publish(response);
|
229
|
+
|
230
|
+
if (options.debug && console) {
|
231
|
+
console.log(response);
|
232
|
+
}
|
233
|
+
|
234
|
+
return $toastElement;
|
235
|
+
|
236
|
+
function hideToast(override) {
|
237
|
+
if ($(':focus', $toastElement).length && !override) {
|
238
|
+
return;
|
239
|
+
}
|
240
|
+
return $toastElement[options.hideMethod]({
|
241
|
+
duration: options.hideDuration,
|
242
|
+
easing: options.hideEasing,
|
243
|
+
complete: function () {
|
244
|
+
removeToast($toastElement);
|
245
|
+
if (options.onHidden) {
|
246
|
+
options.onHidden();
|
247
|
+
}
|
248
|
+
response.state = 'hidden';
|
249
|
+
response.endTime = new Date(),
|
250
|
+
publish(response);
|
251
|
+
}
|
252
|
+
});
|
253
|
+
}
|
254
|
+
|
255
|
+
function delayedhideToast() {
|
256
|
+
if (options.timeOut > 0 || options.extendedTimeOut > 0) {
|
257
|
+
intervalId = setTimeout(hideToast, options.extendedTimeOut);
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
function stickAround() {
|
262
|
+
clearTimeout(intervalId);
|
263
|
+
$toastElement.stop(true, true)[options.showMethod](
|
264
|
+
{ duration: options.showDuration, easing: options.showEasing }
|
265
|
+
);
|
266
|
+
}
|
267
|
+
}
|
268
|
+
function getContainer(options) {
|
269
|
+
if (!options) { options = getOptions(); }
|
270
|
+
$container = $('#' + options.containerId);
|
271
|
+
if ($container.length) {
|
272
|
+
return $container;
|
273
|
+
}
|
274
|
+
$container = $('<div/>')
|
275
|
+
.attr('id', options.containerId)
|
276
|
+
.addClass(options.positionClass);
|
277
|
+
$container.appendTo($(options.target));
|
278
|
+
return $container;
|
279
|
+
}
|
280
|
+
|
281
|
+
function getOptions() {
|
282
|
+
return $.extend({}, getDefaults(), toastr.options);
|
283
|
+
}
|
284
|
+
|
285
|
+
function removeToast($toastElement) {
|
286
|
+
if (!$container) { $container = getContainer(); }
|
287
|
+
if ($toastElement.is(':visible')) {
|
288
|
+
return;
|
289
|
+
}
|
290
|
+
$toastElement.remove();
|
291
|
+
$toastElement = null;
|
292
|
+
if ($container.children().length === 0) {
|
293
|
+
$container.remove();
|
294
|
+
}
|
295
|
+
}
|
296
|
+
//#endregion
|
297
|
+
|
298
|
+
})();
|
299
|
+
});
|
300
|
+
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
|
301
|
+
if (typeof module !== 'undefined' && module.exports) { //Node
|
302
|
+
module.exports = factory(require(deps[0]));
|
303
|
+
} else {
|
304
|
+
window['toastr'] = factory(window['jQuery']);
|
305
|
+
}
|
306
|
+
}));
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.flash_msgs{
|
2
|
+
padding: 10px 10px 0px 10px;
|
3
|
+
margin-bottom: 15px;
|
4
|
+
border-radius: 5px;
|
5
|
+
cursor: pointer;
|
6
|
+
|
7
|
+
&.alert-info{
|
8
|
+
border: 3px solid #3A87AD;
|
9
|
+
color: #3A87AD;
|
10
|
+
|
11
|
+
p{
|
12
|
+
font-size: 14px;
|
13
|
+
line-height: 130%;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
.error_explanation.alert-danger{
|
19
|
+
border: 3px solid #B94A48;
|
20
|
+
color: #B94A48;
|
21
|
+
|
22
|
+
padding: 10px 10px 0px 10px;
|
23
|
+
margin-bottom: 15px;
|
24
|
+
border-radius: 5px;
|
25
|
+
cursor: pointer;
|
26
|
+
|
27
|
+
ul{
|
28
|
+
margin-left: 15px;
|
29
|
+
padding-bottom: 0.1px;
|
30
|
+
list-style: disc inside none;
|
31
|
+
}
|
32
|
+
li{
|
33
|
+
font-size: 14px;
|
34
|
+
line-height: 130%;
|
35
|
+
margin-bottom: 15px;
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,183 @@
|
|
1
|
+
/*
|
2
|
+
* Toastr
|
3
|
+
* Version 2.0.1
|
4
|
+
* Copyright 2012 John Papa and Hans Fjällemark.
|
5
|
+
* All Rights Reserved.
|
6
|
+
* Use, reproduction, distribution, and modification of this code is subject to the terms and
|
7
|
+
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
|
8
|
+
*
|
9
|
+
* Author: John Papa and Hans Fjällemark
|
10
|
+
* Project: https://github.com/CodeSeven/toastr
|
11
|
+
*/
|
12
|
+
.toast-title {
|
13
|
+
font-weight: bold;
|
14
|
+
}
|
15
|
+
.toast-message {
|
16
|
+
-ms-word-wrap: break-word;
|
17
|
+
word-wrap: break-word;
|
18
|
+
}
|
19
|
+
.toast-message a,
|
20
|
+
.toast-message label {
|
21
|
+
color: #ffffff;
|
22
|
+
}
|
23
|
+
.toast-message a:hover {
|
24
|
+
color: #cccccc;
|
25
|
+
text-decoration: none;
|
26
|
+
}
|
27
|
+
|
28
|
+
.toast-close-button {
|
29
|
+
position: relative;
|
30
|
+
right: -0.3em;
|
31
|
+
top: -0.3em;
|
32
|
+
float: right;
|
33
|
+
font-size: 20px;
|
34
|
+
font-weight: bold;
|
35
|
+
color: #ffffff;
|
36
|
+
-webkit-text-shadow: 0 1px 0 #ffffff;
|
37
|
+
text-shadow: 0 1px 0 #ffffff;
|
38
|
+
opacity: 0.8;
|
39
|
+
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
|
40
|
+
filter: alpha(opacity=80);
|
41
|
+
}
|
42
|
+
.toast-close-button:hover,
|
43
|
+
.toast-close-button:focus {
|
44
|
+
color: #000000;
|
45
|
+
text-decoration: none;
|
46
|
+
cursor: pointer;
|
47
|
+
opacity: 0.4;
|
48
|
+
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
|
49
|
+
filter: alpha(opacity=40);
|
50
|
+
}
|
51
|
+
|
52
|
+
/*Additional properties for button version
|
53
|
+
iOS requires the button element instead of an anchor tag.
|
54
|
+
If you want the anchor version, it requires `href="#"`.*/
|
55
|
+
button.toast-close-button {
|
56
|
+
padding: 0;
|
57
|
+
cursor: pointer;
|
58
|
+
background: transparent;
|
59
|
+
border: 0;
|
60
|
+
-webkit-appearance: none;
|
61
|
+
}
|
62
|
+
.toast-top-full-width {
|
63
|
+
top: 0;
|
64
|
+
right: 0;
|
65
|
+
width: 100%;
|
66
|
+
}
|
67
|
+
.toast-bottom-full-width {
|
68
|
+
bottom: 0;
|
69
|
+
right: 0;
|
70
|
+
width: 100%;
|
71
|
+
}
|
72
|
+
.toast-top-left {
|
73
|
+
top: 12px;
|
74
|
+
left: 12px;
|
75
|
+
}
|
76
|
+
.toast-top-right {
|
77
|
+
top: 12px;
|
78
|
+
right: 12px;
|
79
|
+
}
|
80
|
+
.toast-bottom-right {
|
81
|
+
right: 12px;
|
82
|
+
bottom: 12px;
|
83
|
+
}
|
84
|
+
.toast-bottom-left {
|
85
|
+
bottom: 12px;
|
86
|
+
left: 12px;
|
87
|
+
}
|
88
|
+
#toast-container {
|
89
|
+
position: fixed;
|
90
|
+
z-index: 999999;
|
91
|
+
/*overrides*/
|
92
|
+
|
93
|
+
}
|
94
|
+
#toast-container * {
|
95
|
+
-moz-box-sizing: border-box;
|
96
|
+
-webkit-box-sizing: border-box;
|
97
|
+
box-sizing: border-box;
|
98
|
+
}
|
99
|
+
#toast-container > div {
|
100
|
+
margin: 0 0 6px;
|
101
|
+
padding: 15px 15px 15px 50px;
|
102
|
+
width: 300px;
|
103
|
+
-moz-border-radius: 3px 3px 3px 3px;
|
104
|
+
-webkit-border-radius: 3px 3px 3px 3px;
|
105
|
+
border-radius: 3px 3px 3px 3px;
|
106
|
+
background-position: 15px center;
|
107
|
+
background-repeat: no-repeat;
|
108
|
+
-moz-box-shadow: 0 0 12px #999999;
|
109
|
+
-webkit-box-shadow: 0 0 12px #999999;
|
110
|
+
box-shadow: 0 0 12px #999999;
|
111
|
+
color: #ffffff;
|
112
|
+
opacity: 0.8;
|
113
|
+
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
|
114
|
+
filter: alpha(opacity=80);
|
115
|
+
}
|
116
|
+
#toast-container > :hover {
|
117
|
+
-moz-box-shadow: 0 0 12px #000000;
|
118
|
+
-webkit-box-shadow: 0 0 12px #000000;
|
119
|
+
box-shadow: 0 0 12px #000000;
|
120
|
+
opacity: 1;
|
121
|
+
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
122
|
+
filter: alpha(opacity=100);
|
123
|
+
cursor: pointer;
|
124
|
+
}
|
125
|
+
#toast-container > .toast-info {
|
126
|
+
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
|
127
|
+
}
|
128
|
+
#toast-container > .toast-error {
|
129
|
+
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
|
130
|
+
}
|
131
|
+
#toast-container > .toast-success {
|
132
|
+
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
|
133
|
+
}
|
134
|
+
#toast-container > .toast-warning {
|
135
|
+
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
|
136
|
+
}
|
137
|
+
#toast-container.toast-top-full-width > div,
|
138
|
+
#toast-container.toast-bottom-full-width > div {
|
139
|
+
width: 96%;
|
140
|
+
margin: auto;
|
141
|
+
}
|
142
|
+
.toast {
|
143
|
+
background-color: #030303;
|
144
|
+
}
|
145
|
+
.toast-success {
|
146
|
+
background-color: #51a351;
|
147
|
+
}
|
148
|
+
.toast-error {
|
149
|
+
background-color: #bd362f;
|
150
|
+
}
|
151
|
+
.toast-info {
|
152
|
+
background-color: #2f96b4;
|
153
|
+
}
|
154
|
+
.toast-warning {
|
155
|
+
background-color: #f89406;
|
156
|
+
}
|
157
|
+
/*Responsive Design*/
|
158
|
+
@media all and (max-width: 240px) {
|
159
|
+
#toast-container > div {
|
160
|
+
padding: 8px 8px 8px 50px;
|
161
|
+
width: 11em;
|
162
|
+
}
|
163
|
+
#toast-container .toast-close-button {
|
164
|
+
right: -0.2em;
|
165
|
+
top: -0.2em;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
@media all and (min-width: 241px) and (max-width: 480px) {
|
169
|
+
#toast-container > div {
|
170
|
+
padding: 8px 8px 8px 50px;
|
171
|
+
width: 18em;
|
172
|
+
}
|
173
|
+
#toast-container .toast-close-button {
|
174
|
+
right: -0.2em;
|
175
|
+
top: -0.2em;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
@media all and (min-width: 481px) and (max-width: 768px) {
|
179
|
+
#toast-container > div {
|
180
|
+
padding: 15px 15px 15px 50px;
|
181
|
+
width: 25em;
|
182
|
+
}
|
183
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TheNotification
|
2
|
+
module LocalizedErrors
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# include TheNotification::LocalizedErrors
|
6
|
+
|
7
|
+
# @post.localized_errors(except: [:'comment.title'])
|
8
|
+
def localized_errors opts = {}
|
9
|
+
opts.symbolize_keys!
|
10
|
+
excepts = opts.delete(:except) || []
|
11
|
+
|
12
|
+
errors.inject({}) do |hash, (k, v)|
|
13
|
+
unless excepts.include?(k.to_sym)
|
14
|
+
k = self.class.human_attribute_name k
|
15
|
+
hash[k].blank? ? hash[k] = [v] : hash[k].push(v)
|
16
|
+
end
|
17
|
+
hash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
- format = (format || TheNotification.config.default_type).to_s
|
2
|
+
- flash_types = %w[ notice alert error errors ]
|
3
|
+
|
4
|
+
- if format == 'html'
|
5
|
+
- flash_types.each do |level|
|
6
|
+
- unless flash[level].blank?
|
7
|
+
.alert.flash_msgs class=flash_class(level)
|
8
|
+
= content_tag :p, flash[level]
|
9
|
+
- else
|
10
|
+
- unless flash.blank?
|
11
|
+
= javascript_tag defer: :defer, type: "text/javascript" do
|
12
|
+
| window.the_notifications = window.the_notifications || {};
|
13
|
+
| window.the_notifications['flash'] = window.the_notifications['flash'] || {};
|
14
|
+
|
15
|
+
- flash_types.each do |level|
|
16
|
+
- unless flash[level].blank?
|
17
|
+
= javascript_tag defer: :defer, type: "text/javascript" do
|
18
|
+
| window.the_notifications['flash']['#{ level }'] = JSON.parse('#{ raw j flash[level].to_json }');
|
@@ -0,0 +1,28 @@
|
|
1
|
+
-# Error mesages
|
2
|
+
-# Post.model_name.human => activerecord.models.post
|
3
|
+
-# Post.human_attribute_name('title') => activerecord.attributes.post.title
|
4
|
+
- format = (format || TheNotification.config.default_type).to_s
|
5
|
+
|
6
|
+
- if object.try(:errors).try(:any?)
|
7
|
+
- _errors = object.try(:localized_errors) || object.errors
|
8
|
+
- if format == 'html'
|
9
|
+
.error_explanation.alert.alert-danger
|
10
|
+
h4= t "the_notification.form_errors"
|
11
|
+
ul
|
12
|
+
- _errors.map do |name, msgs|
|
13
|
+
- if msgs.is_a? Array
|
14
|
+
- msgs.each do |msg|
|
15
|
+
li
|
16
|
+
strong= name
|
17
|
+
'
|
18
|
+
= msg
|
19
|
+
- else
|
20
|
+
li
|
21
|
+
strong= name
|
22
|
+
'
|
23
|
+
= msgs
|
24
|
+
|
25
|
+
- else
|
26
|
+
= javascript_tag defer: :defer, type: "text/javascript" do
|
27
|
+
| window.the_notifications = window.the_notifications || {};
|
28
|
+
| window.the_notifications['errors'] = JSON.parse('#{ raw j _errors.to_json }');
|
data/gem_version.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'slim'
|
2
|
+
require 'the_notification/version'
|
3
|
+
require 'the_notification/config'
|
4
|
+
|
5
|
+
module TheNotification
|
6
|
+
class Engine < Rails::Engine; end
|
7
|
+
end
|
8
|
+
|
9
|
+
_root_ = File.expand_path('../../', __FILE__)
|
10
|
+
|
11
|
+
%w[ localized_errors ].each do |concern|
|
12
|
+
require "#{ _root_ }/app/models/concerns/#{ concern }.rb"
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TheNotification
|
2
|
+
def self.configure(&block)
|
3
|
+
yield @config ||= TheNotification::Configuration.new
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.config
|
7
|
+
@config
|
8
|
+
end
|
9
|
+
|
10
|
+
# Configuration class
|
11
|
+
class Configuration
|
12
|
+
include ActiveSupport::Configurable
|
13
|
+
|
14
|
+
config_accessor :default_type
|
15
|
+
end
|
16
|
+
|
17
|
+
configure do |config|
|
18
|
+
config.default_type = :html # :json
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../../gem_version'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'the_notification/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "the_notification"
|
8
|
+
spec.version = TheNotification::VERSION
|
9
|
+
spec.authors = ["Ilya N. Zykin"]
|
10
|
+
spec.email = ["zykin-ilya@ya.ru"]
|
11
|
+
spec.description = %q{notifications and alerts}
|
12
|
+
spec.summary = %q{common code for notifications and alerts}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'slim'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: the_notification
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilya N. Zykin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: slim
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: notifications and alerts
|
56
|
+
email:
|
57
|
+
- zykin-ilya@ya.ru
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- app/assets/javascripts/the_notification.js.coffee
|
68
|
+
- app/assets/javascripts/the_notification/vendors/toastr.js
|
69
|
+
- app/assets/stylesheets/the_notification.css.scss
|
70
|
+
- app/assets/stylesheets/the_notification/vendors/toastr.css
|
71
|
+
- app/helpers/the_notification_helper.rb
|
72
|
+
- app/models/concerns/localized_errors.rb
|
73
|
+
- app/views/the_notification/_flash.html.slim
|
74
|
+
- app/views/the_notification/_form.html.slim
|
75
|
+
- config/locales/en.yml
|
76
|
+
- config/locales/ru.yml
|
77
|
+
- gem_version.rb
|
78
|
+
- lib/the_notification.rb
|
79
|
+
- lib/the_notification/config.rb
|
80
|
+
- lib/the_notification/version.rb
|
81
|
+
- the_notification.gemspec
|
82
|
+
homepage: ''
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: common code for notifications and alerts
|
106
|
+
test_files: []
|