thesis 0.0.1 → 0.0.4
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.
- data/README.md +147 -7
- data/lib/assets/javascripts/thesis/hallo.js +2949 -0
- data/lib/assets/javascripts/thesis/thesis.js.coffee +27 -0
- data/lib/assets/javascripts/thesis.js +2 -0
- data/lib/assets/stylesheets/thesis/thesis.css.scss +16 -0
- data/lib/assets/stylesheets/thesis.css +4 -0
- data/lib/generators/thesis/install/install_generator.rb +108 -0
- data/lib/generators/thesis/install/templates/migrations/create_page.rb +18 -0
- data/lib/generators/thesis/install/templates/migrations/create_page_content.rb +15 -0
- data/lib/generators/thesis/install/templates/page_templates/default.html.erb +38 -0
- data/lib/generators/thesis/install/templates/page_templates/default.html.haml +29 -0
- data/lib/generators/thesis/install/templates/page_templates/default.html.slim +29 -0
- data/lib/tasks/thesis_tasks.rake +4 -0
- data/lib/thesis/colorizer.rb +51 -0
- data/lib/thesis/controllers/controller_helpers.rb +39 -0
- data/lib/thesis/controllers/thesis_controller.rb +53 -0
- data/lib/thesis/engine.rb +5 -0
- data/lib/thesis/exceptions.rb +17 -0
- data/lib/thesis/models/page.rb +43 -0
- data/lib/thesis/models/page_content.rb +41 -0
- data/lib/thesis/railtie.rb +12 -0
- data/lib/thesis/routing/route_constraint.rb +7 -0
- data/lib/thesis/routing/routes.rb +10 -0
- data/lib/thesis/version.rb +1 -1
- data/lib/thesis.rb +10 -1
- data/spec/factories/page_contents.rb +7 -0
- data/spec/factories/pages.rb +9 -0
- data/spec/lib/thesis/controllers/thesis_controller_spec.rb +68 -0
- data/spec/lib/thesis/models/page_content_spec.rb +33 -0
- data/spec/lib/thesis/models/page_spec.rb +49 -0
- data/spec/spec_helper.rb +64 -0
- metadata +58 -14
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -1
- data/lib/thesis/base.rb +0 -5
- data/thesis.gemspec +0 -19
@@ -0,0 +1,27 @@
|
|
1
|
+
Thesis =
|
2
|
+
setup: ->
|
3
|
+
if this.requirements()
|
4
|
+
this.bindings()
|
5
|
+
|
6
|
+
|
7
|
+
requirements: ->
|
8
|
+
if jQuery.ui
|
9
|
+
true
|
10
|
+
else
|
11
|
+
alert "jQuery UI not included. Thesis will not work properly without it."
|
12
|
+
false
|
13
|
+
|
14
|
+
page_is_editable: ->
|
15
|
+
$("#thesis-editor").length > 0
|
16
|
+
|
17
|
+
bindings: ->
|
18
|
+
thesis = $("#thesis-editor")
|
19
|
+
if thesis
|
20
|
+
thesis.append $("<div></div>").addClass("thesis-container")
|
21
|
+
.append $("<h3></h3>").text("Thesis Editor")
|
22
|
+
|
23
|
+
|
24
|
+
jQuery ($)->
|
25
|
+
Thesis.setup()
|
26
|
+
|
27
|
+
# window.Thesis = Thesis # Enable if necessary
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
|
3
|
+
module Thesis
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
desc "install or upgrade Thesis"
|
11
|
+
|
12
|
+
def self.next_migration_number(path)
|
13
|
+
unless @prev_migration_nr
|
14
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
15
|
+
else
|
16
|
+
@prev_migration_nr += 1
|
17
|
+
end
|
18
|
+
@prev_migration_nr.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def copy_migrations
|
22
|
+
migration_template "migrations/create_page.rb", "db/migrate/create_page.rb"
|
23
|
+
migration_template "migrations/create_page_content.rb", "db/migrate/create_page_content.rb"
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_folders
|
27
|
+
copy_file "page_templates/default.html.slim", "app/views/page_templates/default.html.slim" if Slim
|
28
|
+
copy_file "page_templates/default.html.haml", "app/views/page_templates/default.html.haml" if Haml
|
29
|
+
copy_file "page_templates/default.html.erb", "app/views/page_templates/default.html.erb" unless Haml || Slim
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_up_routes
|
33
|
+
route "thesis_routes # This needs to be the last route!"
|
34
|
+
end
|
35
|
+
|
36
|
+
def install_js
|
37
|
+
filename = "app/assets/javascripts/application.js"
|
38
|
+
existing = File.binread("#{filename}").include?("require thesis")
|
39
|
+
|
40
|
+
if existing && generating?
|
41
|
+
say_status("skipped", "insert into #{filename}", :yellow)
|
42
|
+
else
|
43
|
+
insert_into_file "#{filename}", after: %r{//= require +['"]?jquery_ujs['"]?} do
|
44
|
+
"\n//= require jquery-ui" +
|
45
|
+
"\n//= require thesis"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def install_css
|
51
|
+
filename = "app/assets/stylesheets/application.css.scss"
|
52
|
+
existing = File.binread("#{filename}").include?("require thesis")
|
53
|
+
|
54
|
+
if existing && generating?
|
55
|
+
say_status("skipped", "insert into #{filename}", :yellow)
|
56
|
+
else
|
57
|
+
insert_into_file "#{filename}", after: %r{ *= require_self} do
|
58
|
+
"\n *= require thesis"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def install_page_is_editable
|
64
|
+
filename = "app/controllers/application_controller.rb"
|
65
|
+
existing = File.binread("#{filename}").include?("def page_is_editable?")
|
66
|
+
|
67
|
+
if existing && generating?
|
68
|
+
say_status("skipped", "insert into #{filename}", :yellow)
|
69
|
+
else
|
70
|
+
insert_into_file "#{filename}", after: %r{ protect_from_forgery} do
|
71
|
+
"\n" +
|
72
|
+
"\n # Thesis authentication" +
|
73
|
+
"\n def page_is_editable?(page)" +
|
74
|
+
"\n # Add your own criteria here for editing privileges. Examples:" +
|
75
|
+
"\n # current_user.admin? # Basic admin" +
|
76
|
+
"\n # can? :update, page # CanCan" +
|
77
|
+
"\n true # EVERYONE has access right now." +
|
78
|
+
"\n end"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def complete_message
|
84
|
+
require "thesis/colorizer"
|
85
|
+
|
86
|
+
if generating?
|
87
|
+
puts " "
|
88
|
+
puts " Thesis installed.".green
|
89
|
+
puts " Now run `rake db:migrate` to set up your database.".pink
|
90
|
+
else
|
91
|
+
puts " "
|
92
|
+
puts " Thesis uninstalled.".red
|
93
|
+
puts " You will need to remove the database tables manually if you've already run `rake db:migrate`.".pink
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def generating?
|
100
|
+
:invoke == behavior
|
101
|
+
end
|
102
|
+
|
103
|
+
def destroying?
|
104
|
+
:revoke == behavior
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreatePage < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :pages do |t|
|
4
|
+
t.integer :parent_id
|
5
|
+
t.string :name
|
6
|
+
t.string :slug
|
7
|
+
t.string :title
|
8
|
+
t.string :description
|
9
|
+
t.integer :sort_order, default: 0, null: false
|
10
|
+
t.string :template, default: "default", null: false
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :pages
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreatePageContent < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :page_contents do |t|
|
4
|
+
t.integer :page_id, null: false
|
5
|
+
t.string :name, null: false
|
6
|
+
t.text :content, default: "Edit This Content Area"
|
7
|
+
t.string :content_type, default: :html
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :page_contents
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= current_page.title %></title>
|
5
|
+
<meta type="description" content="<%= current_page.content("Description", :text) %>" />
|
6
|
+
|
7
|
+
<%= stylesheet_link_tag "application", :media => "all" %>
|
8
|
+
<%= javascript_include_tag "application" %>
|
9
|
+
<%= csrf_meta_tags %>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<%= thesis_editor %>
|
13
|
+
<header>
|
14
|
+
<h1><%= current_page.title %></h1>
|
15
|
+
</header>
|
16
|
+
|
17
|
+
<nav>
|
18
|
+
<ul>
|
19
|
+
<% root_pages.each do |p| %>
|
20
|
+
<li><%= link_to p.name, p.path %></li>
|
21
|
+
<% end %>
|
22
|
+
</ul>
|
23
|
+
</nav>
|
24
|
+
|
25
|
+
<article>
|
26
|
+
<div class="main-image"><%= current_page.content("Main Image", :image) %></div>
|
27
|
+
<div class="content"><%= current_page.content("Main Content", :html) %></div>
|
28
|
+
</article>
|
29
|
+
|
30
|
+
<aside>
|
31
|
+
<%= current_page.content("Sidebar Content", :html) %>
|
32
|
+
</aside>
|
33
|
+
|
34
|
+
<footer>
|
35
|
+
<p><%= current_page.content("Footer Content", :text) %></p>
|
36
|
+
</footer>
|
37
|
+
</body>
|
38
|
+
</html>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title= current_page.title
|
5
|
+
%meta{ content: current_page.content("Description", :text), type: "description" }
|
6
|
+
|
7
|
+
= stylesheet_link_tag "application", :media => "all"
|
8
|
+
= javascript_include_tag "application"
|
9
|
+
= csrf_meta_tags
|
10
|
+
%body
|
11
|
+
= thesis_editor
|
12
|
+
|
13
|
+
%header
|
14
|
+
%h1= current_page.title
|
15
|
+
|
16
|
+
%nav
|
17
|
+
%ul
|
18
|
+
- root_pages.each do |p|
|
19
|
+
%li= link_to p.name, p.path
|
20
|
+
|
21
|
+
%article
|
22
|
+
.main-image= current_page.content("Main Image", :image)
|
23
|
+
.content= current_page.content("Main Content", :html)
|
24
|
+
|
25
|
+
%aside
|
26
|
+
= current_page.content("Sidebar Content", :html)
|
27
|
+
|
28
|
+
%footer
|
29
|
+
%p= current_page.content("Footer Content", :text)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
doctype html
|
2
|
+
html
|
3
|
+
head
|
4
|
+
title= current_page.title
|
5
|
+
meta content=current_page.content("Description", :text) type="description"
|
6
|
+
|
7
|
+
= stylesheet_link_tag "application", :media => "all"
|
8
|
+
= javascript_include_tag "application"
|
9
|
+
= csrf_meta_tags
|
10
|
+
body
|
11
|
+
= thesis_editor
|
12
|
+
|
13
|
+
header
|
14
|
+
h1= current_page.title
|
15
|
+
|
16
|
+
nav
|
17
|
+
ul
|
18
|
+
- root_pages.each do |p|
|
19
|
+
li= link_to p.name, p.path
|
20
|
+
|
21
|
+
article
|
22
|
+
.main-image= current_page.content("Main Image", :image)
|
23
|
+
.content= current_page.content("Main Content", :html)
|
24
|
+
|
25
|
+
aside
|
26
|
+
= current_page.content("Sidebar Content", :html)
|
27
|
+
|
28
|
+
footer
|
29
|
+
p= current_page.content("Footer Content", :text)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class String
|
2
|
+
# colorization
|
3
|
+
def colorize(color_code)
|
4
|
+
"\e[#{color_code}m#{self}\e[0m"
|
5
|
+
end
|
6
|
+
|
7
|
+
def red
|
8
|
+
colorize 31
|
9
|
+
end
|
10
|
+
|
11
|
+
def green
|
12
|
+
colorize 32
|
13
|
+
end
|
14
|
+
|
15
|
+
def yellow
|
16
|
+
colorize 33
|
17
|
+
end
|
18
|
+
|
19
|
+
def pink
|
20
|
+
colorize 35
|
21
|
+
end
|
22
|
+
|
23
|
+
def gray
|
24
|
+
colorize 37
|
25
|
+
end
|
26
|
+
|
27
|
+
def brown
|
28
|
+
colorize 33
|
29
|
+
end
|
30
|
+
|
31
|
+
def blue
|
32
|
+
colorize 34
|
33
|
+
end
|
34
|
+
|
35
|
+
def magenta
|
36
|
+
colorize 35
|
37
|
+
end
|
38
|
+
|
39
|
+
def cyan
|
40
|
+
colorize 36
|
41
|
+
end
|
42
|
+
|
43
|
+
def bold
|
44
|
+
colorize 1
|
45
|
+
end
|
46
|
+
|
47
|
+
def blink
|
48
|
+
colorize 5
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Thesis
|
2
|
+
module ControllerHelpers
|
3
|
+
module ClassMethods
|
4
|
+
def class_method_here
|
5
|
+
# Sample
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
raise ActiveRecordRequired.new("Currently, Thesis only works with ActiveRecord.") unless defined? ActiveRecord
|
11
|
+
|
12
|
+
# base.extend ClassMethods
|
13
|
+
# base.helper_method :class_method_here
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_page
|
17
|
+
@current_page ||= Page.where(slug: request.fullpath).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def root_pages
|
21
|
+
@root_pages ||= Page.where(parent_id: nil).order("sort_order ASC").all
|
22
|
+
end
|
23
|
+
|
24
|
+
def page_is_editable?(page)
|
25
|
+
raise RequiredMethodNotImplemented.new("Add a `page_is_editable?(page)` method to your controller that returns true or false.")
|
26
|
+
end
|
27
|
+
|
28
|
+
def thesis_editor
|
29
|
+
"<div id='thesis-editor'></div>".html_safe if page_is_editable?(current_page)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if defined? ActionController::Base
|
35
|
+
ActionController::Base.class_eval do
|
36
|
+
include Thesis::ControllerHelpers
|
37
|
+
helper_method :current_page, :root_pages, :page_is_editable?, :thesis_editor
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Thesis
|
2
|
+
class ThesisController < ActionController::Base
|
3
|
+
include ControllerHelpers
|
4
|
+
|
5
|
+
def show
|
6
|
+
raise ActionController::RoutingError.new('Not Found') unless current_page
|
7
|
+
|
8
|
+
if current_page.template && template_exists?("page_templates/#{current_page.template}")
|
9
|
+
render "page_templates/#{current_page.template}"
|
10
|
+
else
|
11
|
+
raise PageRequiresTemplate.new("Page requires a template but none was specified.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_page
|
16
|
+
page = Page.new
|
17
|
+
return head :forbidden unless page_is_editable?(page)
|
18
|
+
|
19
|
+
update_page_attributes page
|
20
|
+
|
21
|
+
head page.save ? :ok : :not_acceptable
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_page
|
25
|
+
page = current_page
|
26
|
+
return head :forbidden unless page_is_editable?(page)
|
27
|
+
|
28
|
+
update_page_attributes page
|
29
|
+
|
30
|
+
head page.save ? :ok : :not_acceptable
|
31
|
+
end
|
32
|
+
|
33
|
+
def page_attributes
|
34
|
+
[ :name, :title, :description, :parent_id ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_page_attributes(page)
|
38
|
+
page_attributes.each { |a| page.send("#{a}=", params[a]) if params[a] }
|
39
|
+
page
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def page_is_editable?(page)
|
45
|
+
appcon = ApplicationController.new
|
46
|
+
if appcon.respond_to?("page_is_editable?")
|
47
|
+
appcon.page_is_editable?(page)
|
48
|
+
else
|
49
|
+
raise RequiredMethodNotImplemented.new("Add a `page_is_editable?(page)` method to your controller that returns true or false.")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Thesis
|
2
|
+
# A generic Thesis exception
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# When a required method is not implemented
|
6
|
+
class RequiredMethodNotImplemented < StandardError; end
|
7
|
+
|
8
|
+
# ActiveRecord is the only ORM that works with this currently
|
9
|
+
class ActiveRecordRequired < StandardError; end
|
10
|
+
|
11
|
+
# 404s
|
12
|
+
# class PageNotFound < ActionController::RoutingError; end
|
13
|
+
|
14
|
+
# No template specified
|
15
|
+
class PageRequiresTemplate < StandardError; end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Thesis
|
2
|
+
class Page < ActiveRecord::Base
|
3
|
+
self.table_name = "pages"
|
4
|
+
|
5
|
+
belongs_to :parent, class_name: "Page"
|
6
|
+
has_many :subpages, class_name: "Page", foreign_key: "parent_id", order: "sort_order ASC"
|
7
|
+
has_many :page_contents
|
8
|
+
|
9
|
+
before_validation :update_slug
|
10
|
+
after_save :update_subpage_slugs
|
11
|
+
|
12
|
+
validates :slug, uniqueness: { message: "There's already a page like that. Change your page name." }, presence: true
|
13
|
+
|
14
|
+
def update_slug
|
15
|
+
self.slug = "/" << self.name.parameterize
|
16
|
+
self.slug = "#{parent.slug.to_s}#{self.slug.to_s}" if parent
|
17
|
+
end
|
18
|
+
|
19
|
+
def update_subpage_slugs
|
20
|
+
subpages.each(&:save) if slug_changed?
|
21
|
+
end
|
22
|
+
|
23
|
+
def content(name, content_type = :html)
|
24
|
+
pc = find_or_create_page_content(name, content_type)
|
25
|
+
pc.render
|
26
|
+
end
|
27
|
+
|
28
|
+
def path
|
29
|
+
self.slug
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def find_or_create_page_content(name, content_type)
|
35
|
+
page_content = self.page_contents.where(name: name).first_or_create do |pc|
|
36
|
+
pc.content = "Edit This Area"
|
37
|
+
end
|
38
|
+
page_content.content_type = content_type
|
39
|
+
page_content.save if page_content.changed?
|
40
|
+
page_content
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Thesis
|
2
|
+
class PageContent < ActiveRecord::Base
|
3
|
+
self.table_name = "page_contents"
|
4
|
+
|
5
|
+
belongs_to :page
|
6
|
+
|
7
|
+
def render
|
8
|
+
case self.content_type.to_sym
|
9
|
+
when :html
|
10
|
+
render_html
|
11
|
+
when :text
|
12
|
+
render_text
|
13
|
+
else
|
14
|
+
render_html
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def render_html
|
21
|
+
h = "<div class='thesis-content thesis-content-html' data-thesis-content-id='#{self.id}'>" +
|
22
|
+
"#{self.content}" +
|
23
|
+
"</div>"
|
24
|
+
h.html_safe
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_text
|
28
|
+
h = "<span class='thesis-content thesis-content-text' data-thesis-content-id='#{self.id}'>" +
|
29
|
+
"#{self.content}" +
|
30
|
+
"</span>"
|
31
|
+
h.html_safe
|
32
|
+
end
|
33
|
+
|
34
|
+
def render_image
|
35
|
+
h = "<div class='thesis-content thesis-content-image'>" +
|
36
|
+
"<img src='#{self.content}' />" +
|
37
|
+
"</div>"
|
38
|
+
h.html_safe
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/thesis/version.rb
CHANGED
data/lib/thesis.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
+
require "thesis/engine"
|
1
2
|
require "thesis/version"
|
2
|
-
require "thesis/
|
3
|
+
require "thesis/exceptions"
|
4
|
+
require "thesis/controllers/controller_helpers" # Included into ActionController::Base
|
5
|
+
require "thesis/controllers/thesis_controller"
|
6
|
+
require "thesis/routing/route_constraint"
|
7
|
+
require "thesis/routing/routes"
|
8
|
+
|
9
|
+
# Models
|
10
|
+
require "thesis/models/page"
|
11
|
+
require "thesis/models/page_content"
|
3
12
|
|
4
13
|
module Thesis
|
5
14
|
end
|