fustrate-rails 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/lib/fustrate-rails.rb +4 -0
  3. data/lib/fustrate/rails/engine.rb +14 -0
  4. data/lib/fustrate/rails/version.rb +6 -0
  5. data/vendor/assets/javascripts/awesomplete.js +402 -0
  6. data/vendor/assets/javascripts/fustrate.coffee +6 -0
  7. data/vendor/assets/javascripts/fustrate/_module.coffee +134 -0
  8. data/vendor/assets/javascripts/fustrate/components/_module.coffee +3 -0
  9. data/vendor/assets/javascripts/fustrate/components/alert_box.coffee +10 -0
  10. data/vendor/assets/javascripts/fustrate/components/autocomplete.coffee +161 -0
  11. data/vendor/assets/javascripts/fustrate/components/disclosure.coffee +12 -0
  12. data/vendor/assets/javascripts/fustrate/components/drop_zone.coffee +9 -0
  13. data/vendor/assets/javascripts/fustrate/components/dropdown.coffee +48 -0
  14. data/vendor/assets/javascripts/fustrate/components/file_picker.coffee +10 -0
  15. data/vendor/assets/javascripts/fustrate/components/flash.coffee +31 -0
  16. data/vendor/assets/javascripts/fustrate/components/modal.coffee +213 -0
  17. data/vendor/assets/javascripts/fustrate/components/pagination.coffee +84 -0
  18. data/vendor/assets/javascripts/fustrate/components/tabs.coffee +28 -0
  19. data/vendor/assets/javascripts/fustrate/components/tooltip.coffee +72 -0
  20. data/vendor/assets/javascripts/fustrate/generic_form.coffee +31 -0
  21. data/vendor/assets/javascripts/fustrate/generic_page.coffee +40 -0
  22. data/vendor/assets/javascripts/fustrate/generic_table.coffee +57 -0
  23. data/vendor/assets/javascripts/fustrate/listenable.coffee +25 -0
  24. data/vendor/assets/javascripts/fustrate/object.coffee +21 -0
  25. data/vendor/assets/javascripts/fustrate/record.coffee +23 -0
  26. data/vendor/assets/stylesheets/_fustrate.sass +7 -0
  27. data/vendor/assets/stylesheets/awesomplete.sass +75 -0
  28. data/vendor/assets/stylesheets/fustrate/_colors.sass +9 -0
  29. data/vendor/assets/stylesheets/fustrate/_settings.sass +20 -0
  30. data/vendor/assets/stylesheets/fustrate/components/_components.sass +36 -0
  31. data/vendor/assets/stylesheets/fustrate/components/_functions.sass +40 -0
  32. data/vendor/assets/stylesheets/fustrate/components/alerts.sass +78 -0
  33. data/vendor/assets/stylesheets/fustrate/components/buttons.sass +103 -0
  34. data/vendor/assets/stylesheets/fustrate/components/disclosures.sass +23 -0
  35. data/vendor/assets/stylesheets/fustrate/components/dropdowns.sass +31 -0
  36. data/vendor/assets/stylesheets/fustrate/components/flash.sass +33 -0
  37. data/vendor/assets/stylesheets/fustrate/components/forms.sass +188 -0
  38. data/vendor/assets/stylesheets/fustrate/components/grid.sass +204 -0
  39. data/vendor/assets/stylesheets/fustrate/components/labels.sass +63 -0
  40. data/vendor/assets/stylesheets/fustrate/components/modals.sass +119 -0
  41. data/vendor/assets/stylesheets/fustrate/components/pagination.sass +57 -0
  42. data/vendor/assets/stylesheets/fustrate/components/panels.sass +49 -0
  43. data/vendor/assets/stylesheets/fustrate/components/popovers.sass +15 -0
  44. data/vendor/assets/stylesheets/fustrate/components/tables.sass +58 -0
  45. data/vendor/assets/stylesheets/fustrate/components/tabs.sass +44 -0
  46. data/vendor/assets/stylesheets/fustrate/components/tooltips.sass +28 -0
  47. data/vendor/assets/stylesheets/fustrate/components/typography.sass +355 -0
  48. metadata +211 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d5f71aa31c1e5bad989dc3c933c549a5e62f1a5
