loft 0.1.0
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +24 -0
- data/Gemfile +3 -0
- data/LICENSE.md +21 -0
- data/README.md +55 -0
- data/Rakefile +3 -0
- data/app/assets/javascripts/chr/loft/asset-item.coffee +67 -0
- data/app/assets/javascripts/chr/loft/group-actions.coffee +62 -0
- data/app/assets/javascripts/chr/loft/module.coffee +99 -0
- data/app/assets/javascripts/loft.coffee +3 -0
- data/app/assets/stylesheets/_loft.scss +107 -0
- data/app/uploaders/asset_file_uploader.rb +7 -0
- data/lib/loft.rb +7 -0
- data/lib/loft/engine.rb +5 -0
- data/lib/loft/version.rb +3 -0
- data/lib/mongoid/loft_asset.rb +129 -0
- data/lib/uploaders/asset_file_uploader.rb +23 -0
- data/loft.gemspec +33 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ccac65018592298f1e32ccdc370f0c0b7bb845ad
|
4
|
+
data.tar.gz: ec7a87c3cbc6b444957a82ba71a9086a613bf1a4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea38f740b9bc4a63612cc738e4603e539f72a59f1f93047fd684d3fa88d7385c2b6fd312e88ba533547c7a99f193799a59c5e02f526cbb10c383bb350f2cf8b9
|
7
|
+
data.tar.gz: 038275e74677eacc7818653af9f2567afe4d2eed4cf830c2827107d03059d27bc4ee96ebf2e6c29bfa09bbefa90fd41b0a366fc45dfa025b149bd882fb3b4286
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
We love pull requests. Here’s a quick guide:
|
2
|
+
|
3
|
+
1. Fork the repository.
|
4
|
+
2. Make your changes in a topic branch.
|
5
|
+
3. Squash your commits into a single one (more on that [here](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)).
|
6
|
+
4. Rebase against `origin/master`, push to your fork and submit a pull request.
|
7
|
+
5. If you are writing a new feature please add documentation for it by making another pull request to the `gh-pages` branch.
|
8
|
+
|
9
|
+
At this point you’re waiting on us. We like to at least comment on, if not
|
10
|
+
accept, pull requests within three business days (and, typically, one business
|
11
|
+
day). We may suggest some changes or improvements or alternatives.
|
12
|
+
|
13
|
+
Some things that will increase the chance that your pull request is accepted:
|
14
|
+
|
15
|
+
* Fix a bug, refactor code or expand an existing feature.
|
16
|
+
* Use the right syntax and naming conventions.
|
17
|
+
* Update parts of the documentation that are affected by your contribution.
|
18
|
+
|
19
|
+
**Git Commit Messages**
|
20
|
+
|
21
|
+
* Capitalize your commit messages.
|
22
|
+
* Start your message with a verb.
|
23
|
+
* Use present tense.
|
24
|
+
* Refer to the issue/PR number in your squashed commit message.
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright © 2015 [Slate Studio, LLC](http://slatestudio.com)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the “Software”), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Loft
|
2
|
+
|
3
|
+
## Character CMS media assets plugin
|
4
|
+
|
5
|
+
### Installation
|
6
|
+
|
7
|
+
Add to ```Gemfile```:
|
8
|
+
|
9
|
+
gem 'loft'
|
10
|
+
|
11
|
+
Setup a new model for assets ```asset.rb```:
|
12
|
+
|
13
|
+
class Asset
|
14
|
+
include Mongoid::Document
|
15
|
+
include Mongoid::Timestamps
|
16
|
+
include Mongoid::SerializableId
|
17
|
+
include Mongoid::LoftAsset
|
18
|
+
end
|
19
|
+
|
20
|
+
Add controller for asset model to make it accesible via CMS, e.g. ```app/controllers/admin/assets_controller.rb```:
|
21
|
+
|
22
|
+
class Admin::AssetsController < Admin::BaseController
|
23
|
+
mongosteen
|
24
|
+
has_scope :by_type
|
25
|
+
json_config({ methods: [ :list_item_thumbnail, :created_ago ] })
|
26
|
+
end
|
27
|
+
|
28
|
+
Add admin assets controller to ```routes.rb```:
|
29
|
+
|
30
|
+
resources :assets
|
31
|
+
|
32
|
+
Add to ```admin.scss```:
|
33
|
+
|
34
|
+
@import "loft";
|
35
|
+
|
36
|
+
Add to ```admin.coffee``` character configuration object:
|
37
|
+
|
38
|
+
assets: new Loft('Library', 'asset', '/admin/assets')
|
39
|
+
|
40
|
+
|
41
|
+
## Loft family
|
42
|
+
|
43
|
+
- [Mongosteen](https://github.com/slate-studio/mongosteen): An easy way to add restful actions for mongoid models
|
44
|
+
- [Character](https://github.com/slate-studio/chr): A simple and lightweight javascript library for building data management web apps
|
45
|
+
- [Inverter](https://github.com/slate-studio/inverter): An easy way to connect Rails templates content to CMS
|
46
|
+
|
47
|
+
## Credits
|
48
|
+
|
49
|
+
[](http://slatestudio.com)
|
50
|
+
|
51
|
+
Inverter is maintained and funded by [Slate Studio, LLC](http://slatestudio.com). Tweet your questions or suggestions to [@slatestudio](https://twitter.com/slatestudio) and while you’re at it follow us too.
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
Copyright © 2015 [Slate Studio, LLC](http://slatestudio.com). Character is free software, and may be redistributed under the terms specified in the [license](LICENSE.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# add file icon
|
2
|
+
# add selectbox for delete
|
3
|
+
# add modal dialog mode
|
4
|
+
|
5
|
+
class @LoftAssetItem extends Item
|
6
|
+
constructor: (@module, @path, @object, @config) ->
|
7
|
+
@$el =$ "<div class='item asset' data-id='#{ @object._id }' data-title=''></div>"
|
8
|
+
@render()
|
9
|
+
|
10
|
+
|
11
|
+
render: ->
|
12
|
+
@$el.html('').removeClass('item-folder has-subtitle has-thumbnail')
|
13
|
+
|
14
|
+
@_render_title()
|
15
|
+
@_render_subtitle()
|
16
|
+
|
17
|
+
# asset icon with link
|
18
|
+
@$link =$ "<a class='asset-icon' href='#{ @object.file.url }' target='_blank'></a>"
|
19
|
+
@$el.prepend(@$link)
|
20
|
+
|
21
|
+
# checkbox for item selection
|
22
|
+
@$checkbox =$ "<input class='asset-checkbox' type='checkbox' />"
|
23
|
+
@$el.prepend(@$checkbox)
|
24
|
+
|
25
|
+
# input for assets name
|
26
|
+
name = @$el.attr('data-title')
|
27
|
+
@$nameInput =$ "<input class='asset-name' type='text' value='#{ name }' />"
|
28
|
+
@$title.before @$nameInput
|
29
|
+
@_bind_name_input()
|
30
|
+
|
31
|
+
# handler for asset name change on title click
|
32
|
+
@$title.on 'click', (e) => @_edit_name(e)
|
33
|
+
|
34
|
+
|
35
|
+
_bind_name_input: ->
|
36
|
+
@$nameInput.on 'blur', (e) => @_update_name_if_changed()
|
37
|
+
@$nameInput.on 'keyup', (e) =>
|
38
|
+
if e.keyCode == 13 then $(e.target).blur()
|
39
|
+
if e.keyCode == 27 then @_cancel_name_change()
|
40
|
+
|
41
|
+
|
42
|
+
_edit_name: (e) ->
|
43
|
+
@$el.addClass('edit-name')
|
44
|
+
@$nameInput.focus().select()
|
45
|
+
|
46
|
+
|
47
|
+
_cancel_name_change: ->
|
48
|
+
@$el.removeClass('edit-name')
|
49
|
+
name = @$title.html()
|
50
|
+
@$nameInput.val(name)
|
51
|
+
|
52
|
+
|
53
|
+
_update_name_if_changed: ->
|
54
|
+
@$el.removeClass('edit-name')
|
55
|
+
name = @$nameInput.val()
|
56
|
+
|
57
|
+
if name == @$title.html() then return
|
58
|
+
@$title.html(name)
|
59
|
+
|
60
|
+
@config.arrayStore.update @object._id, { '[name]': name },
|
61
|
+
onSuccess: (object) =>
|
62
|
+
onError: (errors) => # process errors
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class @LoftGroupActions
|
2
|
+
constructor: (@list, @module) ->
|
3
|
+
@_render()
|
4
|
+
@_bind_checkboxes()
|
5
|
+
|
6
|
+
|
7
|
+
_render: ->
|
8
|
+
@$el =$ "<div class='assets-group-actions' style='display:none;'></div>"
|
9
|
+
@list.$header.append @$el
|
10
|
+
|
11
|
+
@$unselectBtn =$ "<a href='#' class='unselect'>Unselect All</a>"
|
12
|
+
@$unselectBtn.on 'click', (e) => e.preventDefault(); @_unselect_list_items()
|
13
|
+
@$el.append @$unselectBtn
|
14
|
+
|
15
|
+
@$deleteBtn =$ "<a href='#' class='delete'>Delete Selected</a>"
|
16
|
+
@$deleteBtn.on 'click', (e) => e.preventDefault(); @_delete_selected_list_items()
|
17
|
+
@$el.append @$deleteBtn
|
18
|
+
|
19
|
+
|
20
|
+
_bind_checkboxes: ->
|
21
|
+
@list.$el.on 'click', '.asset .asset-checkbox', (e) =>
|
22
|
+
selectedItems = @_selected_list_items()
|
23
|
+
if selectedItems.length > 0
|
24
|
+
@_show()
|
25
|
+
else
|
26
|
+
@_hide()
|
27
|
+
|
28
|
+
|
29
|
+
_selected_list_items: ->
|
30
|
+
@list.$el.find '.asset .asset-checkbox:checked'
|
31
|
+
|
32
|
+
|
33
|
+
_unselect_list_items: ->
|
34
|
+
@list.$el.find('.asset .asset-checkbox').prop('checked', false)
|
35
|
+
@_hide()
|
36
|
+
|
37
|
+
|
38
|
+
_delete_selected_list_items: ->
|
39
|
+
if confirm("Are you sure?")
|
40
|
+
selectedItems = @_selected_list_items()
|
41
|
+
filesToRemoveCounter = selectedItems.length
|
42
|
+
|
43
|
+
# we have on scroll pagination so after some items are removed,
|
44
|
+
# next page request might skip items that replaced removed ones
|
45
|
+
for item in selectedItems
|
46
|
+
objectId = $(item).parent().attr('data-id')
|
47
|
+
@list.config.arrayStore.remove objectId,
|
48
|
+
onSuccess: => # success notification
|
49
|
+
onError: => # error notification
|
50
|
+
@_hide()
|
51
|
+
|
52
|
+
|
53
|
+
_show: ->
|
54
|
+
@$el.show()
|
55
|
+
|
56
|
+
|
57
|
+
_hide: ->
|
58
|
+
@$el.hide()
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class @Loft
|
2
|
+
constructor: (title, @resource, @resourcePath) ->
|
3
|
+
@module = {}
|
4
|
+
@store = {}
|
5
|
+
|
6
|
+
@_uploadsCounter = 0
|
7
|
+
|
8
|
+
moduleConfig =
|
9
|
+
title: title
|
10
|
+
showNestedListsAside: true
|
11
|
+
items:
|
12
|
+
assets_all: @_nested_list_config 'All'
|
13
|
+
assets_images: @_nested_list_config 'Images', 'image'
|
14
|
+
assets_text: @_nested_list_config 'Text', 'text'
|
15
|
+
assets_archives: @_nested_list_config 'Archives', 'archive'
|
16
|
+
assets_audio: @_nested_list_config 'Audio', 'audio'
|
17
|
+
assets_video: @_nested_list_config 'Video', 'video'
|
18
|
+
assets_other: @_nested_list_config 'Other', 'other'
|
19
|
+
|
20
|
+
onModuleInit: (module) =>
|
21
|
+
@_initialize_module(module)
|
22
|
+
|
23
|
+
return moduleConfig
|
24
|
+
|
25
|
+
|
26
|
+
_initialize_module: (module) ->
|
27
|
+
@module = module
|
28
|
+
@store = @module.nestedLists.assets_all.config.arrayStore
|
29
|
+
|
30
|
+
|
31
|
+
_nested_list_config: (moduleName, assetType) ->
|
32
|
+
arrayStoreConfig =
|
33
|
+
resource: @resource
|
34
|
+
path: @resourcePath
|
35
|
+
searchable: true
|
36
|
+
|
37
|
+
if assetType
|
38
|
+
$.extend(arrayStoreConfig, { urlParams: { by_type: assetType } })
|
39
|
+
|
40
|
+
config =
|
41
|
+
title: moduleName
|
42
|
+
itemTitleField: 'name'
|
43
|
+
itemSubtitleField: 'created_ago'
|
44
|
+
itemClass: LoftAssetItem
|
45
|
+
arrayStore: new MongosteenArrayStore(arrayStoreConfig)
|
46
|
+
onListInit: (list) => @_inititialize_list(list)
|
47
|
+
|
48
|
+
return config
|
49
|
+
|
50
|
+
|
51
|
+
_inititialize_list: (list) ->
|
52
|
+
# uploading spinner
|
53
|
+
list.$loading =$ "<div class='loader'></div>"
|
54
|
+
list.$el.append list.$loading
|
55
|
+
|
56
|
+
# file input button for uploading new files
|
57
|
+
list.$uploadInput =$ "<input class='asset-upload' type='file' multiple='multiple' />"
|
58
|
+
list.$search.before list.$uploadInput
|
59
|
+
|
60
|
+
# file upload handler
|
61
|
+
list.$uploadInput.on 'change', (e) =>
|
62
|
+
files = e.target.files
|
63
|
+
if files.length > 0
|
64
|
+
@_upload(file, list) for file in files
|
65
|
+
|
66
|
+
# group actions toolbar
|
67
|
+
list.$groupActions = new LoftGroupActions(list, this)
|
68
|
+
|
69
|
+
|
70
|
+
_upload: (file, list) ->
|
71
|
+
obj = {}
|
72
|
+
obj["__FILE__[file]"] = file
|
73
|
+
|
74
|
+
@_start_file_upload()
|
75
|
+
@store.push obj,
|
76
|
+
onSuccess: (object) => @_finish_file_upload(list)
|
77
|
+
onError: (errors) => @_finish_file_upload(list)
|
78
|
+
# + process validation errors, if any
|
79
|
+
|
80
|
+
|
81
|
+
_start_file_upload: ->
|
82
|
+
@_uploadsCounter += 1
|
83
|
+
@module.$el.addClass('assets-uploading')
|
84
|
+
|
85
|
+
|
86
|
+
_finish_file_upload: (list) ->
|
87
|
+
@_uploadsCounter -= 1
|
88
|
+
if @_uploadsCounter == 0
|
89
|
+
@module.$el.removeClass('assets-uploading')
|
90
|
+
|
91
|
+
# update data in list if it's not assets_all,
|
92
|
+
# in there new objects are added automatically
|
93
|
+
visibleList = @module.visibleNestedListShownWithParent()
|
94
|
+
if visibleList.name != 'assets_all'
|
95
|
+
visibleList.updateItems()
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
//
|
2
|
+
// Styles for Loft Character CMS plugin, this should be included in
|
3
|
+
// admin.scss (default)
|
4
|
+
//
|
5
|
+
// - mobile version
|
6
|
+
//
|
7
|
+
|
8
|
+
/* Tablet Layout */
|
9
|
+
@media #{$tablet} {
|
10
|
+
.module.assets {
|
11
|
+
.list:not(:first-child) {
|
12
|
+
.items {
|
13
|
+
.item { min-height: 49px; }
|
14
|
+
.item-title { display: inline-block; }
|
15
|
+
.item-subtitle { display: inline; float: right; }
|
16
|
+
.item.has-subtitle { padding: 1em; }
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
// Group Actions
|
24
|
+
.assets-group-actions {
|
25
|
+
@include absolutePosition(0 0 0 0); background: $white;
|
26
|
+
.unselect { @include headerButton($stableColor); float: left; margin-left: 1em; }
|
27
|
+
.delete { @include headerButton($assertiveColor); float: right; margin-right: 1em; }
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
// Icons for Parrent List
|
32
|
+
.list.assets {
|
33
|
+
.items .item {
|
34
|
+
.item-title { margin-left: 2.05em; }
|
35
|
+
&:before {
|
36
|
+
content: '';
|
37
|
+
position: absolute;
|
38
|
+
display: block; width: 16px; height: 16px;
|
39
|
+
margin-right: 1em;
|
40
|
+
background-color: $lightColor;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
// Upload Button
|
47
|
+
.asset-upload {
|
48
|
+
@include absolutePosition(0 0 inherit inherit);
|
49
|
+
@extend .icon-plus;
|
50
|
+
cursor: pointer;
|
51
|
+
right: -40px;
|
52
|
+
padding-left: 80px;
|
53
|
+
&:focus { outline: none; }
|
54
|
+
}
|
55
|
+
|
56
|
+
.list header {
|
57
|
+
.asset-upload + .search { @include absolutePosition(0 40px inherit inherit); }
|
58
|
+
}
|
59
|
+
|
60
|
+
.list.list-search header {
|
61
|
+
.asset-upload + .search { @include absolutePosition(0 0 inherit 0); }
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
// Loader Spinner
|
66
|
+
.module.assets.assets-uploading .list:not(:first-child) header .spinner { display: inline-block; }
|
67
|
+
|
68
|
+
|
69
|
+
// List Item
|
70
|
+
.item.asset {
|
71
|
+
.item-title {
|
72
|
+
cursor: pointer;
|
73
|
+
position: relative;
|
74
|
+
&:hover { color: $positiveColor; text-decoration: underline; }
|
75
|
+
}
|
76
|
+
.asset-name {
|
77
|
+
display: none;
|
78
|
+
width: 50%;
|
79
|
+
position: absolute;
|
80
|
+
line-height: 1;
|
81
|
+
padding: 0em .3em .3em .375em;
|
82
|
+
top: .55em; bottom: .55em; left: 4.5em;
|
83
|
+
z-index: 1;
|
84
|
+
border-radius: 3px;
|
85
|
+
&:focus {
|
86
|
+
outline: none !important;
|
87
|
+
border: 1px solid $stableColor;
|
88
|
+
box-shadow: 0 0 10px $lightColor;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
.asset-checkbox {
|
92
|
+
position: relative; top: -.25em;
|
93
|
+
margin-right: 1em;
|
94
|
+
}
|
95
|
+
.asset-icon {
|
96
|
+
display: inline-block; width: 16px; height: 16px;
|
97
|
+
margin-right: 1em;
|
98
|
+
background-color: $lightColor; }
|
99
|
+
|
100
|
+
&.edit-name {
|
101
|
+
.asset-name { display: block; }
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
data/lib/loft.rb
ADDED
data/lib/loft/engine.rb
ADDED
data/lib/loft/version.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'autoinc'
|
2
|
+
require 'mongoid_search'
|
3
|
+
|
4
|
+
module Mongoid
|
5
|
+
module LoftAsset
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
|
10
|
+
include Mongoid::Autoinc
|
11
|
+
include Mongoid::Search
|
12
|
+
include ActionView::Helpers::DateHelper
|
13
|
+
include ActionView::Helpers::NumberHelper
|
14
|
+
|
15
|
+
# attributes
|
16
|
+
field :name, default: ''
|
17
|
+
field :filename, default: ''
|
18
|
+
field :size, type: Integer
|
19
|
+
field :humanized_size, default: ''
|
20
|
+
field :type, default: 'other'
|
21
|
+
# - image
|
22
|
+
# - video
|
23
|
+
# - audio
|
24
|
+
# - archive
|
25
|
+
# - text
|
26
|
+
|
27
|
+
# increment value, used by uploader
|
28
|
+
field :_number, type: Integer
|
29
|
+
increments :number
|
30
|
+
|
31
|
+
# uploaders
|
32
|
+
mount_uploader :file, AssetFileUploader
|
33
|
+
|
34
|
+
# validations
|
35
|
+
validates :file, presence: true
|
36
|
+
|
37
|
+
# search
|
38
|
+
search_in :name, :filename
|
39
|
+
|
40
|
+
# scopes
|
41
|
+
default_scope -> { desc(:created_at) }
|
42
|
+
scope :by_type, -> asset_type { where(type: asset_type) }
|
43
|
+
|
44
|
+
# indexes
|
45
|
+
index({ created_at: -1 })
|
46
|
+
|
47
|
+
# callbacks
|
48
|
+
before_save :update_asset_attributes
|
49
|
+
|
50
|
+
|
51
|
+
# helpers
|
52
|
+
def created_ago
|
53
|
+
time_ago_in_words(self.created_at) + " ago"
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def list_item_thumbnail
|
58
|
+
if is_image? and file?
|
59
|
+
file.small_150.url
|
60
|
+
else
|
61
|
+
''
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def content_type
|
67
|
+
@content_type ||= file.content_type
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def is_image?
|
72
|
+
return false unless file?
|
73
|
+
content_type.match(/image\//) ? true : false
|
74
|
+
end
|
75
|
+
|
76
|
+
def is_text?
|
77
|
+
return false unless file?
|
78
|
+
content_type.match(/text\//) ? true : false
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_archive?
|
82
|
+
return false unless file?
|
83
|
+
# need to add more archive types: rar, gz, bz2, gzip
|
84
|
+
content_type.match(/zip/) ? true : false
|
85
|
+
end
|
86
|
+
|
87
|
+
def is_audio?
|
88
|
+
return false unless file?
|
89
|
+
content_type.match(/audio\//) ? true : false
|
90
|
+
end
|
91
|
+
|
92
|
+
def is_video?
|
93
|
+
return false unless file?
|
94
|
+
content_type.match(/video\//) ? true : false
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def update_asset_attributes
|
99
|
+
if file.present? && file_changed?
|
100
|
+
|
101
|
+
# save original file name for search
|
102
|
+
self.filename = file.file.original_filename
|
103
|
+
|
104
|
+
# save file size in plain for search
|
105
|
+
self.size = file.file.size
|
106
|
+
|
107
|
+
# save humanized file size
|
108
|
+
self.humanized_size = number_to_human_size(self.size)
|
109
|
+
|
110
|
+
# asset types
|
111
|
+
self.type = 'image' if self.is_image?
|
112
|
+
self.type = 'text' if self.is_text?
|
113
|
+
self.type = 'archive' if self.is_archive?
|
114
|
+
self.type = 'audio' if self.is_audio?
|
115
|
+
self.type = 'video' if self.is_video?
|
116
|
+
end
|
117
|
+
|
118
|
+
# use filename as an asset name if name is empty ''
|
119
|
+
self.name = self.name.empty? ? self.filename : self.name
|
120
|
+
end
|
121
|
+
private :update_asset_attributes
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Loft
|
2
|
+
module AssetFileUploader
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
|
6
|
+
include CarrierWave::MiniMagick
|
7
|
+
|
8
|
+
def store_dir
|
9
|
+
"assets/loft/#{ model._number }"
|
10
|
+
end
|
11
|
+
|
12
|
+
version :small_150, if: :is_image? do
|
13
|
+
process :resize_to_fill => [150, 150]
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_image? new_file
|
17
|
+
model.is_image?
|
18
|
+
end
|
19
|
+
private :is_image?
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/loft.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'loft/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'loft'
|
7
|
+
s.version = Loft::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Alexander Kravets']
|
10
|
+
s.email = 'alex@slatestudio.com'
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.homepage = 'http://slatestudio.com'
|
13
|
+
s.summary = 'Character CMS media assets plugin.'
|
14
|
+
s.description = <<-DESC
|
15
|
+
This Character CMS plugin adds an assets library that provides an
|
16
|
+
easy way to upload, manage and insert files into documents.
|
17
|
+
DESC
|
18
|
+
|
19
|
+
s.rubyforge_project = 'loft'
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.add_dependency("mongoid_search", ">= 0.3.1")
|
25
|
+
s.add_dependency("mongoid-autoinc", ">= 4.0.0")
|
26
|
+
s.add_dependency("mini_magick", ">= 4.1.0")
|
27
|
+
s.add_dependency("mongoid-grid_fs", ">= 2.1.0")
|
28
|
+
s.add_dependency("carrierwave-mongoid", ">= 0.7.1")
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: loft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Kravets
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mongoid_search
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongoid-autoinc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mini_magick
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.1.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mongoid-grid_fs
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.1.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: carrierwave-mongoid
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.7.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.7.1
|
83
|
+
description: |
|
84
|
+
This Character CMS plugin adds an assets library that provides an
|
85
|
+
easy way to upload, manage and insert files into documents.
|
86
|
+
email: alex@slatestudio.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- CONTRIBUTING.md
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.md
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- app/assets/javascripts/chr/loft/asset-item.coffee
|
97
|
+
- app/assets/javascripts/chr/loft/group-actions.coffee
|
98
|
+
- app/assets/javascripts/chr/loft/module.coffee
|
99
|
+
- app/assets/javascripts/loft.coffee
|
100
|
+
- app/assets/stylesheets/_loft.scss
|
101
|
+
- app/uploaders/asset_file_uploader.rb
|
102
|
+
- lib/loft.rb
|
103
|
+
- lib/loft/engine.rb
|
104
|
+
- lib/loft/version.rb
|
105
|
+
- lib/mongoid/loft_asset.rb
|
106
|
+
- lib/uploaders/asset_file_uploader.rb
|
107
|
+
- loft.gemspec
|
108
|
+
homepage: http://slatestudio.com
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project: loft
|
128
|
+
rubygems_version: 2.4.5
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Character CMS media assets plugin.
|
132
|
+
test_files: []
|