Index: /home/mislav/projects/radiant/app/controllers/application.rb
===================================================================
--- /home/mislav/projects/radiant/app/controllers/application.rb (revision 573)
+++ /home/mislav/projects/radiant/app/controllers/application.rb (working copy)
@@ -1,9 +1,5 @@
require_dependency 'radiant'

-ActionView::Base.field_error_proc = Proc.new do |html, instance|
- %{<div class="error-with-field">#{html} <small class="error">&bull; #{[instance.error_message].flatten.first}</small></div>}
-end
-
class ApplicationController < ActionController::Base
include LoginSystem

@@ -19,7 +15,9 @@
@config = Radiant::Config
end

+ # helpers to include additional assets from actions or views
helper_method :include_stylesheet, :include_javascript
+
def include_stylesheet(sheet)
@stylesheets << sheet
end
@@ -36,6 +34,7 @@
super
end
end
+
private

def set_current_user
@@ -43,7 +42,7 @@
end

def set_javascripts_and_stylesheets
- @stylesheets = ['admin/main']
- @javascripts = ['prototype', 'string', 'effects', 'dragdrop', 'controls', 'tabcontrol', 'ruledtable']
+ @stylesheets = %w(admin/main)
+ @javascripts = %w(prototype string effects tabcontrol ruledtable admin)
end
end
Index: /home/mislav/projects/radiant/app/controllers/admin/page_controller.rb
===================================================================
--- /home/mislav/projects/radiant/app/controllers/admin/page_controller.rb (revision 573)
+++ /home/mislav/projects/radiant/app/controllers/admin/page_controller.rb (working copy)
@@ -47,6 +47,7 @@

def add_part
part = PagePart.new(params[:part])
+ @index = params[:index].to_i if params[:index]
render(:partial => 'part', :object => part, :layout => false)
end

Index: /home/mislav/projects/radiant/app/controllers/admin/user_controller.rb
===================================================================
--- /home/mislav/projects/radiant/app/controllers/admin/user_controller.rb (revision 573)
+++ /home/mislav/projects/radiant/app/controllers/admin/user_controller.rb (working copy)
@@ -1,7 +1,8 @@
class Admin::UserController < Admin::AbstractModelController
model_class User

- only_allow_access_to :index, :new, :edit, :remove, :when => :admin,
+ only_allow_access_to :index, :new, :edit, :remove,
+ :when => :admin,
:denied_url => {:controller => 'page', :action => :index},
:denied_message => 'You must have administrative privileges to perform this action.'

Index: /home/mislav/projects/radiant/app/controllers/admin/export_controller.rb
===================================================================
--- /home/mislav/projects/radiant/app/controllers/admin/export_controller.rb (revision 573)
+++ /home/mislav/projects/radiant/app/controllers/admin/export_controller.rb (working copy)
@@ -1,6 +1,6 @@
class Admin::ExportController < ApplicationController
def yaml
response.headers['Content-Type'] = "text/yaml"
- render_text Radiant::Exporter.export
+ render :text => Radiant::Exporter.export
end
end
Index: /home/mislav/projects/radiant/app/views/admin/page/_part.rhtml
===================================================================
--- /home/mislav/projects/radiant/app/views/admin/page/_part.rhtml (revision 573)
+++ /home/mislav/projects/radiant/app/views/admin/page/_part.rhtml (working copy)
@@ -1,18 +1,13 @@
-<%
-@part = part
-@index = (params[:index] || @index || 1).to_i
--%>
-<div class="page" id="page-<%= @index %>">
- <div class="part" id="part-<%= @index %>">
- <%= hidden_field_tag "part[#{@index - 1}][name]", @part.name %>
+<% @index ||= 0 -%>
+<div class="page" id="page-<%= @index + 1 %>">
+ <div class="part" id="part-<%= @index + 1 %>">
+ <%= hidden_field_tag "part[#{@index}][name]", part.name %>
<p>
- <label for="part[<%= @index - 1 %>][filter_id]">Filter</label>
- <%= select_tag "part[#{@index - 1}][filter_id]", options_for_select([['<none>', '']] + TextFilter.descendants.map { |s| s.filter_name }.sort, @part.filter_id) %>
- <span id="reference-links">Reference: <span id="filter-reference-link-<%= @index-1 %>"><%= link_to_function "Filter", "load_filter_reference(#{@index - 1})" %></span> <span id="tag-reference-link-<%= @index -1 %>"><%= link_to_function 'Available Tags', "load_tag_reference(#{@index-1});" %></span></span>
+ <label for="part[<%= @index %>][filter_id]">Filter</label>
+ <%= select_tag "part[#{@index}][filter_id]", options_for_select([['<none>', '']] + TextFilter.descendants.map { |s| s.filter_name }.sort, part.filter_id) %>
+ <span id="reference-links">Reference: <span id="filter-reference-link-<%= @index %>"><%= link_to_function "Filter", "load_filter_reference(#{@index})" %></span> <span id="tag-reference-link-<%= @index %>"><%= link_to_function 'Available Tags', "load_tag_reference(#{@index});" %></span></span>
</p>
- <div><%= text_area_tag "part[#{@index - 1}][content]", h(@part.content), :class => "textarea", :style => "width: 100%" %></div>
+ <div><%= text_area_tag "part[#{@index}][content]", h(part.content), :class => "textarea", :style => "width: 100%" %></div>
</div>
</div>
-<%
-@index += 1;
--%>
\ No newline at end of file
+<% @index += 1 -%>
Index: /home/mislav/projects/radiant/app/views/admin/page/edit.rhtml
===================================================================
--- /home/mislav/projects/radiant/app/views/admin/page/edit.rhtml (revision 573)
+++ /home/mislav/projects/radiant/app/views/admin/page/edit.rhtml (working copy)
@@ -1,87 +1,34 @@
<% content_for('page_scripts') do -%>
- function part_added() {
- var partNameField = $('part-name-field');
- var partIndexField = $('part-index-field');
- var index = parseInt(partIndexField.value);
- var tab = 'tab-' + index;
- var caption = partNameField.value;
- var page = 'page-' + index;
- tabControl.addTab(tab, caption, page);
- Element.hide('add-part-popup');
- Element.hide('busy');
- partNameField.value = '';
- partIndexField.value = (index + 1).toString();
- $('add-part-button').disabled = false;
- Field.focus(partNameField);
- tabControl.select(tab);
- }
- function part_loading() {
- $('add-part-button').disabled = true;
- new Effect.Appear('busy');
- }
- function valid_part_name() {
- var partNameField = $('part-name-field');
- var name = partNameField.value.downcase().strip();
- var result = true;
- if (name == '') {
- alert('Part name cannot be empty.');
- return false;
- }
- tabControl.tabs.each(function(pair){
- if (tabControl.tabs.get(pair.key).caption == name) {
- result = false;
- alert('Part name must be unique.');
- throw $break;
- }
- })
- return result;
- }
- function center(element) {
- var header = $('header')
- element = $(element);
- element.style.position = 'absolute';
- var dim = Element.getDimensions(element);
- var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
- element.style.top = (top + 200) + 'px';
- element.style.left = ((header.offsetWidth - dim.width) / 2) + 'px';
- }
- function toggle_add_part_popup() {
- var popup = $('add-part-popup');
- var partNameField = $('part-name-field');
- center(popup);
- Element.toggle(popup);
- Field.focus(partNameField);
- }
- var last_type = "<%= @page.class_name %>";
- function load_tag_reference(part) {
- page_type = $F('page_class_name');
- popup = $('tag-reference-popup');
- if(last_type != page_type) {
- url = "<%= tag_reference_url %>";
- params = "class_name=" + page_type;
- new Effect.Highlight('tag-reference-link-'+ part);
- req = new Ajax.Request(url, { method: 'get', parameters: params, evalScripts: true });
- } else {
- center(popup);
- Element.toggle(popup);
- }
- return false;
- }
- var last_filter = "<%= default_filter_name %>";
- function load_filter_reference(part) {
- filter_type = $F("part[" + part + "][filter_id]");
- popup = $('filter-reference-popup');
- if(last_filter != filter_type) {
- url = "<%= filter_reference_url %>";
- params = "filter_name=" + filter_type;
- new Effect.Highlight('filter-reference-link-'+ part);
- req = new Ajax.Request(url, { method: 'get', parameters: params, evalScripts: true });
- } else {
- center(popup);
- Element.toggle(popup);
- }
- return false;
- }
+ var last_type = "<%= @page.class_name %>";
+ function load_tag_reference(part) {
+ page_type = $F('page_class_name');
+ popup = $('tag-reference-popup');
+ if(last_type != page_type) {
+ url = "<%= tag_reference_url %>";
+ params = "class_name=" + page_type;
+ new Effect.Highlight('tag-reference-link-'+ part);
+ req = new Ajax.Request(url, { method: 'get', parameters: params, evalScripts: true });
+ } else {
+ center(popup);
+ Element.toggle(popup);
+ }
+ return false;
+ }
+ var last_filter = "<%= default_filter_name %>";
+ function load_filter_reference(part) {
+ filter_type = $F("part[" + part + "][filter_id]");
+ popup = $('filter-reference-popup');
+ if(last_filter != filter_type) {
+ url = "<%= filter_reference_url %>";
+ params = "filter_name=" + filter_type;
+ new Effect.Highlight('filter-reference-link-'+ part);
+ req = new Ajax.Request(url, { method: 'get', parameters: params, evalScripts: true });
+ } else {
+ center(popup);
+ Element.toggle(popup);
+ }
+ return false;
+ }
<% end -%>

<% content_for :page_css do %>
@@ -115,25 +62,11 @@
<%= text_field "page", "title", :class => 'textbox', :maxlength => 255 %>
</p>
<div id="extended-metadata" class="row"<%= meta_visible(:meta) %>>
- <table class="fieldset" cellpadding="0" cellspacing="0" border="0">
+ <table class="fieldset">
<% for meta in @meta %>
<%= render :partial => "meta_row", :object => meta %>
<% end %>
</table>
- <script type="text/javascript">
- // <![CDATA[
- $title = $('page_title');
- $slug = $('page_slug');
- $breadcrumb = $('page_breadcrumb');
- $old_title = $title.value || '';
- function title_updated() {
- if ($old_title.toSlug() == $slug.value) $slug.value = $title.value.toSlug();
- if ($old_title == $breadcrumb.value) $breadcrumb.value = $title.value;
- $old_title = $title.value;
- }
- new Form.Element.Observer('page_title', 0.15, title_updated);
- // ]]>
- </script>
</div>
<p class="more-or-less">
<small>
@@ -152,21 +85,7 @@
<%= render :partial => 'part', :collection => @page.parts %>
</div>
</div>
- <script type="text/javascript">
- // <![CDATA[
- var tabControl = new TabControl('tab-control');
-<%
-@index = 0
-for @part in @page.parts do
- @index += 1
--%>
- tabControl.addTab('tab-<%= @index %>', '<%= @part.name %>', 'page-<%= @index %>');
-<%
-end
--%>
- tabControl.select(tabControl.firstTab());
- // ]]>
- </script>
+
<div class="row">
<p><label for="page_layout_id">Layout</label>
<%= select "page", "layout_id", [['<inherit>', '']] + Layout.find(:all).map { |s| [s.name, s.id] } %></p>
@@ -199,11 +118,11 @@
:condition => 'valid_part_name()'
) do %>
<div>
- <%= hidden_field_tag 'index', @index + 1, :id => 'part-index-field' %>
+ <%= hidden_field_tag 'index', @index, :id => 'part-index-field' %>
<%= text_field_tag "part[name]", "", :id => 'part-name-field', :maxlength => 100 %>
<%= submit_tag "Add Part", :id => 'add-part-button' %>
</div>
- <p><%= link_to_function 'Close', "Element.hide('add-part-popup')", :class => 'close-link' %></p>
+ <p><%= link_to_function 'Close', "$(this).up('.popup').hide()", :class => 'close-link' %></p>
<% end %>
</div>
<div class="popup" id="tag-reference-popup" style="display:none;">
@@ -219,5 +138,3 @@
<p><%= link_to_function 'Close', "Element.hide('filter-reference-popup')", :class => 'close-link' %></p>
</div>
<% end -%>
-
-<%= focus 'page_title' %>
Index: /home/mislav/projects/radiant/app/views/admin/page/index.rhtml
===================================================================
--- /home/mislav/projects/radiant/app/views/admin/page/index.rhtml (revision 573)
+++ /home/mislav/projects/radiant/app/views/admin/page/index.rhtml (working copy)
@@ -2,7 +2,7 @@

