diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb new file mode 100644 index 00000000..ba97469f --- /dev/null +++ b/app/controllers/admin/base_controller.rb @@ -0,0 +1,27 @@ +class Admin::BaseController < ::ApplicationController + + include Locomotive::Routing::SiteDispatcher + + layout 'admin' + + before_filter :authenticate_account! + + before_filter :require_site + + helper_method :sections + + protected + + def self.sections(main, sub = nil) + write_inheritable_attribute(:sections, { :main => main, :sub => sub }) + end + + def sections(key = nil) + if !key.nil? && key.to_sym == :sub + self.class.read_inheritable_attribute(:sections)[:sub] || self.controller_name.dasherize + else + self.class.read_inheritable_attribute(:sections)[:main] + end + end + +end \ No newline at end of file diff --git a/app/controllers/admin/pages_controller.rb b/app/controllers/admin/pages_controller.rb new file mode 100644 index 00000000..7e2cc315 --- /dev/null +++ b/app/controllers/admin/pages_controller.rb @@ -0,0 +1,8 @@ +class Admin::PagesController < Admin::BaseController + + sections 'contents' + + def index + end + +end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c588fe1..7d9f490a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,11 +1,11 @@ class ApplicationController < ActionController::Base protect_from_forgery - before_filter :set_locale - - protected - - def set_locale - I18n.locale = 'fr' - end + # before_filter :set_locale + # + # protected + # + # def set_locale + # I18n.locale = 'fr' + # end end diff --git a/app/helpers/admin/base_helper.rb b/app/helpers/admin/base_helper.rb new file mode 100644 index 00000000..6f637f44 --- /dev/null +++ b/app/helpers/admin/base_helper.rb @@ -0,0 +1,8 @@ +module Admin::BaseHelper + + def admin_menu_item(name, url) + label = content_tag(:em) + escape_once(' ') + t("admin.shared.menu.#{name}") + content_tag(:li, link_to(label, url), :class => name.dasherize) + end + +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e70987f8..108c796c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,6 +19,10 @@ module ApplicationHelper end end + def nocoffee_tag + link_to content_tag(:em, 'no') + 'Coffee', 'http://www.nocoffee.fr', :id => 'nocoffee' + end + def submit_button_tag(label) content_tag(:button, content_tag(:span, label), :type => 'submit', :class => 'button') end diff --git a/app/views/admin/pages/_form.html.haml b/app/views/admin/pages/_form.html.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/admin/pages/edit.html.haml b/app/views/admin/pages/edit.html.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/admin/pages/index.html.haml b/app/views/admin/pages/index.html.haml new file mode 100644 index 00000000..7bbc51ba --- /dev/null +++ b/app/views/admin/pages/index.html.haml @@ -0,0 +1,5 @@ +- title t('.title') + + +- content_for :submenu do + = render 'admin/shared/contents_menu' diff --git a/app/views/admin/pages/new.html.haml b/app/views/admin/pages/new.html.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/admin/shared/_contents_menu.html.haml b/app/views/admin/shared/_contents_menu.html.haml new file mode 100644 index 00000000..8fec1811 --- /dev/null +++ b/app/views/admin/shared/_contents_menu.html.haml @@ -0,0 +1,3 @@ +%ul + %li.pages + = link_to find_and_preserve('Pages '), '#' \ No newline at end of file diff --git a/app/views/admin/shared/_footer.html.haml b/app/views/admin/shared/_footer.html.haml new file mode 100644 index 00000000..8cd482d3 --- /dev/null +++ b/app/views/admin/shared/_footer.html.haml @@ -0,0 +1,5 @@ +%p.tright + = t('.developed_by') + = nocoffee_tag + = t('.powered_by') + = link_to 'Ruby on Rails', 'http://www.rubyonrails.com', :id => 'powered-by' \ No newline at end of file diff --git a/app/views/admin/shared/_head.html.haml b/app/views/admin/shared/_head.html.haml new file mode 100644 index 00000000..40ee6eaf --- /dev/null +++ b/app/views/admin/shared/_head.html.haml @@ -0,0 +1,13 @@ +%title= escape_once("#{Locomotive.config.name} — #{current_site.name}") + += csrf_meta_tag + += stylesheet_link_tag 'blueprint/screen', :media => 'screen' +/ [if IE] + = stylesheet_link_tag('blueprint/ie', :media => 'screen') + += stylesheet_link_tag 'admin/layout', 'admin/menu', 'admin/buttons', 'admin/formtastic', 'admin/formtastic_changes', 'admin/application', :media => 'screen', :cache => Rails.env.production? + += javascript_include_tag 'jquery', 'jquery.ui', 'rails', :cache => Rails.env.production? + += yield :head \ No newline at end of file diff --git a/app/views/admin/shared/_header.html.haml b/app/views/admin/shared/_header.html.haml new file mode 100644 index 00000000..3d55509c --- /dev/null +++ b/app/views/admin/shared/_header.html.haml @@ -0,0 +1,8 @@ +%h1= link_to current_site.name, '#' + +#global-actions-bar + = t('.welcome', :name => link_to(current_account.name, '#')) + %span= '|' + = link_to t('.see'), '#' + %span= '|' + = link_to t('.logout'), destroy_account_session_url, :confirm => t('admin.messages.confirm') \ No newline at end of file diff --git a/app/views/admin/shared/_menu.html.haml b/app/views/admin/shared/_menu.html.haml new file mode 100644 index 00000000..5f84d5e7 --- /dev/null +++ b/app/views/admin/shared/_menu.html.haml @@ -0,0 +1,5 @@ +%ul#menu + = admin_menu_item('contents', admin_pages_url) + = admin_menu_item('assets', '#') + = admin_menu_item('settings', '#') + %li.clear diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml new file mode 100644 index 00000000..3a90bbe1 --- /dev/null +++ b/app/views/layouts/admin.html.haml @@ -0,0 +1,26 @@ +!!! XML +!!! +%html{ :xmlns => 'http://www.w3.org/1999/xhtml' } + %head + = render 'admin/shared/head' + %body{ :class => sections } + #wrapper + .container + #header + = render 'admin/shared/header' + = render 'admin/shared/menu' + + #submenu + = yield :submenu + + #content + .inner + %h2= title + + #local-actions-bar + = yield :buttons + + = yield + + #footer + = render 'admin/shared/footer' \ No newline at end of file diff --git a/app/views/layouts/login.html.haml b/app/views/layouts/login.html.haml index d7f0c936..d26a458f 100644 --- a/app/views/layouts/login.html.haml +++ b/app/views/layouts/login.html.haml @@ -3,9 +3,11 @@ %html{ :xmlns => 'http://www.w3.org/1999/xhtml' } %head %title= escape_once("#{Locomotive.config.name} — #{current_site.name}") + = stylesheet_link_tag 'blueprint/screen', 'admin/login', :media => 'screen' / [if IE] = stylesheet_link_tag('blueprint/ie', :media => 'screen') + %body #wrapper #light.container diff --git a/config/locales/admin_ui_en.yml b/config/locales/admin_ui_en.yml index 2690b192..ff11cdce 100644 --- a/config/locales/admin_ui_en.yml +++ b/config/locales/admin_ui_en.yml @@ -2,7 +2,7 @@ en: admin: sessions: new: - title: Login to + title: Login link: "I forgot my password" email: "Email" password: "Password" @@ -18,6 +18,26 @@ en: password: "Your new password" password_confirmation: "Confirmation of your new password" + messages: + confirm: Are you sure ? + + shared: + header: + welcome: Welcome, {{name}} + see: See website + logout: Log out + menu: + contents: Contents + assets: Assets + settings: Settings + footer: + developed_by: Developed by + powered_by: and Powered by + + pages: + index: + title: Listing pages + buttons: login: Log in send_password: Send diff --git a/config/locales/admin_ui_fr.yml b/config/locales/admin_ui_fr.yml index 10f75b58..5b1b81d4 100644 --- a/config/locales/admin_ui_fr.yml +++ b/config/locales/admin_ui_fr.yml @@ -2,7 +2,7 @@ fr: admin: sessions: new: - title: Connexion à + title: Connexion link: "J'ai oublié mon mot de passe" email: "Email" password: "Mot de passe" diff --git a/config/routes.rb b/config/routes.rb index 223aa648..99305836 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,6 +15,10 @@ Locomotive::Application.routes.draw do |map| # admin interface for each website namespace 'admin' do + root :to => 'pages#index' + + resources :pages + # get 'login' => 'sessions#new', :as => :new_account_session # post 'login' => 'sessions#create', :as => :account_session # get 'logout' => 'sessions#destroy', :as => :destroy_account_session diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 00000000..dc8ef6d8 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,8 @@ +- scoping +- devise messages in French +- localize devise emails +x admin layout +x logout button +- pages section (CRUD) +- my account section (part of settings) +- snippets section diff --git a/public/images/admin/login/bg.png b/public/images/admin/background/body.png similarity index 100% rename from public/images/admin/login/bg.png rename to public/images/admin/background/body.png diff --git a/public/images/admin/background/footer.png b/public/images/admin/background/footer.png new file mode 100644 index 00000000..d5d779cb Binary files /dev/null and b/public/images/admin/background/footer.png differ diff --git a/public/images/admin/background/light.png b/public/images/admin/background/light.png new file mode 100644 index 00000000..5f501b8a Binary files /dev/null and b/public/images/admin/background/light.png differ diff --git a/public/images/admin/buttons/action-left.png b/public/images/admin/buttons/action-left.png new file mode 100644 index 00000000..c3d3856d Binary files /dev/null and b/public/images/admin/buttons/action-left.png differ diff --git a/public/images/admin/buttons/action-right.png b/public/images/admin/buttons/action-right.png new file mode 100644 index 00000000..40fed74b Binary files /dev/null and b/public/images/admin/buttons/action-right.png differ diff --git a/public/images/admin/buttons/add-left.png b/public/images/admin/buttons/add-left.png new file mode 100644 index 00000000..efd8f942 Binary files /dev/null and b/public/images/admin/buttons/add-left.png differ diff --git a/public/images/admin/buttons/add-right.png b/public/images/admin/buttons/add-right.png new file mode 100644 index 00000000..6f7acd54 Binary files /dev/null and b/public/images/admin/buttons/add-right.png differ diff --git a/public/images/admin/buttons/dark-gray-left.png b/public/images/admin/buttons/dark-gray-left.png new file mode 100644 index 00000000..c4e60fb2 Binary files /dev/null and b/public/images/admin/buttons/dark-gray-left.png differ diff --git a/public/images/admin/buttons/dark-gray-right.png b/public/images/admin/buttons/dark-gray-right.png new file mode 100644 index 00000000..5d83d68b Binary files /dev/null and b/public/images/admin/buttons/dark-gray-right.png differ diff --git a/public/images/admin/buttons/emboss-left.png b/public/images/admin/buttons/emboss-left.png new file mode 100644 index 00000000..9a8bb862 Binary files /dev/null and b/public/images/admin/buttons/emboss-left.png differ diff --git a/public/images/admin/buttons/emboss-right.png b/public/images/admin/buttons/emboss-right.png new file mode 100644 index 00000000..50258f09 Binary files /dev/null and b/public/images/admin/buttons/emboss-right.png differ diff --git a/public/images/admin/buttons/gray-left.png b/public/images/admin/buttons/gray-left.png new file mode 100644 index 00000000..e7c9ae53 Binary files /dev/null and b/public/images/admin/buttons/gray-left.png differ diff --git a/public/images/admin/buttons/gray-right.png b/public/images/admin/buttons/gray-right.png new file mode 100644 index 00000000..d1f2ff33 Binary files /dev/null and b/public/images/admin/buttons/gray-right.png differ diff --git a/public/images/admin/buttons/light-gray-left.png b/public/images/admin/buttons/light-gray-left.png new file mode 100644 index 00000000..4059fad4 Binary files /dev/null and b/public/images/admin/buttons/light-gray-left.png differ diff --git a/public/images/admin/buttons/light-gray-right.png b/public/images/admin/buttons/light-gray-right.png new file mode 100644 index 00000000..a8d3c5b7 Binary files /dev/null and b/public/images/admin/buttons/light-gray-right.png differ diff --git a/public/images/admin/buttons/search.png b/public/images/admin/buttons/search.png new file mode 100644 index 00000000..2b95b301 Binary files /dev/null and b/public/images/admin/buttons/search.png differ diff --git a/public/images/admin/buttons/transparent-left.png b/public/images/admin/buttons/transparent-left.png new file mode 100644 index 00000000..f5a35e20 Binary files /dev/null and b/public/images/admin/buttons/transparent-left.png differ diff --git a/public/images/admin/buttons/transparent-right.png b/public/images/admin/buttons/transparent-right.png new file mode 100644 index 00000000..3921c447 Binary files /dev/null and b/public/images/admin/buttons/transparent-right.png differ diff --git a/public/images/admin/menu/arrow.png b/public/images/admin/menu/arrow.png new file mode 100644 index 00000000..a74ff6a6 Binary files /dev/null and b/public/images/admin/menu/arrow.png differ diff --git a/public/images/admin/menu/blue-bg.png b/public/images/admin/menu/blue-bg.png new file mode 100644 index 00000000..98e2eb95 Binary files /dev/null and b/public/images/admin/menu/blue-bg.png differ diff --git a/public/images/admin/menu/blue-border.png b/public/images/admin/menu/blue-border.png new file mode 100644 index 00000000..a6b34c95 Binary files /dev/null and b/public/images/admin/menu/blue-border.png differ diff --git a/public/images/admin/menu/gray-bg.png b/public/images/admin/menu/gray-bg.png new file mode 100644 index 00000000..f429f47d Binary files /dev/null and b/public/images/admin/menu/gray-bg.png differ diff --git a/public/images/admin/menu/gray-border.png b/public/images/admin/menu/gray-border.png new file mode 100644 index 00000000..10f814ce Binary files /dev/null and b/public/images/admin/menu/gray-border.png differ diff --git a/public/images/admin/menu/green-bg.png b/public/images/admin/menu/green-bg.png new file mode 100644 index 00000000..10e88bde Binary files /dev/null and b/public/images/admin/menu/green-bg.png differ diff --git a/public/images/admin/menu/green-border.png b/public/images/admin/menu/green-border.png new file mode 100644 index 00000000..b335eccc Binary files /dev/null and b/public/images/admin/menu/green-border.png differ diff --git a/public/images/admin/menu/icons/add.png b/public/images/admin/menu/icons/add.png new file mode 100644 index 00000000..4524b972 Binary files /dev/null and b/public/images/admin/menu/icons/add.png differ diff --git a/public/images/admin/menu/icons/bullet.png b/public/images/admin/menu/icons/bullet.png new file mode 100644 index 00000000..2bd6cfc9 Binary files /dev/null and b/public/images/admin/menu/icons/bullet.png differ diff --git a/public/images/admin/menu/icons/folder.png b/public/images/admin/menu/icons/folder.png new file mode 100644 index 00000000..ddc58429 Binary files /dev/null and b/public/images/admin/menu/icons/folder.png differ diff --git a/public/images/admin/menu/icons/settings.png b/public/images/admin/menu/icons/settings.png new file mode 100644 index 00000000..d1b5589d Binary files /dev/null and b/public/images/admin/menu/icons/settings.png differ diff --git a/public/images/admin/menu/left.png b/public/images/admin/menu/left.png new file mode 100644 index 00000000..e3267009 Binary files /dev/null and b/public/images/admin/menu/left.png differ diff --git a/public/images/admin/menu/popup-body.png b/public/images/admin/menu/popup-body.png new file mode 100644 index 00000000..e28d9ca5 Binary files /dev/null and b/public/images/admin/menu/popup-body.png differ diff --git a/public/images/admin/menu/popup-footer.png b/public/images/admin/menu/popup-footer.png new file mode 100644 index 00000000..6381c33d Binary files /dev/null and b/public/images/admin/menu/popup-footer.png differ diff --git a/public/images/admin/menu/popup-header.png b/public/images/admin/menu/popup-header.png new file mode 100644 index 00000000..aba29e82 Binary files /dev/null and b/public/images/admin/menu/popup-header.png differ diff --git a/public/images/admin/menu/right.png b/public/images/admin/menu/right.png new file mode 100644 index 00000000..cbee52fb Binary files /dev/null and b/public/images/admin/menu/right.png differ diff --git a/public/images/admin/menu/shadow.png b/public/images/admin/menu/shadow.png new file mode 100644 index 00000000..6501a8d6 Binary files /dev/null and b/public/images/admin/menu/shadow.png differ diff --git a/public/images/admin/menu/top-left.png b/public/images/admin/menu/top-left.png new file mode 100644 index 00000000..3906e56a Binary files /dev/null and b/public/images/admin/menu/top-left.png differ diff --git a/public/images/admin/menu/top.png b/public/images/admin/menu/top.png new file mode 100644 index 00000000..e91fb3cf Binary files /dev/null and b/public/images/admin/menu/top.png differ diff --git a/public/images/nocoffee.gif b/public/images/nocoffee.gif new file mode 100644 index 00000000..7c246a55 Binary files /dev/null and b/public/images/nocoffee.gif differ diff --git a/public/javascripts/controls.js b/public/javascripts/controls.js deleted file mode 100644 index ca29aefd..00000000 --- a/public/javascripts/controls.js +++ /dev/null @@ -1,963 +0,0 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com) -// Contributors: -// Richard Livsey -// Rahul Bhargava -// Rob Wills -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// Autocompleter.Base handles all the autocompletion functionality -// that's independent of the data source for autocompletion. This -// includes drawing the autocompletion menu, observing keyboard -// and mouse events, and similar. -// -// Specific autocompleters need to provide, at the very least, -// a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method -// should get the text for which to provide autocompletion by -// invoking this.getToken(), NOT by directly accessing -// this.element.value. This is to allow incremental tokenized -// autocompletion. Specific auto-completion logic (AJAX, etc) -// belongs in getUpdatedChoices. -// -// Tokenized incremental autocompletion is enabled automatically -// when an autocompleter is instantiated with the 'tokens' option -// in the options parameter, e.g.: -// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -// will incrementally autocomplete with a comma as the token. -// Additionally, ',' in the above example can be replaced with -// a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most -// useful when one of the tokens is \n (a newline), as it -// allows smart autocompletion after linebreaks. - -if(typeof Effect == 'undefined') - throw("controls.js requires including script.aculo.us' effects.js library"); - -var Autocompleter = { }; -Autocompleter.Base = Class.create({ - baseInitialize: function(element, update, options) { - element = $(element); - this.element = element; - this.update = $(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - this.oldElementValue = this.element.value; - - if(this.setOptions) - this.setOptions(options); - else - this.options = options || { }; - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || - function(element, update){ - if(!update.style.position || update.style.position=='absolute') { - update.style.position = 'absolute'; - Position.clone(element, update, { - setHeight: false, - offsetTop: element.offsetHeight - }); - } - Effect.Appear(update,{duration:0.15}); - }; - this.options.onHide = this.options.onHide || - function(element, update){ new Effect.Fade(update,{duration:0.15}) }; - - if(typeof(this.options.tokens) == 'string') - this.options.tokens = new Array(this.options.tokens); - // Force carriage returns as token delimiters anyway - if (!this.options.tokens.include('\n')) - this.options.tokens.push('\n'); - - this.observer = null; - - this.element.setAttribute('autocomplete','off'); - - Element.hide(this.update); - - Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); - Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); - }, - - show: function() { - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); - if(!this.iefix && - (Prototype.Browser.IE) && - (Element.getStyle(this.update, 'position')=='absolute')) { - new Insertion.After(this.update, - ''); - this.iefix = $(this.update.id+'_iefix'); - } - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); - }, - - fixIEOverlapping: function() { - Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - }, - - hide: function() { - this.stopIndicator(); - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); - if(this.iefix) Element.hide(this.iefix); - }, - - startIndicator: function() { - if(this.options.indicator) Element.show(this.options.indicator); - }, - - stopIndicator: function() { - if(this.options.indicator) Element.hide(this.options.indicator); - }, - - onKeyPress: function(event) { - if(this.active) - switch(event.keyCode) { - case Event.KEY_TAB: - case Event.KEY_RETURN: - this.selectEntry(); - Event.stop(event); - case Event.KEY_ESC: - this.hide(); - this.active = false; - Event.stop(event); - return; - case Event.KEY_LEFT: - case Event.KEY_RIGHT: - return; - case Event.KEY_UP: - this.markPrevious(); - this.render(); - Event.stop(event); - return; - case Event.KEY_DOWN: - this.markNext(); - this.render(); - Event.stop(event); - return; - } - else - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || - (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; - - this.changed = true; - this.hasFocus = true; - - if(this.observer) clearTimeout(this.observer); - this.observer = - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); - }, - - activate: function() { - this.changed = false; - this.hasFocus = true; - this.getUpdatedChoices(); - }, - - onHover: function(event) { - var element = Event.findElement(event, 'LI'); - if(this.index != element.autocompleteIndex) - { - this.index = element.autocompleteIndex; - this.render(); - } - Event.stop(event); - }, - - onClick: function(event) { - var element = Event.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - - onBlur: function(event) { - // needed to make click events working - setTimeout(this.hide.bind(this), 250); - this.hasFocus = false; - this.active = false; - }, - - render: function() { - if(this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) - this.index==i ? - Element.addClassName(this.getEntry(i),"selected") : - Element.removeClassName(this.getEntry(i),"selected"); - if(this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - - markPrevious: function() { - if(this.index > 0) this.index--; - else this.index = this.entryCount-1; - this.getEntry(this.index).scrollIntoView(true); - }, - - markNext: function() { - if(this.index < this.entryCount-1) this.index++; - else this.index = 0; - this.getEntry(this.index).scrollIntoView(false); - }, - - getEntry: function(index) { - return this.update.firstChild.childNodes[index]; - }, - - getCurrentEntry: function() { - return this.getEntry(this.index); - }, - - selectEntry: function() { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - - updateElement: function(selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = $(selectedElement).select('.' + this.options.select) || []; - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); - } else - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - - var bounds = this.getTokenBounds(); - if (bounds[0] != -1) { - var newValue = this.element.value.substr(0, bounds[0]); - var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = newValue + value + this.element.value.substr(bounds[1]); - } else { - this.element.value = value; - } - this.oldElementValue = this.element.value; - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - }, - - updateChoices: function(choices) { - if(!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - Element.cleanWhitespace(this.update); - Element.cleanWhitespace(this.update.down()); - - if(this.update.firstChild && this.update.down().childNodes) { - this.entryCount = - this.update.down().childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - this.index = 0; - - if(this.entryCount==1 && this.options.autoSelect) { - this.selectEntry(); - this.hide(); - } else { - this.render(); - } - } - }, - - addObservers: function(element) { - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); - Event.observe(element, "click", this.onClick.bindAsEventListener(this)); - }, - - onObserverEvent: function() { - this.changed = false; - this.tokenBounds = null; - if(this.getToken().length>=this.options.minChars) { - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - this.oldElementValue = this.element.value; - }, - - getToken: function() { - var bounds = this.getTokenBounds(); - return this.element.value.substring(bounds[0], bounds[1]).strip(); - }, - - getTokenBounds: function() { - if (null != this.tokenBounds) return this.tokenBounds; - var value = this.element.value; - if (value.strip().empty()) return [-1, 0]; - var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); - var offset = (diff == this.oldElementValue.length ? 1 : 0); - var prevTokenPos = -1, nextTokenPos = value.length; - var tp; - for (var index = 0, l = this.options.tokens.length; index < l; ++index) { - tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); - if (tp > prevTokenPos) prevTokenPos = tp; - tp = value.indexOf(this.options.tokens[index], diff + offset); - if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; - } - return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); - } -}); - -Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { - var boundary = Math.min(newS.length, oldS.length); - for (var index = 0; index < boundary; ++index) - if (newS[index] != oldS[index]) - return index; - return boundary; -}; - -Ajax.Autocompleter = Class.create(Autocompleter.Base, { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - this.startIndicator(); - - var entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(Autocompleter.Base, { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
=0))l||m.push(v);else if(l)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,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.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,l){return!!k(l[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,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l =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 l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=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(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l ";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q =0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f
0)for(var j=d;j 0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e -1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.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(qa(a[0])||qa(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);eb.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||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.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===w||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 Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"+d+">"},F={option:[1,""],legend:[1,""],thead:[1," ","
"],tr:[2,"","
"],td:[3,""],col:[2,"
"," "],area:[1,""],_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
"," ",""];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!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(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}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},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(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}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);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e 0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===" "&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.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 w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;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= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,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?i():c.swap(a,ob,i);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=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$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(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=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=j}}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 sb=J(),tb=/