thesis 0.0.1 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/README.md +147 -7
  2. data/lib/assets/javascripts/thesis/hallo.js +2949 -0
  3. data/lib/assets/javascripts/thesis/thesis.js.coffee +27 -0
  4. data/lib/assets/javascripts/thesis.js +2 -0
  5. data/lib/assets/stylesheets/thesis/thesis.css.scss +16 -0
  6. data/lib/assets/stylesheets/thesis.css +4 -0
  7. data/lib/generators/thesis/install/install_generator.rb +108 -0
  8. data/lib/generators/thesis/install/templates/migrations/create_page.rb +18 -0
  9. data/lib/generators/thesis/install/templates/migrations/create_page_content.rb +15 -0
  10. data/lib/generators/thesis/install/templates/page_templates/default.html.erb +38 -0
  11. data/lib/generators/thesis/install/templates/page_templates/default.html.haml +29 -0
  12. data/lib/generators/thesis/install/templates/page_templates/default.html.slim +29 -0
  13. data/lib/tasks/thesis_tasks.rake +4 -0
  14. data/lib/thesis/colorizer.rb +51 -0
  15. data/lib/thesis/controllers/controller_helpers.rb +39 -0
  16. data/lib/thesis/controllers/thesis_controller.rb +53 -0
  17. data/lib/thesis/engine.rb +5 -0
  18. data/lib/thesis/exceptions.rb +17 -0
  19. data/lib/thesis/models/page.rb +43 -0
  20. data/lib/thesis/models/page_content.rb +41 -0
  21. data/lib/thesis/railtie.rb +12 -0
  22. data/lib/thesis/routing/route_constraint.rb +7 -0
  23. data/lib/thesis/routing/routes.rb +10 -0
  24. data/lib/thesis/version.rb +1 -1
  25. data/lib/thesis.rb +10 -1
  26. data/spec/factories/page_contents.rb +7 -0
  27. data/spec/factories/pages.rb +9 -0
  28. data/spec/lib/thesis/controllers/thesis_controller_spec.rb +68 -0
  29. data/spec/lib/thesis/models/page_content_spec.rb +33 -0
  30. data/spec/lib/thesis/models/page_spec.rb +49 -0
  31. data/spec/spec_helper.rb +64 -0
  32. metadata +58 -14
  33. data/.gitignore +0 -17
  34. data/Gemfile +0 -4
  35. data/LICENSE.txt +0 -22
  36. data/Rakefile +0 -1
  37. data/lib/thesis/base.rb +0 -5
  38. 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,2 @@
1
+ //= require ./thesis/hallo
2
+ //= require ./thesis/thesis
@@ -0,0 +1,16 @@
1
+ #thesis-editor {
2
+ display: block;
3
+ width:100%;
4
+ clear:both;
5
+ height:100px;
6
+ background-color:#343434;
7
+ color:#ECECEC;
8
+ border:solid 2px #444444;
9
+
10
+ & .thesis-container {
11
+ max-width: 960px;
12
+ margin: 0 auto;
13
+ }
14
+ }
15
+
16
+
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= require_self
3
+ *= require_tree .
4
+ */
@@ -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,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :thesis do
3
+ # # Task goes here
4
+ # end
@@ -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,5 @@
1
+ module Thesis
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Thesis
4
+ end
5
+ 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
@@ -0,0 +1,12 @@
1
+ require 'thesis'
2
+ require 'rails'
3
+
4
+ module Thesis
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :thesis
7
+
8
+ rake_tasks do
9
+ # load File.join(File.dirname(__FILE__), "tasks/db.rake") # Load rake tasks here
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Thesis
2
+ class RouteConstraint
3
+ def self.matches?(request)
4
+ Page.where(slug: request.path.to_s).select("id").first.present?
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ def thesis_routes
4
+ # Page crud (AJAX)
5
+ post "thesis/new_page", "thesis/thesis#new_page"
6
+
7
+ get "*slug" => 'thesis/thesis#show', constraints: ::Thesis::RouteConstraint
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Thesis
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/thesis.rb CHANGED
@@ -1,5 +1,14 @@
1
+ require "thesis/engine"
1
2
  require "thesis/version"
2
- require "thesis/base"
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
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :page_content, class: Thesis::PageContent do
3
+ name "Content Block"
4
+ content "<h1>Some Header</h1><p>A little paragraph.</p>"
5
+ content_type "html"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :page, class: Thesis::Page do
3
+ name "Some Page"
4
+ slug "some-page"
5
+ title "An Awesome Page"
6
+ description "A description goes here"
7
+ template "default"
8
+ end
9
+ end