adva_cells 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a31acd0faa774a966b3b3e5d7ffcde47a1d2c72a
4
+ data.tar.gz: e03500610437b0c644ef3964222fd5c398836931
5
+ SHA512:
6
+ metadata.gz: 2a8f443c48f1f8cf1a38f05456e041a10be84c82a538f2095fe36d06853d78151da9a763bcdab37586adba6cf51ac59c03ab259e92d10f266cee739a2b0e0139
7
+ data.tar.gz: 494eb02234bc920f62f4efab7198973394cdfa6ec5d6730a0f6efe125d62538aba0e9cd63d169380695bfdde2e8989ac0bb26b5702df2f191272bbdcf446a8e9
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in adva_cells.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Micah Geisel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # AdvaCells
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'adva_cells'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install adva_cells
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/adva_cells/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Micah Geisel"]
6
+ gem.email = ["micah@botandrose.com"]
7
+ gem.description = %q{Adva Cells}
8
+ gem.summary = %q{Engine for Adva CMS embedable cells}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "adva_cells"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = AdvaCells::VERSION
17
+
18
+ gem.add_dependency "cells"
19
+ gem.add_dependency "tilt"
20
+ end
@@ -0,0 +1,83 @@
1
+ require "cells"
2
+ require "cell/base"
3
+ require "tilt"
4
+
5
+ class BaseCell < Cell::Base
6
+ def self.to_xml(options={})
7
+ options[:root] ||= 'cell'
8
+ options[:indent] ||= 2
9
+ options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
10
+
11
+ cell_name = self.to_s.gsub('Cell', '').underscore
12
+
13
+ options[:builder].tag!(options[:root]) do |cell_node|
14
+ cell_node.id cell_name
15
+ cell_node.name cell_name.humanize
16
+ cell_node.states do |states_node|
17
+ self.action_methods.each do |state|
18
+ states_node.state do |state_node|
19
+ state = state.to_s
20
+
21
+ template_path = "#{view_paths.first}/#{cell_name}/#{state}_form.html*"
22
+ possible_templates = Dir.glob(template_path)
23
+ template = possible_templates.first
24
+ form = template ? Tilt.new(template).render : ''
25
+
26
+ state_node.id state
27
+ state_node.name state.humanize
28
+ state_node.description I18n.translate(:"adva.cells.#{cell_name}.states.#{state}.description", :default => '')
29
+ state_node.form form
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.to_json
37
+ cell_name = self.to_s.sub("Cell", "").underscore
38
+ action_methods.map do |state|
39
+ {
40
+ id: "#{cell_name}/#{state.to_s}",
41
+ name: "#{cell_name.humanize} #{state.to_s.humanize}",
42
+ }
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ def symbolize_options!
49
+ @opts.symbolize_keys!
50
+ end
51
+
52
+ def set_site
53
+ @site = controller.site or raise "can not set site from controller"
54
+ end
55
+
56
+ def set_section
57
+ if section = @opts[:section]
58
+ @section = @site.sections.find(:first, :conditions => ["id = ? OR permalink = ?", section, section])
59
+ end
60
+ @section ||= controller.section
61
+ @section ||= @site.sections.root
62
+ end
63
+
64
+ # TODO make this a class level dsl, so cells can say something like:
65
+ # has_option :include_child_section => {:type => :boolean, :default => true}
66
+ def include_child_sections?
67
+ boolean_option(:include_child_sections)
68
+ end
69
+
70
+ def boolean_option(key)
71
+ value = @opts[key]
72
+ !!(value.blank? || value == 'false' || value == '0' ? false : true)
73
+ end
74
+
75
+ def with_sections_scope(klass, &block)
76
+ conditions = include_child_sections? ?
77
+ ["(sections.lft >= ?) and (sections.rgt <= ?)", @section.lft, @section.rgt] :
78
+ { :section_id => @section.id }
79
+ options = { :find => { :conditions => conditions, :include => 'section' }}
80
+
81
+ klass.send :with_scope, options, &block
82
+ end
83
+ end
@@ -0,0 +1,10 @@
1
+ class Admin::CellsController < Admin::BaseController
2
+ def index
3
+ @cells = Cell.all
4
+
5
+ respond_to do |format|
6
+ format.xml { render :xml => @cells.to_xml(:root => 'cells', :skip_types => true) }
7
+ format.json { render :json => { cells: @cells.map(&:to_json).flatten } }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module ContactMailerHelper
2
+ def render_fields(fields)
3
+ builder = ContactMailFormBuilder.new
4
+ fields.each { |field| builder.add_field(field.symbolize_keys!) }
5
+ builder.render_fields
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ Rails.application.routes.draw do
2
+ namespace :admin do
3
+ get "cells" => "cells#index"
4
+ end
5
+ end
6
+
@@ -0,0 +1,13 @@
1
+ # require "adva_cells/version"
2
+ require "rails"
3
+ require "cells"
4
+ require "cells_ext"
5
+ require "output_filter/cells"
6
+
7
+ module AdvaCells
8
+ class Engine < Rails::Engine
9
+ initializer "adva_cells.init" do |app|
10
+ app.config.middleware.use "OutputFilter::Cells"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module AdvaCells
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ module Cell
2
+ class << self
3
+ def all
4
+ @all ||= begin
5
+ require_all_cells
6
+ BaseCell.subclasses
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def require_all_cells
13
+ # TODO pull in cells from engines, too
14
+ cell_files = Dir[::Rails.root.join('app/cells/*.rb')]
15
+ cell_files.each { |cell_file| require cell_file }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,178 @@
1
+ class ContactMailFormBuilder
2
+ def add_fields(fields)
3
+ fields.each do |field|
4
+ add_field(field)
5
+ end
6
+ end
7
+
8
+ def add_field(field)
9
+ fields << case field[:type]
10
+ when 'header' then Tags::Header.new(field)
11
+ when 'text_field' then Tags::TextField.new(field)
12
+ when 'text_area' then Tags::TextArea.new(field)
13
+ when 'radio_button' then Tags::RadioButton.new(field)
14
+ when 'check_box' then Tags::CheckBox.new(field)
15
+ when 'select' then Tags::Select.new(field)
16
+ else ''
17
+ end
18
+ end
19
+
20
+ def fields
21
+ @fields ||= []
22
+ end
23
+
24
+ def render_fields
25
+ html = ""
26
+ fields.collect do |field|
27
+ if field.valid?
28
+ if field.is_a?(Tags::Header)
29
+ html += "\n" + field.render + "\n"
30
+ else
31
+ html += "<p>\n" + field.render + "</p>\n"
32
+ end
33
+ end
34
+ end
35
+ html
36
+ end
37
+ end
38
+
39
+ module Tags
40
+ class Base
41
+ include ActionView::Helpers::FormTagHelper
42
+ include ActionView::Helpers::FormOptionsHelper
43
+ include ActionView::Helpers::TagHelper
44
+
45
+ attr_accessor :options
46
+
47
+ def initialize(options = {})
48
+ @options = options[:options] || {}
49
+ end
50
+
51
+ def type
52
+ self.class.to_s.sub(/Tags::/, '')
53
+ end
54
+
55
+ def valid?
56
+ true
57
+ end
58
+
59
+ def render
60
+ ""
61
+ end
62
+ end
63
+
64
+ class FormFieldBase < Base
65
+ attr_accessor :name, :label, :value
66
+
67
+ def initialize(options = {})
68
+ super
69
+ @name = options[:name]
70
+ @value = options[:value]
71
+ @label = options[:label]
72
+ end
73
+
74
+ def valid?
75
+ !!name
76
+ end
77
+
78
+ def label_for
79
+ field = label ? label : name.capitalize
80
+ "\t<label for='contact_mail_#{dehumanize(field)}'>#{field}</label>\n"
81
+ end
82
+
83
+ def dehumanize(string)
84
+ string.gsub(/([^A-Za-z0-9_])/, "_").gsub(/([_.][_.]+)/, "_").gsub(/(^[_.]|[_.]$)/, "").downcase
85
+ end
86
+
87
+ def dehumanized_name
88
+ :"contact_mail[#{dehumanize(name)}]"
89
+ end
90
+
91
+ end
92
+
93
+ class CheckableBase < FormFieldBase
94
+ attr_accessor :checked
95
+
96
+ def initialize(options = {})
97
+ super
98
+ @checked = options[:checked]
99
+ end
100
+ end
101
+
102
+ class TextField < FormFieldBase
103
+ def render
104
+ label_for + "\t" + text_field_tag(dehumanized_name, value, options) + "\n"
105
+ end
106
+ end
107
+
108
+ class TextArea < FormFieldBase
109
+ def text_area_options
110
+ options[:id] ? options : options.merge(:id => "contact_mail_#{name}")
111
+ end
112
+
113
+ def render
114
+ label_for + "\t" + text_area_tag(dehumanized_name, value, text_area_options) + "\n"
115
+ end
116
+ end
117
+
118
+ class Select < FormFieldBase
119
+ attr_accessor :option_tags
120
+
121
+ def initialize(options = {})
122
+ super
123
+ if options[:option_tags]
124
+ @option_tags = options[:option_tags].delete('option')
125
+ elsif options[:options] && options[:options]['option']
126
+ @option_tags = options[:options].delete('option')
127
+ else
128
+ @option_tags = {}
129
+ end
130
+ end
131
+
132
+ def formatted_option_tags
133
+ option_tags.collect { |option| [option["label"], option["value"]] }
134
+ end
135
+
136
+ def valid?
137
+ name && !option_tags.blank?
138
+ end
139
+
140
+ def render
141
+ label_for + "\t" + select_tag(dehumanized_name, options_for_select(formatted_option_tags), options) + "\n"
142
+ end
143
+ end
144
+
145
+ class RadioButton < CheckableBase
146
+ def valid?
147
+ name && value
148
+ end
149
+
150
+ def render
151
+ label_for + "\t" + radio_button_tag(dehumanized_name, value, checked, options) + "\n"
152
+ end
153
+ end
154
+
155
+ class CheckBox < CheckableBase
156
+ def render
157
+ label_for + "\t" + check_box_tag(dehumanized_name, value, checked, options) + "\n"
158
+ end
159
+ end
160
+
161
+ class Header < Base
162
+ attr_accessor :title, :level
163
+
164
+ def initialize(options = {})
165
+ super
166
+ @title = options[:title]
167
+ @level = options[:level] || 1
168
+ end
169
+
170
+ def valid?
171
+ (1..6).include?(level.to_i)
172
+ end
173
+
174
+ def render
175
+ content_tag(:"h#{level}", title, options)
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,48 @@
1
+ module OutputFilter
2
+ class Cells
3
+ def initialize app
4
+ @app = app
5
+ end
6
+
7
+ def call env
8
+ status, headers, body = @app.call env
9
+ return [status, headers, body] unless headers["Content-Type"].try(:include?, "text/html")
10
+
11
+ new_body = ""
12
+ body.each { |part| new_body << part }
13
+ process! new_body
14
+ headers["Content-Length"] = new_body.length.to_s
15
+ [status, headers, [new_body]]
16
+ end
17
+
18
+ private
19
+
20
+ def process! body
21
+ cells = cells body
22
+
23
+ body.gsub!(/(#{cells.keys.join('|')})/) do |tag|
24
+ name, state, attrs = cells[tag]
25
+ attrs = HashWithIndifferentAccess.new(attrs)
26
+ cell = "#{name.camelize}Cell".constantize.new
27
+ args = [state]
28
+ attrs.delete "class" # ignore styling class
29
+ args << attrs unless attrs.empty?
30
+ begin
31
+ cell.render_state *args
32
+ rescue AbstractController::ActionNotFound
33
+ "<strong>Cell “#{name.capitalize} #{state}” not found!</strong>"
34
+ end
35
+ end unless cells.empty?
36
+ end
37
+
38
+ def cells body
39
+ body.scan(/(<cell[^>]*\/\s*>|<cell[^>]*>.*?<\/cell>)/m).inject({}) do |cells, matches|
40
+ tag = matches.first
41
+ attrs = Hash.from_xml(tag)['cell']
42
+ name, state = attrs.delete('name').split('/')
43
+ cells[tag] = [name, state, attrs]
44
+ cells
45
+ end
46
+ end
47
+ end
48
+ end