loft 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/loft.coffee +4 -1
- data/app/assets/javascripts/loft/asset-item.coffee +2 -17
- data/app/assets/javascripts/loft/group-actions.coffee +4 -21
- data/app/assets/javascripts/loft/inputs/loft-image.coffee +37 -38
- data/app/assets/javascripts/loft/module.coffee +57 -123
- data/app/assets/stylesheets/inputs/loft-image.scss +46 -5
- data/app/assets/stylesheets/loft.scss +109 -104
- data/app/controllers/admin/assets_controller.rb +7 -3
- data/app/models/concerns/loft_asset.rb +3 -26
- data/lib/loft.rb +10 -8
- data/lib/loft/routing.rb +7 -0
- data/lib/loft/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfbd343f5dbe51c685e42a35545b11ba6cfc9a75
|
4
|
+
data.tar.gz: d170f5aae6bf0409f13384c08a5f681fa3b0a271
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97cbd7ec0cf1be3aa5dcfeeed783771992fc0fa9aa6ab1eec0325924be97f4936130fd9ede409c1370195cd2855156359a10246cc6e163877c51399d5e5f409c
|
7
|
+
data.tar.gz: 2ac7ed3b842e923257cb9a3dc5950b825f9f5768f7f73ca6939364477ccf3993099ca9064fcc10a024b9d794a45eca9bbf2063408e97c3c74578b815b268b5ed
|
@@ -7,5 +7,8 @@
|
|
7
7
|
## OPTIONAL
|
8
8
|
# require loft/redactor-loft
|
9
9
|
|
10
|
+
@Icons.upload = "<i class='fa fa-cloud-upload'></i>"
|
11
|
+
@Icons.remove = "<i class='fa fa-close'></i>"
|
12
|
+
|
10
13
|
# TODOs:
|
11
|
-
# - refactor group remove action: delete a bunch first, then reload the page
|
14
|
+
# - refactor group remove action: delete a bunch first, then reload the page
|
@@ -1,11 +1,6 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
3
|
# Slate Studio (http://www.slatestudio.com)
|
4
|
-
#
|
5
|
-
# Coding Guide:
|
6
|
-
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
-
# -----------------------------------------------------------------------------
|
8
|
-
|
9
4
|
# -----------------------------------------------------------------------------
|
10
5
|
# Loft Asset Item
|
11
6
|
# -----------------------------------------------------------------------------
|
@@ -14,8 +9,7 @@ class @LoftAssetItem extends Item
|
|
14
9
|
@$el =$ "<div class='item asset asset-#{ @object.type }' data-id='#{ @object._id }'></div>"
|
15
10
|
@render()
|
16
11
|
|
17
|
-
|
18
|
-
# PRIVATE ===============================================
|
12
|
+
# PRIVATE ===================================================================
|
19
13
|
|
20
14
|
_bind_name_input: ->
|
21
15
|
@$nameInput.on 'blur', (e) => @_update_name_if_changed()
|
@@ -23,18 +17,15 @@ class @LoftAssetItem extends Item
|
|
23
17
|
if e.keyCode == 13 then $(e.target).blur()
|
24
18
|
if e.keyCode == 27 then @_cancel_name_change()
|
25
19
|
|
26
|
-
|
27
20
|
_edit_name: (e) ->
|
28
21
|
@$el.addClass('edit-name')
|
29
22
|
@$nameInput.focus().select()
|
30
23
|
|
31
|
-
|
32
24
|
_cancel_name_change: ->
|
33
25
|
@$el.removeClass('edit-name')
|
34
26
|
name = @$title.html()
|
35
27
|
@$nameInput.val(name)
|
36
28
|
|
37
|
-
|
38
29
|
_update_name_if_changed: ->
|
39
30
|
@$el.removeClass('edit-name')
|
40
31
|
name = @$nameInput.val()
|
@@ -46,8 +37,7 @@ class @LoftAssetItem extends Item
|
|
46
37
|
onSuccess: (object) =>
|
47
38
|
onError: (errors) => # process errors
|
48
39
|
|
49
|
-
|
50
|
-
# PUBLIC ================================================
|
40
|
+
# PUBLIC ====================================================================
|
51
41
|
|
52
42
|
render: ->
|
53
43
|
@$el.html('').removeClass('item-folder has-subtitle has-thumbnail')
|
@@ -72,7 +62,6 @@ class @LoftAssetItem extends Item
|
|
72
62
|
@$checkbox.append(@$checkboxInput)
|
73
63
|
@$el.prepend(@$checkbox)
|
74
64
|
|
75
|
-
|
76
65
|
# input for assets name
|
77
66
|
name = @$title.text()
|
78
67
|
@$name =$ "<div class='asset-name'></div>"
|
@@ -83,7 +72,3 @@ class @LoftAssetItem extends Item
|
|
83
72
|
|
84
73
|
# handler for asset name change on title click
|
85
74
|
@$title.on 'click', (e) => @_edit_name(e)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
@@ -1,11 +1,6 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
3
|
# Slate Studio (http://www.slatestudio.com)
|
4
|
-
#
|
5
|
-
# Coding Guide:
|
6
|
-
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
-
# -----------------------------------------------------------------------------
|
8
|
-
|
9
4
|
# -----------------------------------------------------------------------------
|
10
5
|
# Loft Group Actions
|
11
6
|
# -----------------------------------------------------------------------------
|
@@ -14,8 +9,7 @@ class @LoftGroupActions
|
|
14
9
|
@_render()
|
15
10
|
@_bind_checkboxes()
|
16
11
|
|
17
|
-
|
18
|
-
# PRIVATE ===============================================
|
12
|
+
# PRIVATE ===================================================================
|
19
13
|
|
20
14
|
_render: ->
|
21
15
|
@$el =$ "<div class='assets-group-actions' style='display:none;'></div>"
|
@@ -36,7 +30,6 @@ class @LoftGroupActions
|
|
36
30
|
@$unselectBtn.on 'click', (e) => e.preventDefault(); @_unselect_list_items()
|
37
31
|
@$el.append @$unselectBtn
|
38
32
|
|
39
|
-
|
40
33
|
_bind_checkboxes: ->
|
41
34
|
@list.$el.on 'click', '.asset .asset-checkbox input', (e) =>
|
42
35
|
# when multiple selection disabled select only one asset a time
|
@@ -49,22 +42,19 @@ class @LoftGroupActions
|
|
49
42
|
else
|
50
43
|
@hide()
|
51
44
|
|
52
|
-
|
53
45
|
_select_single_item: ($checkbox) ->
|
54
46
|
if $checkbox.prop('checked')
|
55
47
|
@list.$el.find('.asset .asset-checkbox input:checked').prop('checked' , false)
|
56
48
|
$checkbox.prop('checked', true)
|
57
49
|
|
58
|
-
|
59
50
|
_selected_list_items: ->
|
60
|
-
$.map @list.$el.find('.asset .asset-checkbox input:checked'), (checkbox) ->
|
61
|
-
|
51
|
+
$.map @list.$el.find('.asset .asset-checkbox input:checked'), (checkbox) ->
|
52
|
+
$(checkbox).parent().parent()
|
62
53
|
|
63
54
|
_unselect_list_items: ->
|
64
55
|
@list.$el.find('.asset .asset-checkbox input').prop('checked', false)
|
65
56
|
@hide()
|
66
57
|
|
67
|
-
|
68
58
|
_delete_selected_list_items: ->
|
69
59
|
if confirm("Are you sure?")
|
70
60
|
$selectedItems = @_selected_list_items()
|
@@ -79,7 +69,6 @@ class @LoftGroupActions
|
|
79
69
|
onError: => # error notification
|
80
70
|
@hide()
|
81
71
|
|
82
|
-
|
83
72
|
_accept_selected_items: ->
|
84
73
|
$selectedItems = @_selected_list_items()
|
85
74
|
|
@@ -96,16 +85,10 @@ class @LoftGroupActions
|
|
96
85
|
else
|
97
86
|
@loft.onAcceptCallback(objects, => @loft.closeModal())
|
98
87
|
|
99
|
-
|
100
88
|
_show: ->
|
101
89
|
@$el.show()
|
102
90
|
|
103
|
-
|
104
|
-
# PUBLIC ================================================
|
91
|
+
# PUBLIC ====================================================================
|
105
92
|
|
106
93
|
hide: ->
|
107
94
|
@$el.hide()
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
@@ -1,36 +1,41 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
3
|
# Slate Studio (http://www.slatestudio.com)
|
4
|
-
#
|
5
|
-
# Coding Guide:
|
6
|
-
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
-
# -----------------------------------------------------------------------------
|
8
|
-
|
9
4
|
# -----------------------------------------------------------------------------
|
10
5
|
# INPUT LOFT IMAGE
|
11
6
|
# -----------------------------------------------------------------------------
|
12
7
|
class @InputLoftImage extends InputString
|
13
8
|
|
14
|
-
# PRIVATE
|
9
|
+
# PRIVATE ===================================================================
|
15
10
|
|
16
11
|
_add_input: ->
|
17
|
-
@config.placeholder ?= 'Image
|
12
|
+
@config.placeholder ?= 'Image URL'
|
13
|
+
|
14
|
+
type = "string"
|
15
|
+
if @config.fullsizePreview
|
16
|
+
@$el.addClass "fullsize-preview"
|
17
|
+
type = "hidden"
|
18
18
|
|
19
|
-
@$input =$ "<input type='
|
19
|
+
@$input =$ """<input type='#{type}'
|
20
|
+
name='#{ @name }'
|
21
|
+
value='#{ @_safe_value() }'
|
22
|
+
id='#{ @name }' />"""
|
20
23
|
@$el.append @$input
|
21
24
|
@$input.on 'change', (e) =>
|
22
25
|
@updateValue($(e.target).val())
|
23
26
|
|
24
|
-
@
|
27
|
+
if @config.fullsizePreview
|
28
|
+
@_update_preview_background()
|
29
|
+
else
|
30
|
+
@_add_image()
|
31
|
+
@_update_image()
|
32
|
+
|
25
33
|
@_add_actions()
|
26
34
|
@_update_input_class()
|
27
35
|
|
28
|
-
|
29
36
|
_add_image: ->
|
30
37
|
@$image =$ "<a href='' target='_blank' class='image'><img src='' /></a>"
|
31
38
|
@$el.append @$image
|
32
|
-
@_update_image()
|
33
|
-
|
34
39
|
|
35
40
|
_add_actions: ->
|
36
41
|
@$actions =$ "<span class='input-actions'></span>"
|
@@ -39,57 +44,51 @@ class @InputLoftImage extends InputString
|
|
39
44
|
@_add_choose_button()
|
40
45
|
@_add_remove_button()
|
41
46
|
|
42
|
-
|
43
47
|
_add_choose_button: ->
|
44
|
-
@$chooseBtn =$ "<
|
48
|
+
@$chooseBtn =$ "<button class='choose'>#{Icons.upload}</button>"
|
45
49
|
@$actions.append @$chooseBtn
|
46
50
|
|
47
|
-
@_update_choose_button_title()
|
48
|
-
|
49
51
|
@$chooseBtn.on 'click', (e) =>
|
50
|
-
e.preventDefault()
|
51
52
|
chr.modules.loft.showModal 'images', false, (objects) =>
|
52
53
|
asset = objects[0]
|
53
54
|
@updateValue(asset.file.url)
|
54
55
|
|
55
|
-
|
56
56
|
_add_remove_button: ->
|
57
|
-
@$removeBtn =$ "<
|
57
|
+
@$removeBtn =$ "<button class='remove'>#{Icons.remove}</button>"
|
58
58
|
@$actions.append @$removeBtn
|
59
59
|
|
60
60
|
@$removeBtn.on 'click', (e) =>
|
61
|
-
e.preventDefault()
|
62
61
|
if confirm('Are you sure?')
|
63
62
|
@updateValue('')
|
64
63
|
|
64
|
+
_update_preview_background: ->
|
65
|
+
url = @value
|
66
|
+
@$el.css { "background-image": "url(#{url})" }
|
65
67
|
|
66
68
|
_update_image: ->
|
67
69
|
url = @value
|
68
|
-
@$image.attr('href',
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
title = if @value == '' then 'Choose or upload an image' else 'Choose other or upload'
|
74
|
-
@$chooseBtn.html(title)
|
75
|
-
|
70
|
+
@$image.attr('href', url).children().attr('src', url)
|
71
|
+
if url == ''
|
72
|
+
@$image.hide()
|
73
|
+
else
|
74
|
+
@$image.show()
|
76
75
|
|
77
76
|
_update_input_class: ->
|
78
|
-
if @value == ''
|
77
|
+
if @value == ''
|
78
|
+
@$el.removeClass('has-value')
|
79
|
+
else
|
80
|
+
@$el.addClass('has-value')
|
79
81
|
|
80
|
-
|
81
|
-
# PUBLIC ================================================
|
82
|
+
# PUBLIC ====================================================================
|
82
83
|
|
83
84
|
updateValue: (@value) ->
|
84
85
|
@$input.val(@value)
|
85
86
|
|
86
|
-
@
|
87
|
-
|
88
|
-
|
87
|
+
if @config.fullsizePreview
|
88
|
+
@_update_preview_background()
|
89
|
+
else
|
90
|
+
@_update_image()
|
89
91
|
|
92
|
+
@_update_input_class()
|
90
93
|
|
91
94
|
chr.formInputs['loft-image'] = InputLoftImage
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
@@ -1,135 +1,84 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
3
|
# Slate Studio (http://www.slatestudio.com)
|
4
|
-
#
|
5
|
-
# Coding Guide:
|
6
|
-
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
-
# -----------------------------------------------------------------------------
|
8
|
-
|
9
4
|
# -----------------------------------------------------------------------------
|
10
5
|
# Loft
|
11
6
|
# -----------------------------------------------------------------------------
|
12
|
-
#
|
13
7
|
# Public methods:
|
14
8
|
# new Loft(title, resource, resourcePath)
|
15
9
|
# showModal(assetType, @selectMultipleAssets, @onAcceptCallback, @closeOnAccept)
|
16
10
|
# closeModal()
|
17
|
-
#
|
18
11
|
# -----------------------------------------------------------------------------
|
19
12
|
class @Loft
|
20
|
-
constructor: (title=
|
13
|
+
constructor: (title="Media", resource="asset", resourcePath="/admin/assets") ->
|
21
14
|
@module = {}
|
22
15
|
@store = {}
|
16
|
+
@_uploadsCounter = 0
|
17
|
+
|
18
|
+
@title = title
|
19
|
+
@menuIcon = "cloud-upload"
|
23
20
|
|
24
|
-
@
|
25
|
-
@
|
26
|
-
resource:
|
27
|
-
path:
|
28
|
-
sortBy:
|
21
|
+
@itemClass = LoftAssetItem
|
22
|
+
@arrayStore = new RailsArrayStore
|
23
|
+
resource: resource
|
24
|
+
path: resourcePath
|
25
|
+
sortBy: "created_at"
|
29
26
|
sortReverse: true
|
30
27
|
searchable: true
|
31
28
|
|
32
|
-
@
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
menuIcon: 'cloud-upload'
|
37
|
-
showNestedListsAside: true
|
38
|
-
items:
|
39
|
-
loft_all: @_nested_list_config 'All'
|
40
|
-
loft_images: @_nested_list_config 'Images', 'image'
|
41
|
-
loft_text: @_nested_list_config 'Text', 'text'
|
42
|
-
loft_archives: @_nested_list_config 'Archives', 'archive'
|
43
|
-
loft_audio: @_nested_list_config 'Audio', 'audio'
|
44
|
-
loft_video: @_nested_list_config 'Video', 'video'
|
45
|
-
loft_other: @_nested_list_config 'Other', 'other'
|
29
|
+
@listTabs =
|
30
|
+
"All": {}
|
31
|
+
"Images": { images: true }
|
32
|
+
"Documents": { not_images: true }
|
46
33
|
|
47
|
-
|
48
|
-
|
34
|
+
@onListInit = (list) =>
|
35
|
+
@_add_upload_button(list)
|
36
|
+
@_add_group_actions(list)
|
37
|
+
@_add_mode_switch(list)
|
49
38
|
|
50
|
-
|
39
|
+
@onListShow = (list) =>
|
40
|
+
@_clear_assets_selection(list)
|
51
41
|
|
42
|
+
@onModuleInit = (module) =>
|
43
|
+
@_initialize_module(module)
|
52
44
|
|
53
|
-
# PRIVATE
|
45
|
+
# PRIVATE ===================================================================
|
54
46
|
|
55
|
-
_initialize_module: (module) ->
|
56
|
-
@
|
57
|
-
@store
|
58
|
-
@nestedLists = @module.nestedLists
|
59
|
-
moduleName = @module.name
|
60
|
-
firstNestedListPath = _firstNonEmptyValue(@nestedLists).path
|
47
|
+
_initialize_module: (@module) ->
|
48
|
+
@selectMultipleAssets = true
|
49
|
+
@store = @module.rootList.config.arrayStore
|
61
50
|
|
62
|
-
# API method
|
63
51
|
@module.showModal = (assetType, selectMultipleAssets, callback, closeOnAccept) =>
|
64
52
|
@showModal(assetType, selectMultipleAssets, callback, closeOnAccept)
|
65
|
-
@selectMultipleAssets = true
|
66
53
|
|
67
|
-
|
54
|
+
@_add_close_button()
|
55
|
+
@_enable_grid_mode()
|
56
|
+
|
57
|
+
_add_close_button: ->
|
68
58
|
@module.rootList.$modalCloseBtn =$ """<a href='#' class='modal-close'>
|
69
59
|
<i class='fa fa-times'></i>
|
70
60
|
</a>"""
|
71
61
|
@module.rootList.$header.prepend @module.rootList.$modalCloseBtn
|
72
|
-
@module.rootList.$modalCloseBtn.on
|
73
|
-
|
74
|
-
|
75
|
-
@module.rootList.$items.on 'click', 'a', (e) =>
|
76
|
-
if @module.$el.hasClass 'module-modal'
|
77
|
-
e.preventDefault()
|
78
|
-
|
79
|
-
$item = $(e.currentTarget)
|
80
|
-
listName = $item.attr('href').split('/')[2]
|
62
|
+
@module.rootList.$modalCloseBtn.on "click", (e) =>
|
63
|
+
e.preventDefault()
|
64
|
+
@closeModal()
|
81
65
|
|
82
|
-
|
83
|
-
@module.showList(listName)
|
84
|
-
@module.activeList.updateItems()
|
85
|
-
|
86
|
-
$item.parent().children('.active').removeClass('active')
|
87
|
-
$item.addClass('active')
|
88
|
-
|
89
|
-
# enable grid mode as default on desktop/tablet
|
66
|
+
_enable_grid_mode: ->
|
90
67
|
if ! chr.isMobile()
|
91
|
-
@module.$el.addClass
|
92
|
-
|
93
|
-
@module.$el.addClass("module-categories")
|
94
|
-
if chr.isDesktop()
|
95
|
-
chr.$mainMenu
|
96
|
-
.find(".menu-#{moduleName}")
|
97
|
-
.attr("href", firstNestedListPath)
|
68
|
+
@module.$el.addClass "grid-mode"
|
98
69
|
|
99
|
-
|
100
|
-
_nested_list_config: (moduleName, assetType) ->
|
101
|
-
storeConfig = {}
|
102
|
-
$.extend(storeConfig, @arrayStoreConfig)
|
103
|
-
|
104
|
-
if assetType
|
105
|
-
$.extend(storeConfig, { urlParams: { by_type: assetType } })
|
106
|
-
|
107
|
-
config =
|
108
|
-
title: moduleName
|
109
|
-
showWithParent: true
|
110
|
-
itemClass: LoftAssetItem
|
111
|
-
arrayStore: new @arrayStoreClass(storeConfig)
|
112
|
-
onListInit: (list) => @_inititialize_list(list)
|
113
|
-
onListShow: (list) => @_clear_assets_selection()
|
114
|
-
|
115
|
-
return config
|
116
|
-
|
117
|
-
|
118
|
-
_inititialize_list: (list) ->
|
119
|
-
# file input button for uploading new files
|
70
|
+
_add_upload_button: (list) ->
|
120
71
|
list.$uploadInput =$ "<input class='asset-upload' type='file' multiple='multiple' />"
|
121
72
|
list.$search.before list.$uploadInput
|
122
|
-
|
123
|
-
# file upload handler
|
124
|
-
list.$uploadInput.on 'change', (e) =>
|
73
|
+
list.$uploadInput.on "change", (e) =>
|
125
74
|
files = e.target.files
|
126
75
|
if files.length > 0
|
127
76
|
@_upload(file, list) for file in files
|
128
77
|
|
129
|
-
|
78
|
+
_add_group_actions: (list) ->
|
130
79
|
list.groupActions = new LoftGroupActions(list, this)
|
131
80
|
|
132
|
-
|
81
|
+
_add_mode_switch: (list) ->
|
133
82
|
list.$switchMode =$ """<a class='assets-switch-mode' href='#'>
|
134
83
|
<i class='fa fa-fw fa-th-large'></i>
|
135
84
|
<i class='fa fa-fw fa-th-list'></i>
|
@@ -137,12 +86,11 @@ class @Loft
|
|
137
86
|
list.$backBtn.after list.$switchMode
|
138
87
|
list.$switchMode.on 'click', (e) => e.preventDefault() ; @module.$el.toggleClass('grid-mode')
|
139
88
|
|
140
|
-
# modal back for mobiles
|
141
|
-
list.$header.on 'click', '.back', (e) =>
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
89
|
+
# # modal back for mobiles
|
90
|
+
# list.$header.on 'click', '.back', (e) =>
|
91
|
+
# if @module.$el.hasClass 'module-modal'
|
92
|
+
# e.preventDefault()
|
93
|
+
# @module.showList()
|
146
94
|
|
147
95
|
_upload: (file, list) ->
|
148
96
|
obj = {}
|
@@ -153,49 +101,35 @@ class @Loft
|
|
153
101
|
onSuccess: (object) => @_finish_file_upload(list)
|
154
102
|
onError: (errors) =>
|
155
103
|
@_finish_file_upload(list)
|
156
|
-
chr.showError(
|
157
|
-
|
104
|
+
chr.showError("Can't upload file.")
|
158
105
|
|
159
106
|
_start_file_upload: ->
|
160
107
|
@_uploadsCounter += 1
|
161
|
-
@module.$el.addClass(
|
162
|
-
|
108
|
+
@module.$el.addClass("assets-uploading")
|
163
109
|
|
164
110
|
_finish_file_upload: (list) ->
|
165
111
|
@_uploadsCounter -= 1
|
166
112
|
if @_uploadsCounter == 0
|
167
|
-
@module.$el.removeClass(
|
113
|
+
@module.$el.removeClass("assets-uploading")
|
168
114
|
|
169
115
|
# update data in list if it's not loft_all,
|
170
116
|
# in loft_all new objects are added automatically
|
171
|
-
if @module.activeList.name != 'loft_all'
|
172
|
-
|
117
|
+
# if @module.activeList.name != 'loft_all'
|
118
|
+
# @module.activeList.updateItems()
|
173
119
|
|
120
|
+
_clear_assets_selection: (list) ->
|
121
|
+
list.groupActions.hide()
|
122
|
+
list.$items.find(".asset-checkbox").prop("checked", false)
|
174
123
|
|
175
|
-
|
176
|
-
for name, list of @module.nestedLists
|
177
|
-
list.groupActions.hide()
|
178
|
-
list.$items.find('.asset-checkbox').prop('checked', false)
|
179
|
-
|
180
|
-
|
181
|
-
# PUBLIC ================================================
|
124
|
+
# PUBLIC ====================================================================
|
182
125
|
|
183
126
|
closeModal: ->
|
184
127
|
@selectMultipleAssets = true
|
185
|
-
@_clear_assets_selection()
|
186
|
-
@module.$el.removeClass(
|
128
|
+
@_clear_assets_selection(@module.activeList)
|
129
|
+
@module.$el.removeClass("module-modal")
|
187
130
|
@module.hide()
|
188
131
|
|
189
|
-
|
190
|
-
|
191
|
-
showModal: (assetType='all', @selectMultipleAssets=false, @onAcceptCallback=$.noop, @closeOnAccept=true) ->
|
192
|
-
# modal mode
|
193
|
-
@module.$el.addClass('module-modal')
|
194
|
-
# show module
|
132
|
+
showModal: (assetType="all", @selectMultipleAssets=false, @onAcceptCallback=$.noop, @closeOnAccept=true) ->
|
133
|
+
@module.$el.addClass("module-modal")
|
195
134
|
@module.show()
|
196
|
-
# show nested list
|
197
|
-
@module.showList("loft_#{ assetType }")
|
198
135
|
@module.activeList.updateItems()
|
199
|
-
# select active item
|
200
|
-
@module.rootList.$items.children().removeClass('active')
|
201
|
-
@module.rootList.$items.children("[href='#/loft/loft_#{ assetType }']").addClass('active')
|
@@ -1,8 +1,49 @@
|
|
1
1
|
.input-loft-image {
|
2
|
-
input { margin-bottom: .25em; }
|
3
|
-
.image img { max-height: 6em; margin: .25em .75em .25em 0; float: left; }
|
4
|
-
.remove { display: none; }
|
5
2
|
|
6
|
-
|
3
|
+
input { margin-bottom: .25em; }
|
4
|
+
.image img { max-height: 6em; margin: .25em .75em .25em 0; float: left; }
|
5
|
+
.remove { display: none; }
|
6
|
+
|
7
|
+
&.has-value { min-height: 11em; }
|
7
8
|
&.has-value .remove { display: inline; }
|
8
|
-
}
|
9
|
+
}
|
10
|
+
|
11
|
+
.input-loft-image.fullsize-preview {
|
12
|
+
@include no-bottom-border;
|
13
|
+
@include position(absolute, 3.3em null null 0.5em);
|
14
|
+
z-index: 1;
|
15
|
+
width: 5em;
|
16
|
+
height: 5em;
|
17
|
+
min-height: 5em;
|
18
|
+
background-color: $border-color;
|
19
|
+
background-size: cover;
|
20
|
+
padding: 0.15em;
|
21
|
+
|
22
|
+
input,
|
23
|
+
.label-title,
|
24
|
+
.error-message { display: none; }
|
25
|
+
|
26
|
+
button {
|
27
|
+
width: 2em;
|
28
|
+
line-height: 2;
|
29
|
+
text-align: center;
|
30
|
+
border: 0;
|
31
|
+
padding: 0;
|
32
|
+
border-radius: 1.75em;
|
33
|
+
margin: 0.15em;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
/* Tablet ------------------------------------------------------------------ */
|
38
|
+
@media #{$tablet} {
|
39
|
+
.input-loft-image.fullsize-preview {
|
40
|
+
padding: 0.25em;
|
41
|
+
width: 14em;
|
42
|
+
height: 14em;
|
43
|
+
|
44
|
+
button {
|
45
|
+
width: 2.5em;
|
46
|
+
line-height: 2.5;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
@@ -1,10 +1,11 @@
|
|
1
|
-
// -----------------------------------------------------------------------
|
2
|
-
// Basic styles for Loft Character CMS plugin, this should be included in
|
3
|
-
// admin.scss (default)
|
4
|
-
// -----------------------------------------------------------------------
|
5
1
|
@import "inputs/loft-image";
|
6
2
|
|
7
3
|
// MIXINS
|
4
|
+
@mixin loft-icon-base($bgSize, $width, $height) {
|
5
|
+
display: block; background-size: $bgSize; width: $width; height: $height;
|
6
|
+
background-image: image-url("loft/library@3x.png");
|
7
|
+
}
|
8
|
+
|
8
9
|
@mixin loft-icon-label($title) {
|
9
10
|
&:before {
|
10
11
|
display: block; margin-top: 2.6em;
|
@@ -14,51 +15,9 @@
|
|
14
15
|
}
|
15
16
|
}
|
16
17
|
|
17
|
-
@mixin loft-icon-base($bgSize, $width, $height) {
|
18
|
-
display: block; background-size: $bgSize; width: $width; height: $height;
|
19
|
-
background-image: image-url("loft/library@3x.png");
|
20
|
-
}
|
21
|
-
|
22
|
-
// ASSET TYPE ICONS
|
23
|
-
.loft .list:first-child .items {
|
24
|
-
.item {
|
25
|
-
.item-title { margin-left: 2.05em; }
|
26
|
-
&:before { @include position(absolute, null null null 1em); content: ''; display: block; }
|
27
|
-
}
|
28
|
-
|
29
|
-
.item {
|
30
|
-
&:before { @include loft-icon-base(32px 112px, 16px, 16px); }
|
31
|
-
&.active:before { background-position: 16px 0px; }
|
32
|
-
}
|
33
|
-
.item:nth-child(2) {
|
34
|
-
&:before { background-position: 0px -16px; }
|
35
|
-
&.active { &:before { background-position: 16px -16px; } }
|
36
|
-
}
|
37
|
-
.item:nth-child(3) {
|
38
|
-
&:before { background-position: 0px -32px; }
|
39
|
-
&.active { &:before { background-position: 16px -32px; } }
|
40
|
-
}
|
41
|
-
.item:nth-child(4) {
|
42
|
-
&:before { background-position: 0px -48px; }
|
43
|
-
&.active { &:before { background-position: 16px -48px; } }
|
44
|
-
}
|
45
|
-
.item:nth-child(5) {
|
46
|
-
&:before { background-position: 0px -64px; }
|
47
|
-
&.active { &:before { background-position: 16px -64px; } }
|
48
|
-
}
|
49
|
-
.item:nth-child(6) {
|
50
|
-
&:before { background-position: 0px -80px; }
|
51
|
-
&.active { &:before { background-position: 16px -80px; } }
|
52
|
-
}
|
53
|
-
.item:nth-child(7) {
|
54
|
-
&:before { background-position: 0px -96px; }
|
55
|
-
&.active { &:before { background-position: 16px -96px; } }
|
56
|
-
}
|
57
|
-
}
|
58
|
-
|
59
18
|
// LIST MODE
|
60
|
-
.loft .
|
61
|
-
padding-left: 6.25em;
|
19
|
+
.list.loft .items .item.asset {
|
20
|
+
padding-left: 6.25em;
|
62
21
|
|
63
22
|
// checkbox
|
64
23
|
.asset-checkbox {
|
@@ -116,7 +75,7 @@
|
|
116
75
|
.module-modal .assets-group-actions .delete { display: none; }
|
117
76
|
|
118
77
|
// UPLOAD BUTTON
|
119
|
-
.loft .
|
78
|
+
.list.loft .header:before {
|
120
79
|
@include position(absolute, 0px 0px null null);
|
121
80
|
@include header-icon-base;
|
122
81
|
display: block;
|
@@ -136,38 +95,80 @@
|
|
136
95
|
|
137
96
|
.list header .asset-upload + .search { @include position(absolute, 0 40px null null); }
|
138
97
|
.list.list-search header .asset-upload + .search { @include position(absolute, 0 0 null 0); }
|
139
|
-
.loft.assets-uploading .list
|
98
|
+
.loft.assets-uploading .list header .spinner { visibility: visible; }
|
140
99
|
|
141
100
|
// MODAL MODE
|
142
101
|
.loft {
|
143
102
|
.modal-close { display: none; }
|
144
103
|
&.module-modal {
|
145
|
-
@include position(absolute, 0 .5em 0 .5em);
|
104
|
+
@include position(absolute, 0 .5em 0 .5em);
|
105
|
+
z-index: 1100;
|
146
106
|
|
147
107
|
&:after { display: none; }
|
148
108
|
|
149
|
-
// dark background
|
150
109
|
&:before {
|
151
|
-
@include position(fixed, 0px 0px 0px 0px);
|
152
|
-
|
110
|
+
@include position(fixed, 0px 0px 0px 0px);
|
111
|
+
z-index: 0;
|
112
|
+
content: '';
|
113
|
+
display: block;
|
114
|
+
background: rgba(0, 0, 0, 0.25);
|
153
115
|
}
|
154
116
|
|
155
117
|
.modal-close {
|
156
118
|
@include header-icon-base;
|
157
|
-
@include position(absolute, null
|
119
|
+
@include position(absolute, null null null 0);
|
158
120
|
display: block;
|
121
|
+
color: $secondary-font-color;
|
122
|
+
|
123
|
+
&:hover {
|
124
|
+
color: $base-font-color;
|
125
|
+
}
|
159
126
|
}
|
160
|
-
.header { top: 0; left: .5em; right: .5em; width: auto; }
|
161
127
|
|
162
|
-
.
|
128
|
+
.header {
|
129
|
+
top: 0;
|
130
|
+
left: 0.5em;
|
131
|
+
right: 0.5em;
|
132
|
+
width: auto;
|
133
|
+
}
|
134
|
+
|
135
|
+
.back {
|
136
|
+
display: none;
|
137
|
+
}
|
163
138
|
}
|
164
139
|
}
|
165
140
|
|
166
|
-
/* Tablet
|
141
|
+
/* Tablet ----------------------------------------------------------------- */
|
167
142
|
@media #{$tablet} {
|
143
|
+
// LAYOUT
|
144
|
+
.list.loft {
|
145
|
+
width: initial;
|
146
|
+
background-color: $bg-color;
|
147
|
+
|
148
|
+
.header {
|
149
|
+
background-color: $bg-color;
|
150
|
+
}
|
151
|
+
|
152
|
+
.item {
|
153
|
+
background-color: $white-color;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
168
157
|
// ITEMS
|
169
|
-
.loft .
|
170
|
-
|
158
|
+
.list.loft .items {
|
159
|
+
font-size: 1em;
|
160
|
+
padding-top: 1.5em;
|
161
|
+
}
|
162
|
+
|
163
|
+
.list.loft .item {
|
164
|
+
@include no-bottom-border;
|
165
|
+
background-color: $white-color;
|
166
|
+
box-shadow: 0 0 1px rgba(0,0,0,0.15);
|
167
|
+
margin: 0 auto;
|
168
|
+
max-width: 44em;
|
169
|
+
}
|
170
|
+
|
171
|
+
.list.loft .items .item.asset {
|
171
172
|
padding-top: 19px; padding-bottom: 19px;
|
172
173
|
.item-title {
|
173
174
|
display: inline; cursor: pointer;
|
@@ -183,62 +184,66 @@
|
|
183
184
|
|
184
185
|
// GRID MODE
|
185
186
|
.assets-switch-mode {
|
186
|
-
@include position(absolute, null null null
|
187
|
-
display: inline
|
187
|
+
@include position(absolute, null 5.5em null null);
|
188
|
+
display: inline-block;
|
189
|
+
line-height: 2.5;
|
188
190
|
i:first-child { color: $border-color; }
|
189
|
-
i:last-child { color: rgba($base-font-color, .4); }
|
191
|
+
i:last-child { color: rgba($base-font-color, 0.4); }
|
190
192
|
}
|
193
|
+
|
191
194
|
.loft.grid-mode .assets-switch-mode {
|
192
|
-
i:first-child { color: rgba($base-font-color, .4); }
|
195
|
+
i:first-child { color: rgba($base-font-color, 0.4); }
|
193
196
|
i:last-child { color: $border-color; }
|
194
197
|
}
|
195
198
|
|
196
|
-
.loft.grid-mode {
|
197
|
-
|
198
|
-
padding: 1em .25em 5em .75em;
|
199
|
-
.item.asset { margin: 0 .75em 1.5em; float: left; display: inline-block; }
|
200
|
-
|
201
|
-
.item.asset {
|
202
|
-
padding-left: 1em; width: 222px; height: 222px;
|
203
|
-
@include no-bottom-border; border: 1px solid rgba($base-font-color, .2); border-radius: 4px;
|
199
|
+
.loft.grid-mode .list .items {
|
200
|
+
padding: 1em .25em 5em .75em;
|
204
201
|
|
205
|
-
|
206
|
-
.asset-checkbox {
|
207
|
-
top: 10px; left: 10px; width: 24px; height: 24px; background: white;
|
208
|
-
box-shadow: 0 1px 0 rgba(0,0,0,0.05),1px 0 0 rgba(0,0,0,0.05); border-bottom-right-radius: 4px;
|
209
|
-
}
|
202
|
+
.item.asset { margin: 0 .75em 1.5em; float: left; display: inline-block; }
|
210
203
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
}
|
204
|
+
.item.asset {
|
205
|
+
padding-left: 1em; width: 222px; height: 222px;
|
206
|
+
@include no-bottom-border;
|
207
|
+
box-shadow: 0 0 1px rgba(0,0,0,0.2);
|
208
|
+
border-radius: 4px;
|
217
209
|
|
218
|
-
|
219
|
-
|
210
|
+
// checkbox: position + decoration
|
211
|
+
.asset-checkbox {
|
212
|
+
top: 10px;
|
213
|
+
left: 10px;
|
214
|
+
width: 24px;
|
215
|
+
height: 24px;
|
216
|
+
background: $white-color;
|
217
|
+
box-shadow: 0 1px 0 rgba(0,0,0,0.05),1px 0 0 rgba(0,0,0,0.05);
|
218
|
+
border-bottom-right-radius: 4px;
|
219
|
+
}
|
220
220
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
221
|
+
// thumbnail
|
222
|
+
.asset-icon {
|
223
|
+
@include position(absolute, 10px null null 10px);
|
224
|
+
width: 200px; height: 150px; background: white; border-radius: 0;
|
225
|
+
&:after {
|
226
|
+
@include position(absolute, 0 0 0 0);
|
227
|
+
box-shadow: 0 0 1px rgba(0,0,0,0.2) inset;
|
228
|
+
content: '';
|
229
|
+
display: block;
|
230
|
+
}
|
225
231
|
}
|
226
232
|
|
227
|
-
|
228
|
-
.asset-
|
229
|
-
.asset-archive .asset-icon { @include loft-icon-label('Archive'); }
|
230
|
-
.asset-audio .asset-icon { @include loft-icon-label('Audio'); }
|
231
|
-
.asset-video .asset-icon { @include loft-icon-label('Video'); }
|
232
|
-
.asset-other .asset-icon { @include loft-icon-label('File'); }
|
233
|
-
}
|
234
|
-
}
|
235
|
-
}
|
233
|
+
.asset-thumbnail-small { display: none; }
|
234
|
+
.asset-thumbnail-medium { display: block; }
|
236
235
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
236
|
+
// name & subtitle
|
237
|
+
.item-title { display: block; margin-top: 9.45em; }
|
238
|
+
.item-subtitle { display: block; position: initial; margin-top: .3em; }
|
239
|
+
&.edit-name .asset-name { top: inherit; bottom: 27px; left: 10px; right: 10px; }
|
240
|
+
}
|
241
241
|
|
242
|
-
|
243
|
-
|
242
|
+
// asset type labels
|
243
|
+
.asset-text .asset-icon { @include loft-icon-label('Text'); }
|
244
|
+
.asset-archive .asset-icon { @include loft-icon-label('Archive'); }
|
245
|
+
.asset-audio .asset-icon { @include loft-icon-label('Audio'); }
|
246
|
+
.asset-video .asset-icon { @include loft-icon-label('Video'); }
|
247
|
+
.asset-other .asset-icon { @include loft-icon-label('File'); }
|
248
|
+
}
|
244
249
|
}
|
@@ -1,5 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Admin
|
2
|
+
class AssetsController < Admin::BaseController
|
3
|
+
mongosteen
|
3
4
|
|
4
|
-
|
5
|
+
has_scope :by_type
|
6
|
+
has_scope :images, type: :boolean
|
7
|
+
has_scope :not_images, type: :boolean
|
8
|
+
end
|
5
9
|
end
|
@@ -1,20 +1,13 @@
|
|
1
|
-
require 'autoinc'
|
2
|
-
|
3
1
|
module LoftAsset
|
4
2
|
extend ActiveSupport::Concern
|
5
|
-
|
6
3
|
included do
|
7
|
-
|
8
4
|
include Mongoid::Timestamps
|
9
5
|
include Mongoid::Autoinc
|
10
6
|
include Mongoid::Search
|
11
|
-
|
12
7
|
include Ants::Id
|
13
|
-
|
14
8
|
include ActionView::Helpers::DateHelper
|
15
9
|
include ActionView::Helpers::NumberHelper
|
16
10
|
|
17
|
-
|
18
11
|
## Attributes
|
19
12
|
field :name, default: ''
|
20
13
|
field :filename, default: ''
|
@@ -31,43 +24,36 @@ module LoftAsset
|
|
31
24
|
field :_number, type: Integer
|
32
25
|
increments :_number
|
33
26
|
|
34
|
-
|
35
27
|
## Uploaders
|
36
28
|
mount_uploader :file, AssetFileUploader
|
37
29
|
|
38
|
-
|
39
30
|
## Validations
|
40
31
|
validates :file, presence: true
|
41
32
|
|
42
|
-
|
43
33
|
## Search
|
44
34
|
search_in :name, :filename
|
45
35
|
|
46
|
-
|
47
36
|
## Scopes
|
48
|
-
default_scope
|
37
|
+
default_scope -> { desc(:created_at) }
|
49
38
|
scope :by_type, -> asset_type { where(type: asset_type) }
|
50
|
-
|
39
|
+
scope :images, -> { where(type: "image") }
|
40
|
+
scope :not_images, -> { where(:type.ne => "image" ) }
|
51
41
|
|
52
42
|
## Indexes
|
53
43
|
index({ created_at: -1 })
|
54
44
|
|
55
|
-
|
56
45
|
## Callbacks
|
57
46
|
before_save :update_asset_attributes
|
58
47
|
|
59
|
-
|
60
48
|
## Helpers
|
61
49
|
def _list_item_title
|
62
50
|
name
|
63
51
|
end
|
64
52
|
|
65
|
-
|
66
53
|
def _list_item_subtitle
|
67
54
|
time_ago_in_words(self.created_at) + " ago"
|
68
55
|
end
|
69
56
|
|
70
|
-
|
71
57
|
def _list_item_thumbnail
|
72
58
|
if is_image?
|
73
59
|
{ medium: file._200x150_2x.url, small: file._40x40_2x.url }
|
@@ -76,49 +62,41 @@ module LoftAsset
|
|
76
62
|
end
|
77
63
|
end
|
78
64
|
|
79
|
-
|
80
65
|
def content_type
|
81
66
|
@content_type ||= file.content_type
|
82
67
|
end
|
83
68
|
|
84
|
-
|
85
69
|
def is_image?
|
86
70
|
return false unless file?
|
87
71
|
content_type.match(/image\//) ? true : false
|
88
72
|
end
|
89
73
|
|
90
|
-
|
91
74
|
def is_text?
|
92
75
|
return false unless file?
|
93
76
|
content_type.match(/text\//) ? true : false
|
94
77
|
end
|
95
78
|
|
96
|
-
|
97
79
|
def is_pdf?
|
98
80
|
return false unless file?
|
99
81
|
content_type.match(/pdf/) ? true : false
|
100
82
|
end
|
101
83
|
|
102
|
-
|
103
84
|
def is_archive?
|
104
85
|
return false unless file?
|
105
86
|
# need to add more archive types: rar, gz, bz2, gzip
|
106
87
|
content_type.match(/zip/) ? true : false
|
107
88
|
end
|
108
89
|
|
109
|
-
|
110
90
|
def is_audio?
|
111
91
|
return false unless file?
|
112
92
|
content_type.match(/audio\//) ? true : false
|
113
93
|
end
|
114
94
|
|
115
|
-
|
116
95
|
def is_video?
|
117
96
|
return false unless file?
|
118
97
|
content_type.match(/video\//) ? true : false
|
119
98
|
end
|
120
99
|
|
121
|
-
|
122
100
|
def update_asset_attributes
|
123
101
|
if file.present? && file_changed?
|
124
102
|
|
@@ -144,6 +122,5 @@ module LoftAsset
|
|
144
122
|
self.name = self.name.empty? ? self.filename : self.name
|
145
123
|
end
|
146
124
|
private :update_asset_attributes
|
147
|
-
|
148
125
|
end
|
149
126
|
end
|
data/lib/loft.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
require "chr"
|
2
|
+
require "ants"
|
3
|
+
require "mongosteen"
|
4
|
+
require "mini_magick"
|
5
|
+
require "mongoid_search"
|
6
|
+
require "mongoid-grid_fs"
|
7
|
+
require "carrierwave/mongoid"
|
8
|
+
require "autoinc"
|
8
9
|
|
9
10
|
module Loft
|
10
11
|
class Engine < ::Rails::Engine
|
11
|
-
require
|
12
|
+
require "loft/engine"
|
13
|
+
require "loft/routing"
|
12
14
|
end
|
13
15
|
end
|
data/lib/loft/routing.rb
ADDED
data/lib/loft/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: loft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Kravets
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chr
|
@@ -181,6 +181,7 @@ files:
|
|
181
181
|
- app/uploaders/asset_file_uploader.rb
|
182
182
|
- lib/loft.rb
|
183
183
|
- lib/loft/engine.rb
|
184
|
+
- lib/loft/routing.rb
|
184
185
|
- lib/loft/version.rb
|
185
186
|
- loft.gemspec
|
186
187
|
homepage: http://slatestudio.com
|