1
0
mirror of https://github.com/danbee/danbarberphoto synced 2025-03-04 08:49:07 +00:00

Photos are now paginated. Admin is handled by Typus, including file uploads. Exif reading isn't working when uploading via Typus though.

This commit is contained in:
Dan Barber 2010-10-09 08:28:42 -04:00
parent b35354a764
commit 023a119160
283 changed files with 22964 additions and 30 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
public/system

View File

@ -0,0 +1,4 @@
# Controller generated by Typus, use it to extend admin functionality.
class Admin::CategoriesController < Admin::MasterController
end

View File

@ -0,0 +1,4 @@
# Controller generated by Typus, use it to extend admin functionality.
class Admin::PhotosController < Admin::MasterController
end

View File

@ -0,0 +1,4 @@
# Controller generated by Typus, use it to extend admin functionality.
class Admin::TypusUsersController < Admin::MasterController
end

View File

@ -7,9 +7,11 @@ class PhotosController < ApplicationController
def index def index
if params[:category_id] if params[:category_id]
@category = Category.find_by_id(params[:category_id]) @category = Category.find_by_id(params[:category_id])
@photos = Photo.find(:all, :conditions => { :category_id => params[:category_id] }) @photos = @category.photos.paginate :page => params[:page], :per_page => 11
@num_photos = @photos.count
else else
@photos = Photo.find(:all) @photos = Photo.paginate :all, :page => params[:page], :per_page => 11
@num_photos = @photos.count
end end
end end

View File

@ -1,3 +1,3 @@
class Category < ActiveRecord::Base class Category < ActiveRecord::Base
has_many :photos has_and_belongs_to_many :photos
end end

View File

@ -1,7 +1,7 @@
require 'exifr' require 'exifr'
class Photo < ActiveRecord::Base class Photo < ActiveRecord::Base
belongs_to :category has_and_belongs_to_many :categories
has_attached_file :photo, :styles => { :original => "1024x1024>", has_attached_file :photo, :styles => { :original => "1024x1024>",
:size11 => "308x308#", :size11 => "308x308#",
@ -10,9 +10,9 @@ class Photo < ActiveRecord::Base
:size3 => "84x84#", :size3 => "84x84#",
:size2 => "56x56#" } :size2 => "56x56#" }
validates_presence_of :category after_create :get_exif
before_post_process :get_exif @@per_page = 11
private private
def get_exif def get_exif

View File

@ -1,14 +1,11 @@
</div>
<div class="sg-24 sgParent"> <div class="sg-24 sgParent">
<% @categories.each do |category| %> <% @categories.each do |category| %>
<div class="sg-8 sgParent"> <div class="category sg-5" style="background: <%= category.base_colour %>">
<div class="category sg-7" style="background: <%= category.base_colour %>"> <%= link_to '<h3>'+h(category.name.downcase)+'</h3>', category_photos_path(category) %>
<%= link_to '<h3>'+h(category.name.downcase)+'</h3>', category_photos_path(category) %> </div>
</div>
</div>
<% end %> <% end %>
<div class="sg-7 category blank-category">
</div>
</div> </div>

View File

@ -14,9 +14,11 @@
<div id="wrapper"> <div id="wrapper">
<div id="container"> <div id="container">
<div id="header" class="sg-11"><h1><%= image_tag('title.png') %></h1></div> <div class="sgParent sg-12">
<%= yield %> <div id="header" class="sg-11"><h1><%= image_tag('title.png') %></h1></div>
<%= yield %>
</div> </div>
</div> </div>

View File

@ -1,11 +1,40 @@
<div class="sg-5">
</div>
<div class="sg-5 page-links">
<% if @photos.previous_page -%>
<%= link_to '<div>&larr;</div>', { :page => @photos.previous_page }, :class => 'prev-link' %>
<% end %>
<% if @photos.next_page -%>
<%= link_to '<div>&rarr;</div>', { :page => @photos.next_page }, :class => 'next-link' %>
<% end %>
</div>
</div>
<div class="sg-24 sgParent">
<% if @category %> <% if @category %>
<div class="sg-5 category" style="background: <%= @category.base_colour %>"> <div class="sg-5 category" style="background: <%= @category.base_colour %>">
<h3><%=h @category.name.downcase %></h3> <%= link_to '<h3>'+h(@category.name.downcase)+'</h3><div class="arrow">&uarr;</div>', categories_url %>
</div>
<% else %>
<div class="sg-5 category" style="background: #333;">
<h3>all photos</h3>
</div> </div>
<% end %> <% end %>
<% @num_blank = 11 - @num_photos -%>
<% @photos.each do |photo| %> <% @photos.each do |photo| %>
<div class="sg-5 photo" style="background: url('<%= photo.photo.url(:size5) %>')"><%= link_to '&nbsp;', photo.photo.url, :rel => 'photo', :class => 'fancy' %></div> <div class="sg-5 photo" style="background: url('<%= photo.photo.url(:size5) %>')">
<%= link_to '&nbsp;', photo.photo.url, :rel => 'photo', :class => 'fancy' %>
</div>
<% end %> <% end %>
<% @num_blank.times do %>
<div class="sg-5 photo blank-photo">
</div>
<% end %>
</div>

View File

@ -6,10 +6,6 @@
<%= f.label :image_file %>:<br /> <%= f.label :image_file %>:<br />
<%= f.file_field :photo %> <%= f.file_field :photo %>
</p> </p>
<p>
<%= f.label :category %>
<%= f.select :category_id, @categories %>
</p>
<p> <p>
<%= submit_tag 'Upload' %> <%= submit_tag 'Upload' %>
</p> </p>

View File

@ -19,6 +19,8 @@ Rails::Initializer.run do |config|
# config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
# config.gem "sqlite3-ruby", :lib => "sqlite3" # config.gem "sqlite3-ruby", :lib => "sqlite3"
# config.gem "aws-s3", :lib => "aws/s3" # config.gem "aws-s3", :lib => "aws/s3"
config.gem "exifr"
config.gem "will_paginate"
# Only load the plugins named here, in the order given (default is alphabetical). # Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named # :all can be used as a placeholder for all plugins not explicitly named

View File

@ -0,0 +1,26 @@
# Be sure to restart your server when you modify this file.
# System wide options
Typus::Configuration.options[:app_name] = 'photos'
# Typus::Configuration.options[:email] = 'admin@example.com'
# Typus::Configuration.options[:file_preview] = :typus_preview
# Typus::Configuration.options[:file_thumbnail] = :typus_thumbnail
# Typus::Configuration.options[:relationship] = 'typus_users'
# Typus::Configuration.options[:root] = 'admin'
Typus::Configuration.options[:user_class_name] = 'TypusUser'
Typus::Configuration.options[:user_fk] = 'typus_user_id'
# Model options which can also be defined by model on the yaml files.
# Typus::Configuration.options[:default_action_on_item] = 'edit'
# Typus::Configuration.options[:end_year] = Time.now.year + 1
# Typus::Configuration.options[:form_rows] = 15
# Typus::Configuration.options[:index_after_save] = true
# Typus::Configuration.options[:minute_step] = 5
# Typus::Configuration.options[:nil] = 'nil'
# Typus::Configuration.options[:on_header] = false
# Typus::Configuration.options[:only_user_items] = false
# Typus::Configuration.options[:per_page] = 15
# Typus::Configuration.options[:sidebar_selector] = 5
# Typus::Configuration.options[:start_year] = Time.now.year - 10

View File

@ -1,4 +1,5 @@
ActionController::Routing::Routes.draw do |map| ActionController::Routing::Routes.draw do |map|
Typus::Routes.draw(map)
# The priority is based upon order of creation: first created -> highest priority. # The priority is based upon order of creation: first created -> highest priority.
# Sample of regular route: # Sample of regular route:

71
config/typus/README Normal file
View File

@ -0,0 +1,71 @@
# Models
This is an example of a **Typus** enabled model with all available
options. You can use this example to customize your YAML files which
only have set the most common settings.
Post:
fields:
list: id, title, category_id, created_at, is_published?
form: title, body, is_published?, created_at
show: title, category, is_published?
relationship: title, status
options:
auto_generated:
booleans:
is_published: ["Yes, it is", "No, it isn't"]
date_formats:
created_at: post_long
selectors:
read_only:
filter_by_date_range: valid_until
templates:
body: rich_text
actions:
index: cleanup
edit: send_as_newsletter
show: rebuild
export: csv, xml, pdf
order_by: created_at
relationships:
filters: is_published?, created_at, category_id
search: title, body
application: Application
description: Some text to describe the model
options:
default_action_on_item: show
end_year: 2015
form_rows: 25
index_after_save: false
minute_step: 15
nil: 'nil'
on_header: true
only_user_items: true
per_page: 5
sidebar_selector: 5
start_year: 1990
Note: To define namespace models use :: as a separator. (i.e. Delayed::Job)
# Roles
In this file you can configure the actions available for each of
your models on the application. You can also use the 'all' shortcut
to allow the user the access to all actions.
admin:
Post: create, read, update, delete
Category: create, read, update, delete
TypusUser: all
editor:
Post: create, read, update
Category: read, update
You can also define `resources` which are not related to a model,
for example to control MemCached or see the Starling queue
statistics.
admin:
Starling: index
MemCached: index, cleanup

View File

@ -0,0 +1,26 @@
# Typus Models Configuration File
#
# Use the README file as a reference to customize settings.
Category:
fields:
default: name, photo_id, base_colour, sort
list: name, photo_id, base_colour, sort
form: name, description, photo_id, base_colour, sort
order_by:
relationships: photos
filters:
search: name
application: photos
Photo:
fields:
default: photo_file_name, photo_content_type, photo_file_size, photo_updated_at, title, sort
list: photo_file_name, categories, photo_content_type, photo_file_size, photo_updated_at, title, sort
form: photo, flickr_url, title, description, sort
order_by:
relationships: categories
filters:
search: title
application: photos

View File

@ -0,0 +1,7 @@
# Typus Roles Configuration File
#
# Use the README file as a reference to customize settings.
admin:
Category: create, read, update, delete
Photo: create, read, update, delete

17
config/typus/typus.yml Normal file
View File

@ -0,0 +1,17 @@
# Typus Models Configuration File
#
# Use the README file as a reference to customize settings.
TypusUser:
fields:
default: first_name, last_name, email, role, status
list: email, role, status
form: first_name, last_name, role, email, password, password_confirmation, language
options:
selectors: role, language
booleans:
status: Active, Inactive
filters: status, role
search: first_name, last_name, email, role
application: Admin Panel
description: Admin Panel Users Administration

View File

@ -0,0 +1,6 @@
# Typus Roles Configuration File
#
# Use the README file as a reference to customize settings.
admin:
TypusUser: all

Binary file not shown.

View File

@ -0,0 +1,14 @@
class MoveToManyToMany < ActiveRecord::Migration
def self.up
remove_column :photos, :category_id
create_table :categories_photos, :id => false do |t|
t.integer :category_id
t.integer :photo_id
end
end
def self.down
add_column :photos, :category_id, :integer
drop_table :categories_photos
end
end

View File

@ -0,0 +1,22 @@
class CreateTypusUsers < ActiveRecord::Migration
def self.up
create_table :typus_users do |t|
t.string :first_name, :default => "", :null => false
t.string :last_name, :default => "", :null => false
t.string :role, :null => false
t.string :email, :null => false
t.boolean :status, :default => false
t.string :token, :null => false
t.string :salt, :null => false
t.string :crypted_password, :null => false
t.string :preferences
t.timestamps
end
end
def self.down
drop_table :typus_users
end
end

View File

@ -9,7 +9,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20101008122736) do ActiveRecord::Schema.define(:version => 20101008175640) do
create_table "categories", :force => true do |t| create_table "categories", :force => true do |t|
t.string "name" t.string "name"
@ -21,8 +21,12 @@ ActiveRecord::Schema.define(:version => 20101008122736) do
t.integer "sort" t.integer "sort"
end end
create_table "categories_photos", :id => false, :force => true do |t|
t.integer "category_id"
t.integer "photo_id"
end
create_table "photos", :force => true do |t| create_table "photos", :force => true do |t|
t.integer "category_id"
t.string "flickr_url" t.string "flickr_url"
t.string "photo_file_name" t.string "photo_file_name"
t.string "photo_content_type" t.string "photo_content_type"
@ -35,4 +39,18 @@ ActiveRecord::Schema.define(:version => 20101008122736) do
t.integer "sort" t.integer "sort"
end end
create_table "typus_users", :force => true do |t|
t.string "first_name", :default => "", :null => false
t.string "last_name", :default => "", :null => false
t.string "role", :null => false
t.string "email", :null => false
t.boolean "status", :default => false
t.string "token", :null => false
t.string "salt", :null => false
t.string "crypted_password", :null => false
t.string "preferences"
t.datetime "created_at"
t.datetime "updated_at"
end
end end

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,2 @@
// Place your application-specific JavaScript functions and classes for
// Typus here.

View File

