Permalink
Browse files

Major progress. Basic functions working, test/test_app included with …

…examples and test page content. Site map working in HTML.
  • Loading branch information...
1 parent bda3788 commit d8caa5297f64ed4fa02f15426569e6e1210722b5 @aceofspades committed Feb 20, 2012
Showing with 1,039 additions and 193 deletions.
  1. +6 −1 Gemfile
  2. +9 −0 Gemfile.lock
  3. +1 −1 Rakefile
  4. +10 −6 app/controllers/caloris/application_controller_ext.rb
  5. +23 −5 app/controllers/caloris/content_controller.rb
  6. +19 −0 app/controllers/caloris_controller.rb
  7. +73 −0 app/models/caloris/content_page.rb
  8. +48 −0 app/models/caloris/metadata.rb
  9. +93 −0 app/models/caloris/page.rb
  10. +34 −0 app/models/caloris/persistence/file_system/page.rb
  11. +59 −0 app/models/caloris/persistence/file_system/page_store.rb
  12. +162 −0 app/models/caloris/site.rb
  13. +35 −0 app/models/caloris/template.rb
  14. +9 −0 app/views/caloris/modals/_metadata_group.html.erb
  15. 0 app/views/caloris/modals/_metadatum.html.erb
  16. +19 −0 app/views/caloris/modals/metadata.html.erb
  17. +22 −4 lib/caloris.rb
  18. +7 −3 lib/caloris/engine.rb
  19. +26 −0 lib/caloris/erb_string.rb
  20. +0 −80 lib/caloris/page.rb
  21. +0 −88 lib/caloris/site.rb
  22. 0 lib/{caloris → }/mercury/engine_ext.rb
  23. +1 −0 lib/{caloris → }/mercury/mercury_config.rb
  24. +1 −2 script/rails
  25. +16 −0 test/test_app/Gemfile
  26. +160 −0 test/test_app/Gemfile.lock
  27. +10 −0 test/test_app/app/controllers/application_controller.rb
  28. +5 −2 test/test_app/config/application.rb
  29. +3 −1 test/test_app/config/environments/production.rb
  30. 0 test/test_app/db/.gitkeep
  31. +20 −0 test/test_app/lib/caloris_init.rb
  32. +5 −0 test/test_app/public/assets/application.css
  33. +19 −0 test/test_app/public/assets/application.js
  34. +3 −0 test/test_app/public/assets/manifest.yml
  35. +16 −0 test/test_content/assets/stylesheets/test_css.css
  36. +3 −0 test/test_content/assets/stylesheets/test_css_manifest.css
  37. +15 −0 test/test_content/views/layouts/test_layout.html.erb
  38. +18 −0 test/test_content/views/pages/branch/leaf.html.erb
  39. +22 −0 test/test_content/views/pages/commented.html.erb
  40. 0 test/test_content/views/pages/empty.html.erb
  41. +22 −0 test/test_content/views/pages/index.html.erb
  42. +18 −0 test/test_content/views/pages/sitemap.html.erb
  43. +9 −0 test/test_content/views/pages/sitemap.xml.builder
  44. +12 −0 test/test_content/views/pages/unpublished.html.erb
  45. +6 −0 test/test_content/views/templates/test_template.html.erb