<h1>Pages</h1>

-<table id="site-map" class="index" cellpadding="0" cellspacing="0" border="0">
+<table id="site-map" class="index" summary="Page hierarchy of the current site">
<thead>
<tr>
<th class="page">Page</th>
@@ -20,11 +20,7 @@
<% end -%>
</tbody>
</table>
-<script type="text/javascript">
-// <![CDATA[
- new SiteMap('site-map', <%= expanded_rows.to_json %>);
-// ]]>
-</script>
+
<form action="<%= clear_cache_url %>" method="post">
<p>
<% unless @homepage -%>
Index: /home/mislav/projects/radiant/config/environment.rb
===================================================================
--- /home/mislav/projects/radiant/config/environment.rb (revision 573)
+++ /home/mislav/projects/radiant/config/environment.rb (working copy)
@@ -67,12 +67,13 @@

# Auto-require text filters
Dir["#{RADIANT_ROOT}/app/models/*_filter.rb"].each do |filter|
- filter = $1 if filter =~ %r{/([^/]+)\.rb}
- require_dependency filter
+ require_dependency File.basename(filter).sub(/\.rb$/, '')
end

# Response Caching Defaults
ResponseCache.defaults[:directory] = ActionController::Base.page_cache_directory
ResponseCache.defaults[:logger] = ActionController::Base.logger

