uikit-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,238 @@
1
+
2
+ /**
3
+ * Expose `Menu`.
4
+ */
5
+
6
+ exports.Menu = Menu;
7
+
8
+ /**
9
+ * Create a new `Menu`.
10
+ *
11
+ * @return {Menu}
12
+ * @api public
13
+ */
14
+
15
+ exports.menu = function(){
16
+ return new Menu;
17
+ };
18
+
19
+ /**
20
+ * Initialize a new `Menu`.
21
+ *
22
+ * Emits:
23
+ *
24
+ * - "show" when shown
25
+ * - "hide" when hidden
26
+ * - "remove" with the item name when an item is removed
27
+ * - * menu item events are emitted when clicked
28
+ *
29
+ * @api public
30
+ */
31
+
32
+ function Menu() {
33
+ ui.Emitter.call(this);
34
+ this.items = {};
35
+ this.el = $(html).hide().appendTo('body');
36
+ this.el.hover(this.deselect.bind(this));
37
+ $('html').click(this.hide.bind(this));
38
+ this.on('show', this.bindKeyboardEvents.bind(this));
39
+ this.on('hide', this.unbindKeyboardEvents.bind(this));
40
+ };
41
+
42
+ /**
43
+ * Inherit from `Emitter.prototype`.
44
+ */
45
+
46
+ Menu.prototype = new ui.Emitter;
47
+
48
+ /**
49
+ * Deselect selected menu items.
50
+ *
51
+ * @api private
52
+ */
53
+
54
+ Menu.prototype.deselect = function(){
55
+ this.el.find('.selected').removeClass('selected');
56
+ };
57
+
58
+ /**
59
+ * Bind keyboard events.
60
+ *
61
+ * @api private
62
+ */
63
+
64
+ Menu.prototype.bindKeyboardEvents = function(){
65
+ $(document).bind('keydown.menu', this.onkeydown.bind(this));
66
+ return this;
67
+ };
68
+
69
+ /**
70
+ * Unbind keyboard events.
71
+ *
72
+ * @api private
73
+ */
74
+
75
+ Menu.prototype.unbindKeyboardEvents = function(){
76
+ $(document).unbind('keydown.menu');
77
+ return this;
78
+ };
79
+
80
+ /**
81
+ * Handle keydown events.
82
+ *
83
+ * @api private
84
+ */
85
+
86
+ Menu.prototype.onkeydown = function(e){
87
+ switch (e.keyCode) {
88
+ // up
89
+ case 38:
90
+ e.preventDefault();
91
+ this.move('prev');
92
+ break;
93
+ // down
94
+ case 40:
95
+ e.preventDefault();
96
+ this.move('next');
97
+ break;
98
+ }
99
+ };
100
+
101
+ /**
102
+ * Focus on the next menu item in `direction`.
103
+ *
104
+ * @param {String} direction "prev" or "next"
105
+ * @api public
106
+ */
107
+
108
+ Menu.prototype.move = function(direction){
109
+ var prev = this.el.find('.selected').eq(0);
110
+
111
+ var next = prev.length
112
+ ? prev[direction]()
113
+ : this.el.find('li:first-child');
114
+
115
+ if (next.length) {
116
+ prev.removeClass('selected');
117
+ next.addClass('selected');
118
+ next.find('a').focus();
119
+ }
120
+ };
121
+
122
+ /**
123
+ * Add menu item with the given `text` and optional callback `fn`.
124
+ *
125
+ * When the item is clicked `fn()` will be invoked
126
+ * and the `Menu` is immediately closed. When clicked
127
+ * an event of the name `text` is emitted regardless of
128
+ * the callback function being present.
129
+ *
130
+ * @param {String} text
131
+ * @param {Function} fn
132
+ * @return {Menu}
133
+ * @api public
134
+ */
135
+
136
+ Menu.prototype.add = function(text, fn){
137
+ var self = this
138
+ , el = $('<li><a href="#">' + text + '</a></li>')
139
+ .addClass(slug(text))
140
+ .appendTo(this.el)
141
+ .click(function(e){
142
+ e.preventDefault();
143
+ e.stopPropagation();
144
+ self.hide();
145
+ self.emit(text);
146
+ fn && fn();
147
+ });
148
+
149
+ this.items[text] = el;
150
+ return this;
151
+ };
152
+
153
+ /**
154
+ * Remove menu item with the given `text`.
155
+ *
156
+ * @param {String} text
157
+ * @return {Menu}
158
+ * @api public
159
+ */
160
+
161
+ Menu.prototype.remove = function(text){
162
+ var item = this.items[text];
163
+ if (!item) throw new Error('no menu item named "' + text + '"');
164
+ this.emit('remove', text);
165
+ item.remove();
166
+ delete this.items[text];
167
+ return this;
168
+ };
169
+
170
+ /**
171
+ * Check if this menu has an item with the given `text`.
172
+ *
173
+ * @param {String} text
174
+ * @return {Boolean}
175
+ * @api public
176
+ */
177
+
178
+ Menu.prototype.has = function(text){
179
+ return !! this.items[text];
180
+ };
181
+
182
+ /**
183
+ * Move context menu to `(x, y)`.
184
+ *
185
+ * @param {Number} x
186
+ * @param {Number} y
187
+ * @return {Menu}
188
+ * @api public
189
+ */
190
+
191
+ Menu.prototype.moveTo = function(x, y){
192
+ this.el.css({
193
+ top: y,
194
+ left: x
195
+ });
196
+ return this;
197
+ };
198
+
199
+ /**
200
+ * Show the menu.
201
+ *
202
+ * @return {Menu}
203
+ * @api public
204
+ */
205
+
206
+ Menu.prototype.show = function(){
207
+ this.emit('show');
208
+ this.el.show();
209
+ return this;
210
+ };
211
+
212
+ /**
213
+ * Hide the menu.
214
+ *
215
+ * @return {Menu}
216
+ * @api public
217
+ */
218
+
219
+ Menu.prototype.hide = function(){
220
+ this.emit('hide');
221
+ this.el.hide();
222
+ return this;
223
+ };
224
+
225
+ /**
226
+ * Generate a slug from `str`.
227
+ *
228
+ * @param {String} str
229
+ * @return {String}
230
+ * @api private
231
+ */
232
+
233
+ function slug(str) {
234
+ return str
235
+ .toLowerCase()
236
+ .replace(/ +/g, '-')
237
+ .replace(/[^a-z0-9-]/g, '');
238
+ }
@@ -0,0 +1,240 @@
1
+
2
+ /**
3
+ * Notification list.
4
+ */
5
+
6
+ var list;
7
+
8
+ /**
9
+ * Expose `Notification`.
10
+ */
11
+
12
+ exports.Notification = Notification;
13
+
14
+ // list
15
+
16
+ $(function(){
17
+ list = $('<ul id="notifications">');
18
+ list.appendTo('body');
19
+ })
20
+
21
+ /**
22
+ * Return a new `Notification` with the given
23
+ * (optional) `title` and `msg`.
24
+ *
25
+ * @param {String} title or msg
26
+ * @param {String} msg
27
+ * @return {Dialog}
28
+ * @api public
29
+ */
30
+
31
+ exports.notify = function(title, msg){
32
+ switch (arguments.length) {
33
+ case 2:
34
+ return new Notification({ title: title, message: msg })
35
+ .show()
36
+ .hide(4000);
37
+ case 1:
38
+ return new Notification({ message: title })
39
+ .show()
40
+ .hide(4000);
41
+ }
42
+ };
43
+
44
+ /**
45
+ * Construct a notification function for `type`.
46
+ *
47
+ * @param {String} type
48
+ * @return {Function}
49
+ * @api private
50
+ */
51
+
52
+ function type(type) {
53
+ return function(title, msg){
54
+ return exports.notify.apply(this, arguments)
55
+ .type(type);
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Notification methods.
61
+ */
62
+
63
+ exports.info = exports.notify;
64
+ exports.warn = type('warn');
65
+ exports.error = type('error');
66
+
67
+ /**
68
+ * Initialize a new `Notification`.
69
+ *
70
+ * Options:
71
+ *
72
+ * - `title` dialog title
73
+ * - `message` a message to display
74
+ *
75
+ * @param {Object} options
76
+ * @api public
77
+ */
78
+
79
+ function Notification(options) {
80
+ ui.Emitter.call(this);
81
+ options = options || {};
82
+ this.template = html;
83
+ this.el = $(this.template);
84
+ this.render(options);
85
+ if (Notification.effect) this.effect(Notification.effect);
86
+ };
87
+
88
+ /**
89
+ * Inherit from `Emitter.prototype`.
90
+ */
91
+
92
+ Notification.prototype = new ui.Emitter;
93
+
94
+ /**
95
+ * Render with the given `options`.
96
+ *
97
+ * @param {Object} options
98
+ * @api public
99
+ */
100
+
101
+ Notification.prototype.render = function(options){
102
+ var el = this.el
103
+ , title = options.title
104
+ , msg = options.message
105
+ , self = this;
106
+
107
+ el.find('.close').click(function(){
108
+ self.hide();
109
+ return false;
110
+ });
111
+
112
+ el.click(function(e){
113
+ e.preventDefault();
114
+ self.emit('click', e);
115
+ });
116
+
117
+ el.find('h1').text(title);
118
+ if (!title) el.find('h1').remove();
119
+
120
+ // message
121
+ if ('string' == typeof msg) {
122
+ el.find('p').text(msg);
123
+ } else if (msg) {
124
+ el.find('p').replaceWith(msg.el || msg);
125
+ }
126
+
127
+ setTimeout(function(){
128
+ el.removeClass('hide');
129
+ }, 0);
130
+ };
131
+
132
+ /**
133
+ * Enable the dialog close link.
134
+ *
135
+ * @return {Notification} for chaining
136
+ * @api public
137
+ */
138
+
139
+ Notification.prototype.closable = function(){
140
+ this.el.addClass('closable');
141
+ return this;
142
+ };
143
+
144
+ /**
145
+ * Set the effect to `type`.
146
+ *
147
+ * @param {String} type
148
+ * @return {Notification} for chaining
149
+ * @api public
150
+ */
151
+
152
+ Notification.prototype.effect = function(type){
153
+ this._effect = type;
154
+ this.el.addClass(type);
155
+ return this;
156
+ };
157
+
158
+ /**
159
+ * Show the notification.
160
+ *
161
+ * @return {Notification} for chaining
162
+ * @api public
163
+ */
164
+
165
+ Notification.prototype.show = function(){
166
+ this.el.appendTo(list);
167
+ return this;
168
+ };
169
+
170
+ /**
171
+ * Set the notification `type`.
172
+ *
173
+ * @param {String} type
174
+ * @return {Notification} for chaining
175
+ * @api public
176
+ */
177
+
178
+ Notification.prototype.type = function(type){
179
+ this._type = type;
180
+ this.el.addClass(type);
181
+ return this;
182
+ };
183
+
184
+ /**
185
+ * Make it stick (clear hide timer), and make it closable.
186
+ *
187
+ * @return {Notification} for chaining
188
+ * @api public
189
+ */
190
+
191
+ Notification.prototype.sticky = function(){
192
+ return this.hide(0).closable();
193
+ };
194
+
195
+ /**
196
+ * Hide the dialog with optional delay of `ms`,
197
+ * otherwise the notification is removed immediately.
198
+ *
199
+ * @return {Number} ms
200
+ * @return {Notification} for chaining
201
+ * @api public
202
+ */
203
+
204
+ Notification.prototype.hide = function(ms){
205
+ var self = this;
206
+
207
+ // duration
208
+ if ('number' == typeof ms) {
209
+ clearTimeout(this.timer);
210
+ if (!ms) return this;
211
+ this.timer = setTimeout(function(){
212
+ self.hide();
213
+ }, ms);
214
+ return this;
215
+ }
216
+
217
+ // hide / remove
218
+ this.el.addClass('hide');
219
+ if (this._effect) {
220
+ setTimeout(function(){
221
+ self.remove();
222
+ }, 500);
223
+ } else {
224
+ self.remove();
225
+ }
226
+
227
+ return this;
228
+ };
229
+
230
+ /**
231
+ * Hide the notification without potential animation.
232
+ *
233
+ * @return {Dialog} for chaining
234
+ * @api public
235
+ */
236
+
237
+ Notification.prototype.remove = function(){
238
+ this.el.remove();
239
+ return this;
240
+ };