View
@@ -5,7 +5,12 @@ source "http://rubygems.org"
# development dependencies will be added by default to the :development group.
gemspec
-# jquery-rails is used by the dummy application
+# test_app requirements
gem "jquery-rails"
+group :assets do
+ gem 'sass-rails', '~> 3.1.5'
+ gem 'coffee-rails', '~> 3.1.1'
+ gem 'uglifier', '>= 1.0.3'
+end
gem "pry"
View
@@ -43,6 +43,9 @@ GEM
builder (3.0.0)
cocaine (0.2.1)
coderay (0.9.8)
+ coffee-rails (3.1.1)
+ coffee-script (>= 2.2.0)
+ railties (~> 3.1.0)
coffee-script (2.2.0)
coffee-script-source
execjs
@@ -148,14 +151,20 @@ GEM
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.31)
+ uglifier (1.2.3)
+ execjs (>= 0.3.0)
+ multi_json (>= 1.0.2)
PLATFORMS
ruby
DEPENDENCIES
caloris!
+ coffee-rails (~> 3.1.1)
jquery-rails
mocha
pry
rspec (~> 2.7)
+ sass-rails (~> 3.1.5)
sqlite3
+ uglifier (>= 1.0.3)
View
@@ -20,7 +20,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('lib/**/*.rb')
end
-APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
+APP_RAKEFILE = File.expand_path("../test/test_app/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'
@@ -3,13 +3,17 @@ module ApplicationControllerExt
# https://github.com/jejacks0n/mercury/wiki/Rails-Integration-Techniques
begin
- def layout_with_mercury
- !params[:mercury_frame] && is_editing_with_mercury? ? 'mercury' : nil
- end
+
+ protected
+
+ def layout_with_mercury
+ !params[:mercury_frame] && is_editing_with_mercury? ? 'mercury' : nil
+ end
- def is_editing_with_mercury?
- true
- end
+ def is_editing_with_mercury?
+ true
+ end
+
end
end
@@ -1,15 +1,23 @@
module Caloris
class ContentController < ApplicationController
- layout :set_layout
respond_to :json
before_filter :load_page
def show
raise PageNotFound unless @page
- @page.site.using_view_paths(view_context) do
- render file: @page.pathname
+
+ # TODO when editing, it may be unnecessarily rendering the page twice,
+ # first when rendering the mercury frame, then on the iframe request for the page content
+
+ Rails.logger.info "Caloris: rendering page \"#{@page.name}\""
+ using_view_paths do
+ respond_to do |format|
+ format.html { render inline: @page.render, layout: layout }
+ # TODO require metadata to enable xml?
+ #format.xml { render @page.pathname }
+ end
end
end
@@ -19,17 +27,27 @@ def update
render json: {}, location: File.join(request.base_url, @page.full_path)
end
+ def view_assigns
+ {page: @page, site: @page.site, metadata: @page.metadata}
+ end
+
private
- def set_layout
+ def layout
layout_with_mercury || @page.layout
end
def load_page
- @page = Page.find_by_request(request)
+ @page = Site.find_page_by_request(request)
+ @page = nil unless @page.published?
if @page && @page.site.authorization.present?
raise AccessDenied unless @site.authorization.call(self, @page)
end
+ Rails.logger.info "Caloris: loaded page #{@page.inspect}"
+ end
+
+ def using_view_paths
+ @page.site.using_view_paths(view_context) { yield }
end
end
@@ -0,0 +1,19 @@
+# Based on mercury-rails/app/controllers/mercury_controller.rb
+
+class CalorisController < ActionController::Base
+ #include ::Mercury::Authentication
+
+ protect_from_forgery
+ before_filter :authenticate, :only => :edit
+ layout false
+
+ def resource
+ render :action => "/#{params[:type]}/#{params[:resource]}"
+ end
+
+ private
+
+ def authenticate
+ redirect_to params[:requested_uri] || '/' unless can_edit?
+ end
+end
@@ -0,0 +1,73 @@
+module Caloris
+
+ # Mixin for pages that are structures with content sections: single top-level div, followed by divs for
+ # metadata, named content sections, and the page content section.
+ #
+ # <div>
+ # <div id="caloris_metadata">
+ # <meta name="page_id" content="test"/>
+ # <meta name="page_title" content="Test page</"/>
+ # <meta name="description" content="This is a test page"/>
+ # <meta name="published" scheme="boolean" content="true"/>
+ # <meta name="template" content="test_template"/>
+ # </div>
+ # <div class="caloris_content" data-content-for="layout_header">
+ # This content will be substituted in the layout yielding to :layout_header
+ # </div>
+ # <div class="caloris_content" data-content-for="template_header">
+ # This content will be substituted in the template yielding to :template_header
+ # </div>
+ # <div class="caloris_content">
+ # This is the page content, substituted for "yield :page"
+ # </div>
+ # </div>
+ #
+ module ContentPage
+
+ # Return memoized page metadata as a hash
+ # @return [Caloris::Metadata] Page metadata
+ def metadata
+ @metadata ||= raw_metadata ? Caloris::Metadata.parse(raw_metadata) : Caloris::Metadata.new({})
+ end
+
+ private
+
+ # Raw HTML of metadata markup from page
+ # @return [Nokogiri::XML::Element]
+ def raw_metadata
+ @raw_metadata ||= doc.search('#caloris_metadata').first
+ end
+
+ # Returns page HTML as a string, containing content_for elements for non-body sections.
+ # @return [String] of HTML content
+ def page_content
+ wrapped_contents.values.join
+ end
+
+ # Wraps contents in content_for tags for page content elements, with the exception of the page content itself,
+ # which will have a nil key.
+ # @return [Hash] of HTML content elements
+ def wrapped_contents
+ wrapped_contents = contents.dup
+ wrapped_contents.each do |key, value|
+ wrapped_contents[key] = "<% content_for :#{key.to_sym} do %>#{value}<% end %>" if key
+ end
+ end
+
+ # Return a hash of content elements, where keys come from the data-content-for attribute from the caloris_content
+ # wrapper, or nil for the main page content.
+ # @return [Hash] of HTML content elements
+ def contents
+ unless @contents
+ @contents = {}
+ doc.search('.caloris_content').each do |content|
+ key = content.attributes['data-content-for'].try(:value)
+ @contents[key] = content.inner_html.strip
+ end
+ end
+ @contents
+ end
+
+ end
+
+end
@@ -0,0 +1,48 @@
+module Caloris
+
+ # Stores page metadata, accessible like a hash.
+ class Metadata
+
+ def initialize data
+ @metadata = data
+ end
+
+ # Parse Nokogiri content for metadata
+ # @param fragment [Nokogiri::XML::Element]
+ # @return [Caloris::Metadata]
+ def self.parse fragment
+ select_attrs = %w(content scheme)
+ metadata = Hash[fragment.search('meta').map {|elem|
+ attrs = Hash[elem.attributes.select{|k, v| select_attrs.include? k }.map{|k, v| [k, v.value]}]
+ [elem.attributes['name'].value, attrs]}]
+ new(metadata)
+ end
+
+ # Return metadata for the given key
+ # @param key [String]
+ # @return [String/Boolean] typecast value
+ def [] key
+ value(key)
+ end
+
+ # Return metadata for the given key
+ # @param key [String]
+ # @return [String/Boolean] typecast value
+ def value key
+ return nil unless @metadata[key]
+ case @metadata[key]['scheme']
+ when 'boolean'
+ @metadata[key]['content'] == 'true'
+ else
+ @metadata[key]['content']
+ end
+ end
+
+ # Data type of given key
+ # @return [String] Data type
+ def type key
+ @metadata[key] && @metadata[key]['scheme']
+ end
+
+ end
+end
View
@@ -0,0 +1,93 @@
+require 'nokogiri'
+require 'tilt_ext'
+
+module Caloris
+ class Page
+ attr_reader :site, :path
+
+ def layout
+ metadata && metadata['layout'] || @site.layout
+ end
+
+ # Create a Page instance.
+ # TODO?: An optional block can return the data (html) to be stored by the instance.
+ def initialize path, site, options, &block
+ @path = path
+ @site = site
+ @options = options
+ extend @site.page_store.page_storage_mixin
+ #@data = yield if block_given?
+ end
+
+ def update data
+ data.each do |id, elem_data|
+ elem = doc.search("##{id}").try(:first)
+ raise "Element ##{id} not found" unless elem.present?
+ elem.inner_html = elem_data['value']
+ end
+ end
+
+ def metadata
+ Caloris::Metadata.new(default_metadata)
+ end
+
+ def default_metadata
+ {}
+ end
+
+ def published?
+ metadata['published']
+ end
+
+ def name
+ metadata['page_title'] || 'Untitled page'
+ end
+
+ # Return the main page content, that .caloris_content element without a data-content-for attribute
+ def main_page_content
+ content_for(nil)
+ end
+
+ # Return the page content with the given data-for attribute
+ def content_for for_tag
+ contents[for_tag]
+ end
+
+ # Assemble all content, with the data-content-for blocks first
+ def renderable_contents
+ render_for_contents.unshift(content)
+ end
+
+ def render
+ html = render_page
+ html += template.render if template
+ Caloris::ErbString.new(html).to_string
+ end
+
+ def render_page
+ "<% content_for :page do %>#{page_content}<% end %>"
+ end
+
+ private
+
+ def template
+ template_name = metadata && metadata['template'] || site.default_template
+ @template ||= Caloris::Template.new(@site, template_name)
+ end
+
+ def page_content_html
+ #Tilt.new(formatted_name) { raw_page_content }.render
+ #raw_page_content.gsub(/<%/, '<![CDATA[<%').gsub('%>', '%>]]>')
+ Caloris::ErbString.new(raw_page_content)
+ end
+
+ def doc
+ @doc ||= ::Nokogiri::HTML.fragment(page_content_html)
+ end
+
+ def render_tidy
+ Tilt.new(formatted_name) { doc.to_html }.render_tidy
+ end
+
+ end
+end
Oops, something went wrong.

0 comments on commit d8caa52

Please sign in to comment.