-require "status"
+ActionView::Base.field_error_proc = Proc.new do |html, instance|
+ %{<div class="error-with-field">#{html} <small class="error">&bull; #{[instance.error_message].flatten.first}</small></div>}
+end
Index: /home/mislav/projects/radiant/public/javascripts/prototype.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/prototype.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/prototype.js (working copy)
@@ -21,8 +21,9 @@
XPath: !!document.evaluate,
ElementExtensions: !!window.HTMLElement,
SpecificElementExtensions:
+ document.createElement('div').__proto__ &&
document.createElement('div').__proto__ !==
- document.createElement('form').__proto__
+ document.createElement('form').__proto__
},

ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
@@ -561,7 +562,7 @@

var ctx = object, expr = match[3];
var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
- if (match == null) return '';
+ if (match == null) return before;

while (match != null) {
var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
@@ -1092,6 +1093,7 @@
}
})());

+Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
Hash.from = $H;
var ObjectRange = Class.create(Enumerable, {
initialize: function(start, end, exclusive) {
@@ -1399,8 +1401,10 @@

_getHeaderJSON: function() {
var json = this.getHeader('X-JSON');
+ if (!json) return null;
+ json = decodeURIComponent(escape(json));
try {
- return json ? json.evalJSON(this.request.options.sanitizeJSON) : null;
+ return json.evalJSON(this.request.options.sanitizeJSON);
} catch (e) {
this.request.dispatchException(e);
}
@@ -1408,11 +1412,11 @@

_getResponseJSON: function() {
var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')))
+ return null;
try {
- if (options.evalJSON == 'force' || (options.evalJSON &&
- (this.getHeader('Content-type') || '').include('application/json')))
- return this.transport.responseText.evalJSON(options.sanitizeJSON);
- return null;
+ return this.transport.responseText.evalJSON(options.sanitizeJSON);
} catch (e) {
this.request.dispatchException(e);
}
@@ -1859,6 +1863,20 @@

descendantOf: function(element, ancestor) {
element = $(element), ancestor = $(ancestor);
+
+ if (element.compareDocumentPosition)
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+ if (element.sourceIndex) {
+ var e = element.sourceIndex, a = ancestor.sourceIndex,
+ nextAncestor = ancestor.nextSibling;
+ if (!nextAncestor) {
+ do { ancestor = ancestor.parentNode; }
+ while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
+ }
+ if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+ }
+
while (element = element.parentNode)
if (element == ancestor) return true;
return false;
@@ -2248,7 +2266,11 @@
return filter.replace(/alpha\([^\)]*\)/gi,'');
}
element = $(element);
- if (!element.currentStyle.hasLayout) element.style.zoom = 1;
+ var currentStyle = element.currentStyle;
+ if ((currentStyle && !currentStyle.hasLayout) ||
+ (!currentStyle && element.style.zoom == 'normal'))
+ element.style.zoom = 1;
+
var filter = element.getStyle('filter'), style = element.style;
if (value == 1 || value === '') {
(filter = stripAlpha(filter)) ?
@@ -2344,7 +2366,7 @@
})(Element._attributeTranslations.read.values);
}

-else if (Prototype.Browser.Gecko) {
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
Element.Methods.setOpacity = function(element, value) {
element = $(element);
element.style.opacity = (value == 1) ? 0.999999 :
@@ -3684,24 +3706,27 @@
});

Event.Methods = (function() {
+ var isButton;
+
if (Prototype.Browser.IE) {
- function isButton(event, code) {
- return event.button == ({ 0: 1, 1: 4, 2: 2 })[code];
- }
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
+ isButton = function(event, code) {
+ return event.button == buttonMap[code];
+ };

} else if (Prototype.Browser.WebKit) {
- function isButton(event, code) {
+ isButton = function(event, code) {
switch (code) {
case 0: return event.which == 1 && !event.metaKey;
case 1: return event.which == 1 && event.metaKey;
default: return false;
}
- }
+ };

} else {
- function isButton(event, code) {
+ isButton = function(event, code) {
return event.which ? (event.which === code + 1) : (event.button === code);
- }
+ };
}

return {
@@ -3735,6 +3760,7 @@
Event.extend(event);
event.preventDefault();
event.stopPropagation();
+ event.stopped = true;
}
};
})();
@@ -3784,7 +3810,7 @@
}

