loft 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Slate Studio](https://slate-git-images.s3-us-west-1.amazonaws.com/slate.png)](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: []
|