@ -0,0 +1,152 @@
/*!
* jQuery JavaScript Library v1.4.1
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Mon Jan 25 19:43:33 2010 -0500
*/
(function(z,v){function la(){if(!c.isReady){try{r.documentElement.doScroll("left")}catch(a){setTimeout(la,1);return}c.ready()}}function Ma(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var n in b)X(a,n,b[n],f,e,d);return a}if(d!==v){f=!i&&f&&c.isFunction(d);for(n=0;n<j;n++)e(a[n],b,f?d.call(a[n],n,e(a[n],b)):d,i);return a}return j?
e(a[0],b):null}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function ma(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function na(a){var b,d=[],f=[],e=arguments,i,j,n,o,m,s,x=c.extend({},c.data(this,"events").live);if(!(a.button&&a.type==="click")){for(o in x){j=x[o];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete x[o]}i=c(a.target).closest(f,
a.currentTarget);m=0;for(s=i.length;m<s;m++)for(o in x){j=x[o];n=i[m].elem;f=null;if(i[m].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==n)d.push({elem:n,fn:j})}}m=0;for(s=d.length;m<s;m++){i=d[m];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}}function oa(a,b){return"live."+(a?a+".":"")+b.replace(/\./g,"`").replace(/ /g,"&")}function pa(a){return!a||!a.parentNode||a.parentNode.nodeType===
11}function qa(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ra(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0&&(c.support.checkClone||!sa.test(a[0]))){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:r;f=b.createDocumentFragment();
c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=i?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(ta.concat.apply([],ta.slice(0,b)),function(){d[this]=a});return d}function ua(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Na=z.jQuery,Oa=z.$,r=z.document,S,Pa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Qa=/^.[^:#\[\.,]*$/,Ra=/\S/,Sa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Ta=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,O=navigator.userAgent,
va=false,P=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,Q=Array.prototype.slice,wa=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Pa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:r;if(a=Ta.exec(a))if(c.isPlainObject(b)){a=[r.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ra([d[1]],
[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=r.getElementById(d[2])){if(b.id!==d[2])return S.find(a);this.length=1;this[0]=b}this.context=r;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=r;a=r.getElementsByTagName(a)}else return!b||b.jquery?(b||S).find(a):c(b).find(a);else if(c.isFunction(a))return S.ready(a);if(a.selector!==v){this.selector=a.selector;this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,
this)},selector:"",jquery:"1.4.1",length:0,size:function(){return this.length},toArray:function(){return Q.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=0;ba.apply(this,a);return this},each:function(a,b){return c.each(this,
a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(r,c);else P&&P.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(Q.apply(this,arguments),"slice",Q.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};
c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,n;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];n=e[i];if(a!==n)if(f&&n&&(c.isPlainObject(n)||c.isArray(n))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(n)?[]:{};a[i]=c.extend(f,j,n)}else if(n!==v)a[i]=n}return a};c.extend({noConflict:function(a){z.$=
Oa;if(a)z.jQuery=Na;return c},isReady:false,ready:function(){if(!c.isReady){if(!r.body)return setTimeout(c.ready,13);c.isReady=true;if(P){for(var a,b=0;a=P[b++];)a.call(r,c);P=null}c.fn.triggerHandler&&c(r).triggerHandler("ready")}},bindReady:function(){if(!va){va=true;if(r.readyState==="complete")return c.ready();if(r.addEventListener){r.addEventListener("DOMContentLoaded",L,false);z.addEventListener("load",c.ready,false)}else if(r.attachEvent){r.attachEvent("onreadystatechange",L);z.attachEvent("onload",
c.ready);var a=false;try{a=z.frameElement==null}catch(b){}r.documentElement.doScroll&&a&&la()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===v||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;
return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return z.JSON&&z.JSON.parse?z.JSON.parse(a):(new Function("return "+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Ra.test(a)){var b=r.getElementsByTagName("head")[0]||
r.documentElement,d=r.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(r.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===v||c.isFunction(a);if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=
a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Sa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==
v;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=v}else if(b&&!c.isFunction(b)){d=b;b=v}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},
uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});O=c.uaMatch(O);if(O.browser){c.browser[O.browser]=true;c.browser.version=O.version}if(c.browser.webkit)c.browser.safari=true;if(wa)c.inArray=function(a,b){return wa.call(b,a)};S=c(r);if(r.addEventListener)L=function(){r.removeEventListener("DOMContentLoaded",
L,false);c.ready()};else if(r.attachEvent)L=function(){if(r.readyState==="complete"){r.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=r.documentElement,b=r.createElement("script"),d=r.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support=
{leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:r.createElement("select").appendChild(r.createElement("option")).selected,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};
b.type="text/javascript";try{b.appendChild(r.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,a.firstChild);if(z[f]){c.support.scriptEval=true;delete z[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function n(){c.support.noCloneEvent=false;d.detachEvent("onclick",n)});d.cloneNode(true).fireEvent("onclick")}d=r.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=r.createDocumentFragment();a.appendChild(d.firstChild);
c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var n=r.createElement("div");n.style.width=n.style.paddingLeft="1px";r.body.appendChild(n);c.boxModel=c.support.boxModel=n.offsetWidth===2;r.body.removeChild(n).style.display="none"});a=function(n){var o=r.createElement("div");n="on"+n;var m=n in o;if(!m){o.setAttribute(n,"return;");m=typeof o[n]==="function"}return m};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props=
{"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ua=0,xa={},Va={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var f=a[G],e=c.cache;if(!b&&!f)return null;f||(f=++Ua);if(typeof b==="object"){a[G]=f;e=e[f]=c.extend(true,
{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Va:(e[f]={});if(d!==v){a[G]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[G]}catch(i){a.removeAttribute&&a.removeAttribute(G)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,
a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===v){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===v&&this.length)f=c.data(this[0],a);return f===v&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);
return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===v)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||
a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var ya=/[\n\t]/g,ca=/\s+/,Wa=/\r/g,Xa=/href|src|style/,Ya=/(button|input)/i,Za=/(button|input|object|select|textarea)/i,$a=/^(a|area)$/i,za=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=
c(this);m.addClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,n=b.length;j<n;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=c(this);m.removeClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string"||a===v)for(var b=(a||"").split(ca),
d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(ya," "),j=0,n=b.length;j<n;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),n=b,o=
a.split(ca);e=o[i++];){n=f?n:!j.hasClass(e);j[n?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(ya," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===v){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||
{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(za.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Wa,"")}return v}var n=c.isFunction(a);return this.each(function(o){var m=c(this),s=a;if(this.nodeType===1){if(n)s=a.call(this,o,m.val());
if(typeof s==="number")s+="";if(c.isArray(s)&&za.test(this.type))this.checked=c.inArray(m.val(),s)>=0;else if(c.nodeName(this,"select")){var x=c.makeArray(s);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),x)>=0});if(!x.length)this.selectedIndex=-1}else this.value=s}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return v;if(f&&b in c.attrFn)return c(a)[b](d);
f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==v;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Xa.test(b);if(b in a&&f&&!i){if(e){b==="type"&&Ya.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Za.test(a.nodeName)||$a.test(a.nodeName)&&a.href?0:v;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=
""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?v:a}return c.style(a,b,d)}});var ab=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==z&&!a.frameElement)a=z;if(!d.guid)d.guid=c.guid++;if(f!==v){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=
function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):v};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var n,o=0;n=b[o++];){var m=n.split(".");n=m.shift();if(o>1){d=c.proxy(d);if(f!==v)d.data=f}d.type=m.slice(0).sort().join(".");var s=e[n],x=this.special[n]||{};if(!s){s=e[n]={};if(!x.setup||x.setup.call(a,f,m,d)===false)if(a.addEventListener)a.addEventListener(n,i,false);else a.attachEvent&&a.attachEvent("on"+n,i)}if(x.add)if((m=x.add.call(a,
d,f,m,s))&&c.isFunction(m)){m.guid=m.guid||d.guid;m.data=m.data||d.data;m.type=m.type||d.type;d=m}s[d.guid]=d;this.global[n]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===v||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);for(var n=0;i=b[n++];){var o=i.split(".");i=o.shift();var m=!o.length,s=c.map(o.slice(0).sort(),ab);s=new RegExp("(^|\\.)"+
s.join("\\.(?:.*\\.)?")+"(\\.|$)");var x=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var A in f[i])if(m||s.test(f[i][A].type))delete f[i][A];x.remove&&x.remove.call(a,o,j);for(e in f[i])break;if(!e){if(!x.teardown||x.teardown.call(a,o)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(A=c.data(a,"handle"))A.elem=null;c.removeData(a,
"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return v;a.result=v;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,
b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(i){}if(!a.isPropagationStopped()&&f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){d=a.target;var j;if(!(c.nodeName(d,"a")&&e==="click")&&!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){try{if(d[e]){if(j=d["on"+e])d["on"+e]=null;this.triggered=true;d[e]()}}catch(n){}if(j)d["on"+e]=j;this.triggered=false}}},handle:function(a){var b,
d;a=arguments[0]=c.event.fix(a||z.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==v){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||r;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=r.documentElement;d=r.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==v)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;b.liveProxy=a;c.event.add(this,b.live,na,b)},remove:function(a){if(a.length){var b=
0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],na)}},special:{}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};
c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y};var Aa=function(a){for(var b=
a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ba=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ba:Aa,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ba:Aa)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!==
"form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return ma("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return ma("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,
"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var da=/textarea|input|select/i;function Ca(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ea(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Ca(d);if(a.type!=="focusout"||
d.type!=="radio")c.data(d,"_change_data",e);if(!(f===v||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}}c.event.special.change={filters:{focusout:ea,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ea.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ea.call(this,a)},beforeactivate:function(a){a=
a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Ca(a))}},setup:function(a,b,d){for(var f in T)c.event.add(this,f+".specialChange."+d.guid,T[f]);return da.test(this.nodeName)},remove:function(a,b){for(var d in T)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),T[d]);return da.test(this.nodeName)}};var T=c.event.special.change.filters}r.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,
f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){e=f;f=v}var j=b==="one"?c.proxy(e,function(n){c(this).unbind(n,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,
b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+
a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e){var i,j=0;if(c.isFunction(f)){e=f;f=v}for(d=(d||"").split(/\s+/);(i=d[j++])!=null;){i=i==="focus"?"focusin":i==="blur"?"focusout":i==="hover"?d.push("mouseleave")&&"mouseenter":i;b==="live"?c(this.context).bind(oa(i,this.selector),{data:f,selector:this.selector,
live:i},e):c(this.context).unbind(oa(i,this.selector),e?{guid:e.guid+this.selector+i}:null)}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});z.attachEvent&&!z.addEventListener&&z.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
(function(){function a(g){for(var h="",k,l=0;g[l];l++){k=g[l];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===k){y=l[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=k;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}l[q]=y}}}function d(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===
k){y=l[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=k;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(o.filter(h,[t]).length>0){y=t;break}}t=t[g]}l[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,i=Object.prototype.toString,j=false,n=true;[0,0].sort(function(){n=false;return 0});var o=function(g,h,k,l){k=k||[];var q=h=h||r;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||
typeof g!=="string")return k;for(var p=[],u,t,y,R,H=true,M=w(h),I=g;(f.exec(""),u=f.exec(I))!==null;){I=u[3];p.push(u[1]);if(u[2]){R=u[3];break}}if(p.length>1&&s.exec(g))if(p.length===2&&m.relative[p[0]])t=fa(p[0]+p[1],h);else for(t=m.relative[p[0]]?[h]:o(p.shift(),h);p.length;){g=p.shift();if(m.relative[g])g+=p.shift();t=fa(g,t)}else{if(!l&&p.length>1&&h.nodeType===9&&!M&&m.match.ID.test(p[0])&&!m.match.ID.test(p[p.length-1])){u=o.find(p.shift(),h,M);h=u.expr?o.filter(u.expr,u.set)[0]:u.set[0]}if(h){u=
l?{expr:p.pop(),set:A(l)}:o.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=u.expr?o.filter(u.expr,u.set):u.set;if(p.length>0)y=A(t);else H=false;for(;p.length;){var D=p.pop();u=D;if(m.relative[D])u=p.pop();else D="";if(u==null)u=h;m.relative[D](y,u,M)}}else y=[]}y||(y=t);y||o.error(D||g);if(i.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))k.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&
y[g].nodeType===1&&k.push(t[g]);else k.push.apply(k,y);else A(y,k);if(R){o(R,q,k,l);o.uniqueSort(k)}return k};o.uniqueSort=function(g){if(C){j=n;g.sort(C);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};o.matches=function(g,h){return o(g,null,null,h)};o.find=function(g,h,k){var l,q;if(!g)return[];for(var p=0,u=m.order.length;p<u;p++){var t=m.order[p];if(q=m.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");l=m.find[t](q,
h,k);if(l!=null){g=g.replace(m.match[t],"");break}}}}l||(l=h.getElementsByTagName("*"));return{set:l,expr:g}};o.filter=function(g,h,k,l){for(var q=g,p=[],u=h,t,y,R=h&&h[0]&&w(h[0]);g&&h.length;){for(var H in m.filter)if((t=m.leftMatch[H].exec(g))!=null&&t[2]){var M=m.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(u===p)p=[];if(m.preFilter[H])if(t=m.preFilter[H](t,u,k,p,l,R)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=u[U])!=null;U++)if(D){I=M(D,t,U,u);var Da=
l^!!I;if(k&&I!=null)if(Da)y=true;else u[U]=false;else if(Da){p.push(D);y=true}}if(I!==v){k||(u=p);g=g.replace(m.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)o.error(g);else break;q=g}return u};o.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var m=o.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,h){var k=typeof h==="string",l=k&&!/\W/.test(h);k=k&&!l;if(l)h=h.toLowerCase();l=0;for(var q=g.length,
p;l<q;l++)if(p=g[l]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[l]=k||p&&p.nodeName.toLowerCase()===h?p||false:p===h}k&&o.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var l=0,q=g.length;l<q;l++){var p=g[l];if(p){k=p.parentNode;g[l]=k.nodeName.toLowerCase()===h?k:false}}}else{l=0;for(q=g.length;l<q;l++)if(p=g[l])g[l]=k?p.parentNode:p.parentNode===h;k&&o.filter(h,g,true)}},"":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=
h=h.toLowerCase();q=b}q("parentNode",h,l,g,p,k)},"~":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,l,g,p,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];h=h.getElementsByName(g[1]);for(var l=0,q=h.length;l<q;l++)h[l].getAttribute("name")===g[1]&&k.push(h[l]);return k.length===0?null:k}},
TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,l,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var u;(u=h[p])!=null;p++)if(u)if(q^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||l.push(u);else if(k)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&
"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,l,q,p){h=g[1].replace(/\\/g,"");if(!p&&m.attrMap[h])g[1]=m.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,l,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=o(g[3],null,null,h);else{g=o.filter(g[3],h,k,true^q);k||l.push.apply(l,g);return false}else if(m.match.POS.test(g[0])||m.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);
return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!o(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===
g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,h){return h===0},last:function(g,h,k,l){return h===l.length-1},even:function(g,h){return h%2===
0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,l){var q=h[1],p=m.filters[q];if(p)return p(g,k,h,l);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=h[3];k=0;for(l=h.length;k<l;k++)if(h[k]===g)return false;return true}else o.error("Syntax error, unrecognized expression: "+
q)},CHILD:function(g,h){var k=h[1],l=g;switch(k){case "only":case "first":for(;l=l.previousSibling;)if(l.nodeType===1)return false;if(k==="first")return true;l=g;case "last":for(;l=l.nextSibling;)if(l.nodeType===1)return false;return true;case "nth":k=h[2];var q=h[3];if(k===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var u=0;for(l=p.firstChild;l;l=l.nextSibling)if(l.nodeType===1)l.nodeIndex=++u;p.sizcache=h}g=g.nodeIndex-q;return k===0?g===0:g%k===0&&g/k>=
0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=m.attrHandle[k]?m.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var l=h[2];h=h[4];return g==null?l==="!=":l==="="?k===h:l==="*="?k.indexOf(h)>=0:l==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:l==="!="?k!==h:l==="^="?
k.indexOf(h)===0:l==="$="?k.substr(k.length-h.length)===h:l==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,l){var q=m.setFilters[h[2]];if(q)return q(g,k,h,l)}}},s=m.match.POS;for(var x in m.match){m.match[x]=new RegExp(m.match[x].source+/(?![^\[]*\])(?![^\(]*\))/.source);m.leftMatch[x]=new RegExp(/(^(?:.|\r|\n)*?)/.source+m.match[x].source.replace(/\\(\d+)/g,function(g,h){return"\\"+(h-0+1)}))}var A=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};
try{Array.prototype.slice.call(r.documentElement.childNodes,0)}catch(B){A=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,l=g.length;k<l;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var C;if(r.documentElement.compareDocumentPosition)C=function(g,h){if(!g.compareDocumentPosition||!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===
h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in r.documentElement)C=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(r.createRange)C=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),l=h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);l.setStart(h,0);l.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END,
l);if(g===0)j=true;return g};(function(){var g=r.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=r.documentElement;k.insertBefore(g,k.firstChild);if(r.getElementById(h)){m.find.ID=function(l,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(l[1]))?q.id===l[1]||typeof q.getAttributeNode!=="undefined"&&q.getAttributeNode("id").nodeValue===l[1]?[q]:v:[]};m.filter.ID=function(l,q){var p=typeof l.getAttributeNode!=="undefined"&&l.getAttributeNode("id");
return l.nodeType===1&&p&&p.nodeValue===q}}k.removeChild(g);k=g=null})();(function(){var g=r.createElement("div");g.appendChild(r.createComment(""));if(g.getElementsByTagName("*").length>0)m.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var l=0;k[l];l++)k[l].nodeType===1&&h.push(k[l]);k=h}return k};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")m.attrHandle.href=function(h){return h.getAttribute("href",
2)};g=null})();r.querySelectorAll&&function(){var g=o,h=r.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){o=function(l,q,p,u){q=q||r;if(!u&&q.nodeType===9&&!w(q))try{return A(q.querySelectorAll(l),p)}catch(t){}return g(l,q,p,u)};for(var k in g)o[k]=g[k];h=null}}();(function(){var g=r.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){m.order.splice(1,0,"CLASS");m.find.CLASS=function(h,k,l){if(typeof k.getElementsByClassName!=="undefined"&&!l)return k.getElementsByClassName(h[1])};g=null}}})();var E=r.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,h){return g!==h&&(g.contains?g.contains(h):true)},w=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},fa=function(g,h){var k=[],
l="",q;for(h=h.nodeType?[h]:h;q=m.match.PSEUDO.exec(g);){l+=q[0];g=g.replace(m.match.PSEUDO,"")}g=m.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)o(g,h[q],k);return o.filter(l,k)};c.find=o;c.expr=o.selectors;c.expr[":"]=c.expr.filters;c.unique=o.uniqueSort;c.getText=a;c.isXMLDoc=w;c.contains=E})();var bb=/Until$/,cb=/^(?:parents|prevUntil|prevAll)/,db=/,/;Q=Array.prototype.slice;var Ea=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a,
function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Qa.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=
0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ea(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ea(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i={},j;if(f&&a.length){e=0;for(var n=a.length;e<n;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)>
-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var o=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(m,s){for(;s&&s.ownerDocument&&s!==b;){if(o?o.index(s)>-1:c(s).is(a))return s;s=s.parentNode}return null})},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),
a);return this.pushStack(pa(a[0])||pa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},
nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);bb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):
e;if((this.length>1||db.test(f))&&cb.test(a))e=e.reverse();return this.pushStack(e,a,Q.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===v||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==
b&&d.push(a);return d}});var Fa=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ga=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,sa=/checked\s*(?:[^=]|=\s*.checked.)/i,Ia=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],
col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==v)return this.empty().append((this[0]&&this[0].ownerDocument||r).createTextNode(a));return c.getText(this)},
wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?
d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,
false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&
!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Fa,"").replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){qa(this,b);qa(this.find("*"),b.find("*"))}return b},html:function(a){if(a===v)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Fa,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(Ha.exec(a)||
["",""])[1].toLowerCase()]){a=a.replace(Ga,Ia);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,
b,f))});else a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(s){return c.nodeName(s,"table")?s.getElementsByTagName("tbody")[0]||s.appendChild(s.ownerDocument.createElement("tbody")):s}var e,i,j=a[0],n=[];if(!c.support.checkClone&&arguments.length===3&&typeof j===
"string"&&sa.test(j))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(j))return this.each(function(s){var x=c(this);a[0]=j.call(this,s,b?x.html():v);x.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ra(a,this,n);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var o=0,m=this.length;o<m;o++)d.call(b?f(this[o],i):this[o],e.cacheable||this.length>1||o>0?e.fragment.cloneNode(true):e.fragment)}n&&c.each(n,
Ma)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){c.cleanData(this.getElementsByTagName("*"));c.cleanData([this])}this.parentNode&&
this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&c.cleanData(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||r;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||r;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j===
"string"){j=j.replace(Ga,Ia);var n=(Ha.exec(j)||["",""])[1].toLowerCase(),o=F[n]||F._default,m=o[0];i=b.createElement("div");for(i.innerHTML=o[1]+j+o[2];m--;)i=i.lastChild;if(!c.support.tbody){m=fb.test(j);n=n==="table"&&!m?i.firstChild&&i.firstChild.childNodes:o[1]==="<table>"&&!m?i.childNodes:[];for(o=n.length-1;o>=0;--o)c.nodeName(n[o],"tbody")&&!n[o].childNodes.length&&n[o].parentNode.removeChild(n[o])}!c.support.leadingWhitespace&&V.test(j)&&i.insertBefore(b.createTextNode(V.exec(j)[0]),i.firstChild);
j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()==="text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e},cleanData:function(a){for(var b=0,d;(d=a[b])!=null;b++){c.event.remove(d);c.removeData(d)}}});var hb=/z-?index|font-?weight|opacity|zoom|line-?height/i,
Ja=/alpha\([^)]*\)/,Ka=/opacity=([^)]*)/,ga=/float/i,ha=/-([a-z])/ig,ib=/([A-Z])/g,jb=/^-?\d+(?:px)?$/i,kb=/^-?\d/,lb={position:"absolute",visibility:"hidden",display:"block"},mb=["Left","Right"],nb=["Top","Bottom"],ob=r.defaultView&&r.defaultView.getComputedStyle,La=c.support.cssFloat?"cssFloat":"styleFloat",ia=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===v)return c.curCSS(d,f);if(typeof e==="number"&&!hb.test(f))e+="px";c.style(d,f,e)})};
c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return v;if((b==="width"||b==="height")&&parseFloat(d)<0)d=v;var f=a.style||a,e=d!==v;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ja.test(a)?a.replace(Ja,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ka.exec(f.filter)[1])/100+"":""}if(ga.test(b))b=La;b=b.replace(ha,ia);if(e)f[b]=d;return f[b]},css:function(a,
b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?mb:nb;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,lb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&
a.currentStyle){f=Ka.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ga.test(b))b=La;if(!d&&e&&e[b])f=e[b];else if(ob){if(ga.test(b))b="float";b=b.replace(ib,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ha,ia);f=a.currentStyle[b]||a.currentStyle[d];if(!jb.test(f)&&kb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left=
a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var pb=
J(),qb=/<script(.|\s)*?\/script>/gi,rb=/select|textarea/i,sb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ja=/\?/,tb=/(\?|&)_=.*?(&|$)/,ub=/^(\w+:)?\/\/([^\/?#]+)/,vb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=
c.param(b,c.ajaxSettings.traditional);f="POST"}var i=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(j,n){if(n==="success"||n==="notmodified")i.html(e?c("<div />").append(j.responseText.replace(qb,"")).find(e):j.responseText);d&&i.each(d,[j.responseText,n,j])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&
(this.checked||rb.test(this.nodeName)||sb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,
b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:z.XMLHttpRequest&&(z.location.protocol!=="file:"||!z.ActiveXObject)?function(){return new z.XMLHttpRequest}:
function(){try{return new z.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(o,n,j,w);e.global&&f("ajaxSuccess",[w,e])}function d(){e.complete&&e.complete.call(o,w,j);e.global&&f("ajaxComplete",[w,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}
function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,n,o=a&&a.context||e,m=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(m==="GET")N.test(e.url)||(e.url+=(ja.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||
N.test(e.url))){i=e.jsonpCallback||"jsonp"+pb++;if(e.data)e.data=(e.data+"").replace(N,"="+i+"$1");e.url=e.url.replace(N,"="+i+"$1");e.dataType="script";z[i]=z[i]||function(q){n=q;b();d();z[i]=v;try{delete z[i]}catch(p){}A&&A.removeChild(B)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&m==="GET"){var s=J(),x=e.url.replace(tb,"$1_="+s+"$2");e.url=x+(x===e.url?(ja.test(e.url)?"&":"?")+"_="+s:"")}if(e.data&&m==="GET")e.url+=(ja.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&
c.event.trigger("ajaxStart");s=(s=ub.exec(e.url))&&(s[1]&&s[1]!==location.protocol||s[2]!==location.host);if(e.dataType==="script"&&m==="GET"&&s){var A=r.getElementsByTagName("head")[0]||r.documentElement,B=r.createElement("script");B.src=e.url;if(e.scriptCharset)B.charset=e.scriptCharset;if(!i){var C=false;B.onload=B.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;b();d();B.onload=B.onreadystatechange=null;A&&B.parentNode&&
A.removeChild(B)}}}A.insertBefore(B,A.firstChild);return v}var E=false,w=e.xhr();if(w){e.username?w.open(m,e.url,e.async,e.username,e.password):w.open(m,e.url,e.async);try{if(e.data||a&&a.contentType)w.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&w.setRequestHeader("If-None-Match",c.etag[e.url])}s||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",
e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(fa){}if(e.beforeSend&&e.beforeSend.call(o,w,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");w.abort();return false}e.global&&f("ajaxSend",[w,e]);var g=w.onreadystatechange=function(q){if(!w||w.readyState===0||q==="abort"){E||d();E=true;if(w)w.onreadystatechange=c.noop}else if(!E&&w&&(w.readyState===4||q==="timeout")){E=true;w.onreadystatechange=c.noop;j=q==="timeout"?"timeout":!c.httpSuccess(w)?
"error":e.ifModified&&c.httpNotModified(w,e.url)?"notmodified":"success";var p;if(j==="success")try{n=c.httpData(w,e.dataType,e)}catch(u){j="parsererror";p=u}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,w,j,p);d();q==="timeout"&&w.abort();if(e.async)w=null}};try{var h=w.abort;w.abort=function(){w&&h.call(w);g("abort")}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){w&&!E&&g("timeout")},e.timeout);try{w.send(m==="POST"||m==="PUT"||m==="DELETE"?e.data:null)}catch(l){c.handleError(e,
w,null,l);d()}e.async||g();return w}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=
f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(j,n){if(c.isArray(n))c.each(n,
function(o,m){b?f(j,m):d(j+"["+(typeof m==="object"||c.isArray(m)?o:"")+"]",m)});else!b&&n!=null&&typeof n==="object"?c.each(n,function(o,m){d(j+"["+o+"]",m)}):f(j,n)}function f(j,n){n=c.isFunction(n)?n():n;e[e.length]=encodeURIComponent(j)+"="+encodeURIComponent(n)}var e=[];if(b===v)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var i in a)d(i,a[i]);return e.join("&").replace(vb,"+")}});var ka={},wb=/toggle|show|hide/,xb=/^([+-]=)?([\d+-.]+)(.*)$/,
W,ta=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(ka[d])f=ka[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();
ka[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&
c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,n=this.nodeType===1&&c(this).is(":hidden"),
o=this;for(j in a){var m=j.replace(ha,ia);if(j!==m){a[m]=a[j];delete a[j];j=m}if(a[j]==="hide"&&n||a[j]==="show"&&!n)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(s,x){var A=new c.fx(o,i,s);if(wb.test(x))A[x==="toggle"?n?"show":"hide":x](a);
else{var B=xb.exec(x),C=A.cur(true)||0;if(B){x=parseFloat(B[2]);var E=B[3]||"px";if(E!=="px"){o.style[s]=(x||1)+E;C=(x||1)/A.cur(true)*C;o.style[s]=C+E}if(B[1])x=(B[1]==="-="?-1:1)*x+C;A.custom(C,x,E)}else A.custom(C,x,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",
1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,
b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==
null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===
"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=
this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=
c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=
null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in r.documentElement?function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),
f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=
b,e=b.ownerDocument,i,j=e.documentElement,n=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var o=b.offsetTop,m=b.offsetLeft;(b=b.parentNode)&&b!==n&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;o-=b.scrollTop;m-=b.scrollLeft;if(b===d){o+=b.offsetTop;m+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){o+=parseFloat(i.borderTopWidth)||
0;m+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){o+=parseFloat(i.borderTopWidth)||0;m+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){o+=n.offsetTop;m+=n.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){o+=Math.max(j.scrollTop,n.scrollTop);m+=Math.max(j.scrollLeft,n.scrollLeft)}return{top:o,left:m}};c.offset={initialize:function(){var a=r.body,b=r.createElement("div"),
d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);
d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop},
bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left-
e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=
this.offsetParent||r.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==v)return this.each(function(){if(i=ua(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=ua(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}});
c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(i){var j=c(this);j[d](f.call(this,i,j[d]()))});return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||
e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===v?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});z.jQuery=z.$=c})(window);

View File

@ -0,0 +1,43 @@
/*
* FancyBox - jQuery Plugin
* Simple and fancy lightbox alternative
*
* Copyright (c) 20010 Janis Skarnelis
* Examples and documentation at: http://fancybox.net
*
* Version: 1.3.0 (02/02/2010)
* Requires: jQuery v1.3+
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
;(function(b){function H(){v.hide();r.onerror=r.onload=null;F&&F.abort();l.empty()}function Q(){b.fancybox('<p id="fancybox_error">The requested content cannot be loaded.<br />Please try again later.</p>',{scrolling:"no",padding:20,transitionIn:"none",transitionOut:"none"})}function B(){H();var a=q[s];e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));var d,f,o=a.title||b(a).title||e.title||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?
b(a).children("img:first"):b(a);if(o==""&&e.orig)o=e.orig.attr("alt");d=a.nodeName&&/^(?:javascript|#)/i.test(a.href)?e.href||null:e.href||a.href||null;if(e.type){f=e.type;if(!d)d=e.content}else if(e.content)f="html";else if(d)if(d.match(I))f="image";else if(d.match(T))f="swf";else if(b(a).hasClass("iframe"))f="iframe";else if(d.match(/#/)){a=d.substr(d.indexOf("#"));f=b(a).length>0?"inline":"ajax"}else f="ajax";else f="inline";e.type=f;e.href=d;e.title=o;if(e.autoDimensions&&e.type!=="iframe"&&e.type!==
"swf"){e.width="auto";e.height="auto"}if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=false;e.enableEscapeButton=false;e.showCloseButton=false}if(b.isFunction(e.onStart))if(e.onStart(q,s,e)===false){h=false;return}l.css("padding",t+e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(i.children())});switch(f){case "html":l.html(e.content);G();break;case "inline":b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",
function(){b(this).replaceWith(i.children())}).bind("fancybox-cancel",function(){b(this).replaceWith(l.children())});b(a).appendTo(l);G();break;case "image":h=false;b.fancybox.showActivity();r=new Image;r.onerror=function(){Q()};r.onload=function(){r.onerror=null;r.onload=null;U()};r.src=d;break;case "swf":var u="",w="";u+='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+d+'"></param>';b.each(e.swf,function(p,R){u+=
'<param name="'+p+'" value="'+R+'"></param>';w+=" "+p+'="'+R+'"'});u+='<embed src="'+d+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+w+"></embed></object>";l.html(u);G();break;case "ajax":a=d.split("#",2);f=e.ajax.data||{};if(a.length>1){d=a[0];typeof f=="string"?(f+="&selector="+a[1]):(f.selector=a[1])}h=false;b.fancybox.showActivity();F=b.ajax(b.extend(e.ajax,{url:d,data:f,error:Q,success:function(p){if(F.status==200){l.html(p);G()}}}));break;case "iframe":b('<iframe id="fancybox-frame" name="fancybox-frame'+
(new Date).getTime()+'" frameborder="0" hspace="0" scrolling="'+e.scrolling+'" src="'+e.href+'"></iframe>').appendTo(l);J();break}}function U(){h=true;e.width=r.width;e.height=r.height;b("<img />").attr({id:"fancybox-img",src:r.src,alt:e.title}).appendTo(l);J()}function G(){l.width(e.width);l.height(e.height);if(e.width=="auto")e.width=l.width();if(e.height=="auto")e.height=l.height();J()}function J(){v.hide();if(g.is(":visible")&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){b.event.trigger("fancybox-cancel");
h=false;return}j=q;n=s;c=e;i.get(0).scrollTop=0;i.get(0).scrollLeft=0;if(c.overlayShow){K&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});y.css({"background-color":c.overlayColor,opacity:c.overlayOpacity}).unbind().show()}m=V();W();if(g.is(":visible")){b(z.add(C).add(D)).hide();var a=g.position();k={top:a.top,left:a.left,width:g.width(),height:g.height()};
var d=k.width==m.width&&k.height==m.height;i.fadeOut(c.changeFade,function(){function f(){i.html(l.contents()).fadeIn(c.changeFade,L)}b.event.trigger("fancybox-change");i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).empty().css("overflow","hidden");A.prop=0;b(A).animate({prop:1},{duration:d?0:c.changeSpeed,easing:c.easingChange,step:M,complete:f})})}else{g.css("opacity",1);if(c.transitionIn=="elastic"){k=S();i.css({top:c.padding,
left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).html(l.contents());g.css(k).show();if(c.opacity)m.opacity=0;A.prop=0;b(A).animate({prop:1},{duration:c.speedIn,easing:c.easingIn,step:M,complete:L})}else{i.css({top:c.padding,left:c.padding,width:Math.max(m.width-c.padding*2,1),height:Math.max(m.height-c.padding*2-x,1)}).html(l.contents());g.css(m).fadeIn(c.transitionIn=="none"?0:c.speedIn,L)}}}function M(a){var d=Math.round(k.width+(m.width-k.width)*a),
f=Math.round(k.height+(m.height-k.height)*a),o=Math.round(k.top+(m.top-k.top)*a),u=Math.round(k.left+(m.left-k.left)*a);g.css({width:d+"px",height:f+"px",top:o+"px",left:u+"px"});d=Math.max(d-c.padding*2,0);f=Math.max(f-(c.padding*2+x*a),0);i.css({width:d+"px",height:f+"px"});if(typeof m.opacity!=="undefined")g.css("opacity",a<0.5?0.5:a)}function L(){i.css("overflow",overflow=c.scrolling=="auto"?c.type=="image"||c.type=="iframe"||c.type=="swf"?"hidden":"auto":c.scrolling=="yes"?"auto":"visible");
if(!b.support.opacity){i.get(0).style.removeAttribute("filter");g.get(0).style.removeAttribute("filter")}b("#fancybox-title").show();c.hideOnContentClick&&i.one("click",b.fancybox.close);c.hideOnOverlayClick&&y.one("click",b.fancybox.close);c.showCloseButton&&z.show();X();b(window).bind("resize.fb",b.fancybox.center);c.centerOnScroll?b(window).bind("scroll.fb",b.fancybox.center):b(window).unbind("scroll.fb");b.isFunction(c.onComplete)&&c.onComplete(j,n,c);h=false;Y()}function V(){var a=N(),d={},f=
c.margin,o=c.autoScale,u=(t+f)*2,w=(t+f)*2,p=c.padding*2;if(c.width.toString().indexOf("%")>-1){d.width=a[0]*parseFloat(c.width)/100-t*2;o=false}else d.width=c.width+p;if(c.height.toString().indexOf("%")>-1){d.height=a[1]*parseFloat(c.height)/100-t*2;o=false}else d.height=c.height+p;if(o&&(d.width>a[0]-u||d.height>a[1]-w))if(e.type=="image"||e.type=="swf"){u+=p;w+=p;o=Math.min(Math.min(a[0]-u,c.width)/c.width,Math.min(a[1]-w,c.height)/c.height);d.width=Math.round(o*(d.width-p))+p;d.height=Math.round(o*
(d.height-p))+p}else{d.width=Math.min(d.width,a[0]-u);d.height=Math.min(d.height,a[1]-w)}d.top=a[3]+(a[1]-(d.height+t*2))*0.5;d.left=a[2]+(a[0]-(d.width+t*2))*0.5;if(c.autoScale==false){d.top=Math.max(a[3]+f,d.top);d.left=Math.max(a[2]+f,d.left)}return d}function S(){var a=e.orig?b(e.orig):false,d={};if(a&&a.length){a=Z(a);d={width:a.width+c.padding*2,height:a.height+c.padding*2,top:a.top-c.padding-t,left:a.left-c.padding-t}}else{a=N();d={width:1,height:1,top:a[3]+a[1]*0.5,left:a[2]+a[0]*0.5}}return d}
function X(){b(document).unbind("keydown.fb").bind("keydown.fb",function(a){if(a.keyCode==27&&c.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if(a.keyCode==37){a.preventDefault();b.fancybox.prev()}else if(a.keyCode==39){a.preventDefault();b.fancybox.next()}});if(b.fn.mousewheel){g.unbind("mousewheel.fb");j.length>1&&g.bind("mousewheel.fb",function(a,d){a.preventDefault();h||d==0||(d>0?b.fancybox.prev():b.fancybox.next())})}if(c.showNavArrows){if(c.cyclic&&j.length>1||n!=0)C.show();
if(c.cyclic&&j.length>1||n!=j.length-1)D.show()}}function Y(){if(j.length-1>n){var a=j[n+1].href;if(typeof a!=="undefined"&&a.match(I)){var d=new Image;d.src=a}}if(n>0){a=j[n-1].href;if(typeof a!=="undefined"&&a.match(I)){d=new Image;d.src=a}}}function $(){if(v.is(":visible")){b("div",v).css("top",O*-40+"px");O=(O+1)%12}else clearInterval(P)}function N(){return[b(window).width(),b(window).height(),b(document).scrollLeft(),b(document).scrollTop()]}function Z(a){var d=a.offset();d.top+=parseFloat(a.css("paddingTop"))||
0;d.left+=parseFloat(a.css("paddingLeft"))||0;d.top+=parseFloat(a.css("border-top-width"))||0;d.left+=parseFloat(a.css("border-left-width"))||0;d.width=a.width();d.height=a.height();return d}function W(){b("#fancybox-title").remove();x=0;if(c.titleShow!=false){var a=c.title;a=b.isFunction(c.titleFormat)?c.titleFormat(a,j,n,c):aa(a);if(!(!a||a=="")){var d=m.width-c.padding*2;b('<div id="fancybox-title" class="'+("fancybox-title-"+c.titlePosition)+'" />').css({width:d,paddingLeft:c.padding,paddingRight:c.padding}).html(a).appendTo("body");
switch(c.titlePosition){case "inside":x=b("#fancybox-title").outerHeight(true)-c.padding;m.height+=x;break;case "over":b("#fancybox-title").css("bottom",c.padding);break;default:b("#fancybox-title").css("bottom",b("#fancybox-title").outerHeight(true)*-1);break}b("#fancybox-title").appendTo(E).hide();K&&b("#fancybox-title span").fixPNG()}}}function aa(a){if(a&&a.length)switch(c.titlePosition){case "inside":return a;case "over":return'<span id="fancybox-title-over">'+a+"</span>";default:return'<span id="fancybox-title-wrap"><span id="fancybox-title-left"></span><span id="fancybox-title-main">'+
a+'</span><span id="fancybox-title-right"></span></span>'}return false}function ba(){if(!b("#fancybox-wrap").length){b("body").append(l=b('<div id="fancybox-tmp"></div>'),v=b('<div id="fancybox-loading"><div></div></div>'),y=b('<div id="fancybox-overlay"></div>'),g=b('<div id="fancybox-wrap"></div>'));E=b('<div id="fancybox-outer"></div>').append('<div class="fancy-bg" id="fancy-bg-n"></div><div class="fancy-bg" id="fancy-bg-ne"></div><div class="fancy-bg" id="fancy-bg-e"></div><div class="fancy-bg" id="fancy-bg-se"></div><div class="fancy-bg" id="fancy-bg-s"></div><div class="fancy-bg" id="fancy-bg-sw"></div><div class="fancy-bg" id="fancy-bg-w"></div><div class="fancy-bg" id="fancy-bg-nw"></div>').appendTo(g);
E.append(i=b('<div id="fancybox-inner"></div>'),z=b('<a id="fancybox-close"></a>'),C=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),D=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));z.click(b.fancybox.close);v.click(b.fancybox.cancel);C.click(function(a){a.preventDefault();b.fancybox.prev()});D.click(function(a){a.preventDefault();b.fancybox.next()});b.support.opacity||E.find(".fancy-bg").fixPNG();
if(K){b(z.add(".fancy-ico").add("div",v)).fixPNG();y.get(0).style.setExpression("height","document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'");v.get(0).style.setExpression("top","(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'");E.prepend('<iframe id="fancybox-hide-sel-frame" src="javascript:\'\';" scrolling="no" frameborder="0" ></iframe>')}}}
var l,v,y,g,E,i,z,C,D,s=0,e={},q=[],n=0,c={},j=[],F=null,r=new Image,I=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,T=/[^\.]\.(swf)\s*$/i,P,O=1,k,m,h=false,t=20,A=b.extend(b("<div/>")[0],{prop:0}),x=0,K=!b.support.opacity&&!window.XMLHttpRequest;b.fn.fixPNG=function(){return this.each(function(){var a=b(this).css("backgroundImage");if(a.match(/^url\(["']?(.*\.png)["']?\)$/i)){a=RegExp.$1;b(this).css({backgroundImage:"none",filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod="+
(b(this).css("backgroundRepeat")=="no-repeat"?"crop":"scale")+", src='"+a+"')"}).each(function(){var d=b(this).css("position");d!="absolute"&&d!="relative"&&b(this).css("position","relative")}).css("zoom",1)}})};b.fn.fancybox=function(a){b(this).data("fancybox",b.extend({},a));b(this).unbind("click.fb").bind("click.fb",function(d){d.preventDefault();if(!h){h=true;b(this).blur();q=[];s=0;d=b(this).attr("rel")||"";if(!d||d==""||d==="nofollow")q.push(this);else{q=b("a[rel="+d+"], area[rel="+d+"]");s=
q.index(this)}B();return false}});return this};b.fancybox=function(a,d){if(!h){h=true;q=[];s=0;if(b.isArray(a)){for(var f=0,o=a.length;f<o;f++)if(typeof a[f]=="object")b(a[f]).data("fancybox",b.extend({},d,a[f]));else a[f]=b({}).data("fancybox",b.extend({content:a[f]},d));q=jQuery.merge(q,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},d,a));else a=b({}).data("fancybox",b.extend({content:a},d));q.push(a)}B()}};b.fancybox.showActivity=function(){clearInterval(P);v.show();P=setInterval($,
66)};b.fancybox.hideActivity=function(){v.hide()};b.fancybox.next=function(){return b.fancybox.pos(n+1)};b.fancybox.prev=function(){return b.fancybox.pos(n-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);if(a>-1&&j.length>a){s=a;B()}if(c.cyclic&&j.length>1&&a<0){s=j.length-1;B()}if(c.cyclic&&j.length>1&&a>=j.length){s=0;B()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");H();e&&b.isFunction(e.onCancel)&&e.onCancel(q,s,e);h=false}};b.fancybox.close=function(){function a(){y.fadeOut("fast");
g.hide();b.event.trigger("fancybox-cleanup");i.empty();b.isFunction(c.onClosed)&&c.onClosed(j,n,c);j=e=[];n=s=0;c=e={};h=false}if(!(h||g.is(":hidden"))){h=true;if(c&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){h=false;return}H();b(z.add(C).add(D)).hide();b("#fancybox-title").remove();g.add(i).add(y).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");i.css("overflow","hidden");if(c.transitionOut=="elastic"){k=S();var d=g.position();m={top:d.top,left:d.left,
width:g.width(),height:g.height()};if(c.opacity)m.opacity=1;A.prop=1;b(A).animate({prop:0},{duration:c.speedOut,easing:c.easingOut,step:M,complete:a})}else g.fadeOut(c.transitionOut=="none"?0:c.speedOut,a)}};b.fancybox.resize=function(){if(!(h||g.is(":hidden"))){h=true;var a=i.wrapInner("<div style='overflow:auto'></div>").children(),d=a.height();g.css({height:d+c.padding*2+x});i.css({height:d});a.replaceWith(a.children());b.fancybox.center()}};b.fancybox.center=function(){h=true;var a=N(),d=c.margin,
f={};f.top=a[3]+(a[1]-(g.height()-x+t*2))*0.5;f.left=a[2]+(a[0]-(g.width()+t*2))*0.5;f.top=Math.max(a[3]+d,f.top);f.left=Math.max(a[2]+d,f.left);g.css(f);h=false};b.fn.fancybox.defaults={padding:10,margin:20,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.3,overlayColor:"#666",titleShow:true,titlePosition:"outside",
titleFormat:null,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,onStart:null,onCancel:null,onComplete:null,onCleanup:null,onClosed:null};b(document).ready(function(){ba()})})(jQuery);

View File

@ -0,0 +1,333 @@
/*
* FancyBox - jQuery Plugin
* Simple and fancy lightbox alternative
*
* Copyright (c) 20010 Janis Skarnelis
* Examples and documentation at: http://fancybox.net
*
* Version: 1.3.0 (02/02/2010)
* Requires: jQuery v1.3+
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
#fancybox-loading {
position: fixed;
top: 50%;
left: 50%;
height: 40px;
width: 40px;
margin-top: -20px;
margin-left: -20px;
cursor: pointer;
overflow: hidden;
background: transparent;
z-index: 1104;
display: none;
}
* html #fancybox-loading { /* IE6 */
position: absolute;
margin-top: 0;
}
#fancybox-loading div {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 480px;
background: transparent url("../../images/admin/fancybox/fancy_loading.png") no-repeat;
}
#fancybox-overlay {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: #000;
z-index: 1100;
display: none;
}
* html #fancybox-overlay { /* IE6 */
position: absolute;
width: 100%;
}
#fancybox-tmp {
padding: 0;
margin: 0;
border: 0;
overflow: auto;
display: none;
}
#fancybox-wrap {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 20px;
z-index: 1101;
display: none;
}
#fancybox-outer {
position: relative;
width: 100%;
height: 100%;
background: #FFF;
}
#fancybox-inner {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 1px;
padding: 0;
margin: 0;
outline: none;
overflow: hidden;
}
#fancybox-hide-sel-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
}
#fancybox-close {
position: absolute;
top: -15px;
right: -15px;
width: 32px;
height: 32px;
background: url("../../images/admin/fancybox/fancy_close.png") top left no-repeat;
cursor: pointer;
z-index: 1103;
display: none;
}
#fancybox_error {
color: #444;
font: normal 12px/20px Arial;
}
#fancybox-content {
height: auto;
width: auto;
padding: 0;
margin: 0;
}
#fancybox-img {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: none;
outline: none;
line-height: 0;
vertical-align: top;
-ms-interpolation-mode: bicubic;
}
#fancybox-frame {
position: relative;
width: 100%;
height: 100%;
border: none;
display: block;
}
#fancybox-title {
position: absolute;
bottom: 0;
left: 0;
font-family: Arial;
font-size: 12px;
z-index: 1102;
}
.fancybox-title-inside {
padding: 10px 0;
text-align: center;
color: #333;
}
.fancybox-title-outside {
padding-top: 5px;
color: #FFF;
text-align: center;
font-weight: bold;
}
.fancybox-title-over {
color: #FFF;
text-align: left;
}
#fancybox-title-over {
padding: 10px;
background: url("../../images/admin/fancybox/fancy_title_over.png");
display: block;
}
#fancybox-title-wrap {
display: inline-block;
}
#fancybox-title-wrap span {
height: 32px;
float: left;
}
#fancybox-title-left {
padding-left: 15px;
background: transparent url("../../images/admin/fancybox/fancy_title_left.png") repeat-x;
}
#fancybox-title-main {
font-weight: bold;
line-height: 29px;
background: transparent url("../../images/admin/fancybox/fancy_title_main.png") repeat-x;
color: #FFF;
}
#fancybox-title-right {
padding-left: 15px;
background: transparent url("../../images/admin/fancybox/fancy_title_right.png") repeat-x;
}
#fancybox-left, #fancybox-right {
position: absolute;
bottom: 0px;
height: 100%;
width: 35%;
cursor: pointer;
outline: none;
background-image: url("../../images/admin/fancybox/blank.gif");
z-index: 1102;
display: none;
}
#fancybox-left {
left: 0px;
}
#fancybox-right {
right: 0px;
}
#fancybox-left-ico, #fancybox-right-ico {
position: absolute;
top: 50%;
left: -9999px;
width: 30px;
height: 30px;
margin-top: -15px;
cursor: pointer;
z-index: 1102;
display: block;
}
#fancybox-left-ico {
background: transparent url("../../images/admin/fancybox/fancy_nav_left.png") no-repeat;
}
#fancybox-right-ico {
background: transparent url("../../images/admin/fancybox/fancy_nav_right.png") no-repeat;
}
#fancybox-left:hover, #fancybox-right:hover {
visibility: visible; /* IE6 */
}
#fancybox-left:hover span {
left: 20px;
}
#fancybox-right:hover span {
left: auto;
right: 20px;
}
div.fancy-bg {
position: absolute;
padding: 0;
margin: 0;
border: 0;
z-index: 1001;
}
div#fancy-bg-n {
top: -20px;
left: 0;
width: 100%;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_n.png") repeat-x;
}
div#fancy-bg-ne {
top: -20px;
right: -20px;
width: 20px;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_ne.png") no-repeat;
}
div#fancy-bg-e {
top: 0;
right: -20px;
height: 100%;
width: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_e.png") repeat-y;
}
div#fancy-bg-se {
bottom: -20px;
right: -20px;
width: 20px;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_se.png") no-repeat;
}
div#fancy-bg-s {
bottom: -20px;
left: 0;
width: 100%;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_s.png") repeat-x;
}
div#fancy-bg-sw {
bottom: -20px;
left: -20px;
width: 20px;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_sw.png") no-repeat;
}
div#fancy-bg-w {
top: 0;
left: -20px;
height: 100%;
width: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_w.png") repeat-y;
}
div#fancy-bg-nw {
top: -20px;
left: -20px;
width: 20px;
height: 20px;
background: transparent url("../../images/admin/fancybox/fancy_shadow_nw.png") no-repeat;
}