function getDOMEventName(eventName) {
- if (eventName && eventName.match(/:/)) return "dataavailable";
+ if (eventName && eventName.include(':')) return "dataavailable";
return eventName;
}

@@ -3803,8 +3829,9 @@
if (c.pluck("handler").include(handler)) return false;

var wrapper = function(event) {
- if (event.eventName && event.eventName != eventName)
- return false;
+ if (!Event || !Event.extend ||
+ (event.eventName && event.eventName != eventName))
+ return false;

Event.extend(event);
handler.call(element, event)
Index: /home/mislav/projects/radiant/public/javascripts/tabcontrol.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/tabcontrol.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/tabcontrol.js (working copy)
@@ -1,13 +1,13 @@
-TabControl = Class.create({
+var TabControl = Class.create({
/*
Initializes a tab control. The variable +element_id+ must be the id of an HTML element
containing one element with it's class name set to 'tabs' and another element with it's
class name set to 'pages'.
*/
- initialize: function(element_id) {
- TabControl.controls[element_id] = this;
- this.control_id = element_id;
- this.element = $(element_id);
+ initialize: function(element) {
+ this.element = $(element);
+ this.control_id = this.element.identify();
+ TabControl.controls.set(this.control_id, this);
this.tab_container = this.element.down('.tabs');
this.tabs = $H();
},
@@ -19,33 +19,24 @@
itself. When a tab is initially added the page element is hidden.
*/
addTab: function(tab_id, caption, page) {
- this.tab_container.insert(
- '<a class="tab" href="javascript:TabControl.controls[\'#{id}\'].select(\'#{tab_id}\');">#{caption}</a>'.interpolate({
- id: this.control_id, tab_id: tab_id, caption: caption
- })
- );
- var tab = this.tab_container.lastChild;
- tab.tab_id = tab_id;
- tab.caption = caption;
- tab.page = $(page);
- this.tabs.set(tab_id, tab);
- this._setNotHere(tab);
- return tab;
+ var tab = new TabControl.Tab(this, tab_id, caption, page);
+
+ this.tabs.set(tab.id, tab);
+ return this.tab_container.appendChild(tab.createElement());
},

/*
Removes +tab+. The variable +tab+ may be either a tab ID or a tab element.
*/
removeTab: function(tab) {
- var t = this._tabify(tab);
- var id = t.tab_id;
- Element.remove(t.page);
- Element.remove(t);
- this.tabs.unset(id);
+ if (Object.isString(tab)) tab = this.tabs.get(tab);
+ tab.remove();
+ this.tabs.unset(tab);

- if (this.selected.tab_id == id) {
+ if (this.selected == tab) {
var first = this.firstTab();
- if (typeof first != 'undefined') this.select(first.tab_id);
+ if (first) this.select(first);
+ else this.selected = null;
}
},

@@ -54,17 +45,12 @@
tab element.
*/
select: function(tab) {
- var t = this._tabify(tab);
- this.tabs.each(function(pair) {
- if (pair.key == t.tab_id) {
- if (this.selected) this.selected.selected = false;
- this.selected = t;
- t.selected = true;
- this._setHere(pair.key);
- } else {
- this._setNotHere(pair.key);
- }
- }, this);
+ if (Object.isString(tab)) tab = this.tabs.get(tab);
+ if (this.selected) this.selected.unselect();
+ tab.select();
+ this.selected = tab;
+ var persist = this.pageId() + ':' + this.selected.id;
+ document.cookie = "current_tab=" + persist + "; path=/admin";
},

/*
@@ -87,47 +73,53 @@
tabCount: function() {
return this.tabs.keys().length;
},
-
- /*
- Private Methods
- */
-
- /*
- Shows the page for +tab+ and adds the class 'here' to tab. The variable +tab+ may
- be either a tab ID or a tab element.
- */
- _setHere: function(tab) {
- var t = this._tabify(tab);
- Element.show(t.page);
- Element.addClassName(t, 'here');
- },
-
- /*
- Hides the page for +tab+ and removes the class 'here' from tab. The variable +tab+
- may be either a tab ID or a tab element.
- */
- _setNotHere: function(tab) {
- var t = this._tabify(tab);
- Element.hide(t.page);
- Element.removeClassName(t, 'here');
- },

- /*
- Returns a tab when passed a string or tab element. Throws a BadTabError otherwise.
- */
- _tabify: function(something) {
- if (typeof something == 'string') {
- var object = this.tabs.get(something);
- } else {
- var object = something;
+ autoSelect: function() {
+ var tab, matches = document.cookie.match(/current_tab=(.+?);/);
+ if (matches) {
+ matches = matches[1].split(':');
+ var page = matches[0], tabId = matches[1];
+ if (!page || page == this.pageId()) tab = this.tabs.get(tabId);
}
- if ((typeof object != 'undefined') && (object.tab_id)) {
- return object;
- } else {
- throw TabControl.BadTabError;
- }
+ this.select(tab || this.firstTab());
+ },
+
+ pageId: function() {
+ return /(\d+)/.test(window.location.pathname) ? RegExp.$1 : '';
}
});

TabControl.controls = $H();
-TabControl.BadTabError = new Error('TabControl: Invalid tab.');
+
+TabControl.Tab = Class.create({
+ initialize: function(control, id, label, content) {
+ this.content = $(content).hide();
+ this.label = label || id;
+ this.id = id;
+ this.control = control;
+ },
+
+ createElement: function() {
+ return this.element = new Element('a', { className: 'tab', href: '#' }).
+ update(this.label).
+ observe('click', function(event){
+ this.control.select(this.id);
+ event.stop();
+ }.bindAsEventListener(this));
+ },
+
+ select: function() {
+ this.content.show();
+ this.element.addClassName('here');
+ },
+
+ unselect: function() {
+ this.content.hide();
+ this.element.removeClassName('here');
+ },
+
+ remove: function() {
+ this.content.remove();
+ this.element.stopObserving('click').remove();
+ }
+});
Index: /home/mislav/projects/radiant/public/javascripts/pngfix.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/pngfix.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/pngfix.js (working copy)
@@ -1,39 +1,39 @@
-/*
-
-Correctly handle PNG transparency in Win IE 5.5 & 6.
-http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.
+/**
+ * Correctly handle PNG transparency in Win IE 5.5 & 6.
+ * http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.
+ *
+ * Use in <HEAD> with DEFER keyword wrapped in conditional comments:
+ *
+ * <!--[if lt IE 7]>
+ * <script defer type="text/javascript" src="pngfix.js"></script>
+ * <![endif]-->
+ *
+ */

-Use in <HEAD> with DEFER keyword wrapped in conditional comments:
-<!--[if lt IE 7]>
-<script defer type="text/javascript" src="pngfix.js"></script>
-<![endif]-->
+var arVersion = navigator.appVersion.split("MSIE"),
+ version = parseFloat(arVersion[1]),
+ filters = false;
+
+try { filters = !!document.body.filters }
+catch (e) {}

-*/
-
-var arVersion = navigator.appVersion.split("MSIE")
-var version = parseFloat(arVersion[1])
-
-if ((version >= 5.5) && (document.body.filters))
-{
- for(var i=0; i<document.images.length; i++)
- {
- var img = document.images[i]
- var imgName = img.src.toUpperCase()
- if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
- {
- var imgID = (img.id) ? "id='" + img.id + "' " : ""
- var imgClass = (img.className) ? "class='" + img.className + "' " : ""
- var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
- var imgStyle = "display:inline-block;" + img.style.cssText
- if (img.align == "left") imgStyle = "float:left;" + imgStyle
- if (img.align == "right") imgStyle = "float:right;" + imgStyle
- if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
- var strNewHTML = "<span " + imgID + imgClass + imgTitle
- + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
- + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
- + "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
- img.outerHTML = strNewHTML
- i = i-1
- }
- }
-}
\ No newline at end of file
+if (version >= 5.5 && filters) {
+ $A(document.images).each(function(img) {
+ if (!img.src.toLowerCase().endsWith('png')) return;
+
+ var span = new Element('span', { id: img.id, className: img.className, title: (img.title || img.alt) }).
+ setStyle({
+ display: 'inline-block',
+ width: img.width + 'px',
+ height: img.height + 'px',
+ filter: 'progid:DXImageTransform.Microsoft.AplhaImageLoader(src="' + img.src + '", sizingMethod="scale")'
+ }).
+ setStyle(img.style.cssText);
+
+ if (img.align == "left") span.setStyle("float: left");
+ else if (img.align == "right") span.setStyle("float: right");
+ if (img.parentElement.href) span.setStyle("cursor: hand");
+
+ $(img).replace(span);
+ });
+}
Index: /home/mislav/projects/radiant/public/javascripts/tag_reference_search.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/tag_reference_search.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/tag_reference_search.js (working copy)
@@ -1,8 +1,8 @@
function hasWordInElement(word, element) {
if (element.nodeType == Node.TEXT_NODE) {
- return element.nodeValue.match(word) != null;
+ return element.nodeValue.include(word) != null;
} else {
- return $A(element.childNodes).any(function (child) {
+ return $A(element.childNodes).any(function(child) {
return hasWordInElement(word, child);
});
}
Index: /home/mislav/projects/radiant/public/javascripts/sitemap.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/sitemap.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/sitemap.js (working copy)
@@ -1,19 +1,15 @@
var SiteMap = Class.create(RuledTable, {
- initialize: function($super, id, expanded) {
- $super(id);
- this.expandedRows = expanded
+ initialize: function($super, element) {
+ $super(element);
+ this.readExpandedCookie();
+ Event.observe(element, 'click', this.onMouseClickRow.bindAsEventListener(this));
},

- onRowSetup: function(row) {
- Event.observe(row, 'click', this.onMouseClickRow.bindAsEventListener(this));
- },
-
onMouseClickRow: function(event) {
- var element = event.element();
- if (this.isExpander(element)) {
+ if (this.isExpander(event.target)) {
var row = event.findElement('tr');
if (this.hasChildren(row)) {
- this.toggleBranch(row, element);
+ this.toggleBranch(row, event.target);
}
}
},
@@ -31,7 +27,7 @@
},

isRow: function(element) {
- return element.tagName && element.match('tr');
+ return element && element.tagName && element.match('tr');
},

extractLevel: function(row) {
@@ -46,105 +42,90 @@

getExpanderImageForRow: function(row) {
return row.down('img');
- },
+ },

+ readExpandedCookie: function() {
+ var matches = document.cookie.match(/expanded_rows=(.+?);/);
+ this.expandedRows = matches ? matches[1].split(',') : [];
+ },
+
saveExpandedCookie: function() {
document.cookie = "expanded_rows=" + this.expandedRows.uniq().join(",") + "; path=/admin";
},
-
- hideBranch: function(row, img) {
- var level = this.extractLevel(row);
- var sibling = row.next();
- while (sibling != null) {
- if (this.isRow(sibling)) {
- if (this.extractLevel(sibling) <= level) break;
- sibling.hide();
- }
- sibling = sibling.next();
- }
+
+ persistCollapsed: function(row) {
var pageId = this.extractPageId(row);
- this.expandedRows = this.expandedRows.reject(function(row) { return row == pageId });
+ this.expandedRows = this.expandedRows.without(pageId);
this.saveExpandedCookie();
- if (img == null) img = this.getExpanderImageForRow(row);
- img.src = img.src.replace(/collapse/, 'expand');
- row.removeClassName('children-visible');
- row.addClassName('children-hidden');
},
+
+ persistExpanded: function(row) {
+ this.expandedRows.push(this.extractPageId(row));
+ this.saveExpandedCookie();
+ },
+
+ toggleExpanded: function(row, img) {
+ if (!img) img = this.getExpanderImageForRow(row);
+ if (this.isExpanded(row)) {
+ img.src = img.src.replace('collapse', 'expand');
+ row.removeClassName('children-visible');
+ row.addClassName('children-hidden');
+ this.persistCollapsed(row);
+ } else {
+ img.src = img.src.replace('expand', 'collapse');
+ row.removeClassName('children-hidden');
+ row.addClassName('children-visible');
+ this.persistExpanded(row);
+ }
+ },

- showBranchInternal: function(row, img) {
- var level = this.extractLevel(row);
- var sibling = row.next();
- var children = false;
- var childOwningSiblings = [];
- while (sibling != null) {
- if (this.isRow(sibling)) {
- var siblingLevel = this.extractLevel(sibling);
- if (siblingLevel <= level) break;
- if (siblingLevel == level + 1) {
- sibling.show();
- if(sibling.hasClassName('children-visible')) {
- childOwningSiblings.push(sibling);
- } else {
- this.hideBranch(sibling);
- }
- }
- children = true;
- }
- sibling = sibling.next();
+ hideBranch: function(parent, img) {
+ var level = this.extractLevel(parent), row = parent.next();
+ while (this.isRow(row) && this.extractLevel(row) > level) {
+ row.hide();
+ row = row.next();
}
- if (!children) this.getBranch(row);
- if (img == null) img = this.getExpanderImageForRow(row);
- img.src = img.src.replace(/expand/, 'collapse');
- childOwningSiblings.each(function(sib) {
- this.showBranch(sib, null);
- }, this);
- row.removeClassName('children-hidden');
- row.addClassName('children-visible');
+ this.toggleExpanded(parent, img);
},

- showBranch: function(row, img) {
- this.showBranchInternal(row, img);
- this.expandedRows.push(this.extractPageId(row));
- this.saveExpandedCookie();
+ showBranch: function(parent, img) {
+ var level = this.extractLevel(parent), row = parent.next(),
+ children = false, expandLevels = [level + 1];
+
+ while (this.isRow(row)) {
+ var currentLevel = this.extractLevel(row);
+ if (currentLevel <= level) break;
+ children = true;
+ if (currentLevel < expandLevels.last()) expandLevels.pop();
+ if (expandLevels.include(currentLevel)) {
+ row.show();
+ if (this.isExpanded(row)) expandLevels.push(currentLevel + 1);
+ }
+ row = row.next();
+ }
+ if (!children) this.getBranch(parent);
+ this.toggleExpanded(parent, img);
},

getBranch: function(row) {
- var level = this.extractLevel(row).toString();
- var id = this.extractPageId(row).toString();
+ var id = this.extractPageId(row), level = this.extractLevel(row),
+ spinner = $('busy-' + id);
+
new Ajax.Updater(
row,
'../admin/ui/pages/children/' + id + '/' + level,
{
- asynchronous: true,
insertion: "after",
- onLoading: function(request) {
- $('busy-' + id).show();
- this.updating = true;
- }.bind(this),
- onComplete: function(request) {
- var sibling = row.next();
- while (sibling != null) {
- if (this.isRow(sibling)) {
- var siblingLevel = this.extractLevel(sibling);
- if (siblingLevel <= level) break;
- this.setupRow(sibling);
- }
- sibling = sibling.nextSibling;
- }
- this.updating = false;
- $('busy-' + id).fade();
- }.bind(this)
+ onLoading: function() { spinner.show(); this.updating = true }.bind(this),
+ onComplete: function() { spinner.fade(); this.updating = false }.bind(this)
}
);
},

toggleBranch: function(row, img) {
if (!this.updating) {
- if (this.isExpanded(row)) {
- this.hideBranch(row, img);
- } else {
- this.showBranch(row, img);
- }
+ var method = (this.isExpanded(row) ? 'hide' : 'show') + 'Branch';
+ this[method](row, img);
}
}
});
Index: /home/mislav/projects/radiant/public/javascripts/ruledtable.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/ruledtable.js (revision 573)
+++ /home/mislav/projects/radiant/public/javascripts/ruledtable.js (working copy)
@@ -1,19 +1,13 @@
var RuledTable = Class.create({
- initialize: function(element_id) {
- var table = $(element_id).select('tr').each(this.setupRow, this)
+ initialize: function(element) {
+ if (Prototype.Browser.IE)
+ $(element).
+ observe('mouseover', this.onMouseOverRow.bindAsEventListener(this, 'addClassName')).
+ observe('mouseout', this.onMouseOverRow.bindAsEventListener(this, 'removeClassName'));
},

- onMouseOverRow: function(event) {
- this.addClassName('highlight');
- },
-
- onMouseOutRow: function(event) {
- this.removeClassName('highlight');
- },
-
- setupRow: function(row) {
- row.observe('mouseover', this.onMouseOverRow);
- row.observe('mouseout', this.onMouseOutRow);
- if (this.onRowSetup) this.onRowSetup(row);
+ onMouseOverRow: function(event, method) {
+ var row = event.findElement('tr');
+ if (row) row[method]('highlight');
}
});
Index: /home/mislav/projects/radiant/public/stylesheets/admin/main.css
===================================================================
--- /home/mislav/projects/radiant/public/stylesheets/admin/main.css (revision 573)
+++ /home/mislav/projects/radiant/public/stylesheets/admin/main.css (working copy)
@@ -24,6 +24,9 @@
color: red;
}

+table {
+ border-collapse: collapse;
+}

/* main layout */

@@ -252,7 +255,8 @@
font-style: italic;
font-weight: normal;
}
-#content table.index tr.highlight {
+#content table.index tr.highlight,
+#content table.index tr:hover {
background-color: #ffffb3;
}
#content table.index .no-children .w1 {
@@ -464,7 +468,7 @@
height: 280px;
border: 1px solid #cdc295;
font-family: Monaco, "Courier New", Courier, monospace;
- font-size: 85%;
+ font-size: 95%;
}
#content #pages label {
font-size: 85%;
@@ -490,8 +494,10 @@
#popups .popup .close-link {
font-size: 85%;
}
+#add-part-popup {
+ width: 17em;
+}

-
/* tag reference */

#tag-reference-popup {
Index: /home/mislav/projects/radiant/public/javascripts/admin.js
===================================================================
--- /home/mislav/projects/radiant/public/javascripts/admin.js (revision 0)
+++ /home/mislav/projects/radiant/public/javascripts/admin.js (revision 0)
@@ -0,0 +1,89 @@
+document.observe('dom:loaded', function() {
+ when('site-map', function(table) { new SiteMap(table) });
+
+ when('page_title', function(title) {
+ var slug = $('page_slug'),
+ breadcrumb = $('page_breadcrumb'),
+ oldTitle = title.value;
+
+ if (!slug || !breadcrumb) return;
+
+ new Form.Element.Observer(title, 0.15, function() {
+ if (oldTitle.toSlug() == slug.value) slug.value = title.value.toSlug();
+ if (oldTitle == breadcrumb.value) breadcrumb.value = title.value;
+ oldTitle = title.value;
+ });
+ });
+
+ when($$('#pages div.part > input[type=hidden]:first-child'), function(parts) {
+ tabControl = new TabControl('tab-control');
+
+ parts.each(function(part, index) {
+ var page = part.up('.page');
+ tabControl.addTab('tab-' + (index + 1), part.value, page.id);
+ });
+
+ tabControl.autoSelect();
+ });
+});
+
+// When object is available, do function fn.
+function when(obj, fn) {
+ if (Object.isString(obj)) obj = /^[\w-]+$/.test(obj) ? $(obj) : $(document.body).down(obj);
+ if (Object.isArray(obj) && !obj.length) return;
+ if (obj) fn(obj);
+}
+
+function part_added() {
+ var partNameField = $('part-name-field');
+ var partIndexField = $('part-index-field');
+ var index = parseInt(partIndexField.value) + 1;
+ var tab = 'tab-' + index;
+ var caption = partNameField.value;
+ var page = 'page-' + index;
+ tabControl.addTab(tab, caption, page);
+ Element.hide('add-part-popup');
+ Element.hide('busy');
+ partNameField.value = '';
+ partIndexField.value = (index + 1).toString();
+ $('add-part-button').disabled = false;
+ Field.focus(partNameField);
+ tabControl.select(tab);
+}
+function part_loading() {
+ $('add-part-button').disabled = true;
+ $('busy').appear();
+}
+function valid_part_name() {
+ var partNameField = $('part-name-field');
+ var name = partNameField.value.downcase().strip();
+ var result = true;
+ if (name == '') {
+ alert('Part name cannot be empty.');
+ return false;
+ }
+ tabControl.tabs.each(function(pair){
+ if (tabControl.tabs.get(pair.key).caption == name) {
+ result = false;
+ alert('Part name must be unique.');
+ throw $break;
+ }
+ })
+ return result;
+}
+function center(element) {
+ var header = $('header')
+ element = $(element);
+ element.style.position = 'absolute';
+ var dim = Element.getDimensions(element);
+ var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
+ element.style.top = (top + 200) + 'px';
+ element.style.left = ((header.offsetWidth - dim.width) / 2) + 'px';
+}
+function toggle_add_part_popup() {
+ var popup = $('add-part-popup');
+ var partNameField = $('part-name-field');
+ center(popup);
+ Element.toggle(popup);
+ Field.focus(partNameField);
+}