loft 0.1.2 → 0.1.5

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.
data/bower.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "loft",
3
+ "version": "0.1.5",
4
+ "homepage": "https://github.com/slate-studio/loft",
5
+ "authors": [
6
+ "Slate Studio (http://www.slatestudio.com)"
7
+ ],
8
+ "license": "MIT",
9
+ "description": "Media assets manager for Character CMS.",
10
+ "main": "app/assets/stylesheets/_loft.scss, dist/loft.js, app/assets/images/loft/library@3x.png",
11
+ "keywords": [
12
+ "character",
13
+ "cms",
14
+ "gallery",
15
+ "pugin",
16
+ "images",
17
+ "files"
18
+ ],
19
+ "ignore": [
20
+ "**/.*",
21
+ "lib",
22
+ "docs",
23
+ "chr.gemspec",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "Gruntfile.coffee",
27
+ "package.json",
28
+ "Rakefile"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/slate-studio/loft.git"
33
+ },
34
+ "dependencies": {
35
+ "bourbon": ">=4.0",
36
+ "normalize-scss": ">=3.0"
37
+ }
38
+ }
data/dist/loft.js ADDED
@@ -0,0 +1,603 @@
1
+ this.LoftGroupActions = (function() {
2
+ function LoftGroupActions(list, loft) {
3
+ this.list = list;
4
+ this.loft = loft;
5
+ this._render();
6
+ this._bind_checkboxes();
7
+ }
8
+
9
+ LoftGroupActions.prototype._render = function() {
10
+ this.$el = $("<div class='assets-group-actions' style='display:none;'></div>");
11
+ this.list.$header.append(this.$el);
12
+ this.$acceptBtn = $("<a href='#' class='accept'>Accept</a>");
13
+ this.$acceptBtn.on('click', (function(_this) {
14
+ return function(e) {
15
+ e.preventDefault();
16
+ return _this._accept_selected_items();
17
+ };
18
+ })(this));
19
+ this.$el.append(this.$acceptBtn);
20
+ this.$deleteBtn = $("<a href='#' class='delete'>Delete Selected</a>");
21
+ this.$deleteBtn.on('click', (function(_this) {
22
+ return function(e) {
23
+ e.preventDefault();
24
+ return _this._delete_selected_list_items();
25
+ };
26
+ })(this));
27
+ this.$el.append(this.$deleteBtn);
28
+ this.$unselectBtn = $("<a href='#' class='unselect'>Unselect</a>");
29
+ this.$unselectBtn.on('click', (function(_this) {
30
+ return function(e) {
31
+ e.preventDefault();
32
+ return _this._unselect_list_items();
33
+ };
34
+ })(this));
35
+ return this.$el.append(this.$unselectBtn);
36
+ };
37
+
38
+ LoftGroupActions.prototype._bind_checkboxes = function() {
39
+ return this.list.$el.on('click', '.asset .asset-checkbox input', (function(_this) {
40
+ return function(e) {
41
+ var selectedItems;
42
+ if (!_this.loft.selectMultipleAssets) {
43
+ _this._select_single_item($(e.target));
44
+ }
45
+ selectedItems = _this._selected_list_items();
46
+ if (selectedItems.length > 0) {
47
+ return _this._show();
48
+ } else {
49
+ return _this.hide();
50
+ }
51
+ };
52
+ })(this));
53
+ };
54
+
55
+ LoftGroupActions.prototype._select_single_item = function($checkbox) {
56
+ if ($checkbox.prop('checked')) {
57
+ this.list.$el.find('.asset .asset-checkbox input:checked').prop('checked', false);
58
+ return $checkbox.prop('checked', true);
59
+ }
60
+ };
61
+
62
+ LoftGroupActions.prototype._selected_list_items = function() {
63
+ return $.map(this.list.$el.find('.asset .asset-checkbox input:checked'), function(checkbox) {
64
+ return $(checkbox).parent().parent();
65
+ });
66
+ };
67
+
68
+ LoftGroupActions.prototype._unselect_list_items = function() {
69
+ this.list.$el.find('.asset .asset-checkbox input').prop('checked', false);
70
+ return this.hide();
71
+ };
72
+
73
+ LoftGroupActions.prototype._delete_selected_list_items = function() {
74
+ var $item, $selectedItems, filesToRemoveCounter, i, len, objectId;
75
+ if (confirm("Are you sure?")) {
76
+ $selectedItems = this._selected_list_items();
77
+ filesToRemoveCounter = $selectedItems.length;
78
+ for (i = 0, len = $selectedItems.length; i < len; i++) {
79
+ $item = $selectedItems[i];
80
+ objectId = $item.attr('data-id');
81
+ this.list.config.arrayStore.remove(objectId, {
82
+ onSuccess: (function(_this) {
83
+ return function() {};
84
+ })(this),
85
+ onError: (function(_this) {
86
+ return function() {};
87
+ })(this)
88
+ });
89
+ }
90
+ return this.hide();
91
+ }
92
+ };
93
+
94
+ LoftGroupActions.prototype._accept_selected_items = function() {
95
+ var $item, $selectedItems, i, len, object, objectId, objects;
96
+ $selectedItems = this._selected_list_items();
97
+ objects = [];
98
+ for (i = 0, len = $selectedItems.length; i < len; i++) {
99
+ $item = $selectedItems[i];
100
+ objectId = $item.attr('data-id');
101
+ object = this.list.config.arrayStore.get(objectId);
102
+ objects.push(object);
103
+ }
104
+ this.loft.onAcceptCallback(objects);
105
+ return this.loft.closeModal();
106
+ };
107
+
108
+ LoftGroupActions.prototype._show = function() {
109
+ return this.$el.show();
110
+ };
111
+
112
+ LoftGroupActions.prototype.hide = function() {
113
+ return this.$el.hide();
114
+ };
115
+
116
+ return LoftGroupActions;
117
+
118
+ })();
119
+
120
+ var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
121
+ hasProp = {}.hasOwnProperty;
122
+
123
+ this.LoftAssetItem = (function(superClass) {
124
+ extend(LoftAssetItem, superClass);
125
+
126
+ function LoftAssetItem(module, path, object1, config) {
127
+ this.module = module;
128
+ this.path = path;
129
+ this.object = object1;
130
+ this.config = config;
131
+ this.$el = $("<div class='item asset asset-" + this.object.type + "' data-id='" + this.object._id + "'></div>");
132
+ this.render();
133
+ }
134
+
135
+ LoftAssetItem.prototype._bind_name_input = function() {
136
+ this.$nameInput.on('blur', (function(_this) {
137
+ return function(e) {
138
+ return _this._update_name_if_changed();
139
+ };
140
+ })(this));
141
+ return this.$nameInput.on('keyup', (function(_this) {
142
+ return function(e) {
143
+ if (e.keyCode === 13) {
144
+ $(e.target).blur();
145
+ }
146
+ if (e.keyCode === 27) {
147
+ return _this._cancel_name_change();
148
+ }
149
+ };
150
+ })(this));
151
+ };
152
+
153
+ LoftAssetItem.prototype._edit_name = function(e) {
154
+ this.$el.addClass('edit-name');
155
+ return this.$nameInput.focus().select();
156
+ };
157
+
158
+ LoftAssetItem.prototype._cancel_name_change = function() {
159
+ var name;
160
+ this.$el.removeClass('edit-name');
161
+ name = this.$title.html();
162
+ return this.$nameInput.val(name);
163
+ };
164
+
165
+ LoftAssetItem.prototype._update_name_if_changed = function() {
166
+ var name;
167
+ this.$el.removeClass('edit-name');
168
+ name = this.$nameInput.val();
169
+ if (name === this.$title.html()) {
170
+ return;
171
+ }
172
+ this.$title.html(name);
173
+ return this.config.arrayStore.update(this.object._id, {
174
+ '[name]': name
175
+ }, {
176
+ onSuccess: (function(_this) {
177
+ return function(object) {};
178
+ })(this),
179
+ onError: (function(_this) {
180
+ return function(errors) {};
181
+ })(this)
182
+ });
183
+ };
184
+
185
+ LoftAssetItem.prototype.render = function() {
186
+ var name;
187
+ this.$el.html('').removeClass('item-folder has-subtitle has-thumbnail');
188
+ this._render_title();
189
+ this._render_subtitle();
190
+ this.$link = $("<a class='asset-icon' href='" + this.object.file.url + "' target='_blank'></a>");
191
+ this.$el.prepend(this.$link);
192
+ if (this.object.type === 'image' && this.object.grid_item_thumbnail !== '') {
193
+ this.$thumbnailSmall = $("<img class='asset-thumbnail-small' src='" + this.object.item_thumbnail.small + "' />");
194
+ this.$thumbnailMedium = $("<img class='asset-thumbnail-medium' src='" + this.object.item_thumbnail.medium + "' />");
195
+ this.$link.append(this.$thumbnailSmall);
196
+ this.$link.append(this.$thumbnailMedium);
197
+ }
198
+ this.$checkbox = $("<div class='asset-checkbox'></div>");
199
+ this.$checkboxInput = $("<input type='checkbox' />");
200
+ this.$checkbox.append(this.$checkboxInput);
201
+ this.$el.prepend(this.$checkbox);
202
+ name = this.$title.text();
203
+ this.$name = $("<div class='asset-name'></div>");
204
+ this.$nameInput = $("<input type='text' value='" + name + "' />");
205
+ this.$name.append(this.$nameInput);
206
+ this.$title.before(this.$name);
207
+ this._bind_name_input();
208
+ return this.$title.on('click', (function(_this) {
209
+ return function(e) {
210
+ return _this._edit_name(e);
211
+ };
212
+ })(this));
213
+ };
214
+
215
+ return LoftAssetItem;
216
+
217
+ })(Item);
218
+
219
+ this.Loft = (function() {
220
+ function Loft(title, resource, resourcePath, arrayStoreClass, arrayStoreConfig) {
221
+ var moduleConfig;
222
+ this.arrayStoreClass = arrayStoreClass;
223
+ this.arrayStoreConfig = arrayStoreConfig;
224
+ this.module = {};
225
+ this.store = {};
226
+ if (this.arrayStoreClass == null) {
227
+ this.arrayStoreClass = RailsArrayStore;
228
+ }
229
+ if (this.arrayStoreConfig == null) {
230
+ this.arrayStoreConfig = {
231
+ resource: resource,
232
+ path: resourcePath,
233
+ sortBy: 'created_at',
234
+ sortReverse: true,
235
+ searchable: true
236
+ };
237
+ }
238
+ this._uploadsCounter = 0;
239
+ moduleConfig = {
240
+ title: title,
241
+ showNestedListsAside: true,
242
+ items: {
243
+ loft_all: this._nested_list_config('All'),
244
+ loft_images: this._nested_list_config('Images', 'image'),
245
+ loft_text: this._nested_list_config('Text', 'text'),
246
+ loft_archives: this._nested_list_config('Archives', 'archive'),
247
+ loft_audio: this._nested_list_config('Audio', 'audio'),
248
+ loft_video: this._nested_list_config('Video', 'video'),
249
+ loft_other: this._nested_list_config('Other', 'other')
250
+ },
251
+ onModuleInit: (function(_this) {
252
+ return function(module) {
253
+ return _this._initialize_module(module);
254
+ };
255
+ })(this)
256
+ };
257
+ return moduleConfig;
258
+ }
259
+
260
+ Loft.prototype._initialize_module = function(module) {
261
+ this.module = module;
262
+ this.store = this.module.nestedLists.loft_all.config.arrayStore;
263
+ this.module.showModal = (function(_this) {
264
+ return function(assetType, selectMultipleAssets, callback) {
265
+ return _this.showModal(assetType, selectMultipleAssets, callback);
266
+ };
267
+ })(this);
268
+ this.selectMultipleAssets = true;
269
+ this.module.rootList.$modalCloseBtn = $("<a href='#' class='modal-close'>Cancel</a>");
270
+ this.module.rootList.$header.prepend(this.module.rootList.$modalCloseBtn);
271
+ this.module.rootList.$modalCloseBtn.on('click', (function(_this) {
272
+ return function(e) {
273
+ e.preventDefault();
274
+ return _this.closeModal();
275
+ };
276
+ })(this));
277
+ this.module.rootList.$items.on('click', 'a', (function(_this) {
278
+ return function(e) {
279
+ var $item, listName;
280
+ if (_this.module.$el.hasClass('module-modal')) {
281
+ e.preventDefault();
282
+ $item = $(e.currentTarget);
283
+ listName = $item.attr('href').split('/')[2];
284
+ _this.module.activeList.hide();
285
+ _this.module.showList(listName);
286
+ _this.module.activeList.updateItems();
287
+ $item.parent().children('.active').removeClass('active');
288
+ return $item.addClass('active');
289
+ }
290
+ };
291
+ })(this));
292
+ if (!chr.isMobile()) {
293
+ return this.module.$el.addClass('grid-mode');
294
+ }
295
+ };
296
+
297
+ Loft.prototype._nested_list_config = function(moduleName, assetType) {
298
+ var config, storeConfig;
299
+ storeConfig = {};
300
+ $.extend(storeConfig, this.arrayStoreConfig);
301
+ if (assetType) {
302
+ $.extend(storeConfig, {
303
+ urlParams: {
304
+ by_type: assetType
305
+ }
306
+ });
307
+ }
308
+ config = {
309
+ title: moduleName,
310
+ itemTitleField: 'name',
311
+ itemSubtitleField: 'created_ago',
312
+ showWithParent: true,
313
+ itemClass: LoftAssetItem,
314
+ arrayStore: new this.arrayStoreClass(storeConfig),
315
+ onListInit: (function(_this) {
316
+ return function(list) {
317
+ return _this._inititialize_list(list);
318
+ };
319
+ })(this),
320
+ onListShow: (function(_this) {
321
+ return function(list) {
322
+ return _this._clear_assets_selection();
323
+ };
324
+ })(this)
325
+ };
326
+ return config;
327
+ };
328
+
329
+ Loft.prototype._inititialize_list = function(list) {
330
+ list.$uploadInput = $("<input class='asset-upload' type='file' multiple='multiple' />");
331
+ list.$search.before(list.$uploadInput);
332
+ list.$uploadInput.on('change', (function(_this) {
333
+ return function(e) {
334
+ var file, files, i, len, results;
335
+ files = e.target.files;
336
+ if (files.length > 0) {
337
+ results = [];
338
+ for (i = 0, len = files.length; i < len; i++) {
339
+ file = files[i];
340
+ results.push(_this._upload(file, list));
341
+ }
342
+ return results;
343
+ }
344
+ };
345
+ })(this));
346
+ list.groupActions = new LoftGroupActions(list, this);
347
+ list.$switchMode = $("<a class='assets-switch-mode' href='#'></a>");
348
+ list.$backBtn.after(list.$switchMode);
349
+ list.$switchMode.on('click', (function(_this) {
350
+ return function(e) {
351
+ e.preventDefault();
352
+ return _this.module.$el.toggleClass('grid-mode');
353
+ };
354
+ })(this));
355
+ return list.$header.on('click', '.back', (function(_this) {
356
+ return function(e) {
357
+ if (_this.module.$el.hasClass('module-modal')) {
358
+ e.preventDefault();
359
+ return _this.module.showList();
360
+ }
361
+ };
362
+ })(this));
363
+ };
364
+
365
+ Loft.prototype._upload = function(file, list) {
366
+ var obj;
367
+ obj = {};
368
+ obj["__FILE__[file]"] = file;
369
+ this._start_file_upload();
370
+ return this.store.push(obj, {
371
+ onSuccess: (function(_this) {
372
+ return function(object) {
373
+ return _this._finish_file_upload(list);
374
+ };
375
+ })(this),
376
+ onError: (function(_this) {
377
+ return function(errors) {
378
+ _this._finish_file_upload(list);
379
+ return chr.showError('Can\'t upload file.');
380
+ };
381
+ })(this)
382
+ });
383
+ };
384
+
385
+ Loft.prototype._start_file_upload = function() {
386
+ this._uploadsCounter += 1;
387
+ return this.module.$el.addClass('assets-uploading');
388
+ };
389
+
390
+ Loft.prototype._finish_file_upload = function(list) {
391
+ this._uploadsCounter -= 1;
392
+ if (this._uploadsCounter === 0) {
393
+ this.module.$el.removeClass('assets-uploading');
394
+ if (this.module.activeList.name !== 'loft_all') {
395
+ return this.module.activeList.updateItems();
396
+ }
397
+ }
398
+ };
399
+
400
+ Loft.prototype._clear_assets_selection = function() {
401
+ var list, name, ref, results;
402
+ ref = this.module.nestedLists;
403
+ results = [];
404
+ for (name in ref) {
405
+ list = ref[name];
406
+ list.groupActions.hide();
407
+ results.push(list.$items.find('.asset-checkbox').prop('checked', false));
408
+ }
409
+ return results;
410
+ };
411
+
412
+ Loft.prototype.closeModal = function() {
413
+ this.selectMultipleAssets = true;
414
+ this._clear_assets_selection();
415
+ this.module.$el.removeClass('module-modal');
416
+ return this.module.hide();
417
+ };
418
+
419
+ Loft.prototype.showModal = function(assetType, selectMultipleAssets1, onAcceptCallback) {
420
+ if (assetType == null) {
421
+ assetType = 'all';
422
+ }
423
+ this.selectMultipleAssets = selectMultipleAssets1 != null ? selectMultipleAssets1 : false;
424
+ this.onAcceptCallback = onAcceptCallback != null ? onAcceptCallback : $.noop;
425
+ this.module.$el.addClass('module-modal');
426
+ this.module.show();
427
+ this.module.showList("loft_" + assetType);
428
+ this.module.activeList.updateItems();
429
+ this.module.rootList.$items.children().removeClass('active');
430
+ return this.module.rootList.$items.children("[href='#/loft/loft_" + assetType + "']").addClass('active');
431
+ };
432
+
433
+ return Loft;
434
+
435
+ })();
436
+
437
+ if (!this.RedactorPlugins) {
438
+ this.RedactorPlugins = {};
439
+ }
440
+
441
+ RedactorPlugins.loft = function() {
442
+ var methods;
443
+ methods = {
444
+ init: function() {
445
+ var fileButton, imageButton;
446
+ imageButton = this.button.add('image', 'Insert Image');
447
+ this.button.addCallback(imageButton, this.loft.showImagesModal);
448
+ fileButton = this.button.add('file', 'Insert File');
449
+ return this.button.addCallback(fileButton, this.loft.showAllModal);
450
+ },
451
+ showImagesModal: function() {
452
+ return chr.modules.loft.showModal('images', true, (function(_this) {
453
+ return function(objects) {
454
+ return _this.loft.insertImages(objects);
455
+ };
456
+ })(this));
457
+ },
458
+ showAllModal: function() {
459
+ var multipleAssets;
460
+ multipleAssets = this.selection.getText() === '';
461
+ return chr.modules.loft.showModal('all', multipleAssets, (function(_this) {
462
+ return function(objects) {
463
+ return _this.loft.insertFiles(objects);
464
+ };
465
+ })(this));
466
+ },
467
+ insertFiles: function(objects) {
468
+ var asset, html, i, len, links, selectedText;
469
+ if (objects.length > 0) {
470
+ selectedText = this.selection.getText();
471
+ if (selectedText !== '') {
472
+ asset = objects[0];
473
+ html = "<a href='" + asset.file.url + "' target='_blank'>" + selectedText + "</a>";
474
+ } else {
475
+ links = [];
476
+ for (i = 0, len = objects.length; i < len; i++) {
477
+ asset = objects[i];
478
+ links.push("<a href='" + asset.file.url + "' target='_blank'>" + asset.name + "</a>");
479
+ }
480
+ html = links.join('<br>');
481
+ }
482
+ return this.insert.html(html, false);
483
+ }
484
+ },
485
+ insertImages: function(objects) {
486
+ var asset, html, i, images, len;
487
+ if (objects.length > 0) {
488
+ images = [];
489
+ for (i = 0, len = objects.length; i < len; i++) {
490
+ asset = objects[i];
491
+ images.push("<img src='" + asset.file.url + "' alt='" + asset.name + "' />");
492
+ }
493
+ html = images.join('<br>');
494
+ return this.insert.html(html, false);
495
+ }
496
+ }
497
+ };
498
+ return methods;
499
+ };
500
+
501
+
502
+
503
+ var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
504
+ hasProp = {}.hasOwnProperty;
505
+
506
+ this.InputLoftImage = (function(superClass) {
507
+ extend(InputLoftImage, superClass);
508
+
509
+ function InputLoftImage() {
510
+ return InputLoftImage.__super__.constructor.apply(this, arguments);
511
+ }
512
+
513
+ InputLoftImage.prototype._add_input = function() {
514
+ var base;
515
+ if ((base = this.config).placeholder == null) {
516
+ base.placeholder = 'Image url';
517
+ }
518
+ this.$input = $("<input type='string' name='" + this.name + "' value='" + (this._safe_value()) + "' id='" + this.name + "' />");
519
+ this.$el.append(this.$input);
520
+ this.$input.on('change', (function(_this) {
521
+ return function(e) {
522
+ return _this.updateValue($(e.target).val());
523
+ };
524
+ })(this));
525
+ this._add_image();
526
+ this._add_choose_button();
527
+ this._add_remove_button();
528
+ return this._update_input_class();
529
+ };
530
+
531
+ InputLoftImage.prototype._add_image = function() {
532
+ this.$image = $("<a href='' target='_blank' class='image'><img src='' /></a>");
533
+ this.$el.append(this.$image);
534
+ return this._update_image();
535
+ };
536
+
537
+ InputLoftImage.prototype._add_choose_button = function() {
538
+ this.$chooseBtn = $("<a href='#' class='choose'></a><br/>");
539
+ this.$el.append(this.$chooseBtn);
540
+ this._update_choose_button_title();
541
+ return this.$chooseBtn.on('click', (function(_this) {
542
+ return function(e) {
543
+ e.preventDefault();
544
+ return chr.modules.loft.showModal('images', false, function(objects) {
545
+ var asset;
546
+ asset = objects[0];
547
+ return _this.updateValue(asset.file.url);
548
+ });
549
+ };
550
+ })(this));
551
+ };
552
+
553
+ InputLoftImage.prototype._add_remove_button = function() {
554
+ this.$removeBtn = $("<a href='#' class='remove'>Remove</a>");
555
+ this.$el.append(this.$removeBtn);
556
+ return this.$removeBtn.on('click', (function(_this) {
557
+ return function(e) {
558
+ e.preventDefault();
559
+ if (confirm('Are you sure?')) {
560
+ return _this.updateValue('');
561
+ }
562
+ };
563
+ })(this));
564
+ };
565
+
566
+ InputLoftImage.prototype._update_image = function() {
567
+ var url;
568
+ url = this.value;
569
+ this.$image.attr('href', this.value).children().attr('src', this.value);
570
+ if (this.value === '') {
571
+ return this.$image.hide();
572
+ } else {
573
+ return this.$image.show();
574
+ }
575
+ };
576
+
577
+ InputLoftImage.prototype._update_choose_button_title = function() {
578
+ var title;
579
+ title = this.value === '' ? 'Choose or upload' : 'Choose other or upload';
580
+ return this.$chooseBtn.html(title);
581
+ };
582
+
583
+ InputLoftImage.prototype._update_input_class = function() {
584
+ if (this.value === '') {
585
+ return this.$el.removeClass('has-value');
586
+ } else {
587
+ return this.$el.addClass('has-value');
588
+ }
589
+ };
590
+
591
+ InputLoftImage.prototype.updateValue = function(value) {
592
+ this.value = value;
593
+ this.$input.val(this.value);
594
+ this._update_image();
595
+ this._update_choose_button_title();
596
+ return this._update_input_class();
597
+ };
598
+
599
+ return InputLoftImage;
600
+
601
+ })(InputString);
602
+
603
+ chr.formInputs['loft-image'] = InputLoftImage;