type_station 0.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +21 -0
- data/Rakefile +32 -0
- data/app/assets/javascripts/type_station/application.js +14 -0
- data/app/assets/javascripts/type_station/editable_text.js.coffee +54 -0
- data/app/assets/stylesheets/type_station/application.css +17 -0
- data/app/controllers/type_station/admin/pages_controller.rb +23 -0
- data/app/controllers/type_station/admin_controller.rb +21 -0
- data/app/controllers/type_station/application_controller.rb +22 -0
- data/app/controllers/type_station/pages_controller.rb +34 -0
- data/app/helpers/type_station/application_helper.rb +4 -0
- data/app/models/type_station/content.rb +56 -0
- data/app/models/type_station/page.rb +104 -0
- data/app/presenters/type_station/base_presenter.rb +30 -0
- data/app/presenters/type_station/content_presenter.rb +37 -0
- data/app/presenters/type_station/page_presenter.rb +38 -0
- data/app/views/layouts/type_station/application.html.erb +14 -0
- data/app/views/type_station/toolbars/_text.html.haml +3 -0
- data/config/routes.rb +9 -0
- data/lib/tasks/type_station_tasks.rake +4 -0
- data/lib/type_station/configuration.rb +35 -0
- data/lib/type_station/dsl.rb +56 -0
- data/lib/type_station/engine.rb +8 -0
- data/lib/type_station/railtie.rb +9 -0
- data/lib/type_station/version.rb +9 -0
- data/lib/type_station/view_helpers.rb +55 -0
- data/lib/type_station.rb +18 -0
- metadata +211 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6fc0f535d662673d450847fa1b72363c8280c38a
|
4
|
+
data.tar.gz: a600056558b9a35692faf406a2c7b3f2b8cd84b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: afcc7157640ca50284a02207fa981b048d9a81f07f70d7a87af912b79783f44475750871e2e87ff6507f14bb8b33741064e2ec492a17f071e152e9faca62d177
|
7
|
+
data.tar.gz: 975f88b39bfe0f8059662fe30b7f4b9664c9d8f6cfa9431ab94f2d44073f2746f762936199f08c39f89491d9e69850bcff38cd5a137925bee70ab73e6b2a87d7
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
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,21 @@
|
|
1
|
+
# TypeStation
|
2
|
+
|
3
|
+
I wanted a simple CMS that just works and can be bolted onto a rails app with easy.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Not Yet
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Coming Soon...
|
12
|
+
|
13
|
+
## LICENSE
|
14
|
+
|
15
|
+
Copyright 2014 Richard Adams
|
16
|
+
|
17
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
18
|
+
|
19
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
20
|
+
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
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 = 'TypeStation'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,14 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require medium-editor
|
14
|
+
//= require "type_station/editable_text"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
jQuery ->
|
2
|
+
|
3
|
+
elements = document.querySelectorAll('.ts-editable-text')
|
4
|
+
window.t = editor = new MediumEditor elements,
|
5
|
+
disableReturn: true
|
6
|
+
buttons: ['bold', 'italic', 'underline', 'anchor']
|
7
|
+
|
8
|
+
|
9
|
+
elements = document.querySelectorAll('.ts-editable-html')
|
10
|
+
window.t = editor = new MediumEditor elements,
|
11
|
+
buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'unorderedlist', 'orderedlist', 'justifyLeft', 'justifyFull', 'justifyCenter', 'justifyRight']
|
12
|
+
|
13
|
+
$('.ts-editable-text').on 'input', ->
|
14
|
+
console.log this
|
15
|
+
|
16
|
+
# textParserRules =
|
17
|
+
# tags:
|
18
|
+
# strong: {}
|
19
|
+
# b: {}
|
20
|
+
# i: {}
|
21
|
+
# em: {}
|
22
|
+
# br: {}
|
23
|
+
# p:
|
24
|
+
# unwrap: 1
|
25
|
+
# div:
|
26
|
+
# unwrap: 1
|
27
|
+
# span:
|
28
|
+
# unwrap: 1
|
29
|
+
# ul:
|
30
|
+
# unwrap: 1
|
31
|
+
# ol:
|
32
|
+
# unwrap: 1
|
33
|
+
# li:
|
34
|
+
# unwrap: 1
|
35
|
+
# a:
|
36
|
+
# check_attributes:
|
37
|
+
# href: "url" # important to avoid XSS
|
38
|
+
|
39
|
+
# $('.ts-editable-text').each (i)->
|
40
|
+
# $this = $(@)
|
41
|
+
# data = $this.data()
|
42
|
+
# offset = $this.offset()
|
43
|
+
# console.log data
|
44
|
+
# #Set up ID
|
45
|
+
# toolbarId = "#{data.tsId}-#{i}-toolbar"
|
46
|
+
# $($('#ts-editable-text-toolbar').html())
|
47
|
+
# .attr('id', toolbarId)
|
48
|
+
# .css({ position: 'absolute', top: (offset.top - 20), left: offset.left})
|
49
|
+
# .appendTo('body')
|
50
|
+
|
51
|
+
# window.t = editor = new wysihtml5.Editor @,
|
52
|
+
# toolbar: toolbarId
|
53
|
+
# parserRules: textParserRules
|
54
|
+
# contentEditableMode: true
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require medium-editor/medium-editor
|
14
|
+
*= require medium-editor/themes/flat
|
15
|
+
*= require_tree .
|
16
|
+
*= require_self
|
17
|
+
*/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TypeStation
|
2
|
+
module Admin
|
3
|
+
class PagesController < ::TypeStation::AdminController
|
4
|
+
|
5
|
+
def update
|
6
|
+
@page = TypeStation::Page.find(params[:id])
|
7
|
+
|
8
|
+
if @page.update_contents(contents)
|
9
|
+
render json: { status: :success }, status: :ok
|
10
|
+
else
|
11
|
+
render json: @page.errors, status: :unprocessable_entity
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def contents
|
18
|
+
[params[:contents]].flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class AdminController < ::TypeStation::ApplicationController
|
3
|
+
protect_from_forgery with: :null_session
|
4
|
+
|
5
|
+
before_filter :type_station_authenticate!
|
6
|
+
before_filter :type_station_authorise!
|
7
|
+
|
8
|
+
def type_station_authenticate!
|
9
|
+
instance_eval &TypeStation.config.authenticate_with
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_station_authorise!
|
13
|
+
instance_eval &TypeStation.config.authorise_with
|
14
|
+
end
|
15
|
+
|
16
|
+
def type_station_current_user
|
17
|
+
instance_eval &TypeStation.config.current_user
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
rescue_from TypeStation::PageNotFoundError, :with => :page_not_found
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def page_not_found
|
8
|
+
render file: "#{Rails.root}/public/404.html", layout: false, status: 404 and return
|
9
|
+
end
|
10
|
+
|
11
|
+
def present(object, klass = nil)
|
12
|
+
if object.present?
|
13
|
+
object_class = object.class.to_s.gsub(/TypeStation::/, '')
|
14
|
+
klass ||= "TypeStation::#{object_class}Presenter".constantize
|
15
|
+
klass.new(object, view_context)
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class PagesController < TypeStation::ApplicationController
|
3
|
+
layout 'application'
|
4
|
+
|
5
|
+
def index
|
6
|
+
@page = present Page.root
|
7
|
+
render_type_station
|
8
|
+
end
|
9
|
+
|
10
|
+
def show
|
11
|
+
@page = present Page.find_by_path(params[:path])
|
12
|
+
render_type_station
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def render_type_station
|
18
|
+
if @page.present?
|
19
|
+
if @page.redirect?
|
20
|
+
redirect_to @page.redirect_to
|
21
|
+
else
|
22
|
+
if @page.template_name?
|
23
|
+
render "pages/#{@page.template_name}"
|
24
|
+
else
|
25
|
+
raise TypeStation::PageTemplateNameUndefined
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise TypeStation::PageNotFoundError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class Content
|
3
|
+
include ::Mongoid::Document
|
4
|
+
include ::Mongoid::Attributes::Dynamic
|
5
|
+
|
6
|
+
TYPES = [:text, :html, :image, :file, :select, :multiple_select]
|
7
|
+
|
8
|
+
# RELATIONS
|
9
|
+
|
10
|
+
embedded_in :page
|
11
|
+
|
12
|
+
# FIELDS
|
13
|
+
field :name, type: Symbol
|
14
|
+
field :type, type: Symbol, default: TYPES.first
|
15
|
+
|
16
|
+
# VALIDATIONS
|
17
|
+
|
18
|
+
validates :name, presence: true
|
19
|
+
validates :type, presence: true
|
20
|
+
|
21
|
+
# INSTANT METHODS
|
22
|
+
|
23
|
+
def get
|
24
|
+
self[self.type]
|
25
|
+
end
|
26
|
+
|
27
|
+
def set(value)
|
28
|
+
self[self.type] = convert(value)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def convert(value)
|
34
|
+
case type
|
35
|
+
#when :image
|
36
|
+
# preloaded = Cloudinary::PreloadedFile.new(value)
|
37
|
+
# raise "Invalid upload signature" if !preloaded.valid?
|
38
|
+
# preloaded.identifier
|
39
|
+
when :multiple_select
|
40
|
+
convert_to_array(value)
|
41
|
+
else
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def convert_to_array(value)
|
47
|
+
if value.is_a?(String)
|
48
|
+
value.split(',').map(&:strip)
|
49
|
+
elsif value.is_a?(Array)
|
50
|
+
value
|
51
|
+
else
|
52
|
+
raise 'Dont know who to covert value to array'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class Page
|
3
|
+
include ::Mongoid::Document
|
4
|
+
include ::Mongoid::Tree
|
5
|
+
|
6
|
+
# RELATIONS
|
7
|
+
|
8
|
+
embeds_many :contents, class_name: 'TypeStation::Content'
|
9
|
+
|
10
|
+
# FIELDS
|
11
|
+
field :title, type: String, default: 'Untitled'
|
12
|
+
field :template_name, type: String, default: 'undefined'
|
13
|
+
|
14
|
+
field :redirect_to, type: String, default: nil
|
15
|
+
|
16
|
+
field :slug, type: String
|
17
|
+
field :path, type: String
|
18
|
+
|
19
|
+
# VALIDATIONS
|
20
|
+
|
21
|
+
validates :slug, uniqueness: true, on: :update
|
22
|
+
validates :path, presence: true, uniqueness: true, on: :update
|
23
|
+
|
24
|
+
# Validate that they is only one root page
|
25
|
+
validates_each :parent_id do |model, attr, value|
|
26
|
+
root_page = TypeStation::Page.root
|
27
|
+
model.errors.add(attr, 'already have a root page') if value == nil && root_page.present? && model.id != root_page.id
|
28
|
+
end
|
29
|
+
|
30
|
+
# CALLBACKS
|
31
|
+
before_create :generate_slug
|
32
|
+
before_destroy :destroy_children
|
33
|
+
after_rearrange :rebuild_path
|
34
|
+
|
35
|
+
# Rebuild self and children paths upon title change
|
36
|
+
before_save :generate_slug, if: :title_changed?
|
37
|
+
after_save :rebuild_child_paths, if: :has_children?
|
38
|
+
|
39
|
+
# CLASS METHODS
|
40
|
+
|
41
|
+
def self.find_by_path(path)
|
42
|
+
self.where(path: File.join('',path)).first
|
43
|
+
end
|
44
|
+
|
45
|
+
# INSTANT METHODS
|
46
|
+
|
47
|
+
def update_contents(params)
|
48
|
+
params.each do |data|
|
49
|
+
if content?(data[:field])
|
50
|
+
set(data[:field], data[:value])
|
51
|
+
else
|
52
|
+
contents.build(name: data[:field], type: data[:type]).set(data[:value])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
save
|
57
|
+
end
|
58
|
+
|
59
|
+
def get(key)
|
60
|
+
content_attributes[key].get
|
61
|
+
end
|
62
|
+
|
63
|
+
def set(key, value)
|
64
|
+
content_attributes[key].set value
|
65
|
+
end
|
66
|
+
|
67
|
+
def content?(key)
|
68
|
+
content_attributes[key].present?
|
69
|
+
end
|
70
|
+
|
71
|
+
def content_attributes
|
72
|
+
@content_attributes ||= Hash[self.contents.map {|c| [c.name, c]}]
|
73
|
+
end
|
74
|
+
|
75
|
+
def redirect?
|
76
|
+
redirect_to.present?
|
77
|
+
end
|
78
|
+
|
79
|
+
def template_name?
|
80
|
+
template_name.present? && template_name != 'undefined'
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Generates a slug based of the title give by the user
|
86
|
+
def generate_slug
|
87
|
+
self.slug = root? ? "" : title.parameterize
|
88
|
+
rebuild_path
|
89
|
+
end
|
90
|
+
|
91
|
+
# Rebuild a path based of a ancestors slugs
|
92
|
+
def rebuild_path
|
93
|
+
self.path = root? ? "/" : self.ancestors_and_self.collect(&:slug).join('/')
|
94
|
+
end
|
95
|
+
|
96
|
+
def rebuild_child_paths
|
97
|
+
self.children.each do |child|
|
98
|
+
child.send :rebuild_path
|
99
|
+
child.save
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class BasePresenter
|
3
|
+
|
4
|
+
def initialize(object, template)
|
5
|
+
@object = object
|
6
|
+
@template = template
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def self.presents(name)
|
12
|
+
define_method(name) do
|
13
|
+
@object
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def h
|
18
|
+
@template
|
19
|
+
end
|
20
|
+
|
21
|
+
def markdown(text)
|
22
|
+
Redcarpet.new(text, :hard_wrap, :filter_html, :autolink).to_html.html_safe
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(*args, &block)
|
26
|
+
@template.send(*args, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class ContentPresenter < BasePresenter
|
3
|
+
presents :content
|
4
|
+
|
5
|
+
def value
|
6
|
+
content.get
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(&block)
|
10
|
+
case content.type
|
11
|
+
when :image, :file
|
12
|
+
block.call(OpenStruct.new(content.get))
|
13
|
+
when :multiple_select
|
14
|
+
block.call(content.get)
|
15
|
+
when :html
|
16
|
+
content.get.html_safe
|
17
|
+
else
|
18
|
+
content.get
|
19
|
+
end.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def image_struct
|
25
|
+
OpenStruct.new({url: content.get, alt: ''})
|
26
|
+
end
|
27
|
+
|
28
|
+
def image_struct
|
29
|
+
OpenStruct.new({url: '', alt: ''})
|
30
|
+
end
|
31
|
+
|
32
|
+
def select_struct
|
33
|
+
OpenStruct.new({value: content.get, values: content.get })
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module TypeStation
|
2
|
+
class PagePresenter < BasePresenter
|
3
|
+
presents :page
|
4
|
+
delegate :to_param, :path, :slug, :template_name, :template_name?, :redirect_to, :redirect?, to: :page
|
5
|
+
|
6
|
+
def initialize(object, template)
|
7
|
+
super(object, template)
|
8
|
+
build_content_methods
|
9
|
+
end
|
10
|
+
|
11
|
+
def edit_url
|
12
|
+
h.type_station.admin_page_url(page)
|
13
|
+
end
|
14
|
+
|
15
|
+
def title
|
16
|
+
ContentPresenter.new(OpenStruct.new({type: :text, get: page.title}), @template)
|
17
|
+
end
|
18
|
+
|
19
|
+
def children
|
20
|
+
@children ||= page.children.map {|p| PagePresenter.new(p, @template)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def parent
|
24
|
+
@parent ||= PagePresenter.new(page.parent, @template)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def build_content_methods
|
30
|
+
page.content_attributes.each do |key, content_object|
|
31
|
+
self.class.send :define_method, key do
|
32
|
+
ContentPresenter.new(content_object, @template)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>TypeStation</title>
|
5
|
+
<%= stylesheet_link_tag "type_station/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "type_station/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/configurable'
|
2
|
+
|
3
|
+
module TypeStation
|
4
|
+
# Configures global settings for TypeStation
|
5
|
+
# TypeStation.configure do |config|
|
6
|
+
# config.model = User
|
7
|
+
# end
|
8
|
+
def self.configure(&block)
|
9
|
+
yield @config ||= TypeStation::Configuration.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Global settings for TypeStation
|
13
|
+
def self.config
|
14
|
+
@config
|
15
|
+
end
|
16
|
+
|
17
|
+
class Configuration
|
18
|
+
include ActiveSupport::Configurable
|
19
|
+
|
20
|
+
config_accessor :authenticate_with
|
21
|
+
config_accessor :authorise_with
|
22
|
+
config_accessor :current_user
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
configure do |config|
|
27
|
+
config.authenticate_with = Proc.new do
|
28
|
+
request.env['warden'].try(:authenticate!)
|
29
|
+
end
|
30
|
+
config.authorise_with = Proc.new {}
|
31
|
+
config.current_user = Proc.new do
|
32
|
+
request.env["warden"].try(:user) || respond_to?(:current_user) && current_user
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
module TypeStation
|
3
|
+
class DSL
|
4
|
+
|
5
|
+
def self.build(name, options = {}, &block)
|
6
|
+
Page.new(name, options).call(&block)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Page
|
10
|
+
attr_reader :model
|
11
|
+
def initialize(title, options = {}, parent = nil)
|
12
|
+
@title = title
|
13
|
+
@options = options
|
14
|
+
@parent = parent
|
15
|
+
@model = _build_model(@title, @options, @parent)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(&block)
|
19
|
+
if block_given?
|
20
|
+
if block.arity == 1
|
21
|
+
block.call model
|
22
|
+
else
|
23
|
+
instance_eval &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
model
|
27
|
+
end
|
28
|
+
|
29
|
+
def page(name, options = {}, &block)
|
30
|
+
Page.new(name, options, model).call(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def _build_model(title, options, parent)
|
36
|
+
parent_id = parent ? parent.id : nil
|
37
|
+
template_name = options[:template] || (parent ? title.parameterize('_') : 'index')
|
38
|
+
redirect_to = options[:redirect_to]
|
39
|
+
slug = options[:slug]
|
40
|
+
|
41
|
+
model = ::TypeStation::Page.create(title: title, template_name: template_name, redirect_to: redirect_to, parent_id: parent_id)
|
42
|
+
|
43
|
+
if slug.present?
|
44
|
+
model.slug = slug
|
45
|
+
model.save
|
46
|
+
end
|
47
|
+
|
48
|
+
model
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module TypeStation
|
2
|
+
module ViewHelpers
|
3
|
+
|
4
|
+
def editable(model, key, options = {}, &block)
|
5
|
+
result = ''
|
6
|
+
presenter = model.try(key)
|
7
|
+
type = options[:type] || :text
|
8
|
+
|
9
|
+
if presenter.present?
|
10
|
+
result += presenter.call(&block)
|
11
|
+
else
|
12
|
+
result += capture(OpenStruct.new({}), &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
if type_station_current_user
|
16
|
+
case type
|
17
|
+
when :text
|
18
|
+
content_tag(:span, result, class: 'ts-editable-text', id: "#{model.to_param}-#{key}", data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
19
|
+
when :html
|
20
|
+
content_tag(:div, result.html_safe, class: 'ts-editable-html', id: "#{model.to_param}-#{key}", data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
21
|
+
when :image
|
22
|
+
content_tag(:div, result, class: 'ts-editable-image', data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
23
|
+
when :select
|
24
|
+
content_tag(:div, result, class: 'ts-editable-select', data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
25
|
+
when :multiple_select
|
26
|
+
content_tag(:div, result, class: 'ts-editable-multiple-select', data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
27
|
+
end
|
28
|
+
else
|
29
|
+
result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def inline_edit_js
|
34
|
+
result = ''.html_safe
|
35
|
+
if type_station_current_user
|
36
|
+
# TODO INIT JS
|
37
|
+
result << type_station_toolbar('ts-editable-text-toolbar', 'text')
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
def type_station_current_user
|
43
|
+
instance_eval &TypeStation.config.current_user
|
44
|
+
end
|
45
|
+
|
46
|
+
def type_station_toolbar(id, partial_name = 'text')
|
47
|
+
type_station_template(id, render(partial: "type_station/toolbars/#{partial_name}").html_safe)
|
48
|
+
end
|
49
|
+
|
50
|
+
def type_station_template(id, content)
|
51
|
+
content_tag :script, content, id: id, type: 'text/x-type-station-template'
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/type_station.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "type_station/engine"
|
2
|
+
require "type_station/configuration"
|
3
|
+
require "type_station/railtie"
|
4
|
+
|
5
|
+
|
6
|
+
module TypeStation
|
7
|
+
|
8
|
+
# Base class for all TypeStation exceptions
|
9
|
+
class TypeStationError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
class PageNotFoundError < TypeStationError
|
13
|
+
end
|
14
|
+
|
15
|
+
class PageTemplateNameUndefined< TypeStationError
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: type_station
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Richard Adams
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-16 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: 4.1.6
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.1.6
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongoid
|
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: mongoid-tree
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coffee-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: haml-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard-rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 4.3.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 4.3.1
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: shoulda-matchers
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.7.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.7.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: database_cleaner
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 1.4.0
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.4.0
|
153
|
+
description: A Simple Content Management System.
|
154
|
+
email:
|
155
|
+
- richard@madwire.co.uk
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- MIT-LICENSE
|
161
|
+
- README.md
|
162
|
+
- Rakefile
|
163
|
+
- app/assets/javascripts/type_station/application.js
|
164
|
+
- app/assets/javascripts/type_station/editable_text.js.coffee
|
165
|
+
- app/assets/stylesheets/type_station/application.css
|
166
|
+
- app/controllers/type_station/admin/pages_controller.rb
|
167
|
+
- app/controllers/type_station/admin_controller.rb
|
168
|
+
- app/controllers/type_station/application_controller.rb
|
169
|
+
- app/controllers/type_station/pages_controller.rb
|
170
|
+
- app/helpers/type_station/application_helper.rb
|
171
|
+
- app/models/type_station/content.rb
|
172
|
+
- app/models/type_station/page.rb
|
173
|
+
- app/presenters/type_station/base_presenter.rb
|
174
|
+
- app/presenters/type_station/content_presenter.rb
|
175
|
+
- app/presenters/type_station/page_presenter.rb
|
176
|
+
- app/views/layouts/type_station/application.html.erb
|
177
|
+
- app/views/type_station/toolbars/_text.html.haml
|
178
|
+
- config/routes.rb
|
179
|
+
- lib/tasks/type_station_tasks.rake
|
180
|
+
- lib/type_station.rb
|
181
|
+
- lib/type_station/configuration.rb
|
182
|
+
- lib/type_station/dsl.rb
|
183
|
+
- lib/type_station/engine.rb
|
184
|
+
- lib/type_station/railtie.rb
|
185
|
+
- lib/type_station/version.rb
|
186
|
+
- lib/type_station/view_helpers.rb
|
187
|
+
homepage: http://madwire.co.uk
|
188
|
+
licenses:
|
189
|
+
- MIT
|
190
|
+
metadata: {}
|
191
|
+
post_install_message:
|
192
|
+
rdoc_options: []
|
193
|
+
require_paths:
|
194
|
+
- lib
|
195
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - '>='
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
+
requirements:
|
202
|
+
- - '>'
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: 1.3.1
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project:
|
207
|
+
rubygems_version: 2.2.2
|
208
|
+
signing_key:
|
209
|
+
specification_version: 4
|
210
|
+
summary: A Simple Content Management System.
|
211
|
+
test_files: []
|