Changesets can be listed by changeset number.
The Git repository is here.
Changeset 118
Controller integrated with HubSsoLib v0.1.0; see Changeset #113. Page
model now has special HubSsoLib tags but they're no use on any page
behavior that caches output. The news behavior has a new "https"
attribute supported on the inclusion tag to force URLs extracted from
feeds to the HTTPS protocol if the enclosing page is itself being
fetched using HTTPS. Fixed delivery path of administration interface
cookie that records the page tree state. Fixed at typo in the
database migration script. Updated the command run when header, footer
and sidebar snippets are changed.
- Comitted by: adh
- Date: Friday October 27 17:19:47 2006 (over 18 years ago)
Affected files:
- rool/rails/radiant/trunk/lib/rss-parser.rb
- rool/rails/radiant/trunk/app/behaviors/news_behavior.rb (diff)
- rool/rails/radiant/trunk/app/controllers/application.rb (diff)
- rool/rails/radiant/trunk/app/controllers/site_controller.rb (diff)
- rool/rails/radiant/trunk/app/models/page_context.rb (diff)
- rool/rails/radiant/trunk/app/views/admin/page/index.rhtml (diff)
- rool/rails/radiant/trunk/command (diff)
- rool/rails/radiant/trunk/db/migrate/001_create_radiant_tables.rb (diff)
- rool/rails/radiant/trunk/vendor/radius/lib/radius.rb (diff)
rool/rails/radiant/trunk/app/behaviors/news_behavior.rb:
prev. | current | |
# extracted from the feed's "pubDate", "modified" or "dc_date" fields, | ||
# in that order. | ||
# | ||
111 | # The optional 'https' attribute defaults to '0'. If '1', HTTP URLs | |
112 | # are upgraded to HTTPS if @request.ssl? is true, else they are left | |
113 | # alone. Note, requires "@request" to be available to this Behavior. | |
114 | # | |
# Finally, an optional 'escape' attribute, defaulting to '1', ensures | ||
# that RSS titles or links cannot be accidentally interpreted as | ||
113 | | |
117 | # Textile data for Textile filtered parts. Setting the attribute to | |
# '0' disables escaping to allow headlines marked up in Textile to be | ||
# passed through to the Textile parser. | ||
# | ||
... | ... | |
tag 'news' do |tag| | ||
feed = tag.attr['feed'] | ||
dates = (tag.attr['dates'] || '1').to_i | ||
133 | to_https = (tag.attr['https'] || '0').to_i | |
escape = (tag.attr['escape'] || '1').to_i | ||
headlines = (tag.attr['headlines'] || '4').to_i | ||
... | ... | |
# manually converting "~" characters to the "%7E" equivalent. | ||
unless (item.link.nil? or item.link.empty?) | ||
184 | | |
189 | link = item.link | |
190 | ||
191 | if (to_https != 0 && request.ssl?) | |
192 | uri = URI.parse(link) | |
193 | uri.scheme = 'https' if (uri.scheme == 'http') | |
194 | link = uri.to_s | |
195 | end | |
196 | ||
197 | link = URI.escape(link) | |
link.gsub!(/\~/, '%7E') | ||
out << "<a href=\"#{link}\">#{title}</a>" | ||
else |
rool/rails/radiant/trunk/app/controllers/application.rb:
prev. | current | |
end | ||
class ApplicationController < ActionController::Base | ||
8 | ||
9 | # Hub single sign-on support. | |
10 | ||
11 | require 'hub_sso_lib' | |
12 | include HubSsoLib::Core | |
13 | before_filter :hubssolib_beforehand | |
14 | after_filter :hubssolib_afterwards | |
15 | ||
16 | # Radiant's usual gubbins follows. | |
17 | ||
include LoginSystem | ||
9 | | |
19 | ||
model :user | ||
observer :user_action_observer | ||
12 | | |
22 | ||
before_filter :set_current_user | ||
14 | | |
24 | ||
attr_accessor :config | ||
16 | | |
26 | ||
def initialize | ||
super | ||
@config = Radiant::Config | ||
end | ||
21 | | |
31 | ||
def default_parts | ||
(@config['default.parts'] || 'body, extended').strip.split(/\s*,\s*/) | ||
end | ||
25 | | |
35 | ||
private | ||
27 | | |
37 | ||
def set_current_user | ||
UserActionObserver.current_user = session[:user] | ||
end | ||
31 | | |
32 | ||
42 | ||
43 | end |
rool/rails/radiant/trunk/app/controllers/site_controller.rb:
prev. | current | |
require_dependency 'response_cache' | ||
class SiteController < ApplicationController | ||
4 | ||
session :off | ||
5 | | |
6 | ||
no_login_required | ||
7 | | |
8 | ||
attr_accessor :config, :cache | ||
9 | | |
10 | ||
def initialize | ||
@config = Radiant::Config | ||
@cache = ResponseCache.instance | ||
end | ||
14 | | |
15 | ||
def show_page | ||
@response.headers.delete('Cache-Control') | ||
url = params[:url].to_s | ||
... | ... | |
show_uncached_page(url) | ||
end | ||
end | ||
25 | | |
26 | ||
private | ||
27 | | |
28 | ||
def find_page(url) | ||
found = Page.find_by_url(url, live?) | ||
found if found and (found.published? or dev?) | ||
... | ... | |
def dev? | ||
(@request.host == @config['dev.host']) or (@request.host =~ /^dev/) | ||
end | ||
49 | | |
50 | ||
def live? | ||
not dev? | ||
end |
rool/rails/radiant/trunk/app/models/page_context.rb:
prev. | current | |
class PageContext < Radius::Context | ||
2 | require 'hub_sso_lib' | |
3 | include HubSsoLib::Core | |
4 | ||
class TagError < StandardError; end | ||
attr_reader :page | ||
... | ... | |
end | ||
# | ||
372 | # <r:if_hubssolib_logged_in>...</r:if_hubssolib_logged_in> | |
373 | # | |
374 | # Renders the containing elements only if the used is logged into Hub. | |
375 | # | |
376 | define_tag 'if_hubssolib_logged_in' do |tag| | |
377 | page = tag.locals.page | |
378 | tag.expand if hubssolib_logged_in? | |
379 | end | |
380 | ||
381 | # | |
382 | # <r:unless_hubssolib_logged_in>...</r:unless_hubssolib_logged_in> | |
383 | # | |
384 | # Renders the containing elements only if the used is NOT logged into Hub. | |
385 | # | |
386 | define_tag 'unless_hubssolib_logged_in' do |tag| | |
387 | page = tag.locals.page | |
388 | tag.expand unless hubssolib_logged_in? | |
389 | end | |
390 | ||
391 | # | |
392 | # <r:hubssolib_unique_name /> | |
393 | # | |
394 | # Renders the unique name of the currently logged in user (which will be | |
395 | # something like 'Anonymous' if not logged in - exact text depends on the | |
396 | # HubSsoLib Gem). | |
397 | # | |
398 | define_tag 'hubssolib_unique_name' do |tag| | |
399 | page = tag.locals.page | |
400 | hubssolib_unique_name | |
401 | end | |
402 | ||
403 | # | |
404 | # <r:hubssolib_flash_tags /> | |
405 | # | |
406 | # Calls HubSsoLib to obtain Flash tags, from the persistent cookie or | |
407 | # the local application, in order to display messages above pages. | |
408 | # | |
409 | define_tag 'hubssolib_flash_tags' do |tag| | |
410 | page = tag.locals.page | |
411 | hubssolib_flash_tags | |
412 | end | |
413 | ||
414 | # | |
# <r:find url="value_to_find">...</r:find> | ||
# | ||
# Inside this tag all page related tags refer to the tag found at the 'url' attribute. |
rool/rails/radiant/trunk/app/views/admin/page/index.rhtml:
prev. | current | |
var SiteMap = Class.create(); | ||
SiteMap.prototype = Object.extend({}, RuledTable.prototype); // Inherit from RuledTable | ||
Object.extend(SiteMap.prototype, { | ||
5 | | |
5 | ||
expandedRows: <%= expanded_rows.to_json %>, | ||
onRowSetup: function(row) { | ||
Event.observe(row, 'click', this.onMouseClickRow.bindAsEventListener(this), false); | ||
}, | ||
11 | | |
11 | ||
onMouseClickRow: function(event) { | ||
var element = Event.element(event); | ||
if (this.isExpander(element)) { | ||
... | ... | |
} | ||
} | ||
}, | ||
21 | | |
21 | ||
hasChildren: function(row) { | ||
return ! /\bno-children\b/.test(row.className); | ||
}, | ||
25 | | |
25 | ||
isExpander: function(element) { | ||
return (element.tagName.strip().downcase() == 'img') && /\bexpander\b/i.test(element.className); | ||
}, | ||
29 | | |
29 | ||
isExpanded: function(row) { | ||
return /\bchildren-visible\b/i.test(row.className); | ||
}, | ||
33 | | |
33 | ||
isRow: function(element) { | ||
return element.tagName && (element.tagName.strip().downcase() == 'tr'); | ||
}, | ||
37 | | |
37 | ||
extractLevel: function(row) { | ||
if (/level-(\d+)/i.test(row.className)) | ||
return RegExp.$1.toInteger(); | ||
}, | ||
42 | | |
42 | ||
extractPageId: function(row) { | ||
if (/page-(\d+)/i.test(row.id)) | ||
return RegExp.$1.toInteger(); | ||
}, | ||
47 | | |
47 | ||
getExpanderImageForRow: function(row) { | ||
var images = $A(row.getElementsByTagName('img', row)); | ||
var expanders = []; | ||
... | ... | |
expanders.push(image); | ||
}.bind(this)); | ||
return expanders.first(); | ||
55 | | |
56 | | |
55 | }, | |
56 | ||
saveExpandedCookie: function() { | ||
58 | | |
59 | | |
60 | | |
58 | document.cookie = "expanded_rows="+this.expandedRows.join(",")+"; path=<%= PATH_PREFIX %>/admin"; | |
59 | }, | |
60 | ||
hideBranch: function(row, img) { | ||
var level = this.extractLevel(row); | ||
var sibling = row.nextSibling; | ||
... | ... | |
Element.removeClassName(row, 'children-visible'); | ||
Element.addClassName(row, 'children-hidden'); | ||
}, | ||
84 | | |
84 | ||
showBranchInternal: function(row, img) { | ||
var level = this.extractLevel(row); | ||
var sibling = row.nextSibling; | ||
var children = false; | ||
89 | | |
89 | var childOwningSiblings = []; | |
while(sibling != null) { | ||
if (this.isRow(sibling)) { | ||
var siblingLevel = this.extractLevel(sibling); | ||
... | ... | |
if (!children) | ||
this.getBranch(row); | ||
if (img == null) | ||
109 | | |
109 | img = this.getExpanderImageForRow(row); | |
img.src = img.src.replace(/expand/, 'collapse'); | ||
for(i=0; i < childOwningSiblings.length; i++) { | ||
112 | | |
113 | | |
112 | this.showBranch(childOwningSiblings[i], null); | |
113 | } | |
Element.removeClassName(row, 'children-hidden'); | ||
Element.addClassName(row, 'children-visible'); | ||
}, | ||
117 | | |
117 | ||
showBranch: function(row, img) { | ||
this.showBranchInternal(row, img); | ||
this.expandedRows.push(this.extractPageId(row)); | ||
this.saveExpandedCookie(); | ||
}, | ||
123 | | |
123 | ||
getBranch: function(row) { | ||
var level = this.extractLevel(row).toString(); | ||
var id = this.extractPageId(row).toString(); | ||
... | ... | |
} | ||
); | ||
}, | ||
153 | | |
153 | ||
toggleBranch: function(row, img) { | ||
if (! this.updating) { | ||
if (this.isExpanded(row)) { |
rool/rails/radiant/trunk/command:
prev. | current | |
#! /bin/bash | ||
# | ||
3 | ||
4 | ||
3 | # Comprehensive service restart script | |
4 | # ==================================== | |
# | ||
6 | ||
6 | # Shut down all servers, ensure all related processes are definitely | |
7 | # killed off (in case any had crashed and hung), delete all logs and | |
8 | # cached data then restart the servers. | |
8 | ||
9 | ||
10 | ||
11 | ||
sleep 4 | ||
13 | ||
15 | ||
16 | ||
12 | ~/web_services/stop | |
13 | ~/web_services/purge | |
14 | ~/web_services/start |
rool/rails/radiant/trunk/db/migrate/001_create_radiant_tables.rb:
prev. | current | |
t.column "updated_at", :datetime | ||
t.column "created_by", :integer | ||
t.column "updated_by", :integer | ||
38 | | |
38 | t.column "auto_export", :string, :limit => 512 | |
t.column "change_exec", :string, :limit => 512 | ||
end | ||
add_index "snippets", ["name"], :name => "name", :unique => true | ||
... | ... | |
t.column "created_by", :integer | ||
t.column "updated_by", :integer | ||
end | ||
51 | | |
51 | ||
create_table "users" do |t| | ||
t.column "name", :string, :limit => 100 | ||
t.column "email", :string | ||
... | ... | |
t.column "updated_by", :integer | ||
end | ||
add_index "users", ["login"], :name => "login", :unique => true | ||
65 | | |
65 | ||
end | ||
def self.down |
rool/rails/radiant/trunk/vendor/radius/lib/radius.rb:
prev. | current | |
# | ||
# The above copyright notice and this permission notice shall be included in all copies | ||
# or substantial portions of the Software. | ||
13 | ||
13 | # | |
# 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 | ||
... | ... | |
# Abstract base class for all parsing errors. | ||
class ParseError < StandardError | ||
end | ||
25 | | |
25 | ||
# Occurs when Parser cannot find an end tag for a given tag in a template or when | ||
# tags are miss-matched in a template. | ||
class MissingEndTagError < ParseError | ||
29 | | |
29 | # Create a new MissingEndTagError object for +tag_name+. | |
def initialize(tag_name) | ||
super("end tag not found for start tag `#{tag_name}'") | ||
end | ||
end | ||
34 | | |
34 | ||
# Occurs when Context#render_tag cannot find the specified tag on a Context. | ||
class UndefinedTagError < ParseError | ||
37 | | |
37 | # Create a new UndefinedTagError object for +tag_name+. | |
def initialize(tag_name) | ||
super("undefined tag `#{tag_name}'") | ||
end | ||
end | ||
42 | | |
42 | ||
module TagDefinitions # :nodoc: | ||
class TagFactory # :nodoc: | ||
def initialize(context) | ||
@context = context | ||
end | ||
48 | | |
48 | ||
def define_tag(name, options, &block) | ||
options = prepare_options(name, options) | ||
validate_params(name, options, &block) | ||
construct_tag_set(name, options, &block) | ||
expose_methods_as_tags(name, options) | ||
end | ||
55 | | |
55 | ||
protected | ||
# Adds the tag definition to the context. Override in subclasses to add additional tags | ||
... | ... | |
options[:expose] += object.attributes.keys if options[:attributes] | ||
options | ||
end | ||
86 | | |
86 | ||
# Validates parameters passed to tag definition. Override in decendants to add custom | ||
# validations. | ||
def validate_params(name, options, &block) | ||
... | ... | |
raise ArgumentError.new("tag definition must contain a :for option when used with the :expose option") unless options[:expose].empty? | ||
end | ||
end | ||
95 | | |
95 | ||
# Exposes the methods of an object as child tags. | ||
def expose_methods_as_tags(name, options) | ||
options[:expose].each do |method| | ||
... | ... | |
end | ||
end | ||
end | ||
107 | | |
107 | ||
protected | ||
109 | | |
109 | ||
def expand_array_option(value) | ||
[*value].compact.map { |m| m.to_s.intern } | ||
end | ||
113 | | |
113 | ||
def last_part(name) | ||
name.split(':').last | ||
end | ||
end | ||
end | ||
119 | | |
119 | ||
class DelegatingOpenStruct # :nodoc: | ||
attr_accessor :object | ||
122 | | |
122 | ||
def initialize(object = nil) | ||
@object = object | ||
@hash = {} | ||
end | ||
127 | | |
127 | ||
def method_missing(method, *args, &block) | ||
symbol = (method.to_s =~ /^(.*?)=$/) ? $1.intern : method | ||
if (0..1).include?(args.size) | ||
... | ... | |
end | ||
end | ||
end | ||
149 | | |
149 | ||
# | ||
# A tag binding is passed into each tag definition and contains helper methods for working | ||
# with tags. Use it to gain access to the attributes that were passed to the tag, to | ||
... | ... | |
# The Context that the TagBinding is associated with. Used internally. Try not to use | ||
# this object directly. | ||
attr_reader :context | ||
159 | | |
159 | ||
# The locals object for the current tag. | ||
attr_reader :locals | ||
162 | | |
162 | ||
# The name of the tag (as used in a template string). | ||
attr_reader :name | ||
165 | | |
165 | ||
# The attributes of the tag. Also aliased as TagBinding#attr. | ||
attr_reader :attributes | ||
alias :attr :attributes | ||
169 | | |
169 | ||
# The render block. When called expands the contents of the tag. Use TagBinding#expand | ||
# instead. | ||
attr_reader :block | ||
173 | | |
173 | ||
# Creates a new TagBinding object. | ||
def initialize(context, locals, name, attributes, block) | ||
@context, @locals, @name, @attributes, @block = context, locals, name, attributes, block | ||
end | ||
178 | | |
178 | ||
# Evaluates the current tag and returns the rendered contents. | ||
def expand | ||
double? ? block.call : '' | ||
... | ... | |
def double? | ||
not single? | ||
end | ||
193 | | |
193 | ||
# The globals object from which all locals objects ultimately inherit their values. | ||
def globals | ||
@context.globals | ||
end | ||
198 | | |
198 | ||
# Returns a list of the way tags are nested around the current tag as a string. | ||
def nesting | ||
@context.current_nesting | ||
end | ||
203 | | |
203 | ||
# Fires off Context#tag_missing for the current tag. | ||
def missing! | ||
@context.tag_missing(name, attributes, &block) | ||
end | ||
208 | | |
208 | ||
# Renders the tag using the current context . | ||
def render(tag, attributes = {}, &block) | ||
@context.render_tag(tag, attributes, &block) | ||
end | ||
end | ||
214 | | |
214 | ||
# | ||
# A context contains the tag definitions which are available for use in a template. | ||
# See the QUICKSTART[link:files/QUICKSTART.html] for a detailed explaination its | ||
... | ... | |
# A hash of tag definition blocks that define tags accessible on a Context. | ||
attr_accessor :definitions # :nodoc: | ||
attr_accessor :globals # :nodoc: | ||
224 | | |
224 | ||
# Creates a new Context object. | ||
def initialize(&block) | ||
@definitions = {} | ||
... | ... | |
@globals = DelegatingOpenStruct.new | ||
with(&block) if block_given? | ||
end | ||
232 | | |
232 | ||
# Yeild an instance of self for tag definitions: | ||
# | ||
# context.with do |c| | ||
... | ... | |
yield self | ||
self | ||
end | ||
245 | | |
245 | ||
# Creates a tag definition on a context. Several options are available to you | ||
# when creating a tag: | ||
248 | | |
248 | # | |
# +for+:: Specifies an object that the tag is in reference to. This is | ||
# applicable when a block is not passed to the tag, or when the | ||
# +expose+ option is also used. | ||
... | ... | |
specific_name | ||
end | ||
end | ||
330 | | |
330 | ||
# Returns the specificity for +tag_name+ at nesting defined | ||
# by +nesting_parts+ as a number. | ||
def numeric_specificity(tag_name, nesting_parts) | ||
... | ... | |
class ParseContainerTag < ParseTag # :nodoc: | ||
attr_accessor :name, :attributes, :contents | ||
369 | | |
369 | ||
def initialize(name = "", attributes = {}, contents = [], &b) | ||
@name, @attributes, @contents = name, attributes, contents | ||
super(&b) | ||
... | ... | |
class Parser | ||
# The Context object used to expand template tags. | ||
attr_accessor :context | ||
384 | | |
384 | ||
# The string that prefixes all tags that are expanded by a parser | ||
# (the part in the tag name before the first colon). | ||
attr_accessor :tag_prefix | ||
388 | | |
388 | ||
# Creates a new parser object initialized with a Context. | ||
def initialize(context = Context.new, options = {}) | ||
if context.kind_of?(Hash) and options.empty? | ||
... | ... | |
end | ||
new_hash | ||
end | ||
476 | | |
476 | ||
def self.impartial_hash_delete(hash, key) | ||
string = key.to_s | ||
symbol = string.intern | ||
... | ... | |
value2 = hash.delete(string) | ||
value1 || value2 | ||
end | ||
484 | | |
484 | ||
def self.constantize(camelized_string) | ||
raise "invalid constant name `#{camelized_string}'" unless camelized_string.split('::').all? { |part| part =~ /^[A-Za-z]+$/ } | ||
Object.module_eval(camelized_string) | ||
end | ||
489 | | |
489 | ||
def self.camelize(underscored_string) | ||
string = '' | ||
underscored_string.split('_').each { |part| string << part.capitalize } | ||
string | ||
end | ||
end | ||
496 | | |
496 | ||
end | ||