4
+ data.tar.gz: 9a42f14c3770a006361c62eb23fa4403d0679024
5
+ SHA512:
6
+ metadata.gz: 91bf081fd1025eeea96885535db9b86837cb05d9f6f702d9c1c16b49f33c6a6765f25ae9188eb48af9f34d60b4451461d0da6a97c0fc2d264c5054360a3c5380
7
+ data.tar.gz: 97193c0ca4c61d7b5fed80b4f98d6eea38a961a8799ebafa4d04a9cb5910de93dc96f5822c4b391f93474d4068b656363b2c64f59d6283dd3b9a9879c6153254
@@ -0,0 +1,4 @@
1
+ require 'coffee-script'
2
+ require 'sass'
3
+ require 'fustrate/rails/engine'
4
+ require 'fustrate/rails/version'
@@ -0,0 +1,14 @@
1
+ require 'rails/engine'
2
+
3
+ require 'bourbon'
4
+ require 'js-routes'
5
+ require 'modernizr-rails'
6
+ require 'momentjs-rails'
7
+ require 'font-awesome-rails'
8
+
9
+ module Fustrate
10
+ module Rails
11
+ class Engine < ::Rails::Engine
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module Fustrate
3
+ module Rails
4
+ VERSION = '0.3.3'.freeze
5
+ end
6
+ end
@@ -0,0 +1,402 @@
1
+ /* 1795543d988d0fd9ca6237a5ac176f8e88d63990 */
2
+
3
+ /**
4
+ * Simple, lightweight, usable local autocomplete library for modern browsers
5
+ * Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P
6
+ * @author Lea Verou http://leaverou.github.io/awesomplete
7
+ * MIT license
8
+ */
9
+
10
+ (function () {
11
+
12
+ var _ = function (input, o) {
13
+ var me = this;
14
+
15
+ // Setup
16
+
17
+ this.input = $(input);
18
+ this.input.setAttribute("autocomplete", "off");
19
+ this.input.setAttribute("aria-autocomplete", "list");
20
+
21
+ o = o || {};
22
+
23
+ configure(this, {
24
+ minChars: 2,
25
+ maxItems: 10,
26
+ autoFirst: false,
27
+ filter: _.FILTER_CONTAINS,
28
+ sort: _.SORT_BYLENGTH,
29
+ item: _.ITEM,
30
+ replace: _.REPLACE
31
+ }, o);
32
+
33
+ this.index = -1;
34
+
35
+ // Create necessary elements
36
+
37
+ this.container = $.create("div", {
38
+ className: "awesomplete",
39
+ around: input
40
+ });
41
+
42
+ this.ul = $.create("ul", {
43
+ hidden: "hidden",
44
+ inside: this.container
45
+ });
46
+
47
+ this.status = $.create("span", {
48
+ className: "visually-hidden",
49
+ role: "status",
50
+ "aria-live": "assertive",
51
+ "aria-relevant": "additions",
52
+ inside: this.container
53
+ });
54
+
55
+ // Bind events
56
+
57
+ $.bind(this.input, {
58
+ "input": this.evaluate.bind(this),
59
+ "blur": this.close.bind(this),
60
+ "keydown": function(evt) {
61
+ var c = evt.keyCode;
62
+
63
+ // If the dropdown `ul` is in view, then act on keydown for the following keys:
64
+ // Enter / Esc / Up / Down
65
+ if(me.opened) {
66
+ if (c === 13 && me.selected) { // Enter
67
+ evt.preventDefault();
68
+ me.select();
69
+ }
70
+ else if (c === 27) { // Esc
71
+ me.close();
72
+ }
73
+ else if (c === 38 || c === 40) { // Down/Up arrow
74
+ evt.preventDefault();
75
+ me[c === 38? "previous" : "next"]();
76
+ }
77
+ }
78
+ }
79
+ });
80
+
81
+ $.bind(this.input.form, {"submit": this.close.bind(this)});
82
+
83
+ $.bind(this.ul, {"mousedown": function(evt) {
84
+ var li = evt.target;
85
+
86
+ if (li !== this) {
87
+
88
+ while (li && !/li/i.test(li.nodeName)) {
89
+ li = li.parentNode;
90
+ }
91
+
92
+ if (li && evt.button === 0) { // Only select on left click
93
+ evt.preventDefault();
94
+ me.select(li, evt.target);
95
+ }
96
+ }
97
+ }});
98
+
99
+ if (this.input.hasAttribute("list")) {
100
+ this.list = "#" + this.input.getAttribute("list");
101
+ this.input.removeAttribute("list");
102
+ }
103
+ else {
104
+ this.list = this.input.getAttribute("data-list") || o.list || [];
105
+ }
106
+
107
+ _.all.push(this);
108
+ };
109
+
110
+ _.prototype = {
111
+ set list(list) {
112
+ if (Array.isArray(list)) {
113
+ this._list = list;
114
+ }
115
+ else if (typeof list === "string" && list.indexOf(",") > -1) {
116
+ this._list = list.split(/\s*,\s*/);
117
+ }
118
+ else { // Element or CSS selector
119
+ list = $(list);
120
+
121
+ if (list && list.children) {
122
+ this._list = slice.apply(list.children).map(function (el) {
123
+ return el.textContent.trim();
124
+ });
125
+ }
126
+ }
127
+
128
+ if (document.activeElement === this.input) {
129
+ this.evaluate();
130
+ }
131
+ },
132
+
133
+ get selected() {
134
+ return this.index > -1;
135
+ },
136
+
137
+ get opened() {
138
+ return !this.ul.hasAttribute("hidden");
139
+ },
140
+
141
+ close: function () {
142
+ this.ul.setAttribute("hidden", "");
143
+ this.index = -1;
144
+
145
+ $.fire(this.input, "awesomplete-close");
146
+ },
147
+
148
+ open: function () {
149
+ this.ul.removeAttribute("hidden");
150
+
151
+ if (this.autoFirst && this.index === -1) {
152
+ this.goto(0);
153
+ }
154
+
155
+ $.fire(this.input, "awesomplete-open");
156
+ },
157
+
158
+ next: function () {
159
+ var count = this.ul.children.length;
160
+
161
+ this.goto(this.index < count - 1? this.index + 1 : -1);
162
+ },
163
+
164
+ previous: function () {
165
+ var count = this.ul.children.length;
166
+
167
+ this.goto(this.selected? this.index - 1 : count - 1);
168
+ },
169
+
170
+ // Should not be used, highlights specific item without any checks!
171
+ goto: function (i) {
172
+ var lis = this.ul.children;
173
+
174
+ if (this.selected) {
175
+ lis[this.index].setAttribute("aria-selected", "false");
176
+ }
177
+
178
+ this.index = i;
179
+
180
+ if (i > -1 && lis.length > 0) {
181
+ lis[i].setAttribute("aria-selected", "true");
182
+ this.status.textContent = lis[i].textContent;
183
+ }
184
+
185
+ $.fire(this.input, "awesomplete-highlight");
186
+ },
187
+
188
+ select: function (selected, origin) {
189
+ selected = selected || this.ul.children[this.index];
190
+
191
+ if (selected) {
192
+ var allowed = $.fire(this.input, "awesomplete-select", {
193
+ text: selected.textContent,
194
+ data: this.suggestions[$.siblingIndex(selected)],
195
+ origin: origin || selected
196
+ });
197
+
198
+ if (allowed) {
199
+ this.replace(selected.textContent);
200
+ this.close();
201
+ $.fire(this.input, "awesomplete-selectcomplete");
202
+ }
203
+ }
204
+ },
205
+
206
+ evaluate: function() {
207
+ var me = this;
208
+ var value = this.input.value;
209
+
210
+ if (value.length >= this.minChars && this._list.length > 0) {
211
+ this.index = -1;
212
+ // Populate list with options that match
213
+ this.ul.innerHTML = "";
214
+
215
+ this.suggestions = this._list
216
+ .filter(function(item) {
217
+ return me.filter(item, value);
218
+ })
219
+ .sort(this.sort)
220
+ .slice(0, this.maxItems);
221
+
222
+ this.suggestions.forEach(function(text) {
223
+ me.ul.appendChild(me.item(text, value));
224
+ });
225
+
226
+ if (this.ul.children.length === 0) {
227
+ this.close();
228
+ } else {
229
+ this.open();
230
+ }
231
+ }
232
+ else {
233
+ this.close();
234
+ }
235
+ }
236
+ };
237
+
238
+ // Static methods/properties
239
+
240
+ _.all = [];
241
+
242
+ _.FILTER_CONTAINS = function (text, input) {
243
+ return RegExp($.regExpEscape(input.trim()), "i").test(text);
244
+ };
245
+
246
+ _.FILTER_STARTSWITH = function (text, input) {
247
+ return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
248
+ };
249
+
250
+ _.SORT_BYLENGTH = function (a, b) {
251
+ if (a.length !== b.length) {
252
+ return a.length - b.length;
253
+ }
254
+
255
+ return a < b? -1 : 1;
256
+ };
257
+
258
+ _.ITEM = function (text, input) {
259
+ var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
260
+ return $.create("li", {
261
+ innerHTML: html,
262
+ "aria-selected": "false"
263
+ });
264
+ };
265
+
266
+ _.REPLACE = function (text) {
267
+ this.input.value = text;
268
+ };
269
+
270
+ // Private functions
271
+
272
+ function configure(instance, properties, o) {
273
+ for (var i in properties) {
274
+ var initial = properties[i],
275
+ attrValue = instance.input.getAttribute("data-" + i.toLowerCase());
276
+
277
+ if (typeof initial === "number") {
278
+ instance[i] = parseInt(attrValue);
279
+ }
280
+ else if (initial === false) { // Boolean options must be false by default anyway
281
+ instance[i] = attrValue !== null;
282
+ }
283
+ else if (initial instanceof Function) {
284
+ instance[i] = null;
285
+ }
286
+ else {
287
+ instance[i] = attrValue;
288
+ }
289
+
290
+ if (!instance[i] && instance[i] !== 0) {
291
+ instance[i] = (i in o)? o[i] : initial;
292
+ }
293
+ }
294
+ }
295
+
296
+ // Helpers
297
+
298
+ var slice = Array.prototype.slice;
299
+
300
+ function $(expr, con) {
301
+ return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
302
+ }
303
+
304
+ function $$(expr, con) {
305
+ return slice.call((con || document).querySelectorAll(expr));
306
+ }
307
+
308
+ $.create = function(tag, o) {
309
+ var element = document.createElement(tag);
310
+
311
+ for (var i in o) {
312
+ var val = o[i];
313
+
314
+ if (i === "inside") {
315
+ $(val).appendChild(element);
316
+ }
317
+ else if (i === "around") {
318
+ var ref = $(val);
319
+ ref.parentNode.insertBefore(element, ref);
320
+ element.appendChild(ref);
321
+ }
322
+ else if (i in element) {
323
+ element[i] = val;
324
+ }
325
+ else {
326
+ element.setAttribute(i, val);
327
+ }
328
+ }
329
+
330
+ return element;
331
+ };
332
+
333
+ $.bind = function(element, o) {
334
+ if (element) {
335
+ for (var event in o) {
336
+ var callback = o[event];
337
+
338
+ event.split(/\s+/).forEach(function (event) {
339
+ element.addEventListener(event, callback);
340
+ });
341
+ }
342
+ }
343
+ };
344
+
345
+ $.fire = function(target, type, properties) {
346
+ var evt = document.createEvent("HTMLEvents");
347
+
348
+ evt.initEvent(type, true, true );
349
+
350
+ for (var j in properties) {
351
+ evt[j] = properties[j];
352
+ }
353
+
354
+ return target.dispatchEvent(evt);
355
+ };
356
+
357
+ $.regExpEscape = function (s) {
358
+ return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
359
+ };
360
+
361
+ $.siblingIndex = function (el) {
362
+ /* eslint-disable no-cond-assign */
363
+ for (var i = 0; el = el.previousElementSibling; i++);
364
+ return i;
365
+ };
366
+
367
+ // Initialization
368
+
369
+ function init() {
370
+ $$("input.awesomplete").forEach(function (input) {
371
+ new _(input);
372
+ });
373
+ }
374
+
375
+ // Are we in a browser? Check for Document constructor
376
+ if (typeof Document !== "undefined") {
377
+ // DOM already loaded?
378
+ if (document.readyState !== "loading") {
379
+ init();
380
+ }
381
+ else {
382
+ // Wait for it
383
+ document.addEventListener("DOMContentLoaded", init);
384
+ }
385
+ }
386
+
387
+ _.$ = $;
388
+ _.$$ = $$;
389
+
390
+ // Make sure to export Awesomplete on self when in a browser
391
+ if (typeof self !== "undefined") {
392
+ self.Awesomplete = _;
393
+ }
394
+
395
+ // Expose Awesomplete as a CJS module
396
+ if (typeof module === "object" && module.exports) {
397
+ module.exports = _;
398
+ }
399
+
400
+ return _;
401
+
402
+ }());
@@ -0,0 +1,6 @@
1
+ #= require js-routes
2
+ #= require moment
3
+ #= require awesomplete
4
+ #
5
+ #= require_directory ./fustrate
6
+ #= require_tree ./fustrate
@@ -0,0 +1,134 @@
1
+ #= require_self
2
+ #= require_directory .
3
+ #= require_tree .
4
+
5
+ class window.Fustrate
6
+ @VERSION: '0.3.3'
7
+ @libs: {}
8
+
9
+ constructor: ->
10
+ lib.init() for own name, lib of @constructor.libs
11
+
12
+ for own component of Fustrate.Components
13
+ Fustrate.Components[component].initialize()
14
+
15
+ @initialize()
16
+
17
+ initialize: ->
18
+ $('[data-js-class]').each (index, elem) ->
19
+ element = $(elem)
20
+ klass = Fustrate._stringToClass element.data('js-class')
21
+
22
+ element.data 'js-object', new klass(element)
23
+
24
+ $.ajaxSetup
25
+ cache: false
26
+ beforeSend: $.rails.CSRFProtection
27
+
28
+ $('table').wrap '<div class="responsive-table"></div>'
29
+
30
+ $('.number').each (index, elem) ->
31
+ elem = $ @
32
+
33
+ number = if elem.data('number') != undefined
34
+ elem.data('number')
35
+ else
36
+ elem.html()
37
+
38
+ elem.addClass 'negative' if parseInt(number, 10) < 0
39
+
40
+ @_stringToClass: (string) ->
41
+ pieces = string.split('.')
42
+
43
+ Fustrate._arrayToClass(pieces, window)
44
+
45
+ @_arrayToClass: (pieces, root) ->
46
+ if pieces.length == 1
47
+ root[pieces[0]]
48
+ else
49
+ Fustrate._arrayToClass pieces.slice(1), root[pieces[0]]
50
+
51
+ @linkTo: (text, path, options = {}) ->
52
+ $('<a>').prop('href', path).html(text).prop(options).outerHTML()
53
+
54
+ @ajaxUpload: (url, data) ->
55
+ formData = new FormData
56
+
57
+ formData.append key, value for key, value of data
58
+
59
+ $.ajax
60
+ url: url
61
+ type: 'POST'
62
+ data: formData
63
+ processData: false
64
+ contentType: false
65
+ dataType: 'script'
66
+ beforeSend: (xhr) ->
67
+ $.rails.CSRFProtection xhr
68
+
69
+ @humanDate: (date, time = false) ->
70
+ if date.year() == moment().year()
71
+ date.format("M/D#{if time then ' h:mm A' else ''}")
72
+ else
73
+ date.format("M/D/YY#{if time then ' h:mm A' else ''}")
74
+
75
+ @label: (text, type) ->
76
+ type = if type then "#{type} " else ""
77
+
78
+ $('<span>')
79
+ .text(text)
80
+ .prop('class', "label #{type}#{text}".toLowerCase())
81
+
82
+ @icon: (types) ->
83
+ classes = ("fa-#{type}" for type in types.split(' ')).join(' ')
84
+
85
+ "<i class=\"fa #{classes}\"></i>"
86
+
87
+ String::titleize = ->
88
+ @replace(/_/g, ' ').replace /\b[a-z]/g, (char) -> char.toUpperCase()
89
+
90
+ String::capitalize = ->
91
+ @charAt(0).toUpperCase() + @slice(1)
92
+
93
+ String::phoneFormat = ->
94
+ if /^(\d+)(ext|x)(\d+)$/.test @
95
+ @replace /(\d+)(ext|x)(\d+)/, ->
96
+ arguments[1].phoneFormat() + ' x' + arguments[3]
97
+ else if /^1\d{10}$/.test @
98
+ @replace /1(\d{3})(\d{3})(\d{4})/, '1 ($1) $2-$3'
99
+ else if /^\d{10}$/.test @
100
+ @replace /(\d{3})(\d{3})(\d{4})/, '($1) $2-$3'
101
+ else if /^\d{7}$/.test @
102
+ @replace /(\d{3})(\d{4})/, '$1-$2'
103
+ else
104
+ @
105
+
106
+ Array::toSentence = ->
107
+ switch @length
108
+ when 0 then ''
109
+ when 1 then @[0]
110
+ when 2 then "#{@[0]} and #{@[1]}"
111
+ else "#{@slice(0, -1).join(', ')}, and #{@[@length - 1]}"
112
+
113
+ Array::remove = (object) ->
114
+ index = @indexOf object
115
+ @splice index, 1 if index isnt -1
116
+
117
+ Array::first = ->
118
+ @[0]
119
+
120
+ Array::last = ->
121
+ @[@length - 1]
122
+
123
+ Array::peek = Array::last
124
+
125
+ # Used to define getters and setters
126
+ Function::define = (name, methods) ->
127
+ Object.defineProperty @::, name, methods
128
+
129
+ jQuery.fn.outerHTML = ->
130
+ return '' unless @length
131
+
132
+ return @[0].outerHTML if @[0].outerHTML
133
+
134
+ $('<div>').append(@[0].clone()).remove().html()