contents_core 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3e33ec3a230bad84970e4f2b43fe3c700e9ff72a
4
+ data.tar.gz: 9d3f7d53a033c6d52b5d22f580ec3210c90c17a0
5
+ SHA512:
6
+ metadata.gz: 566cb403e239475914c934bd85dd1fb37a1a37ad50ede3ca7701f24c61ebcabb96de6e4ee171ebb90dc53700c0bf745fa1ed71b32bd2cef70ce6172399d7cf95
7
+ data.tar.gz: f07a30421f8d0de813666cc48d0d5b00902d8f07f87553abdf85f17c30a306fec0bda45bcec911ecb9776561181825dd446b440037c27b38b7bb7adf253a6263
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # ContentsCore
2
+
3
+ A Rails gem which offer a simple structure to manage contents in a flexible way.
4
+
5
+ _NOTE_: this is an **ALPHA** version, major changes could happens - this is a refactoring of another gem of mine (editable_components)
6
+
7
+ Goals:
8
+
9
+ - attach the necessary data to a model transparently
10
+
11
+ - simplify the components development in views
12
+
13
+ - add blocks / items (= fields) without migrations
14
+
15
+ ### Install
16
+
17
+ - Add to the Gemfile:
18
+ `gem 'contents_core'`
19
+
20
+ - Copy migrations (Rails 5.x syntax, in Rails 4.x use `rake`):
21
+ `rails contents_core:install:migrations`
22
+
23
+ - Migrate
24
+
25
+ - Add the concern *Blocks* to your model: `include ContentsCore::Blocks`
26
+
27
+ ### Config
28
+
29
+ Edit the conf file: `config/initializers/contents_core.rb`
30
+
31
+ ```ruby
32
+ conf = ContentsCore.config
33
+ # Adds a new custom block
34
+ conf[:cc_blocks][:custom] = {
35
+ name: 'Custom block',
36
+ items: {
37
+ int1: :item_integer,
38
+ int2: :item_integer,
39
+ a_float: :item_float
40
+ }
41
+ }
42
+ ContentsCore.config( { components: conf[:cc_blocks] } )
43
+ ```
44
+
45
+ Create the new view blocks: `app/views/contents_core/_block_custom.html.erb`
46
+
47
+ ```erb
48
+ <% if local_assigns[:block] %>
49
+ <% block = local_assigns[:block] %>
50
+ <div <%= block.editable %>>
51
+ 1st number: <span class="num1"<%= block.props.integers[0].editable %>><%= block.props.integers[0] %></span>
52
+ - 2nd number: <span class="num2"<%= block.props.integers[1].editable %>><%= block.props.integers[1] %></span><br/>
53
+ A float: <span <%= block.props.float.editable %>><%= block.props.float %></span><br/>
54
+ </div>
55
+ <% end %>
56
+ ```
57
+
58
+ ##### Images
59
+
60
+ To add support for images add CarrierWave gem to your Gemfile and execute: `rails generate uploader File` and mount it in the model *app/models/contents_core/item_file.rb*:
61
+
62
+ ```rb
63
+ module ContentsCore
64
+ class ItemFile < Item
65
+ mount_uploader :data_file, ImageUploader
66
+
67
+ alias_attribute :data, :data_file
68
+
69
+ def editable
70
+ false
71
+ end
72
+
73
+ def init
74
+ self.data_file = File.open( Rails.root.join( 'public', 'images', 'original', 'missing.jpg' ) )
75
+ self
76
+ end
77
+
78
+ def self.type_name
79
+ 'file'
80
+ end
81
+ end
82
+ end
83
+ ```
84
+
85
+ ##### Custom blocks
86
+
87
+ To create a "free form" block just use: `Page.first.create_block :intro, name: 'IntroBlock', schema: { intro: :item_string, subtitle: :item_string }`
88
+
89
+ ### Dev Notes
90
+
91
+ ##### Structure
92
+
93
+ - Including the Editable concern to a model will add `has_many :ec_blocks` relationship (the list of blocks attached to a container) and some utility methods
94
+
95
+ - Block: an editable UI component (ex. a text with a title, a slider, a 3 column text widgets, etc.); built with a list of sub blocks (for nested components) and a list of items
96
+
97
+ - Item: a single piece of information (ex. a string, a text, a boolean, an integer, a file, etc.)
98
+
99
+ ## Contributors
100
+
101
+ - [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ContentsCore'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'test'
31
+ t.pattern = 'test/**/*_test.rb'
32
+ t.verbose = false
33
+ end
34
+
35
+
36
+ task default: :test
@@ -0,0 +1,5 @@
1
+ module ContentsCore
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,170 @@
1
+ module ContentsCore
2
+ class Block < ApplicationRecord
3
+ EMPTY_DATA = OpenStruct.new( { data: '' } )
4
+
5
+ # --- fields options ----------------------------------------------------- #
6
+ serialize :options, JSON
7
+ serialize :validations, JSON
8
+
9
+ # --- relations ---------------------------------------------------------- #
10
+ belongs_to :parent, polymorphic: true
11
+ has_many :cc_blocks, as: :parent, dependent: :destroy, foreign_key: 'parent_id', class_name: 'Block'
12
+ has_many :items, dependent: :destroy
13
+ accepts_nested_attributes_for :cc_blocks, allow_destroy: true
14
+ accepts_nested_attributes_for :items
15
+
16
+ # --- hooks -------------------------------------------------------------- #
17
+ before_create :on_before_create
18
+ after_create :on_after_create
19
+
20
+ # --- scopes ------------------------------------------------------------- #
21
+ default_scope { order( :position ) }
22
+ scope :published, -> { where( published: true ) unless ContentsCore.editing }
23
+ scope :with_nested, -> { includes( :items, cc_blocks: :items ) }
24
+
25
+ # --- validations -------------------------------------------------------- #
26
+ validates_presence_of :block_type, :position
27
+
28
+ # --- misc --------------------------------------------------------------- #
29
+ ## amoeba do
30
+ ## enable
31
+ ## # customize( lambda { |original_obj, new_obj|
32
+ ## # original_obj.unit_pictures.each{|p| new_obj.unit_pictures.new(:data => File.open(p.data.file.path))}
33
+ ## # })
34
+ ## end
35
+
36
+ # after_validation :on_after_validation
37
+ #
38
+ # field :block_type, type: String, default: 'text'
39
+ # field :name, type: String, default: ''
40
+ # field :position, type: Integer, default: 0
41
+ # field :published, type: Mongoid::Boolean, default: true
42
+ # field :_init, type: Mongoid::Boolean, default: false
43
+ #
44
+ # embedded_in :parent, polymorphic: true
45
+ #
46
+ # embeds_many :cc_blocks, cascade_callbacks: true, order: :position.desc, class_name: 'ContentsCore::Block'
47
+ # embeds_many :items, cascade_callbacks: true, class_name: 'ContentsCore::Item'
48
+ #
49
+ # accepts_nested_attributes_for :cc_blocks, allow_destroy: true
50
+ # accepts_nested_attributes_for :items
51
+ #
52
+ # # scope :published, -> { where( published: true ) unless ApplicationController.edit_mode }
53
+
54
+ def attr_id
55
+ "#{self.class.to_s.split('::').last}-#{self.id}"
56
+ end
57
+
58
+ def children_type
59
+ ContentsCore.config[:cc_blocks][block_type.to_sym][:children_type]
60
+ end
61
+
62
+ def editable
63
+ ContentsCore.editing ? (
64
+ is_sub_block? ?
65
+ {
66
+ 'data-ec-sub-block': self.id,
67
+ 'data-ec-ct': self.block_type,
68
+ 'data-ec-position': self.position,
69
+ 'data-ec-pub': self.published
70
+ } :
71
+ {
72
+ 'data-ec-block': self.id,
73
+ 'data-ec-container': self.children_type,
74
+ 'data-ec-ct': self.block_type,
75
+ 'data-ec-pub': self.published
76
+ }
77
+ ).map { |k, v| "#{k}=\"#{v}\"" }.join( ' ' ).html_safe : ''
78
+ end
79
+
80
+ # Returns an item by name
81
+ def get( name )
82
+ unless @_items
83
+ @_items = {}
84
+ items.each { |item| @_items[item.name] = item }
85
+ end
86
+ @_items[name]
87
+ end
88
+
89
+ def has_parent?
90
+ parent.present?
91
+ end
92
+
93
+ def has_children?
94
+ cc_blocks.exists?
95
+ end
96
+
97
+ def is_sub_block?
98
+ parent.present? && parent_type == 'ContentsCore::Block'
99
+ end
100
+
101
+ def on_after_create
102
+ # TODO: validates type before creation!
103
+ t = self.block_type.to_sym
104
+ Block::init_items( self, ContentsCore.config[:cc_blocks][t][:items] ) if Block::block_types.include?( t )
105
+ end
106
+
107
+ def on_before_create
108
+ if self.name.blank?
109
+ names = parent.cc_blocks.map &:name
110
+ i = 0
111
+ while( ( i += 1 ) < 1000 ) # Search an empty group
112
+ unless names.include? "#{block_type}-#{i}"
113
+ self.name = "#{block_type}-#{i}"
114
+ break
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ def props
121
+ pieces = {}
122
+
123
+ Item::item_types.each do |type|
124
+ pieces[type.pluralize.to_sym] = []
125
+ end
126
+ items.each do |item| # TODO: improve me
127
+ pieces[item.class.type_name.pluralize.to_sym].push item
128
+ end
129
+ Item::item_types.each do |type|
130
+ pieces[type.to_sym] = pieces[type.pluralize.to_sym].any? ? pieces[type.pluralize.to_sym].first : nil # EMPTY_DATA - empty Item per sti class?
131
+ end
132
+
133
+ # pieces = {
134
+ # images: items.select { |item| item.type == ItemImage.to_s },
135
+ # integers: items.select { |item| item.type == ItemInteger.to_s },
136
+ # strings: items.select { |item| item.type == ItemString.to_s },
137
+ # texts: items.select { |item| item.type == ItemText.to_s },
138
+ # }
139
+
140
+ # pieces[:image] = pieces[:images].any? ? pieces[:images].first : EMPTY_DATA
141
+ # pieces[:integers] = pieces[:integers].any? ? pieces[:integers].first : EMPTY_DATA
142
+ # pieces[:string] = pieces[:strings].any? ? pieces[:strings].first : EMPTY_DATA
143
+ # pieces[:text] = pieces[:texts].any? ? pieces[:texts].first : EMPTY_DATA
144
+
145
+ OpenStruct.new( pieces )
146
+ end
147
+
148
+ def self.block_types
149
+ @@block_types ||= ContentsCore.config[:cc_blocks].keys
150
+ end
151
+
152
+ def self.init_items( block, items )
153
+ items.each do |name, type|
154
+ t = type.to_sym
155
+ if type.to_s.start_with? 'item_'
156
+ c = 'ContentsCore::' + ActiveSupport::Inflector.camelize( t )
157
+ begin
158
+ model = c.constantize
159
+ rescue Exception => e
160
+ Rails.logger.error '[ERROR] ContentsCore - init_items: ' + e.message
161
+ model = false
162
+ end
163
+ block.items << model.new( name: name ).init if model
164
+ elsif Block::block_types.include? t.to_sym
165
+ block.cc_blocks << ( cmp = Block.new( block_type: t, name: name ) )
166
+ end
167
+ end if items
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,50 @@
1
+ module ContentsCore
2
+ class Item < ApplicationRecord
3
+ # field :data, type: String
4
+
5
+ # embedded_in :cc_blocks
6
+
7
+ belongs_to :block
8
+
9
+ def attr_id
10
+ "#{self.class_name}-#{self.id}"
11
+ end
12
+
13
+ def class_name
14
+ self.class.to_s.split('::').last
15
+ end
16
+
17
+ def editable
18
+ ContentsCore.editing ? " data-ec-item=\"#{self.id}\" data-ec-input=\"#{self.opt_input}\" data-ec-type=\"#{self.class_name}\"".html_safe : ''
19
+ end
20
+
21
+ def opt_input
22
+ if self.block.options[self.name] && self.block.options[self.name]['input']
23
+ self.block.options[self.name]['input'].to_s
24
+ elsif config[:input]
25
+ config[:input].to_s
26
+ else
27
+ ''
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ self.data
33
+ end
34
+
35
+ def update_data( value )
36
+ self.data = value
37
+ self.save
38
+ end
39
+
40
+ def self.item_types
41
+ @@item_types ||= ContentsCore.config[:items].keys.map &:to_s
42
+ end
43
+
44
+ protected
45
+
46
+ def config
47
+ @config ||= ContentsCore.config[:items][self.class::type_name.to_sym] ? ContentsCore.config[:items][self.class::type_name.to_sym] : {}
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,23 @@
1
+ module ContentsCore
2
+ class ItemBoolean < Item
3
+ alias_attribute :data, :data_boolean
4
+
5
+ def init
6
+ self.data = 0
7
+ self
8
+ end
9
+
10
+ def update_data( value )
11
+ self.data = ( value == 'true' ) ? 1 : 0
12
+ self.save
13
+ end
14
+
15
+ def to_s
16
+ self.data > 0 ? 'true' : 'false'
17
+ end
18
+
19
+ def self.type_name
20
+ 'boolean'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module ContentsCore
2
+ class ItemDatetime < Item
3
+ alias_attribute :data, :data_datetime
4
+
5
+ def init
6
+ self.data = Time.now
7
+ self
8
+ end
9
+
10
+ def self.type_name
11
+ 'datetime'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ module ContentsCore
2
+ class ItemFile < Item
3
+ # has_attached_file :data_string
4
+ # validates_attachment_content_type :data_string, content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
5
+
6
+ # include Mongoid::Paperclip
7
+ # has_mongoid_attached_file :data
8
+ # validates_attachment_content_type :data, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
9
+
10
+ # mount_uploader :data_file, ::FileUploader
11
+
12
+ alias_attribute :data, :data_file
13
+
14
+ def editable
15
+ ContentsCore.editing ? { 'data-ec-item': self.id, 'data-ec-input': self.opt_input, 'data-ec-type': self.class_name, 'data-ec-block': self.block_id } : {}
16
+ end
17
+
18
+ def init
19
+ # self.data_file = File.open( ContentsCore::Engine.root.join( 'lib', 'data', 'img1.jpg' ) )
20
+ self
21
+ end
22
+
23
+ def self.type_name
24
+ 'file'
25
+ end
26
+
27
+ # before_validation :on_before_validation
28
+ #
29
+ # def on_before_validation
30
+ # self.data = File.open( 'rails/editable_components_test/public/img/img1.jpg' )
31
+ # # binding.pry
32
+ # end
33
+
34
+ # before_save :on_before_save
35
+ # before_validation :on_before_validation
36
+ # before_create :on_before_create
37
+ # before_update :on_before_update
38
+ # before_upsert :on_before_upsert
39
+ #
40
+ # def on_before_save; p '>>> before_save'; end
41
+ # def on_before_validation; p '>>> before_validation'; end
42
+ # def on_before_create; p '>>> before_create'; end
43
+ # def on_before_update; p '>>> before_update'; end
44
+ # def on_before_upsert; p '>>> before_upsert'; end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ module ContentsCore
2
+ class ItemFloat < Item
3
+ alias_attribute :data, :data_float
4
+
5
+ def init
6
+ self.data = 0
7
+ self
8
+ end
9
+
10
+ def update_data( value )
11
+ self.data = value.to_f
12
+ self.save
13
+ end
14
+
15
+ def to_s
16
+ self.data.to_s
17
+ end
18
+
19
+ def self.type_name
20
+ 'float'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module ContentsCore
2
+ class ItemHash < Item
3
+ alias_attribute :data, :data_hash
4
+
5
+ serialize :data_hash, JSON
6
+
7
+ def init
8
+ self.data = {}
9
+ self
10
+ end
11
+
12
+ def self.type_name
13
+ 'hash'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module ContentsCore
2
+ class ItemInteger < Item
3
+ alias_attribute :data, :data_integer
4
+
5
+ def init
6
+ self.data = 0
7
+ self
8
+ end
9
+
10
+ def update_data( value )
11
+ self.data = value.to_i
12
+ self.save
13
+ end
14
+
15
+ def to_s
16
+ self.data.to_s
17
+ end
18
+
19
+ def self.type_name
20
+ 'integer'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ module ContentsCore
2
+ class ItemString < Item
3
+ alias_attribute :data, :data_string
4
+
5
+ validate :on_validate
6
+
7
+ def init
8
+ self.data = self.name.gsub( /-/, ' ' ).humanize
9
+ self
10
+ end
11
+
12
+ def on_validate
13
+ if self.block.validations[self.name]
14
+ if self.block.validations[self.name] == 'required'
15
+ self.errors.add( :base, "#{self.name} is required" ) if self.data_string.blank?
16
+ end
17
+ end
18
+ end
19
+
20
+ def update_data( value )
21
+ self.data = ActionController::Base.helpers.sanitize( value, tags: [] )
22
+ self.save
23
+ end
24
+
25
+ def self.type_name
26
+ 'string'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module ContentsCore
2
+ class ItemText < Item
3
+ alias_attribute :data, :data_text
4
+
5
+ def init
6
+ self.data = self.name.gsub( /-/, ' ' ).humanize
7
+ self
8
+ end
9
+
10
+ def update_data( value )
11
+ self.data = ActionController::Base.helpers.sanitize( CGI.unescapeHTML( value ) )
12
+ self.save
13
+ end
14
+
15
+ def self.type_name
16
+ 'text'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+ module ContentsCore
2
+ @@editing = false
3
+
4
+ @@config = {
5
+ cc_blocks: {
6
+ multi_text: {
7
+ children_type: :text,
8
+ name: 'Multi columns block',
9
+ items: {
10
+ column: :text
11
+ }
12
+ },
13
+ text: {
14
+ name: 'Text block',
15
+ items: {
16
+ title: :item_string,
17
+ content: :item_text
18
+ }
19
+ },
20
+ },
21
+ items: {
22
+ boolean: {},
23
+ datetime: {},
24
+ float: {},
25
+ hash: {},
26
+ file: {
27
+ input: :file_image
28
+ },
29
+ integer: {},
30
+ string: {},
31
+ text: {
32
+ input: :html
33
+ },
34
+ }
35
+ }
36
+
37
+ if defined? CarrierWave
38
+ @@config[:cc_blocks].merge!({
39
+ image: {
40
+ name: 'Image block',
41
+ items: {
42
+ img: :item_file
43
+ }
44
+ },
45
+ slide: {
46
+ name: 'Slide block',
47
+ items: {
48
+ img: :item_file,
49
+ title: :item_string
50
+ }
51
+ },
52
+ slider: {
53
+ children_type: :slide,
54
+ name: 'Slider block',
55
+ items: {
56
+ slide: :slide
57
+ }
58
+ },
59
+ text_with_image: {
60
+ name: 'Text with image block',
61
+ items: {
62
+ img: :item_file,
63
+ title: :item_string,
64
+ content: :item_text
65
+ }
66
+ },
67
+ })
68
+
69
+ # ItemImage.class_eval do
70
+ # mount_uploader :data, ImageUploader
71
+ # end
72
+ end
73
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ if defined? ::Rails
2
+ ContentsCore::Engine.routes.draw do
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ class CreateContentsCoreBlocks < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :contents_core_blocks do |t|
4
+ t.string :block_type, null: false, default: 'text'
5
+ t.integer :version, null: false, default: 0
6
+ t.string :name, null: false, default: ''
7
+ t.integer :position, null: false, default: 0
8
+ t.boolean :published, null: false, default: true
9
+ t.string :options, null: false, default: '{}'
10
+ t.string :validations, null: false, default: '{}'
11
+ t.integer :parent_id
12
+ t.string :parent_type
13
+ end
14
+
15
+ add_index :contents_core_blocks, [:parent_id, :parent_type]
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ class CreateContentsCoreItems < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :contents_core_items do |t|
4
+ t.string :type
5
+ t.string :name, null: false, default: 'data'
6
+ t.integer :block_id
7
+ end
8
+
9
+ add_index :contents_core_items, :block_id
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class AddExtraItems < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :contents_core_items, :data_boolean, :boolean
4
+ add_column :contents_core_items, :data_datetime, :datetime
5
+ add_column :contents_core_items, :data_file, :string # , null: false, default: ''
6
+ add_column :contents_core_items, :data_float, :float
7
+ add_column :contents_core_items, :data_hash, :string # , null: false, default: ''
8
+ add_column :contents_core_items, :data_integer, :integer
9
+ add_column :contents_core_items, :data_string, :string # , null: false, default: ''
10
+ add_column :contents_core_items, :data_text, :text
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ require 'contents_core/blocks'
2
+ require 'contents_core/engine'
3
+
4
+ module ContentsCore
5
+ def self.config( options = {} )
6
+ @@config.merge! options
7
+ @@config
8
+ end
9
+
10
+ def self.editing( editing = nil )
11
+ @@editing = editing unless editing.nil?
12
+ @@editing
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ module ContentsCore
2
+ module Blocks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # embeds_many :cc_blocks, as: :parent, cascade_callbacks: true, order: :position.desc, class_name: 'ContentsCore::Block'
7
+ has_many :cc_blocks, as: :parent, dependent: :destroy, foreign_key: 'parent_id', class_name: Block.to_s
8
+ accepts_nested_attributes_for :cc_blocks, allow_destroy: true
9
+
10
+ def create_block( type = :text, params = {} )
11
+ block = Block.new( block_type: type )
12
+ block.name = params[:name] if params[:name]
13
+ block.options = params[:options] if params[:options]
14
+ block.validations = params[:validations] if params[:validations]
15
+ cc_blocks << block
16
+ Block::init_items block, params[:schema] if params[:schema]
17
+ block
18
+ end
19
+
20
+ def current_blocks( version = 0 )
21
+ return @current_blocks if @current_blocks
22
+ version = 0 unless ContentsCore.editing # no admin = only current version
23
+ @current_blocks = cc_blocks.where( version: version.to_i ).with_nested.published
24
+ end
25
+
26
+ def get_block( name, version = 0 )
27
+ current_blocks( version ).each do |block|
28
+ return block if block.name == name
29
+ end
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ if defined? ::Rails
2
+ module ContentsCore
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace ContentsCore
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module ContentsCore
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :contents_core do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: contents_core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mat
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
27
+ description: A Rails gem which offer a simple structure to manage contents in a flexible
28
+ way
29
+ email:
30
+ - mat@blocknot.es
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - app/models/contents_core/application_record.rb
39
+ - app/models/contents_core/block.rb
40
+ - app/models/contents_core/item.rb
41
+ - app/models/contents_core/item_boolean.rb
42
+ - app/models/contents_core/item_datetime.rb
43
+ - app/models/contents_core/item_file.rb
44
+ - app/models/contents_core/item_float.rb
45
+ - app/models/contents_core/item_hash.rb
46
+ - app/models/contents_core/item_integer.rb
47
+ - app/models/contents_core/item_string.rb
48
+ - app/models/contents_core/item_text.rb
49
+ - config/initializers/contents_core.rb
50
+ - config/routes.rb
51
+ - db/migrate/20170414173603_create_contents_core_blocks.rb
52
+ - db/migrate/20170414173610_create_contents_core_items.rb
53
+ - db/migrate/20170414173611_add_extra_items.rb
54
+ - lib/contents_core.rb
55
+ - lib/contents_core/blocks.rb
56
+ - lib/contents_core/engine.rb
57
+ - lib/contents_core/version.rb
58
+ - lib/tasks/contents_core_tasks.rake
59
+ homepage: https://github.com/blocknotes/contents_core
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.5.2
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Flexible contents structure for Rails
83
+ test_files: []