View File

@ -0,0 +1,68 @@
/* @group Structure Module */
body,html {margin:0;padding:0;}
/* @end */
/* @group Text Module */
abbr,acronym,address,blockquote,br,cite,code,dfn,div,em,h1,h2,h3,h4,h5,h6,kbd,p,pre,q,samp,span,strong,var{font-style:normal;font-weight:normal;text-decoration:none;}
blockquote,code,div,h1,h2,h3,h4,h5,h6,p,span,pre,hr{margin:0;padding:0;}
h1,h2,h3,h4,h5,h6{font-size:100%;}
b,i,em,strong,del,ins,u{font-weight:normal;font-style:normal;text-decoration:none;}
/* @end */
/* @group Hypertext Module */
a{text-decoration:none;}
/* @end */
/* @group List Module */
dl,dt,dd,ol,ul,li{margin:0;padding:0;list-style:none;}
dl,dt,dd,ol,ul,li{padding:0;margin:0;}
/* @end */
/* @group Forms Module */
button,fieldset,form,input,label,legend,select,optgroup,option,textarea{margin:0;padding:0;}
fieldset{border:0;}
/* @end */
/* @group Basic Table Module */
caption,table,td,th,tr{margin:0;padding:0;font-weight:normal;text-align:left;}
table{border-collapse:collapse;border-spacing:0;}
/* @end */
/* @group Image Module */
img{border:0;}
/* @end */
/* @group Object Module */
object,param{}
/* @end */
/* @group Presentation Module */
b,big,hr,i,small,sub,sup,tt{font-size:100%;}
q:before,q:after{content:'';}
sup {vertical-align:text-top;}
sub {vertical-align:text-bottom;}
/* @end */
/* @group Scripting Module */
noscript{}
/* @end */

