contents_core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []