beautiful_scaffold 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/beautiful_scaffold.gemspec +1 -1
  2. data/lib/generators/beautiful_scaffold_generator.rb +19 -4
  3. data/lib/generators/templates/app/assets/images/ui-anim_basic_16x16.gif +0 -0
  4. data/lib/generators/templates/app/assets/javascripts/bootstrap-datetimepicker-for-beautiful-scaffold.js +20 -5
  5. data/lib/generators/templates/app/assets/javascripts/jquery.jstree.js +4551 -0
  6. data/lib/generators/templates/app/assets/javascripts/tagit.js +489 -0
  7. data/lib/generators/templates/app/assets/stylesheets/tagit-dark-grey.css +135 -0
  8. data/lib/generators/templates/app/assets/stylesheets/themes/default/d.gif +0 -0
  9. data/lib/generators/templates/app/assets/stylesheets/themes/default/d.png +0 -0
  10. data/lib/generators/templates/app/assets/stylesheets/themes/default/style.css +74 -0
  11. data/lib/generators/templates/app/assets/stylesheets/themes/default/throbber.gif +0 -0
  12. data/lib/generators/templates/app/controllers/base.rb +11 -0
  13. data/lib/generators/templates/app/controllers/master_base.rb +39 -0
  14. data/lib/generators/templates/app/helpers/beautiful_helper.rb +53 -19
  15. data/lib/generators/templates/app/locales/beautiful_scaffold.en.yml +1 -0
  16. data/lib/generators/templates/app/locales/beautiful_scaffold.fr.yml +2 -1
  17. data/lib/generators/templates/app/views/_form_habtm_tag.html.erb +47 -0
  18. data/lib/generators/templates/app/views/_treeview_js.html.erb +42 -0
  19. data/lib/generators/templates/app/views/edit.html.erb +1 -1
  20. data/lib/generators/templates/app/views/index.html.erb +3 -0
  21. data/lib/generators/templates/app/views/layout.html.erb +1 -7
  22. data/lib/generators/templates/app/views/partials/_form_field.html.erb +1 -1
  23. data/lib/generators/templates/app/views/partials/_index_search.html.erb +4 -0
  24. data/lib/generators/templates/app/views/treeview.html.erb +22 -0
  25. metadata +14 -3