View File

@ -0,0 +1,369 @@
/* @group Defaults */
html { background: #000; height: 100%; margin-bottom: 1px; }
body { color: #000; font-family: "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 75%; }
label { display: block; font-weight: bold; margin-bottom: 5px; margin-top: 0px; }
strong { font-weight: bold; }
em { font-style: italic; }
dl { margin: 14px 0 20px 0; }
dt { font-weight: bold; margin: 0 0 5px 0; }
dd { font-size: 18px; margin: 0 0 15px 0; }
/* @end */
/* @group Links */
a,
a:visited,
a:link { color: #000; font-weight: normal; text-decoration: none; }
a:hover { color: #333; text-decoration: underline; }
a.on { color: #333; font-weight: bold; text-decoration: underline; }
/* @end */
/* @group Wrappers */
#header_wrapper {
background: #000;
margin: 0 auto;
padding: 0 10px;
width: 940px;
}
#wrapper { background: #FFF; }
#content_wrapper {
background: #FFF;
min-height: 400px;
margin: 0 auto;
padding: 0 10px;
width: 940px;
}
/* @end */
/* @group Header */
#header {
background: #000;
color: #FFF;
margin: 0 auto;
padding: 1em 0;
}
#header h1 {
display: block;
float: left;
font-size: 2em;
margin-right: 0.25em;
}
#header a { color: #FFF; }
#header .left { float: left; }
#header .right { float: right; margin-top: 1em; }
#header .left ul { display: block; float: left; margin-top: 1em; }
#header .left li, #header .right li { display: inline; padding-left: 0.5em; }
/* @end */
/* @group Content */
#content { float: left; padding: 1.5em 0; width: 700px; }
#content h2 { font-size: 1.5em; font-weight: bold; margin: 0 0 0.5em 0; }
#content h2 a { font-weight: bold; }
#content h2 small { font-size: 0.75em; }
#content h2 small a { color: #666; }
#content h3 { font-size: 1.25em; font-weight: bold; margin: 1em 0; }
#content h4 { margin: 1em 0; }
#content ol { margin: 1em 2em; }
#content ul { margin: 0 1.5em; }
#content li { list-style: square; line-height: 20px; }
#content ul li { list-style: square; }
#content p { margin: 0 0 1em 0; }
#content p a { text-decoration: underline; }
#content p a:hover { color: #408BB6; }
#content table.typus { background: #000; margin: 1em 0; }
#content h2+table.typus { margin: 0; }
#content pre {
background: #000;
color: #FFF;
font-size: 1.25em;
margin: 1em 0;
overflow: auto;
padding: 1em;
}
#content blockquote {
border-left: 1px solid #999;
font-size: 1.25em;
font-family: georgia;
margin: 1em;
padding: 0 1em;
}
/* @end */
/* @group Sidebar */
#sidebar {
float: left;
margin-left: 20px;
padding: 1.5em 0;
width: 220px;
}
#sidebar h2 { font-size: 1.5em; font-weight: bold; }
#sidebar h3 { margin: 1em 0; }
#sidebar p { margin: 1em 0; }
#sidebar p a { text-decoration: underline; }
#sidebar label { font-size: 15px; }
#sidebar form { margin-bottom: 1.25em; }
#sidebar ul { margin: 1em 0; }
#sidebar code { color: green; font-size: 1.25em; }
#sidebar small { font-size: 0.85em; }
/* @end */
/* @group Footer */
#footer_wrapper { background: #000; }
#footer { background: #000; margin: 0 auto; width: 940px; }
#footer .left { float: left; }
#footer .right { float: right; }
#footer a { color: #FFF; font-weight: normal; text-decoration: underline; }
#footer a:hover { color: #408BB6; }
#footer p {
color: #FFF;
font-size: 0.9em;
line-height: 18px;
padding: 1em 0;
}
/* @end */
/* @group Fieldsets */
fieldset { margin: 0; padding: 0; }
fieldset ol { margin: 0!important; }
fieldset ol li { list-style: none!important; margin: 1em 0!important; }
fieldset small { font-size: 0.9em; font-weight: normal; }
fieldset.inputs { }
fieldset.inputs input[type='text'],
fieldset.inputs input[type='password'] {
border: 1px solid #999;
font-size: 20px;
padding: 5px;
width: 691px;
}
fieldset.inputs input[type='text']:focus,
fieldset.inputs input[type='password']:focus, {
background: #FFFCE1;
}
fieldset.inputs textarea {
border: 1px solid #999;
font-family: "Courier";
font-size: 14px;
padding: 3px;
width: 691px;
}
fieldset.inputs select { border: 1px solid #999; font-size: 1.20em; }
fieldset.inputs textarea:focus { background: #FFFCE1; }
fieldset.inputs label.inline_label { display: inline; }
fieldset.buttons { }
/* @end */
/* @group Content Tables */
#content table.typus { width: 100%; }
#content table.typus small { font-size: 0.8em; }
#content table.typus th { color: #FFF; font-weight: normal; padding: 4px; }
#content table.typus th a { color: #FFF!important; }
#content table.typus td.right { text-align: right; }
#content table.typus tr.even { background: #FFF!important; }
#content table.typus tr.even:hover,
#content table.typus tr.odd:hover { background: #000!important; color: #FFF; }
#content table.typus tr.even:hover a,
#content table.typus tr.odd:hover a { color: #FFF!important; }
#content table.typus tr.odd { background: #F5F5F5; }
#content table.typus span.inactive { color: #888; }
#content table.typus td { border: none; font-weight: normal; padding: 3px 4px; vertical-align: top; }
/* @end */
/* @group Rails Errors */
.fieldWithErrors input { background: #FBE3E4; border: 1px solid #8A1F11!important; }
.errorExplanation {
background: #FBE3E4;
border: 2px solid #FBC2C4;
color: #8a1f11;
padding: 0 10px;
}
.errorExplanation h3 { display: none; }
.errorExplanation p { font-weight: bold; margin: 15px 0 10px 0!important; padding: 0 5px; }
.errorExplanation ul { margin: 0 0 10px 25px!important; }
.errorExplanation ul li { list-style: square!important; margin: 0!important; }
/* @end */
/* @group Search Box */
input#search { border: 1px solid #999; font-size: 1.2em; padding: 3px; }
/* @end */
/* @group Date search boxes */
input.date_input { border: 1px solid #999; margin-bottom: 1em;}
/* @end */
/* @group Login Page Dialog */
#bottom_dialog {
color: #FFF;
font-size: 0.9em;
line-height: 18px;
margin: 0 auto;
padding: 0 1.5em;
text-align: center;
width: 420px;
}
#bottom_dialog a { color: #FFF; font-weight: bold; }
#dialog {
background: #FFF;
border: 0.5em solid #408BB6;
margin: 5em auto 1em auto;
padding: 0 1.5em;
width: 35em;
}
#dialog h1 { font-size: 2em; font-weight: bold; margin: 0.5em 0; }
#dialog h1 a { font-weight: bold; }
#dialog h1 a:hover { color: #000; text-decoration: underline; }
#dialog li { margin: 1em 0; }
#dialog li a { display: inline; font-size: 11px; margin: 0.5em; }
#dialog input.text {
border: 1px solid #999;
font-size: 2em;
padding: 0.25em;
width: 16.75em;
}
#dialog input.button { margin: 0.5em 0; }
#dialog .errorExplanation ul { margin: 10px 0 10px 0!important; }
#dialog .errorExplanation li { font-weight: bold; list-style: none!important; }
/* @end */
/* @group Pagination */
.pagination {
border-bottom: 1px solid #F5F5F5;
border-top: 1px solid #F5F5F5;
margin: 1.5em auto 0 auto;
padding: 1em;
text-align: center;
}
.pagination a {
color: #333;
margin: 2px;
padding: 2px 3px;
text-decoration: none;
}
.pagination a:hover,
.pagination a:active { background: #000; color: #FFF; }
.pagination span.current {
background-color: #408BB6;
color: #FFF;
font-weight: bold;
margin: 2px;
padding: 2px 3px;
}
.pagination span.disabled { color: #DDD; margin: 2px; padding: 2px 3px; }
/* @end */
/* @group Success, notice and error boxes */
.error,
.notice,
.success { border: 1px solid #CCC; font-weight: bold; margin: 0 0 1em 0; }
.error p,
.notice p,
.success p { font-weight: bold; margin: 0!important; padding: 1em; }
.error { background: #FBE3E4; border-color: #FBC2C4; color: #8A1F11; }
.error a { color: #8A1F11; }
.notice { background: #FFF6BF; border-color: #FFD324; color: #514721; }
.notice a { color: #514721; }
.success { background: #E6EFC2; border-color: #C6D880; color: #264409; }
.success a { color: #264409; }
/* @end */
/* @group Microformats */
.box { border: 1px solid #D3D3D3; margin: 1em 0; padding: 10px; }
.box:hover { border: 1px solid #999; }
.box .preview { float: left; margin: 0 15px 0 0; width: 200px; }
.box .content h2 { font-size: 16px!important; margin: 0 0 10px 0!important; }
.box .content h3 { font-size: 14px!important; margin: 0 0 10px 0!important; }
.box .content blockquote p { font-size: 16px!important; }
.box .content p { font-size: 12px!important; margin: 0 0 10px 0!important; }
.box .content ul { margin: 0 0 10px 20px!important; }
.box .metadata { float: left; width: 350px; }
.box .metadata ul { margin: 0!important; padding: 0!important; }
.box .metadata ul li { list-style: none!important; }
.box .actions ul { margin: 0!important; }
.box .actions ul li { display: inline; list-style: none!important; }
.box .actions {
float: right;
position: relative;
top: 0;
right: 0;
text-align: right;
}
/* @end */
/* @group Clean Me */
.box_relationships { border-top: 1px dotted #D3D3D3; padding: 1.5em 0; }
/* @end */
/* @group Hacks */
.clear { clear: both; }
.tip { color: #666; font-size: 10px; margin: -10px 0 10px 0!important; }
/* @end */
/* @group Sprite */
.sprite { background: url(../../images/admin/ui-icons.png) no-repeat; text-indent: -10000px; }
.trash { background-position: -177px -97px; height: 15px; width: 15px; }
.unrelate { background-position: -145px -129px; height: 15px; width: 15px; }
/* @end */

View File

@ -11,7 +11,7 @@ a {
padding-top: 20px; padding-top: 20px;
} }
#wrapper { #wrapper {
background: inherit; background: black;
} }
#header { #header {
position: relative; position: relative;
@ -47,22 +47,58 @@ a {
color: white; color: white;
text-decoration: none; text-decoration: none;
} }
.category a .arrow {
position: absolute;
bottom: 10px;
left: 20px;
}
.category a:focus, .photo a:focus { .category a:focus, .photo a:focus {
background: rgba(255,255,255,0.1); background: rgba(255,255,255,0.1);
} }
.category a:hover, .photo a:hover { .category a:hover, .photo a:hover {
background: rgba(255,255,255,0.2); background: rgba(255,255,255,0.2);
} }
.blank-category { .blank-category, .blank-photo {
background: #222; background: #222;
outline: 1px dashed #444; outline: 1px dashed #444;
} }
.category h3 { .category h3 {
position: absolute; position: absolute;
top: 10px; top: 16px;
right: 20px; right: 0;
text-align: right;
margin: 0 20px;
font-weight: normal; font-weight: normal;
font-size: 1.1em; font-size: 1.1em;
line-height: 1em;
} }
img { img {
} }
.page-links {
background: #c03232;
}
.prev-link, .next-link {
color: white;
position: relative;
display: block;
width: 70px !important;
}
.prev-link {
float: left;
}
.next-link {
float: right;
}
.prev-link div, .next-link div {
position: absolute;
bottom: 10px;
}
.prev-link div {
left: 20px;
}
.next-link div {
right: 20px;
}
.prev-link:hover, .next-link:hover {
background: rgba(255,255,255,0.2);
}

View File

@ -0,0 +1,11 @@
require 'test_helper'
# ControllerTest generated by Typus, use it to test the extended admin functionality.
class Admin::CategoriesControllerTest < ActionController::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

View File

@ -0,0 +1,11 @@
require 'test_helper'
# ControllerTest generated by Typus, use it to test the extended admin functionality.
class Admin::PhotosControllerTest < ActionController::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

View File

@ -0,0 +1,11 @@
require 'test_helper'
# ControllerTest generated by Typus, use it to test the extended admin functionality.
class Admin::TypusUsersControllerTest < ActionController::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

68
vendor/plugins/typus/CHANGES vendored Normal file
View File

@ -0,0 +1,68 @@
= 0.9.40 / 2010-02-??
[X] Refactor all forms to be able to use formtastic.
[X] Cleanup translation files.
[X] Removed FIXME tests.
[X] Pass attribute as symbol.
[X] Simplify configuration files.
[X] Added '/' to admin_edit_typus_user_path because was not linking to
the right path on the namespaced models.
[X] Updated generator defaults.
[X] Write CSV file to disk and then send_file.
[X] Replaced CSV separator. Now uses ';' instead of ','.
[X] Do not show selector on habtm if there are more than 500 records.
[X] Paginate habtm relationships. Was implemented in the has_many.
[X] Fixed unrelate action. Was not working properly when not using
Rails default table names.
[X] Do not humanize fields on the csv generator. We want to keep the
real field name.
[X] Recover password functionality now only needs the email to be defined.
[X] Added json export format.
[X] Added default route with conditions. (Ben Scofield)
[X] We should be able to set preferences and store them on the database.
[X] Fixed stylesheet and search to be able to use `relative_url_root`.
[X] Cleanup `display_link_to_previous` helper.
[X] Cleanup `build_typus_list` helper.
[X] Fix back_to when using `relative_url_root`.
[X] Remove toggle option. We always enable it so it's a good default.
[X] When displaying an item with multiple attachments fancybox preview
was not working properly because there where multiple items with the
same id.
[X] Move partial helpers to `app/views/admin/helpers`.
[X] Do not set ActionMailer::Base.default_url_options[:host] on the
controller.
[X] Cleanup `applications` & `resources`.
[-] Allow users to download the demo hosted at heroku.com
[-] Move html code from helpers to partials.
[ ] Add API authentication.
[ ] Fix problems on routes.rb when using namespaced models.
[ ] Show the right content on the selectors when listing records on tables.
[ ] Update fancybox to the latest version. Fix paths to make it work when
`relative_url_root` is active. (and make a donation)
[ ] Add has_many through relationships.
[ ] Test default typus forms and remove old tests.
[ ] Fixed and tested read-only fields.
[ ] Fixed and tested auto-generated fields.
[ ] Fixed and tested trees.
[ ] Fix all fixme tests.
[ ] Test _form.html.erb can be overwrited by model.
[ ] Show auto_generated, read_only on string fields. (_string.html.erb)
[ ] Pass options hash to form fields.
[ ] Fix css to display correctly "select" fields in relationships.
[ ] Make tests work again.
[ ] Remove Typus "blue" color and use something more neutral.
[ ] Ajax pagination. (?)
[ ] Generate views for custom actions on the controllers/models. This should
verify the view doesn't exist and create it.
[ ] Support for XSS.
[X] Replace "render :partial => 'template', :locals => {}", by
"render 'template', :local => 'local'".
[X] Add support for custom typus_user on the generator.
[ ] Shorten sidebar selectors. (AFS)
[ ] Add test for `typus_table_selector`.
[X] Clicking on a filter removes is. (Gaston Kleiman)
[X] Possibility to filter by date ranges. (Gaston Kleiman)
[ ] Use `inherit_views` code to `inherit_views`.
[ ] Forever loop when schema has not been migrated.
[ ] Pagination doesn't work properly when having multiple paginators on edit page
[ ] Add support for 'has_one' relationships.

20
vendor/plugins/typus/MIT-LICENSE vendored Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2007-2010 Francesc Esplugas Marti
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
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 HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

49
vendor/plugins/typus/README.rdoc vendored Normal file
View File

@ -0,0 +1,49 @@
= Typus: Admin interface for Rails applications
Typus is designed for a single activity:
Trusted users editing structured content.
Typus doesn't try to be all the things to all the people but it's extensible
enough to match lots of use cases.
== Key Features
- Authentication by session or http.
- Access control by users and roles (only on session authentication).
- Show, search, edit and create data on a clean interface.
- Internationalized interface with xtensible and overwritable templates.
- Boolean filtering.
- Supports ActiveRecord.
- Supports Rails 3 and is Ruby 1.9 compatible.
- Tested with SQLite, MySQL, and PostgreSQL.
- MIT License.
== Links
- {Project page}[http://labs.intraducibles.com/projects/typus]
- {Documentation}[http://typus.intraducibles.com/]
- {Plugin source code}[http://github.com/fesplugas/typus]
- {Mailing list}[http://groups.google.com/group/typus]
- {Bug reports}[http://github.com/fesplugas/typus/issues]
- {Gems}[http://gemcutter.org/gems/typus]
- {Contributors}[http://github.com/fesplugas/typus/contributors]
== Installing
Install from GitHub the latest version which it's compatible with
<tt>Rails 2.3.8</tt>.
$ script/plugin install git://github.com/fesplugas/typus.git -r 2-3-stable
Once `typus` is installed, run the generator to create required files and
migrate your database.
$ script/generate typus
$ rake db:migrate
Start the application server and go to {http://0.0.0.0:3000/admin}[http://0.0.0.0:3000/admin].
== License
Copyright &copy; 2007-2010 Francesc Esplugas, released under the MIT license.

57
vendor/plugins/typus/Rakefile vendored Normal file
View File

@ -0,0 +1,57 @@
require 'rubygems'
require 'rake/testtask'
require 'rake/rdoctask'
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
require "typus/version"
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the typus plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Build the gem.'
task :build do
system "gem build typus.gemspec"
end
desc 'Build and release the gem.'
task :release => :build do
version = Typus::VERSION
system "git tag v#{version}"
system "git push origin v#{version}"
system "gem push pkg/typus-#{version}.gem"
system "git clean -fd"
system "gem push typus-#{version}"
end
desc 'Generate specdoc-style documentation from tests'
task :specs do
puts 'Started'
timer, count = Time.now, 0
File.open('SPECDOC', 'w') do |file|
Dir.glob('test/**/*_test.rb').each do |test|
test =~ /.*\/([^\/].*)_test.rb$/
file.puts "#{$1.gsub('_', ' ').capitalize} should:" if $1
File.read(test).map { |line| /test_(.*)$/.match line }.compact.each do |spec|
file.puts "- #{spec[1].gsub('_', ' ')}"
sleep 0.001; print '.'; $stdout.flush; count += 1
end
file.puts
end
end
puts <<-MSG
\nFinished in #{Time.now - timer} seconds.
#{count} specifications documented.
MSG
end

View File

@ -0,0 +1,401 @@
class Admin::MasterController < ApplicationController
skip_filter filter_chain
unloadable
inherit_views 'admin/resources'
layout 'admin'
include Typus::Authentication
include Typus::Format
include Typus::Preferences
include Typus::Reloader
filter_parameter_logging :password
before_filter :reload_config_and_roles
before_filter :require_login
before_filter :set_typus_preferences
before_filter :set_resource
before_filter :find_item,
:only => [ :show, :edit, :update, :destroy, :toggle, :position, :relate, :unrelate, :detach ]
before_filter :check_ownership_of_item,
:only => [ :edit, :update, :destroy, :toggle, :position, :relate, :unrelate ]
before_filter :check_if_user_can_perform_action_on_user,
:only => [ :edit, :update, :toggle, :destroy ]
before_filter :check_if_user_can_perform_action_on_resource
before_filter :set_order,
:only => [ :index ]
before_filter :set_fields,
:only => [ :index, :new, :edit, :create, :update, :show ]
##
# This is the main index of the model. With filters, conditions
# and more.
#
# By default application can respond_to html, csv and xml, but you
# can add your formats.
#
def index
@conditions, @joins = @resource[:class].build_conditions(params)
check_ownership_of_items if @resource[:class].typus_options_for(:only_user_items)
respond_to do |format|
format.html { generate_html }
@resource[:class].typus_export_formats.each do |f|
format.send(f) { send("generate_#{f}") }
end
end
rescue Exception => error
error_handler(error)
end
def new
check_ownership_of_referal_item
item_params = params.dup
%w( controller action resource resource_id back_to selected ).each do |param|
item_params.delete(param)
end
@item = @resource[:class].new(item_params.symbolize_keys)
end
##
# Create new items. There's an special case when we create an
# item from another item. In this case, after the item is
# created we also create the relationship between these items.
#
def create
@item = @resource[:class].new(params[@object_name])
if @resource[:class].typus_user_id?
@item.attributes = { Typus.user_fk => @current_user.id }
end
if @item.valid?
create_with_back_to and return if params[:back_to]
@item.save
flash[:success] = _("%{model} successfully created.",
:model => @resource[:human_name])
if @resource[:class].typus_options_for(:index_after_save)
redirect_to :action => 'index'
else
redirect_to :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id
end
else
render :action => 'new'
end
end
def edit
end
def show
check_ownership_of_item and return if @resource[:class].typus_options_for(:only_user_items)
respond_to do |format|
format.html
format.xml do
fields = @resource[:class].typus_fields_for(:xml).collect { |i| i.first }
render :xml => @item.to_xml(:only => fields)
end
end
end
def update
if @item.update_attributes(params[@object_name])
if @resource[:class].typus_user_id? && @current_user.is_not_root?
@item.update_attributes Typus.user_fk => @current_user.id
end
path = if @resource[:class].typus_options_for(:index_after_save)
params[:back_to] ? "#{params[:back_to]}##{@resource[:self]}" : { :action => 'index' }
else
{ :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id, :back_to => params[:back_to] }
end
# Reload @current_user when updating to see flash message in the
# correct locale.
if @resource[:class].eql?(Typus.user_class)
I18n.locale = @current_user.reload.preferences[:locale]
@resource[:human_name] = params[:controller].extract_human_name
end
flash[:success] = _("%{model} successfully updated.",
:model => @resource[:human_name])
redirect_to path
else
render :action => 'edit'
end
end
def destroy
@item.destroy
flash[:success] = _("%{model} successfully removed.",
:model => @resource[:human_name])
redirect_to request.referer || admin_dashboard_path
rescue Exception => error
error_handler(error, params.merge(:action => 'index', :id => nil))
end
def toggle
@item.toggle(params[:field])
@item.save!
flash[:success] = _("%{model} %{attribute} changed.",
:model => @resource[:human_name],
:attribute => params[:field].humanize.downcase)
redirect_to request.referer || admin_dashboard_path
end
##
# Change item position. This only works if acts_as_list is
# installed. We can then move items:
#
# params[:go] = 'move_to_top'
#
# Available positions are move_to_top, move_higher, move_lower,
# move_to_bottom.
#
def position
@item.send(params[:go])
flash[:success] = _("Record moved %{to}.",
:to => params[:go].gsub(/move_/, '').humanize.downcase)
redirect_to request.referer || admin_dashboard_path
end
##
# Relate a model object to another, this action is used only by the
# has_and_belongs_to_many and has_many relationships.
#
def relate
resource_class = params[:related][:model].constantize
resource_tableized = params[:related][:relation] || params[:related][:model].tableize
if @item.send(resource_tableized) << resource_class.find(params[:related][:id])
flash[:success] = _("%{model_a} related to %{model_b}.",
:model_a => resource_class.typus_human_name,
:model_b => @resource[:human_name])
else
# TODO: Show the reason why cannot be related showing model_a and model_b errors.
flash[:error] = _("%{model_a} cannot be related to %{model_b}.",
:model_a => resource_class.typus_human_name,
:model_b => @resource[:human_name])
end
redirect_to :back
end
##
# Remove relationship between models, this action never removes items!
#
def unrelate
resource_class = params[:resource].classify.constantize
resource_tableized = params[:resource].tableize
resource = resource_class.find(params[:resource_id])
if @resource[:class].
reflect_on_association(resource_class.table_name.singularize.to_sym).
try(:macro) == :has_one
attribute = resource_tableized.singularize
saved_succesfully = @item.update_attribute attribute, nil
else
attribute = resource_tableized
saved_successfully = if @item.respond_to?(attribute)
@item.send(attribute).delete(resource)
elsif @item.respond_to?("related_#{attribute}")
@item.relationships.detect {|rel|
rel.related_id == resource.id &&
rel.related_type == resource.class.name
}.destroy
end
end
if saved_succesfully
flash[:success] = _("%{model_a} unrelated from %{model_b}.",
:model_a => resource_class.typus_human_name,
:model_b => @resource[:human_name])
else
# TODO: Show the reason why cannot be unrelated showing model_a and model_b errors.
flash[:error] = _("%{model_a} cannot be unrelated to %{model_b}.",
:model_a => resource_class.typus_human_name,
:model_b => @resource[:human_name])
end
redirect_to :back
end
def detach
attachment = @resource[:class].human_attribute_name(params[:attachment])
if @item.update_attributes(params[:attachment] => nil)
flash[:success] = _("%{attachment} removed.",
:attachment => attachment)
else
flash[:notice] = _("%{attachment} can't be removed.",
:attachment => attachment)
end
redirect_to :back
end
def current_user
@current_user
end
private
def set_resource
@resource = { :self => params[:controller].extract_resource,
:human_name => params[:controller].extract_human_name,
:class => params[:controller].extract_class,
:pluralized => params[:controller].extract_class.pluralized_human_name }
@object_name = ActionController::RecordIdentifier.singular_class_name(@resource[:class])
rescue Exception => error
error_handler(error)
end
##
# Find model when performing an edit, update, destroy, relate,
# unrelate ...
#
def find_item
@item = @resource[:class].find(params[:id])
end
##
# If item is owned by another user, we only can perform a
# show action on the item. Updated item is also blocked.
#
# before_filter :check_ownership_of_item, :only => [ :edit, :update, :destroy,
# :toggle, :position,
# :relate, :unrelate ]
#
def check_ownership_of_item
# By-pass if current_user is root.
return if @current_user.is_root?
condition_typus_users = @item.respond_to?(Typus.relationship) && !@item.send(Typus.relationship).include?(@current_user)
condition_typus_user_id = @item.respond_to?(Typus.user_fk) && !@item.owned_by?(@current_user)
if condition_typus_users || condition_typus_user_id
flash[:notice] = _("You don't have permission to access this item.")
redirect_to request.referer || admin_dashboard_path
end
end
def check_ownership_of_items
# By-pass if current_user is root.
return if @current_user.is_root?
# Show only related items it @resource has a foreign_key (Typus.user_fk)
# related to the logged user.
if @resource[:class].typus_user_id?
condition = { Typus.user_fk => @current_user }
@conditions = @resource[:class].merge_conditions(@conditions, condition)
end
end
def check_ownership_of_referal_item
return unless params[:resource] && params[:resource_id]
klass = params[:resource].classify.constantize
return if !klass.typus_user_id?
item = klass.find(params[:resource_id])
raise "You're not owner of this record." unless item.owned_by?(@current_user) || @current_user.is_root?
end
def set_fields
mapping = case params[:action]
when 'index' then :list
when 'new', 'edit', 'create', 'update' then :form
else params[:action]
end
@fields = @resource[:class].typus_fields_for(mapping)
end
def set_order
params[:sort_order] ||= 'desc'
@order = params[:order_by] ? "#{@resource[:class].table_name}.#{params[:order_by]} #{params[:sort_order]}" : @resource[:class].typus_order_by
end
##
# When <tt>params[:back_to]</tt> is defined this action is used.
#
# - <tt>has_and_belongs_to_many</tt> relationships.
# - <tt>has_many</tt> relationships (polymorphic ones).
#
def create_with_back_to
if params[:resource] && params[:resource_id]
resource_class = params[:resource].classify.constantize
resource_id = params[:resource_id]
resource = resource_class.find(resource_id)
association = @resource[:class].reflect_on_association(params[:resource].to_sym).macro rescue :polymorphic
else
association = :has_many
end
case association
when :belongs_to
@item.save
when :has_and_belongs_to_many
@item.save
@item.send(params[:resource]) << resource
when :has_many
@item.save
message = _("%{model} successfully created.",
:model => @resource[:human_name])
path = "#{params[:back_to]}?#{params[:selected]}=#{@item.id}"
when :polymorphic
resource.send(@item.class.name.tableize).create(params[@object_name])
end
flash[:success] = message || _("%{model_a} successfully assigned to %{model_b}.",
:model_a => @item.class.typus_human_name,
:model_b => resource_class.typus_human_name)
redirect_to path || params[:back_to]
end
def error_handler(error, path = admin_dashboard_path)
raise error unless Rails.env.production?
flash[:error] = "#{error.message} (#{@resource[:class]})"
redirect_to path
end
include Typus::MasterControllerExtensions rescue nil
end

View File

@ -0,0 +1,146 @@
class TypusController < ApplicationController
skip_filter filter_chain
unloadable
layout :select_layout
include Typus::Authentication
include Typus::QuickEdit
include Typus::Preferences
include Typus::Reloader
filter_parameter_logging :password
before_filter :verify_typus_users_table_schema
before_filter :reload_config_and_roles
before_filter :require_login,
:except => [ :sign_up, :sign_in, :sign_out,
:recover_password, :reset_password,
:quick_edit ]
before_filter :set_typus_preferences, :only => [ :dashboard ]
before_filter :check_if_user_can_perform_action_on_resource_without_model,
:except => [ :sign_up, :sign_in, :sign_out,
:dashboard,
:recover_password, :reset_password,
:quick_edit ]
before_filter :recover_password_disabled?,
:only => [ :recover_password, :reset_password ]
def dashboard
flash[:notice] = _("There are not defined applications in config/typus/*.yml.") if Typus.applications.empty?
end
def sign_in
redirect_to admin_sign_up_path and return if Typus.user_class.count.zero?
if request.post?
if user = Typus.user_class.authenticate(params[:typus_user][:email], params[:typus_user][:password])
session[:typus_user_id] = user.id
redirect_to params[:back_to] || admin_dashboard_path
else
flash[:error] = _("The email and/or password you entered is invalid.")
redirect_to admin_sign_in_path
end
end
end
def sign_out
session[:typus_user_id] = nil
redirect_to admin_sign_in_path
end
def recover_password
if request.post?
if user = Typus.user_class.find_by_email(params[:typus_user][:email])
url = admin_reset_password_url(:token => user.token)
TypusMailer.deliver_reset_password_link(user, url)
flash[:success] = _("Password recovery link sent to your email.")
redirect_to admin_sign_in_path
else
redirect_to admin_recover_password_path
end
end
end
##
# Available if Typus::Configuration.options[:email] is set.
#
def reset_password
@typus_user = Typus.user_class.find_by_token!(params[:token])
if request.post?
@typus_user.password = params[:typus_user][:password]
@typus_user.password_confirmation = params[:typus_user][:password_confirmation]
if !params[:typus_user][:password].blank? && @typus_user.save
session[:typus_user_id] = @typus_user.id
redirect_to admin_dashboard_path
else
render :action => "reset_password"
end
end
end
def sign_up
redirect_to admin_sign_in_path and return unless Typus.user_class.count.zero?
if request.post?
user = Typus.user_class.generate(:email => params[:typus_user][:email],
:password => Typus::Configuration.options[:default_password],
:role => Typus::Configuration.options[:root])
user.status = true
if user.save
session[:typus_user_id] = user.id
flash[:notice] = _("Password set to \"%{password}\".",
:password => Typus::Configuration.options[:default_password])
redirect_to admin_dashboard_path
else
flash[:error] = _("That doesn't seem like a valid email address.")
end
else
flash[:notice] = _("Enter your email below to create the first user.")
end
end
private
def verify_typus_users_table_schema
attributes = Typus.user_class.model_fields.keys
upgrades = ActiveSupport::OrderedHash.new
upgrades[:role] = "typus_update_schema_to_01"
upgrades[:preferences] = "typus_update_schema_to_02"
upgrades.each do |key, value|
message = "Run `script/generate #{value} -f && rake db:migrate` to update database schema."
raise message if !attributes.include?(key)
end
end
def recover_password_disabled?
redirect_to admin_sign_in_path unless Typus::Configuration.options[:email]
end
def select_layout
%w( sign_up sign_in sign_out
recover_password reset_password ).include?(action_name) ? "typus" : "admin"
end
include Typus::TypusControllerExtensions rescue nil
end

View File

@ -0,0 +1,464 @@
module Admin::FormHelper
def build_form(fields, form)
options = { :form => form }
returning(String.new) do |html|
html << (error_messages_for :item, :header_tag => 'h3')
fields.each do |key, value|
if template = @resource[:class].typus_template(key)
html << typus_template_field(key, template, options)
next
end
html << case value
when :belongs_to then typus_belongs_to_field(key, options)
when :tree then typus_tree_field(key, :form => options[:form])
when :boolean, :date, :datetime, :string, :text, :time,
:file, :password, :selector
typus_template_field(key, value, options)
else
typus_template_field(key, :string, options)
end
end
end
end
# OPTIMIZE: Remove returning(String.new) and return directly the html.
def typus_belongs_to_field(attribute, options)
form = options[:form]
##
# We only can pass parameters to 'new' and 'edit', so this hack makes
# the work to replace the current action.
#
params[:action] = (params[:action] == 'create') ? 'new' : params[:action]
back_to = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id])
related = @resource[:class].reflect_on_association(attribute.to_sym).class_name.constantize
related_fk = @resource[:class].reflect_on_association(attribute.to_sym).primary_key_name
confirm = [ _("Are you sure you want to leave this page?"),
_("If you have made any changes to the fields without clicking the Save/Update entry button, your changes will be lost."),
_("Click OK to continue, or click Cancel to stay on this page.") ]
returning(String.new) do |html|
message = link_to _("Add"), { :controller => "admin/#{related.class_name.tableize}",
:action => 'new',
:back_to => back_to,
:selected => related_fk },
:confirm => confirm.join("\n\n") if @current_user.can?('create', related)
if related.respond_to?(:roots)
html << typus_tree_field(related_fk, :items => related.roots,
:attribute_virtual => related_fk,
:form => form)
else
values = related.find(:all, :order => related.typus_order_by).collect { |p| [p.to_label, p.id] }
options = { :include_blank => true }
html_options = { :disabled => attribute_disabled?(attribute) }
label_text = @resource[:class].human_attribute_name(attribute)
html << <<-HTML
<li>
#{form.label related_fk, "#{label_text} <small>#{message}</small>"}
#{form.select related_fk, values, options, html_options }
</li>
HTML
end
end
end
# OPTIMIZE: Move html code to partial.
def typus_tree_field(attribute, *args)
options = args.extract_options!
options[:items] ||= @resource[:class].roots
options[:attribute_virtual] ||= 'parent_id'
form = options[:form]
values = expand_tree_into_select_field(options[:items], options[:attribute_virtual])
label_text = @resource[:class].human_attribute_name(attribute)
<<-HTML
<li>
#{form.label label_text}
#{form.select options[:attribute_virtual], values, { :include_blank => true }}
</li>
HTML
end
# OPTIMIZE: Cleanup the case statement.
def typus_relationships
@back_to = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id])
returning(String.new) do |html|
@resource[:class].typus_defaults_for(:relationships).each do |relationship|
association = @resource[:class].reflect_on_association(relationship.to_sym)
next if @current_user.cannot?('read', association.class_name.constantize)
macro = association.through_reflection ? :has_and_belongs_to_many : association.macro
case macro
when :has_and_belongs_to_many
html << typus_form_has_and_belongs_to_many(relationship)
when :has_many
if association.options[:through]
# Here we will shot the relationship. Better this than raising an error.
else
html << typus_form_has_many(relationship)
end
when :has_one
html << typus_form_has_one(relationship)
end
end
end
end
# OPTIMIZE: Move html code to partial.
def typus_form_has_many(field)
returning(String.new) do |html|
model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
model_to_relate_as_resource = model_to_relate.name.tableize
reflection = @resource[:class].reflect_on_association(field.to_sym)
association = reflection.macro
foreign_key = reflection.through_reflection ? reflection.primary_key_name.pluralize : reflection.primary_key_name
link_options = { :controller => "admin/#{model_to_relate_as_resource.pluralize}",
:action => 'new',
:back_to => "#{@back_to}##{field}",
:resource => @resource[:self].singularize,
:resource_id => @item.id,
foreign_key => @item.id }
condition = if @resource[:class].typus_user_id? && @current_user.is_not_root?
@item.owned_by?(@current_user)
else
true
end
# If the form_for_<model>_relationship partial exists we consider
# we want to add only items from our form, and not going to the
# new action. So we don't show the add new.
# Partial exists?
partial = "form_for_#{model_to_relate_as_resource}_relationship"
partial_path = Rails.root.join('app', 'views', 'admin', 'cars', "_#{partial}.html.erb").to_s
if condition && @current_user.can?('create', model_to_relate) && !File.exists?(partial_path)
add_new = <<-HTML
<small>#{link_to _("Add new"), link_options}</small>
HTML
end
html << <<-HTML
<a name="#{field}"></a>
<div class="box_relationships" id="#{model_to_relate_as_resource}">
<h2>
#{link_to model_to_relate.pluralized_human_name, { :controller => "admin/#{model_to_relate_as_resource}", foreign_key => @item.id }, :title => _("%{model} filtered by %{filtered_by}", :model => model_to_relate.typus_human_name.pluralize, :filtered_by => @item.to_label)}
#{add_new}
</h2>
HTML
if File.exists?(partial_path)
html << <<-HTML
#{render :partial => partial}
HTML
end
##
# It's a has_many relationship, so items that are already assigned to another
# entry are assigned to that entry.
#
items_to_relate = model_to_relate.find(:all, :conditions => ["#{foreign_key} is ?", nil])
if condition && !items_to_relate.empty?
html << <<-HTML
#{form_tag :action => 'relate', :id => @item.id}
#{hidden_field :related, :model, :value => model_to_relate}
<p>#{select :related, :id, items_to_relate.collect { |f| [f.to_label, f.id] }.sort_by { |e| e.first } } &nbsp; #{submit_tag _("Add"), :class => 'button'}</p>
</form>
HTML
end
conditions = if model_to_relate.typus_options_for(:only_user_items) && @current_user.is_not_root?
{ Typus.user_fk => @current_user }
end
options = { :order => model_to_relate.typus_order_by, :conditions => conditions }
items_count = @resource[:class].find(params[:id]).send(field).count(:conditions => conditions)
items_per_page = model_to_relate.typus_options_for(:per_page).to_i
@pager = ::Paginator.new(items_count, items_per_page) do |offset, per_page|
eager_loading = model_to_relate.reflect_on_all_associations(:belongs_to).map { |i| i.name } - [@resource[:class].name.downcase.to_sym]
options.merge!({:limit => per_page, :offset => offset, :include => eager_loading})
items = @resource[:class].find(params[:id]).send(field).find(:all, options)
end
@items = @pager.page(params[:page])
unless @items.empty?
options = { :back_to => "#{@back_to}##{field}", :resource => @resource[:self], :resource_id => @item.id }
html << build_list(model_to_relate,
model_to_relate.typus_fields_for(:relationship),
@items,
model_to_relate_as_resource,
options,
association)
html << pagination(:anchor => model_to_relate.name.tableize) unless pagination.nil?
else
message = _("There are no %{records}.",
:records => model_to_relate.typus_human_name.pluralize.downcase)
html << <<-HTML
<div id="flash" class="notice"><p>#{message}</p></div>
HTML
end
html << <<-HTML
</div>
HTML
end
end
# OPTIMIZE: Move html code to partial.
def typus_form_has_and_belongs_to_many(field)
returning(String.new) do |html|
model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
model_to_relate_as_resource = model_to_relate.name.tableize
reflection = @resource[:class].reflect_on_association(field.to_sym)
association = reflection.macro
through = !reflection.through_reflection.nil?
condition = if @resource[:class].typus_user_id? && !@current_user.is_root?
@item.owned_by?(@current_user)
else
true
end
if condition && @current_user.can?('create', model_to_relate)
add_new = <<-HTML
<small>#{link_to _("Add new"), :controller => field, :action => 'new', :back_to => @back_to, :resource => @resource[:self], :resource_id => @item.id}</small>
HTML
end
html << <<-HTML
<a name="#{field}"></a>
<div class="box_relationships" id="#{model_to_relate_as_resource}">
<h2>
#{link_to model_to_relate.typus_human_name.pluralize, :controller => "admin/#{model_to_relate_as_resource}"}
#{add_new unless through}
</h2>
HTML
if model_to_relate.count < 500
items_to_relate = (model_to_relate.find(:all) - @item.send(field))
if condition && !items_to_relate.empty?
html << <<-HTML
#{form_tag :action => 'relate', :id => @item.id}
#{hidden_field(:related, :relation, :value => field) if through}
#{hidden_field :related, :model, :value => model_to_relate}
<p>#{select :related, :id, items_to_relate.collect { |f| [f.to_label, f.id] }.sort_by { |e| e.first } } &nbsp; #{submit_tag _("Add"), :class => 'button'}</p>
</form>
HTML
end
end
conditions = if model_to_relate.typus_options_for(:only_user_items) && @current_user.is_not_root?
{ Typus.user_fk => @current_user }
end
options = { :order => model_to_relate.typus_order_by, :conditions => conditions }
items_count = @resource[:class].find(params[:id]).send(field).count(:conditions => conditions)
items_per_page = model_to_relate.typus_options_for(:per_page).to_i
@pager = ::Paginator.new(items_count, items_per_page) do |offset, per_page|
options.merge!({:limit => per_page, :offset => offset})
items = @resource[:class].find(params[:id]).send(field).find(:all, options)
end
@items = @pager.page(params[:page])
unless @items.empty?
html << build_list(model_to_relate,
model_to_relate.typus_fields_for(:relationship),
@items,
model_to_relate_as_resource,
{},
association)
html << pagination(:anchor => model_to_relate.name.tableize) unless pagination.nil?
else
message = _("There are no %{records}.",
:records => model_to_relate.typus_human_name.pluralize.downcase)
html << <<-HTML
<div id="flash" class="notice"><p>#{message}</p></div>
HTML
end
html << <<-HTML
</div>
HTML
end
end
# OPTIMIZE: Move html code to partial.
def typus_form_has_one(field)
returning(String.new) do |html|
model_to_relate = @resource[:class].reflect_on_association(field.to_sym).class_name.constantize
model_to_relate_as_resource = model_to_relate.name.tableize
reflection = @resource[:class].reflect_on_association(field.to_sym)
association = reflection.macro
foreign_key = reflection.through_reflection ? reflection.primary_key_name.pluralize : reflection.primary_key_name
link_options = { :controller => "admin/#{model_to_relate_as_resource.pluralize}",
:action => 'new',
:back_to => "#{@back_to}##{field}",
:resource => @resource[:self].singularize,
:resource_id => @item.id,
foreign_key => @item.id }
condition = if @resource[:class].typus_user_id? && !@current_user.is_root?
@item.owned_by?(@current_user)
else
true
end
existing_record = instance_eval("@item.#{field}")
if existing_record.nil? && condition && @current_user.can?('create', model_to_relate)
add_new = <<-HTML
<small>#{link_to _("Add new"), link_options}</small>
HTML
end
html << <<-HTML
<a name="#{field}"></a>
<div class="box_relationships" id="#{model_to_relate_as_resource}">
<h2>
#{link_to model_to_relate.typus_human_name, :controller => "admin/#{model_to_relate_as_resource}"}
#{add_new}
</h2>
HTML
items = Array.new
items << @resource[:class].find(params[:id]).send(field) unless @resource[:class].find(params[:id]).send(field).nil?
unless items.empty?
options = { :back_to => @back_to, :resource => @resource[:self], :resource_id => @item.id }
html << build_list(model_to_relate,
model_to_relate.typus_fields_for(:relationship),
items,
model_to_relate_as_resource,
options,
association)
else
message = _("There is no %{records}.",
:records => model_to_relate.typus_human_name.downcase)
html << <<-HTML
<div id="flash" class="notice"><p>#{message}</p></div>
HTML
end
html << <<-HTML
</div>
HTML
end
end
# OPTIMIZE: Cleanup the rescue ...
def typus_template_field(attribute, template, options = {})
template_name = "admin/templates/#{template}"
custom_options = { :start_year => @resource[:class].typus_options_for(:start_year),
:end_year => @resource[:class].typus_options_for(:end_year),
:minute_step => @resource[:class].typus_options_for(:minute_step),
:disabled => attribute_disabled?(attribute),
:include_blank => true }
render template_name, :resource => @resource,
:attribute => attribute,
:options => custom_options,
:html_options => {},
:form => options[:form],
:label_text => @resource[:class].human_attribute_name(attribute)
end
def attribute_disabled?(attribute)
accessible = @resource[:class].accessible_attributes
return accessible.nil? ? false : !accessible.include?(attribute)
end
def typus_preview(item, attribute)
return nil unless @item.send(attribute).exists?
attachment = attribute.split("_file_name").first
file_preview = Typus::Configuration.options[:file_preview]
file_thumbnail = Typus::Configuration.options[:file_thumbnail]
has_file_preview = item.send(attachment).styles.member?(file_preview)
has_file_thumbnail = item.send(attachment).styles.member?(file_thumbnail)
file_preview_is_image = item.send("#{attachment}_content_type") =~ /^image\/.+/
href = if has_file_preview
url = item.send(attachment).url(file_preview)
if ActionController::Base.relative_url_root
ActionController::Base.relative_url_root + url
else
url
end
else
item.send(attachment).url
end
content = if has_file_thumbnail
image_tag item.send(attachment).url(file_thumbnail)
else
_("View %{attribute}", :attribute => @item.class.human_attribute_name(attribute).downcase)
end
render "admin/helpers/preview",
:attribute => attribute,
:content => content,
:has_file_preview => has_file_preview,
:href => href,
:item => item
end
##
# Tree builder when model +acts_as_tree+
#
def expand_tree_into_select_field(items, attribute)
returning(String.new) do |html|
items.each do |item|
html << %{<option #{"selected" if @item.send(attribute) == item.id} value="#{item.id}">#{"&nbsp;" * item.ancestors.size * 2} &#8627; #{item.to_label}</option>\n}
html << expand_tree_into_select_field(item.children, attribute) unless item.children.empty?
end
end
end
include Typus::FormHelperExtensions rescue nil
end

View File

@ -0,0 +1,63 @@
module Admin::MasterHelper
include TypusHelper
include Admin::SidebarHelper
include Admin::FormHelper
include Admin::TableHelper
def display_link_to_previous
options = {}
options[:resource_from] = @resource[:human_name]
options[:resource_to] = params[:resource].classify.constantize.human_name if params[:resource]
editing = %w( edit update ).include?(params[:action])
message = case
when params[:resource] && editing
"You're updating a %{resource_from} for %{resource_to}."
when editing
"You're updating a %{resource_from}."
when params[:resource]
"You're adding a new %{resource_from} to %{resource_to}."
else
"You're adding a new %{resource_from}."
end
message = _(message,
:resource_from => options[:resource_from],
:resource_to => options[:resource_to])
render "admin/helpers/display_link_to_previous", :message => message
end
def remove_filter_link(filter = request.env['QUERY_STRING'])
return unless filter && !filter.blank?
render "admin/helpers/remove_filter_link"
end
##
# If there's a partial with a "microformat" of the data we want to
# display, this will be used, otherwise we use a default table which
# it's build from the options defined on the yaml configuration file.
#
def build_list(model, fields, items, resource = @resource[:self], link_options = {}, association = nil)
template = "app/views/admin/#{resource}/_#{resource.singularize}.html.erb"
if File.exist?(template)
render :partial => template.gsub('/_', '/'), :collection => items, :as => :item
else
build_typus_table(model, fields, items, link_options, association)
end
end
def pagination(*args)
@options = args.extract_options!
render "admin/helpers/pagination" if @items.prev || @items.next
end
end

View File

@ -0,0 +1,19 @@
module Admin
module PublicHelper
##
# Quick edit usage:
#
# <%= quick_edit(:message => "Edit this article", :path => "articles/edit/#{@article.id}") %>
#
# If user is logged in Typus, a link will appear on the top/right of
# the pages where you insert this helper.
#
def quick_edit(*args)
render "admin/helpers/quick_edit", :options => args.extract_options!
end
end
end

View File

@ -0,0 +1,238 @@
module Admin::SidebarHelper
def build_typus_list(items, *args)
return String.new if items.empty?
options = args.extract_options!
header = if options[:header]
_(options[:header].humanize)
elsif options[:attribute]
@resource[:class].human_attribute_name(options[:attribute])
end
render "admin/helpers/list",
:header => header,
:items => items,
:options => options
end
# TODO: Test "Show entry" case.
def actions
items = []
if @current_user.can?('create', @resource[:class])
items << (link_to_unless_current _("Add new"), { :action => 'new' }, :class => 'new')
end
case params[:action]
when 'edit'
items << (link_to _("Show"), :action => 'show', :id => @item.id)
end
case params[:action]
when 'show'
condition = if @resource[:class].typus_user_id? && @current_user.is_not_root?
@item.owned_by?(@current_user)
else
@current_user.can?('update', @resource[:class])
end
items << (link_to_if condition, _("Edit"), :action => 'edit', :id => @item.id)
end
@resource[:class].typus_actions_on(params[:action]).each do |action|
if @current_user.can?(action, @resource[:class])
items << (link_to _(action.humanize), params.merge(:action => action))
end
end
build_typus_list(items, :header => 'actions')
end
def export
formats = @resource[:class].typus_export_formats.map do |format|
link_to _(format.upcase), params.merge(:format => format)
end
build_typus_list(formats, :header => 'export')
end
def search
typus_search = @resource[:class].typus_defaults_for(:search)
return if typus_search.empty?
search_by = typus_search.collect { |x| @resource[:class].human_attribute_name(x) }.to_sentence
search_params = params.dup
%w( action controller search page id ).each { |p| search_params.delete(p) }
hidden_params = search_params.map { |k, v| hidden_field_tag(k, v) }
render "admin/helpers/search",
:hidden_params => hidden_params,
:search_by => search_by
end
def filters
typus_filters = @resource[:class].typus_filters
return if typus_filters.empty?
current_request = request.env['QUERY_STRING'] || []
returning(String.new) do |html|
typus_filters.each do |key, value|
case value
when :boolean then html << boolean_filter(current_request, key)
when :string then html << string_filter(current_request, key)
when :date, :datetime then html << date_filter(current_request, key)
when :belongs_to then html << relationship_filter(current_request, key)
when :has_many || :has_and_belongs_to_many then
html << relationship_filter(current_request, key, true)
when nil then
# Do nothing. This is ugly but for now it's ok.
else
html << string_filter(current_request, key)
end
end
end
end
# OPTIMIZE: Move html code to partial.
def relationship_filter(request, filter, habtm = false)
att_assoc = @resource[:class].reflect_on_association(filter.to_sym)
class_name = att_assoc.options[:class_name] || ((habtm) ? filter.classify : filter.capitalize.camelize)
model = class_name.constantize
related_fk = (habtm) ? filter : att_assoc.primary_key_name
params_without_filter = params.dup
%w( controller action page ).each { |p| params_without_filter.delete(p) }
params_without_filter.delete(related_fk)
items = []
returning(String.new) do |html|
related_items = model.find(:all, :order => model.typus_order_by)
if related_items.size > model.typus_options_for(:sidebar_selector)
related_items.each do |item|
switch = 'selected' if request.include?("#{related_fk}=#{item.id}")
items << <<-HTML
<option #{switch} value="#{url_for params.merge(related_fk => item.id, :page => nil)}">#{truncate(item.to_label, :length => 25)}</option>
HTML
end
model_pluralized = model.name.downcase.pluralize
form = <<-HTML
<!-- Embedded JS -->
<script>
function surfto_#{model_pluralized}(form) {
var myindex = form.#{model_pluralized}.selectedIndex
if (form.#{model_pluralized}.options[myindex].value != "0") {
top.location.href = form.#{model_pluralized}.options[myindex].value;
}
}
</script>
<!-- /Embedded JS -->
<form class="form" action="#"><p>
<select name="#{model_pluralized}" onChange="surfto_#{model_pluralized}(this.form)">
<option value="#{url_for params_without_filter}">#{_("Filter by")} #{_(model.typus_human_name)}</option>
#{items.join("\n")}
</select>
</p></form>
HTML
else
related_items.each do |item|
switch = request.include?("#{related_fk}=#{item.id}") ? 'on' : 'off'
items << (link_to item.to_label, params.merge(related_fk => item.id, :page => nil), :class => switch)
end
end
if form
html << build_typus_list(items, :attribute => filter, :selector => true)
html << form
else
html << build_typus_list(items, :attribute => filter)
end
end
end
def date_filter(request, filter)
if !@resource[:class].typus_field_options_for(:filter_by_date_range).include?(filter.to_sym)
items = %w( today last_few_days last_7_days last_30_days ).map do |timeline|
switch = request.include?("#{filter}=#{timeline}") ? 'on' : 'off'
options = { :page => nil }
if switch == 'on'
params.delete(filter)
else
options.merge!(filter.to_sym => timeline)
end
link_to _(timeline.humanize), params.merge(options), :class => switch
end
build_typus_list(items, :attribute => filter)
else
date_params = params.dup
%w( action controller page id ).each { |p| date_params.delete(p) }
date_params.delete(filter)
hidden_params = date_params.map { |k, v| hidden_field_tag(k, v) }
render "admin/helpers/date", :hidden_params => hidden_params, :filter => filter, :resource => @resource
end
end
def boolean_filter(request, filter)
item_params = params.dup
items = @resource[:class].typus_boolean(filter).map do |key, value|
switch = request.include?("#{filter}=#{key}") ? 'on' : 'off'
options = { :page => nil }
if switch == 'on'
item_params.delete(filter)
else
options.merge!(filter.to_sym => key)
end
link_to _(value), item_params.merge(options), :class => switch
end
build_typus_list(items, :attribute => filter)
end
def string_filter(request, filter)
item_params = params.dup
values = @resource[:class]::const_get("#{filter.to_s.upcase}")
values = values.invert if values.kind_of?(Hash)
items = values.map do |item|
link_name, link_filter = (values.first.kind_of?(Array)) ? [ item.first, item.last ] : [ item, item ]
switch = (params[filter.to_s] == link_filter) ? 'on' : 'off'
options = { :page => nil }
if switch == 'on'
item_params.delete(filter)
else
options.merge!(filter.to_sym => link_filter)
end
link_to link_name, item_params.merge(options), :class => switch
end
build_typus_list(items, :attribute => filter)
end
include Typus::SidebarHelperExtensions rescue nil
end

View File

@ -0,0 +1,261 @@
module Admin::TableHelper
# OPTIMIZE: Move html code to partial & refactor.
def build_typus_table(model, fields, items, link_options = {}, association = nil)
returning(String.new) do |html|
html << <<-HTML
<table class="typus">
HTML
html << typus_table_header(model, fields)
items.each do |item|
html << <<-HTML
<tr class="#{cycle('even', 'odd')} #{item.class.name.underscore}" id="#{item.to_dom}" name="item_#{item.id}">
HTML
fields.each do |key, value|
case value
when :boolean then html << typus_table_boolean_field(key, item)
when :datetime then html << typus_table_datetime_field(key, item, link_options)
when :date then html << typus_table_datetime_field(key, item, link_options)
when :file then html << typus_table_file_field(key, item, link_options)
when :time then html << typus_table_datetime_field(key, item, link_options)
when :belongs_to then html << typus_table_belongs_to_field(key, item)
when :tree then html << typus_table_tree_field(key, item)
when :position then html << typus_table_position_field(key, item)
when :selector then html << typus_table_selector(key, item)
when :has_and_belongs_to_many then
html << typus_table_has_and_belongs_to_many_field(key, item)
else
html << typus_table_string_field(key, item, link_options)
end
end
action = if model.typus_user_id? && @current_user.is_not_root?
# If there's a typus_user_id column on the table and logged user is not root ...
item.owned_by?(@current_user) ? item.class.typus_options_for(:default_action_on_item) : 'show'
elsif @current_user.cannot?('edit', model)
'show'
else
item.class.typus_options_for(:default_action_on_item)
end
content = link_to _(action.capitalize), :controller => "admin/#{item.class.name.tableize}", :action => action, :id => item.id
html << <<-HTML
<td width="10px">#{content}</td>
HTML
##
# This controls the action to perform. If we are on a model list we
# will remove the entry, but if we inside a model we will remove the
# relationship between the models.
#
# Only shown is the user can destroy/unrelate items.
#
trash = %Q(<div class="sprite trash">Trash</div>)
unrelate = %Q(<div class="sprite unrelate">Unrelate</div>)
case params[:action]
when 'index'
condition = if model.typus_user_id? && @current_user.is_not_root?
item.owned_by?(@current_user)
elsif (@current_user.id.eql?(item.id) && model.eql?(Typus.user_class))
false
else
@current_user.can?('destroy', model)
end
message = _("You are about to delete a %{model}.\nAre you sure you want to continue?", :model => model.human_name.downcase)
perform = link_to trash, { :action => 'destroy', :id => item.id },
:title => _("Remove"),
:confirm => _(message) if condition
when 'edit'
# If we are editing content, we can relate and unrelate always!
perform = link_to unrelate, { :action => 'unrelate', :id => params[:id], :resource => model, :resource_id => item.id },
:title => _("Unrelate"),
:confirm => _("Unrelate %{unrelate_model} from %{unrelate_model_from}?",
:unrelate_model => model.typus_human_name,
:unrelate_model_from => @resource[:human_name])
when 'show'
# If we are showing content, we only can relate and unrelate if we are
# the owners of the owner record.
# If the owner record doesn't have a foreign key (Typus.user_fk) we look
# each item to verify the ownership.
condition = if @resource[:class].typus_user_id? && @current_user.is_not_root?
@item.owned_by?(@current_user)
end
perform = link_to unrelate, { :action => 'unrelate', :id => params[:id], :resource => model, :resource_id => item.id },
:title => _("Unrelate"),
:confirm => _("Unrelate %{unrelate_model} from %{unrelate_model_from}?",
:unrelate_model => model.typus_human_name,
:unrelate_model_from => @resource[:human_name]) if condition
end
html << <<-HTML
<td width="10px">#{perform}</td>
</tr>
HTML
end
html << "</table>"
end
end
def typus_table_header(model, fields)
headers = fields.map do |key, value|
content = key.end_with?('_id') ? key : model.human_attribute_name(key)
if (model.model_fields.map(&:first).collect { |i| i.to_s }.include?(key) || model.reflect_on_all_associations(:belongs_to).map(&:name).include?(key.to_sym)) && params[:action] == 'index'
sort_order = case params[:sort_order]
when 'asc' then ['desc', '&darr;']
when 'desc' then ['asc', '&uarr;']
else
[nil, nil]
end
order_by = model.reflect_on_association(key.to_sym).primary_key_name rescue key
switch = sort_order.last if params[:order_by].eql?(order_by)
options = { :order_by => order_by, :sort_order => sort_order.first }
content = link_to "#{content} #{switch}", params.merge(options)
end
content
end
headers << "&nbsp;" if @current_user.can?('delete', model)
render "admin/helpers/table_header",
:headers => headers
end
# OPTIMIZE: Refactor (Remove rescue)
def typus_table_belongs_to_field(attribute, item)
action = item.send(attribute).class.typus_options_for(:default_action_on_item) rescue 'edit'
att_value = item.send(attribute)
content = if !att_value.nil?
if @current_user.can?(action, att_value.class.name)
link_to item.send(attribute).to_label, :controller => "admin/#{att_value.class.name.tableize}", :action => action, :id => att_value.id
else
att_value.to_label
end
end
return content_tag(:td, content)
end
def typus_table_has_and_belongs_to_many_field(attribute, item)
content = item.send(attribute).map { |i| i.to_label }.join('<br />')
return content_tag(:td, content)
end
def typus_table_string_field(attribute, item, link_options = {})
content = h(item.send(attribute))
return content_tag(:td, content, :class => attribute)
end
def typus_table_selector(attribute, item)
content = h(item.mapping(attribute))
return content_tag(:td, content, :class => attribute)
end
def typus_table_file_field(attribute, item, link_options = {})
attachment = attribute.split("_file_name").first
file_preview = Typus::Configuration.options[:file_preview]
file_thumbnail = Typus::Configuration.options[:file_thumbnail]
has_file_preview = item.send(attachment).styles.member?(file_preview)
file_preview_is_image = item.send("#{attachment}_content_type") =~ /^image\/.+/
content = if has_file_preview && file_preview_is_image
render "admin/helpers/preview",
:attribute => attribute,
:attachment => attachment,
:content => item.send(attribute),
:has_file_preview => has_file_preview,
:href => item.send(attachment).url(file_preview),
:item => item
else
link_to item.send(attribute), item.send(attachment).url
end
return content_tag(:td, content)
end
# OPTIMIZE: Move html code to partial.
def typus_table_tree_field(attribute, item)
<<-HTML
<td>#{item.parent.to_label if item.parent}</td>
HTML
end
# OPTIMIZE: Move html code to partial.
def typus_table_position_field(attribute, item)
html_position = []
[['Up', 'move_higher'], ['Down', 'move_lower']].each do |position|
options = { :controller => item.class.name.tableize,
:action => 'position',
:id => item.id,
:go => position.last }
first_or_last = (item.respond_to?(:first?) && (position.last == 'move_higher' && item.first?)) || (item.respond_to?(:last?) && (position.last == 'move_lower' && item.last?))
html_position << link_to_unless(first_or_last, _(position.first), params.merge(options)) do |name|
%(<span class="inactive">#{name}</span>)
end
end
content = html_position.join(' / ')
return content_tag(:td, content)
end
def typus_table_datetime_field(attribute, item, link_options = {} )
date_format = item.class.typus_date_format(attribute)
content = !item.send(attribute).nil? ? item.send(attribute).to_s(date_format) : item.class.typus_options_for(:nil)
return content_tag(:td, content)
end
def typus_table_boolean_field(attribute, item)
boolean_hash = item.class.typus_boolean(attribute)
status = item.send(attribute)
link_text = boolean_hash["#{status}".to_sym]
options = { :controller => "admin/#{item.class.name.tableize}",
:action => 'toggle',
:id => item.id,
:field => attribute.gsub(/\?$/,'') }
confirm = _("Change %{attribute}?",
:attribute => item.class.human_attribute_name(attribute).downcase)
content = link_to _(link_text), options, :confirm => confirm
return content_tag(:td, content)
end
include Typus::TableHelperExtensions rescue nil
end

View File

@ -0,0 +1,101 @@
module TypusHelper
def applications
apps = ActiveSupport::OrderedHash.new
Typus.applications.each do |app|
available = Typus.application(app).map do |resource|
resource if @current_user.resources.include?(resource)
end.compact
next if available.empty?
apps[app] = available.sort_by { |x| x.constantize.typus_human_name }
end
render "admin/helpers/applications", :applications => apps
end
def resources
available = Typus.resources.map do |resource|
resource if @current_user.resources.include?(resource)
end.compact
return if available.empty?
render "admin/helpers/resources", :resources => available
end
def typus_block(*args)
options = args.extract_options!
partials_path = "admin/#{options[:location]}"
resources_partials_path = 'admin/resources'
partials = ActionController::Base.view_paths.map do |view_path|
Dir["#{view_path.path}/#{partials_path}/*"].map { |f| File.basename(f, '.html.erb') }
end.flatten
resources_partials = Dir["#{Rails.root}/app/views/#{resources_partials_path}/*"].map { |f| File.basename(f, '.html.erb') }
partial = "_#{options[:partial]}"
path = if partials.include?(partial) then partials_path
elsif resources_partials.include?(partial) then resources_partials_path
end
render "#{path}/#{options[:partial]}" if path
end
def page_title(action = params[:action])
crumbs = []
crumbs << @resource[:pluralized] if @resource
crumbs << _(action.humanize) unless %w( index ).include?(action)
return crumbs.compact.map { |x| x }.join(' &rsaquo; ')
end
def header
links = []
links << (link_to_unless_current _("Dashboard"), admin_dashboard_path)
Typus.models_on_header.each do |model|
links << (link_to_unless_current model.constantize.pluralized_human_name, :controller => "/admin/#{model.tableize}")
end
render "admin/helpers/header", :links => links
end
def login_info(user = @current_user)
admin_edit_typus_user_path = { :controller => "/admin/#{Typus::Configuration.options[:user_class_name].tableize}",
:action => 'edit',
:id => user.id }
message = _("Are you sure you want to sign out and end your session?")
user_details = if user.can?('edit', Typus::Configuration.options[:user_class_name])
link_to user.name, admin_edit_typus_user_path, :title => "#{user.email} (#{user.role})"
else
user.name
end
render "admin/helpers/login_info", :message => message, :user_details => user_details
end
def display_flash_message(message = flash)
return if message.empty?
flash_type = message.keys.first
render "admin/helpers/flash_message", :flash_type => flash_type, :message => message
end
end

View File

@ -0,0 +1,12 @@
class TypusMailer < ActionMailer::Base
self.template_root = "#{File.dirname(__FILE__)}/../views"
def reset_password_link(user, url)
subject "[#{Typus::Configuration.options[:app_name]}] #{_("Reset password")}"
body :user => user, :url => url
recipients user.email
from Typus::Configuration.options[:email]
end
end

View File

@ -0,0 +1,8 @@
class TypusUser < ActiveRecord::Base
ROLE = Typus::Configuration.roles.keys.sort
LANGUAGE = Typus.locales
enable_as_typus_user
end

View File

@ -0,0 +1,5 @@
<h2>Welcome!</h2>
<p>If you need help don't hesitate in joining the <%= link_to 'mailing list', 'http://groups.google.com/group/typus' %>.</p>
<p>Replace this sidebar dropping a file named <code>_sidebar.html.erb</code> on the <code>app/views/admin/dashboard</code> folder.</p>

View File

@ -0,0 +1,39 @@
<% applications.each do |app, models| %>
<table class="typus">
<tr>
<th colspan="2"><%= _(app) %></th>
</tr>
<% models.each do |model| %>
<%
klass = model.constantize
klass_resource = klass.name.tableize
klass_human_name = klass.pluralized_human_name
admin_items_path = { :controller => "admin/#{klass_resource}" }
new_admin_item_path = { :controller => "admin/#{klass_resource}", :action => 'new'}
%>
<tr class="<%= cycle('even', 'odd') %>">
<td>
<%= link_to klass_human_name, admin_items_path %><br />
<small><%= _(klass.typus_description) if !klass.typus_description.nil? %></small>
</td>
<td class="right">
<small><%= link_to_if @current_user.can?('create', klass), _("Add"), new_admin_item_path %></small>
</td>
</tr>
<% end %>
</table>
<% end %>

View File

@ -0,0 +1,26 @@
<%
if params[filter.to_s].is_a?(Hash)
date_from = params[filter.to_s]["from"]
date_to = params[filter.to_s]["to"]
else
date_from = ""
date_to = ""
end
date_format = Date::DATE_FORMATS[@resource[:class].typus_date_format(filter)]
%>
<h2><%= @resource[:class].human_attribute_name(filter) %></h2>
<ul>
<% form_tag url_for(:controller => params[:controller], :action => params[:action]), :method => :get do %>
<li>
<%= text_field_tag "#{filter}[from]", date_from, :size => 10, :class => :date_input, :date_format => date_format %>
-
<%= text_field_tag "#{filter}[to]", date_to, :size => 10, :class => :date_input, :date_format => date_format %>
</li>
<li>
<%= hidden_params.sort.join("\n") %>
<%= submit_tag _("Filter") %>
</li>
<% end %>
</ul>

View File

@ -0,0 +1,3 @@
<div id="flash" class="notice">
<p><%= message %> <%= link_to _("Do you want to cancel it?"), params[:back_to] %></p>
</div>

View File

@ -0,0 +1,3 @@
<div id="flash" class="<%= flash_type %>">
<p><%= message[flash_type] %></p>
</div>

View File

@ -0,0 +1,13 @@
<h1>
<% if ActionController::Routing::Routes.named_routes.routes.has_key?(:root) %>
<%= link_to Typus::Configuration.options[:app_name], root_path, :title => _("View site") %>
<% else %>
<%= Typus::Configuration.options[:app_name] %>
<% end %>
</h1>
<ul>
<% links.each do |link| -%>
<li><%= link %></li>
<% end -%>
</ul>

View File

@ -0,0 +1,11 @@
<%= content_tag('h2', header) if header %>
<% unless options[:selector] %>
<ul>
<% items.each do |item| %>
<li><%= item %></li>
<% end %>
</ul>
<% end %>

View File

@ -0,0 +1,4 @@
<ul>
<li><%= _("Logged as") %> <%= user_details %></li>
<li><%= link_to _("Sign out"), admin_sign_out_path, { :confirm => message } %></li>
</ul>

View File

@ -0,0 +1,15 @@
<div class="pagination">
<% if @items.prev? %>
<%= link_to "&larr; " + _("Previous"), params.merge(:page => @items.prev.number, :anchor => @options[:anchor]) %>
<% else %>
<span class="disabled"><%= "&larr; " + _("Previous") %></span>
<% end %>
<% if @items.next? %>
<%= link_to _("Next") + " &rarr;", params.merge(:page => @items.next.number, :anchor => @options[:anchor]) %>
<% else %>
<span class="disabled"><%= _("Next") + " &rarr;" %></span>
<% end %>
</div>

View File

@ -0,0 +1,13 @@
<%
dom = item.to_dom(:suffix => "#{attribute}_preview" )
%>
<% if has_file_preview %>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$("#<%= dom %>").fancybox();
});
</script>
<% end %>
<a id="<%= dom %>" href="<%= href %>" title="<%= item.to_label %>"><%= content %></a>

View File

@ -0,0 +1,3 @@
<script type="text/javascript">
document.write('<script type="text/javascript" src="<%= admin_quick_edit_path %>?#<%= options.to_query %>" />');
</script>

View File

@ -0,0 +1 @@
<small><%= link_to _("Remove filter") %></small>

View File

@ -0,0 +1,14 @@
<table class="typus">
<tr>
<th colspan="2"><%= _("Resources") %></th>
</tr>
<% resources.each do |resource| %>
<tr class="<%= cycle('even', 'odd') %>">
<td><%= link_to _(resource.titleize.capitalize), :controller => "admin/#{resource.underscore}" %></td>
<td align="right" style="vertical-align: bottom;"></td>
</tr>
<% end %>
</table>

View File

@ -0,0 +1,8 @@
<h2><%= _("Search") %></h2>
<% form_tag url_for(:controller => params[:controller]), :method => :get do %>
<p><input id="search" name="search" type="text" value="<%= params[:search] %>"/></p>
<%= hidden_params.sort.join("\n") %>
<% end %>
<p class="tip"><%= _("Search by") %> <%= search_by.downcase %>.</p>

View File

@ -0,0 +1,5 @@
<tr>
<% headers.each do |header| %>
<th><%= header %></th>
<% end %>
</tr>

View File

@ -0,0 +1,12 @@
<% form_for @item, :url => options, :builder => ActionView::Helpers::FormBuilder, :html => { :multipart => true } do |form| %>
<fieldset class="inputs">
<ol>
<%= build_form(@fields, form) %>
</ol>
</fieldset>
<fieldset class="buttons">
<ol>
<li><%= submit_tag button , :class => 'commit' %></li>
</ol>
</fieldset>
<% end %>

View File

@ -0,0 +1,25 @@
<% content_for :sidebar do %>
<%= typus_block :location => @resource[:self], :partial => 'sidebar' %>
<%= actions %>
<%= search %>
<% end %>
<%= display_link_to_previous if params[:back_to] %>
<h2><%= link_to @resource[:pluralized], :action => 'index' %> &rsaquo;
<%= _("Edit") %></h2>
<%= typus_block :location => @resource[:self], :partial => 'edit' %>
<%
options = { :action => 'update',
:id => @item.id ,
:back_to => params[:back_to],
:resource => params[:resource],
:resource_id => params[:resource_id]}
button = _("Save %{resource}", :resource => @resource[:human_name])
%>
<%= render "form", :options => options, :button => button %>
<%= typus_relationships %>

View File

@ -0,0 +1,21 @@
<% content_for :sidebar do %>
<%= typus_block :location => @resource[:self], :partial => 'sidebar' %>
<%= actions %>
<%= export %>
<%= search %>
<%= filters %>
<% end %>
<h2><%= @resource[:pluralized] %> <%= remove_filter_link %></h2>
<%= typus_block :location => @resource[:self], :partial => 'index' %>
<% unless @items.count.zero? -%>
<%= build_list(@resource[:class], @fields, @items) %>
<%= pagination %>
<% else %>
<div id="flash" class="notice">
<% message = @resource[:class].count.zero? ? "There are no %{records}." : "There are no %{records} under this filter." %>
<p><%= _(message, :records => @resource[:human_name].pluralize.downcase) %></p>
</div>
<% end %>

View File

@ -0,0 +1,22 @@
<% content_for :sidebar do %>
<%= typus_block :location => @resource[:self], :partial => 'sidebar' %>
<%= actions %>
<% end %>
<%= display_link_to_previous if params[:back_to] %>
<h2><%= link_to @resource[:pluralized], :action => 'index' %> &rsaquo;
<%= _("New") %></h2>
<%= typus_block :location => @resource[:self], :partial => 'new' %>
<%
options = { :action => 'create',
:back_to => params[:back_to],
:selected => params[:selected],
:resource => params[:resource],
:resource_id => params[:resource_id] }
button = _("Create %{resource}", :resource => @resource[:human_name])
%>
<%= render "form", :options => options, :button => button %>

View File

@ -0,0 +1,45 @@
<% content_for :sidebar do %>
<%= typus_block :location => @resource[:self], :partial => 'sidebar' %>
<%= actions %>
<%= search %>
<% end %>
<h2><%= link_to @resource[:pluralized], :action => 'index' %> &rsaquo;
<%= _("Show") %></h2>
<%= typus_block :location => @resource[:self], :partial => 'show' %>
<dl>
<%- @fields.each do |field| -%>
<dt><%=h @resource[:class].human_attribute_name(field.first) %></dt>
<%-
data_type = field.last
raw_data = @item.send(field.first)
data = case data_type
when :boolean
boolean_hash = @resource[:class].typus_boolean(field.first)
!raw_data.nil? ? boolean_hash["#{raw_data}".to_sym] : @resource[:class].typus_options_for(:nil)
when :belongs_to
if !raw_data.nil?
controller = raw_data.class.name.extract_resource.pluralize
action = raw_data.class.typus_options_for(:default_action_on_item)
options = { :controller => controller, :action => action, :id => raw_data }
link_to raw_data.to_label, options
else
h(raw_data)
end
when :file
typus_preview(@item, field.first)
when :text
defined?(RDiscount) ? markdown(raw_data) : simple_format(h(raw_data))
when :selector
@item.mapping(field.first)
else
h(raw_data)
end
-%>
<dd><%= !data.blank? ? data : ('&#151;') %></dd>
<%- end -%>
</dl>
<%= typus_relationships %>

View File

@ -0,0 +1 @@
<p><%= link_to 'Typus', 'http://core.typuscms.com/' %> by <%= link_to 'intraducibles.com', 'http://intraducibles.com' %>.</p>

View File

@ -0,0 +1,4 @@
<li>
<%= form.label attribute, label_text, :class => 'inline_label' %>
<%= form.check_box attribute, options %>
</li>

View File

@ -0,0 +1,9 @@
<%
custom = { :include_blank => false }
options.merge!(custom)
%>
<li>
<%= form.label attribute, label_text %>
<%= form.date_select attribute, options, html_options %>
</li>

View File

@ -0,0 +1,9 @@
<%
custom = { :include_blank => false }
options.merge!(custom)
%>
<li>
<%= form.label attribute, label_text %>
<%= form.datetime_select attribute, options, html_options %>
</li>

View File

@ -0,0 +1,19 @@
<%
if @item.send(attribute).exists?
message = _("Remove %{attribute}", :attribute => @item.class.human_attribute_name(attribute).downcase)
label_text << <<-HTML
<small>#{link_to message, { :action => 'detach',
:id => @item.id,
:attachment => attribute },
:confirm => _("Are you sure?")}</small>
HTML
end
%>
<li>
<%= form.label attribute, label_text %>
<%= form.file_field attribute, options %>
<%= typus_preview(@item, attribute) %>
</li>

View File

@ -0,0 +1,4 @@
<li>
<%= form.label attribute, label_text %>
<%= form.password_field attribute, options %>
</li>

View File

@ -0,0 +1,9 @@
<%
values = @resource[:class]::const_get("#{attribute.upcase}")
values = values.invert if values.kind_of?(Hash)
%>
<li>
<%= form.label attribute, label_text %>
<%= form.select attribute, values, options, html_options %>
</li>

View File

@ -0,0 +1,22 @@
<%
# Read only fields.
if @resource[:class].typus_field_options_for(:read_only).to_s.include?(attribute)
custom = { :readonly => 'readonly' }
label_text << " <small>#{_("Read only")}</small>"
end
# Auto generated fields.
if @resource[:class].typus_field_options_for(:auto_generated).include?(attribute)
custom = { :auto_generated => true }
label_text << " <small>#{_("Auto generated")}</small>"
end
options.merge!(custom) if custom
%>
<li>
<%= form.label attribute, label_text %>
<%= form.text_field attribute, options %>
</li>

View File

@ -0,0 +1,9 @@
<%
custom = { :rows => @resource[:class].typus_options_for(:form_rows) }
options = options.merge!(custom)
%>
<li>
<%= form.label attribute, label_text %>
<%= form.text_area attribute, options %>
</li>

View File

@ -0,0 +1,9 @@
<%
custom = { :include_blank => false }
options.merge!(custom)
%>
<li>
<%= form.label attribute, label_text %>
<%= form.time_select attribute, options, html_options %>
</li>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><%= page_title %></title>
<%= stylesheet_link_tag 'admin/reset',
'admin/screen',
'admin/jquery.fancybox-1.3.0' %>
<%= yield :stylesheets -%>
<%= javascript_include_tag 'admin/jquery-1.4.1.min',
'admin/jquery.fancybox-1.3.0.pack',
'admin/application' %>
<%= yield :javascripts -%>
</head>
<body>
<div id="header_wrapper">
<div id="header">
<div class="left">
<%= header %>
</div>
<div class="right">
<%= login_info %>
</div>
<div class="clear"></div>
</div>
</div>
<div id="wrapper">
<div id="content_wrapper">
<div id="content">
<%= display_flash_message %>
<%= yield %>
</div>
<div id="sidebar">
<%= yield :sidebar %>
</div>
<div class="clear"></div>
</div>
</div>
<div id="footer_wrapper">
<div id="footer">
<%= typus_block :location => 'shared', :partial => 'footer' %>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="viewport" content="width=500, initial-scale=0.60, minimum-scale=0.60" />
<title><%= page_title %></title>
<%= stylesheet_link_tag 'admin/reset', :media => 'screen' %>
<%= stylesheet_link_tag 'admin/screen', :media => 'screen' %>
</head>
<body>
<div id="dialog">
<h1><%= Typus::Configuration.options[:app_name] %></h1>
<%= display_flash_message %>
<%= yield %>
</div>
<div id="bottom_dialog">
<%= typus_block :location => 'shared', :partial => 'footer' %>
</div>
</body>
</html>

View File

@ -0,0 +1,9 @@
<% content_for :sidebar do %>
<%= typus_block :location => 'dashboard', :partial => 'sidebar' %>
<% end %>
<h2><%= _("Dashboard") %></h2>
<%= applications %>
<%= resources %>

View File

@ -0,0 +1,16 @@
<% form_for :typus_user, :url => { :action => :recover_password } do |form| %>
<ul>
<li>
<%= form.label :email, Typus.user_class.human_attribute_name(:email) %>
<%= form.text_field :email, :size => 20, :class => 'text' %>
</li>
<li>
<%= submit_tag _("Recover password"), :class => 'button' %> <%= link_to _("I remember my password"), admin_sign_in_path %>
</li>
</ul>
<% end %>

Some files were not shown because too many files have changed in this diff Show More