@@ -0,0 +1,489 @@
1
+ /*
2
+ * INFORMATION
3
+ * ---------------------------
4
+ * Owner: jquery.webspirited.com
5
+ * Developer: Matthew Hailwood
6
+ * ---------------------------
7
+ */
8
+
9
+ (function ($) {
10
+ $.widget("ui.tagit", {
11
+
12
+ // default options
13
+ options:{
14
+ //Maps directly to the jQuery-ui Autocomplete option
15
+ tagSource:[],
16
+ //What keys should trigger the completion of a tag
17
+ triggerKeys:['enter', 'space', 'comma', 'tab'],
18
+ //array method for setting initial tags
19
+ initialTags:[],
20
+ //minimum length of tags
21
+ minLength:1,
22
+ //should an html select be rendered to allow for normal form submission
23
+ select:false,
24
+ //if false only tags from `tagSource` are able to be entered
25
+ allowNewTags:true,
26
+ //should tag and Tag be treated as identical
27
+ caseSensitive:false,
28
+ //should tags be drag-and-drop sortable?
29
+ //true: entire tag is draggable
30
+ //'handle': a handle is rendered which is draggable
31
+ sortable:false,
32
+ //color to highlight text when a duplicate tag is entered
33
+ highlightOnExistColor:'#0F0',
34
+ //empty search on focus
35
+ emptySearch:true,
36
+ //callback function for when tags are changed
37
+ //tagValue: value of tag that was changed
38
+ //action e.g. removed, added, sorted
39
+ tagsChanged:function (tagValue, action, element) {
40
+ ;
41
+ },
42
+ maxTags:undefined,
43
+ //should 'paste' event trigger 'blur', thus potentially adding a new tag
44
+ // (true for backwards compatibility)
45
+ blurOnPaste:true
46
+ },
47
+
48
+ _splitAt:/\ |,/g,
49
+ _existingAtIndex:0,
50
+ _keys:{
51
+ backspace:[8],
52
+ enter:[13],
53
+ space:[32],
54
+ comma:[44, 188],
55
+ tab:[9]
56
+ },
57
+
58
+ _sortable:{
59
+ sorting:-1
60
+ },
61
+
62
+ //initialization function
63
+ _create:function () {
64
+
65
+ var self = this;
66
+ this.tagsArray = [];
67
+ this.timer = null;
68
+
69
+ //add class "tagit" for theming
70
+ this.element.addClass("tagit");
71
+
72
+ //add any initial tags added through html to the array
73
+ this.element.children('li').each(function () {
74
+ var tag = $(this);
75
+ var tagValue = tag.attr('tagValue') || tag.data('value');
76
+ self.options.initialTags.push({label:tag.text(), value:(tagValue ? tagValue : tag.text())});
77
+ });
78
+
79
+ //setup split according to the trigger keys
80
+ self._splitAt = null;
81
+ if ($.inArray('space', self.options.triggerKeys) > 0 && $.inArray('comma', self.options.triggerKeys) > 0)
82
+ self._splitAt = /\ |,/g;
83
+ else if ($.inArray('space', self.options.triggerKeys) > 0)
84
+ self._splitAt = /\ /g;
85
+ else if ($.inArray('comma', self.options.triggerKeys) > 0)
86
+ self._splitAt = /,/g;
87
+
88
+ //add the html input
89
+ this.element.html('<li class="tagit-new"><input class="tagit-input" type="text" /></li>');
90
+
91
+ this.input = this.element.find(".tagit-input");
92
+
93
+ //setup click handler
94
+ $(this.element).click(function (e) {
95
+ if ($(e.target).hasClass('tagit-close')) {
96
+ // Removes a tag when the little 'x' is clicked.
97
+ var parent = $(e.target).parent();
98
+
99
+ var tag = self.tagsArray[parent.index()];
100
+
101
+ tag.element.remove();
102
+ self._popTag(tag);
103
+ }
104
+ else {
105
+ self.input.focus();
106
+ if (self.options.emptySearch && $(e.target).hasClass('tagit-input') && self.input.val() == '' && self.input.autocomplete != undefined) {
107
+ self.input.autocomplete('search');
108
+ }
109
+ }
110
+ });
111
+
112
+ //setup autocomplete handler
113
+ var os = this.options.select;
114
+ this.options.appendTo = this.element;
115
+ this.options.source = this.options.tagSource;
116
+ this.options.select = function (event, ui) {
117
+ self.input.data('autoCompleteTag', true);
118
+ clearTimeout(self.timer);
119
+ if (self.options.maxTags !== undefined && self.tagsArray.length == self.options.maxTags) {
120
+ self.input.val("");
121
+ }
122
+ else {
123
+ if (ui.item.label === undefined)
124
+ self._addTag(ui.item.value);
125
+ else
126
+ self._addTag(ui.item.label, ui.item.value);
127
+ }
128
+
129
+ return false;
130
+ },
131
+
132
+ this.options.focus = function (event, ui) {
133
+ if (ui.item.label !== undefined && /^key/.test(event.originalEvent.originalEvent.type)) {
134
+ self.input.val(ui.item.label);
135
+ self.input.data('value', ui.item.value);
136
+ return false;
137
+ }
138
+ };
139
+ this.options.autoFocus = !this.options.allowNewTags;
140
+ this.input.autocomplete(this.options);
141
+ this.options.select = os;
142
+
143
+ //setup keydown handler
144
+ this.input.keydown(function (e) {
145
+ var lastLi = self.element.children(".tagit-choice:last");
146
+ if (e.which == self._keys.backspace)
147
+ return self._backspace(lastLi);
148
+
149
+ if (self._isInitKey(e.which) && !(self._isTabKey(e.which) && this.value == '' && !self.input.data('autoCompleteTag'))) {
150
+ e.preventDefault();
151
+
152
+ self.input.data('autoCompleteTag', false);
153
+
154
+ if (!self.options.allowNewTags || (self.options.maxTags !== undefined && self.tagsArray.length == self.options.maxTags)) {
155
+ self.input.val("");
156
+ }
157
+ else if (self.options.allowNewTags && $(this).val().length >= self.options.minLength) {
158
+ self._addTag($(this).val());
159
+ }
160
+ }
161
+
162
+ if (self.options.maxLength !== undefined && self.input.val().length == self.options.maxLength) {
163
+ e.preventDefault();
164
+ }
165
+
166
+ if (lastLi.hasClass('selected'))
167
+ lastLi.removeClass('selected');
168
+
169
+ self.lastKey = e.which;
170
+ });
171
+
172
+ this.input.bind("paste", function (e) {
173
+ if (self.options.blurOnPaste) {
174
+ var input = $(this);
175
+ self.timer = setTimeout(function () { input.blur(); }, 0);
176
+ }
177
+ });
178
+
179
+ //setup blur handler
180
+ this.input.blur(function (e) {
181
+ self.currentLabel = $(this).val();
182
+ self.currentValue = $(this).data('value');
183
+ if (self.options.allowNewTags) {
184
+ self.timer = setTimeout(function () {
185
+ self._addTag(self.currentLabel, self.currentValue);
186
+ self.currentValue = '';
187
+ self.currentLabel = '';
188
+ }, 400);
189
+ }
190
+ $(this).val('').removeData('value');
191
+ return false;
192
+ });
193
+
194
+ //define missing trim function for strings
195
+ if (!String.prototype.trim) {
196
+ String.prototype.trim = function () {
197
+ return this.replace(/^\s+|\s+$/g, '');
198
+ };
199
+ }
200
+
201
+ if (this.options.select) {
202
+ this.select = $('<select class="tagit-hiddenSelect" name="' +
203
+ (this.element.attr('name') || this.element.data('name')) +
204
+ '" multiple="multiple"></select>');
205
+ this.element.after(this.select);
206
+ }
207
+ this._initialTags();
208
+
209
+ //setup sortable handler
210
+ if (self.options.sortable !== false) {
211
+
212
+ var soptions = {
213
+ items:'.tagit-choice',
214
+ containment:'parent',
215
+ opacity: 0.6,
216
+ tolerance: 'pointer',
217
+ start:function (event, ui) {
218
+ self._sortable.tag = $(ui.item);
219
+ self._sortable.origIndex = self._sortable.tag.index();
220
+ },
221
+ update:function (event, ui) {
222
+ self._sortable.newIndex = self._sortable.tag.index();
223
+ self._moveTag(self._sortable.origIndex, self._sortable.newIndex);
224
+ if(self.options.tagsChanged){
225
+ var tag = self.tagsArray[self._sortable.newIndex];
226
+ self.options.tagsChanged(tag.value, 'moved', tag.element);
227
+ }
228
+ }
229
+ };
230
+
231
+ if (self.options.sortable == 'handle') {
232
+ soptions.handle = 'a.ui-icon';
233
+ soptions.cursor = 'move';
234
+ }
235
+
236
+ self.element.sortable(soptions);
237
+ }
238
+
239
+ },
240
+
241
+ _popSelect:function (tag) {
242
+ $('option:eq(' + tag.index + ')', this.select).remove();
243
+ this.select.change();
244
+ },
245
+
246
+ _addSelect:function (tag) {
247
+ this.select.append('<option selected="selected" value="' + tag.value + '">' + tag.label + '</option>');
248
+ this.select.change();
249
+ },
250
+
251
+ _popTag:function (tag) {
252
+
253
+ //are we removing the last tag or a specific tag?
254
+ if (tag === undefined)
255
+ tag = this.tagsArray.pop();
256
+ else
257
+ this.tagsArray.splice(tag.index, 1);
258
+
259
+
260
+ //maintain the indexes
261
+ for (var ind in this.tagsArray)
262
+ this.tagsArray[ind].index = ind;
263
+
264
+ if (this.options.select)
265
+ this._popSelect(tag);
266
+ if (this.options.tagsChanged)
267
+ this.options.tagsChanged(tag.value || tag.label, 'popped', tag);
268
+ return;
269
+ },
270
+
271
+ _addTag:function (label, value) {
272
+ this.input.autocomplete('close').val("");
273
+
274
+ //are we trying to add a tag that should be split?
275
+ if (this._splitAt && label.search(this._splitAt) > 0) {
276
+ var result = label.split(this._splitAt);
277
+ for (var i = 0; i < result.length; i++)
278
+ this._addTag(result[i], value);
279
+ return;
280
+ }
281
+
282
+ label = label.replace(/,+$/, "").trim();
283
+
284
+ if (label == "")
285
+ return false;
286
+
287
+ var tagExists = this._exists(label, value);
288
+ if (tagExists !== false) {
289
+ this._highlightExisting(tagExists);
290
+ return false;
291
+ }
292
+
293
+ var tag = this.tag(label, value);
294
+ tag.element = $('<li class="tagit-choice"'
295
+ + (value !== undefined ? ' tagValue="' + value + '"' : '') + '>'
296
+ + (this.options.sortable == 'handle' ? '<a class="ui-icon ui-icon-grip-dotted-vertical" style="float:left"></a>' : '')
297
+ + label + '<a class="tagit-close">x</a></li>');
298
+ tag.element.insertBefore(this.input.parent());
299
+ this.tagsArray.push(tag);
300
+
301
+ this.input.val("");
302
+
303
+ if (this.options.select)
304
+ this._addSelect(tag);
305
+ if (this.options.tagsChanged)
306
+ this.options.tagsChanged(tag.label, 'added', tag.element);
307
+ return true;
308
+ },
309
+
310
+ _exists:function (label, value) {
311
+ if (this.tagsArray.length == 0)
312
+ return false;
313
+
314
+ label = this._lowerIfCaseInsensitive(label);
315
+ value = this._lowerIfCaseInsensitive(value);
316
+
317
+ for (var ind in this.tagsArray) {
318
+ if (this._lowerIfCaseInsensitive(this.tagsArray[ind].label) == label) {
319
+ if (value !== undefined) {
320
+ if (this._lowerIfCaseInsensitive(this.tagsArray[ind].value) == value)
321
+ return ind;
322
+ } else {
323
+ return ind;
324
+ }
325
+ }
326
+ }
327
+
328
+ return false;
329
+ },
330
+
331
+ _highlightExisting:function (index) {
332
+ if (this.options.highlightOnExistColor === undefined)
333
+ return;
334
+ var tag = this.tagsArray[index];
335
+ tag.element.stop();
336
+
337
+ var initialColor = tag.element.css('color');
338
+ tag.element.animate({color:this.options.highlightOnExistColor}, 100).animate({'color':initialColor}, 800);
339
+ },
340
+
341
+ _isInitKey:function (keyCode) {
342
+ var keyName = "";
343
+ for (var key in this._keys)
344
+ if ($.inArray(keyCode, this._keys[key]) != -1)
345
+ keyName = key;
346
+
347
+ if ($.inArray(keyName, this.options.triggerKeys) != -1)
348
+ return true;
349
+ return false;
350
+ },
351
+
352
+ _isTabKey:function (keyCode) {
353
+ var tabKeys = this._keys['tab'];
354
+ return $.inArray(keyCode, tabKeys) > -1;
355
+ },
356
+
357
+ _removeTag:function () {
358
+ this._popTag();
359
+ this.element.children(".tagit-choice:last").remove();
360
+ },
361
+
362
+ _backspace:function (li) {
363
+ if (this.input.val() == "") {
364
+ // When backspace is pressed, the last tag is deleted.
365
+ if (this.lastKey == this._keys.backspace) {
366
+ this._popTag();
367
+ li.remove();
368
+ this.lastKey = null;
369
+ } else {
370
+ li.addClass('selected');
371
+ this.lastKey = this._keys.backspace;
372
+ }
373
+ }
374
+ return true;
375
+ },
376
+
377
+ _initialTags:function () {
378
+ var input = this;
379
+ var _temp;
380
+ if (this.options.tagsChanged)
381
+ _temp = this.options.tagsChanged;
382
+ this.options.tagsChanged = null;
383
+
384
+ if (this.options.initialTags.length != 0) {
385
+ $(this.options.initialTags).each(function (i, element) {
386
+ if (typeof (element) == "object")
387
+ input._addTag(element.label, element.value);
388
+ else
389
+ input._addTag(element);
390
+ });
391
+ }
392
+ this.options.tagsChanged = _temp;
393
+ },
394
+
395
+ _lowerIfCaseInsensitive:function (inp) {
396
+
397
+ if (inp === undefined || typeof(inp) != typeof("a"))
398
+ return inp;
399
+
400
+ if (this.options.caseSensitive)
401
+ return inp;
402
+
403
+ return inp.toLowerCase();
404
+
405
+ },
406
+
407
+ _moveTag: function (old_index, new_index) {
408
+ this.tagsArray.splice(new_index, 0, this.tagsArray.splice(old_index, 1)[0]);
409
+ for (var ind in this.tagsArray)
410
+ this.tagsArray[ind].index = ind;
411
+
412
+ if(this.options.select){
413
+ $('option:eq(' + old_index + ')', this.select).insertBefore($('option:eq(' + new_index + ')', this.select));
414
+ }
415
+ },
416
+ tags:function () {
417
+ return this.tagsArray;
418
+ },
419
+
420
+ destroy:function () {
421
+ $.Widget.prototype.destroy.apply(this, arguments); // default destroy
422
+ this.tagsArray = [];
423
+ },
424
+
425
+ reset:function () {
426
+ this.element.find(".tagit-choice").remove();
427
+ this.tagsArray = [];
428
+ if (this.options.select) {
429
+ this.select.children().remove();
430
+ this.select.change();
431
+ }
432
+ this._initialTags();
433
+ if (this.options.tagsChanged)
434
+ this.options.tagsChanged(null, 'reset', null);
435
+ },
436
+
437
+ fill:function (tags) {
438
+
439
+ if (tags !== undefined)
440
+ this.options.initialTags = tags;
441
+ this.reset();
442
+ },
443
+
444
+ add:function (label, value) {
445
+ if(typeof(label) == "object")
446
+ return this._addTag(label.label, label.value);
447
+ else
448
+ return this._addTag(label, value);
449
+ },
450
+
451
+ autocomplete: function(){
452
+ return this.input.data("autocomplete");
453
+ },
454
+
455
+ tag:function (label, value, element) {
456
+ var self = this;
457
+ return {
458
+ label:label,
459
+ value:(value === undefined ? label : value),
460
+ element:element,
461
+ index:self.tagsArray.length
462
+ };
463
+ },
464
+
465
+ remove:function (label, value) {
466
+ if (this.tagsArray.length == 0)
467
+ return false;
468
+
469
+ label = this._lowerIfCaseInsensitive(label);
470
+ value = this._lowerIfCaseInsensitive(value);
471
+
472
+ for (var i = 0; i < this.tagsArray.length; i++) {
473
+ if (this._lowerIfCaseInsensitive(this.tagsArray[i].value) == value || this._lowerIfCaseInsensitive(this.tagsArray[i].label) == label) {
474
+ break;
475
+ }
476
+ }
477
+
478
+ if (i >= 0 && i < this.tagsArray.length) {
479
+ var tag = this.tagsArray[i];
480
+ tag.element.remove();
481
+ this._popTag(tag);
482
+ return true;
483
+ }
484
+ return false;
485
+ }
486
+
487
+
488
+ });
489
+ })(jQuery);