Commit 90efe3ca9da72beb3c46a6e347253a5bedd94c2a
Committed by
Joenio Costa
1 parent
2836c18c
Exists in
master
and in
8 other branches
Enhancing edition of product
Fixing categories selection and fixing width of sideboxes in leftbar and rightbar templates Added themes to jquery-ui (ActionItem1392)
Showing
88 changed files
with
2905 additions
and
196 deletions
Show diff stats
app/controllers/my_profile/manage_products_controller.rb
| 1 | 1 | class ManageProductsController < ApplicationController |
| 2 | 2 | needs_profile |
| 3 | 3 | |
| 4 | - protect 'manage_products', :profile | |
| 4 | + protect 'manage_products', :profile, :except => [:show] | |
| 5 | 5 | before_filter :check_environment_feature |
| 6 | + before_filter :login_required, :except => [:show] | |
| 6 | 7 | |
| 7 | 8 | protected |
| 9 | + | |
| 8 | 10 | def check_environment_feature |
| 9 | 11 | if profile.environment.enabled?('disable_products_for_enterprises') |
| 10 | 12 | render_not_found |
| ... | ... | @@ -13,6 +15,7 @@ class ManageProductsController < ApplicationController |
| 13 | 15 | end |
| 14 | 16 | |
| 15 | 17 | public |
| 18 | + | |
| 16 | 19 | def index |
| 17 | 20 | @products = @profile.products |
| 18 | 21 | @consumptions = @profile.consumptions |
| ... | ... | @@ -51,15 +54,34 @@ class ManageProductsController < ApplicationController |
| 51 | 54 | end |
| 52 | 55 | |
| 53 | 56 | def edit |
| 54 | - @object = @product = @profile.products.find(params[:id]) | |
| 55 | - @current_category = @product.product_category | |
| 56 | - @categories = @current_category.nil? ? [] : @current_category.children | |
| 57 | + @product = @profile.products.find(params[:id]) | |
| 58 | + field = params[:field] | |
| 57 | 59 | if request.post? |
| 58 | - if @product.update_attributes(params[:product]) | |
| 59 | - flash[:notice] = _('Product succesfully updated') | |
| 60 | - redirect_back_or_default :action => 'show', :id => @product | |
| 61 | - else | |
| 60 | + begin | |
| 61 | + @product.update_attributes!(params[:product]) | |
| 62 | + render :partial => "display_#{field}", :locals => {:product => @product} | |
| 63 | + rescue Exception => e | |
| 64 | + render :partial => "edit_#{field}", :locals => {:product => @product, :errors => true} | |
| 65 | + end | |
| 66 | + else | |
| 67 | + render :partial => "edit_#{field}", :locals => {:product => @product, :errors => false} | |
| 68 | + end | |
| 69 | + end | |
| 70 | + | |
| 71 | + def edit_category | |
| 72 | + @product = @profile.products.find(params[:id]) | |
| 73 | + @category = @product.product_category | |
| 74 | + @categories = ProductCategory.top_level_for(environment) | |
| 75 | + @edit = true | |
| 76 | + @level = @category.level | |
| 77 | + if request.post? | |
| 78 | + begin | |
| 79 | + @product.update_attributes!(params[:product]) | |
| 80 | + render :partial => 'shared/redirect_via_javascript', | |
| 81 | + :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } | |
| 82 | + rescue Exception => e | |
| 62 | 83 | flash[:notice] = _('Could not update the product') |
| 84 | + render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } | |
| 63 | 85 | end |
| 64 | 86 | end |
| 65 | 87 | end | ... | ... |
app/controllers/public/catalog_controller.rb
| 1 | 1 | class CatalogController < PublicController |
| 2 | 2 | needs_profile |
| 3 | + | |
| 3 | 4 | before_filter :check_enterprise_and_environment |
| 4 | 5 | |
| 5 | 6 | def index |
| 6 | 7 | @products = @profile.products |
| 7 | 8 | end |
| 8 | 9 | |
| 9 | - def show | |
| 10 | - @product = @profile.products.find(params[:id]) | |
| 11 | - end | |
| 12 | - | |
| 13 | 10 | protected |
| 14 | 11 | def check_enterprise_and_environment |
| 15 | 12 | unless @profile.kind_of?(Enterprise) && !@profile.environment.enabled?('disable_products_for_enterprises') | ... | ... |
app/helpers/application_helper.rb
| ... | ... | @@ -907,7 +907,7 @@ module ApplicationHelper |
| 907 | 907 | (@section ? @section.title + ' - ' : '') + |
| 908 | 908 | (@toc ? _('Online Manual') + ' - ' : '') + |
| 909 | 909 | environment.name + |
| 910 | - (@category ? "→ #{@category.full_name}" : '') | |
| 910 | + (@category ? " - #{@category.full_name}" : '') | |
| 911 | 911 | end |
| 912 | 912 | |
| 913 | 913 | def noosfero_javascript |
| ... | ... | @@ -921,6 +921,7 @@ module ApplicationHelper |
| 921 | 921 | 'lightbox', |
| 922 | 922 | 'colorpicker', |
| 923 | 923 | pngfix_stylesheet_path, |
| 924 | + 'jquery.ui/sunny/jquery-ui-1.8.2.custom', | |
| 924 | 925 | ] |
| 925 | 926 | end |
| 926 | 927 | |
| ... | ... | @@ -960,13 +961,16 @@ module ApplicationHelper |
| 960 | 961 | text_field_tag(name, value, options.merge(:class => 'colorpicker_field')) |
| 961 | 962 | end |
| 962 | 963 | |
| 963 | - # for now force currency to Brazillian format, like: "12.345,20" | |
| 964 | - def float_to_currency(price) | |
| 965 | - number_to_currency(price, :unit => 'R$', :separator => ',', :delimiter => '.') | |
| 966 | - end | |
| 967 | - | |
| 968 | 964 | def ui_icon(icon_type) |
| 969 | 965 | "<span class='ui-icon ui-icon-#{icon_type}' style='float:left; margin-right:7px;'></span>" |
| 970 | 966 | end |
| 971 | 967 | |
| 968 | + def ui_button(label, url, html_options = {}) | |
| 969 | + link_to(label, url, html_options.merge(:class => 'ui_button fg-button')) | |
| 970 | + end | |
| 971 | + | |
| 972 | + def ui_button_to_remote(label, options, html_options = {}) | |
| 973 | + link_to_remote(label, options, html_options.merge(:class => 'ui_button fg-button')) | |
| 974 | + end | |
| 975 | + | |
| 972 | 976 | end | ... | ... |
app/helpers/catalog_helper.rb
| 1 | 1 | module CatalogHelper |
| 2 | 2 | |
| 3 | 3 | include DisplayHelper |
| 4 | +include ManageProductsHelper | |
| 4 | 5 | |
| 5 | 6 | def display_products_list(profile, products) |
| 6 | 7 | data = '' |
| ... | ... | @@ -19,7 +20,7 @@ include DisplayHelper |
| 19 | 20 | content_tag('h1', _('Products/Services')) + content_tag('ul', data, :id => 'product_list') |
| 20 | 21 | end |
| 21 | 22 | |
| 22 | -private | |
| 23 | + private | |
| 23 | 24 | |
| 24 | 25 | def product_category_name(profile, product_category) |
| 25 | 26 | if profile.enabled? | ... | ... |
app/helpers/display_helper.rb
| ... | ... | @@ -2,7 +2,7 @@ module DisplayHelper |
| 2 | 2 | |
| 3 | 3 | def link_to_product(product, opts={}) |
| 4 | 4 | return _('No product') unless product |
| 5 | - target = product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'catalog', :action => 'show', :id => product) : product.enterprise.url | |
| 5 | + target = product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url | |
| 6 | 6 | link_to content_tag( 'span', product.name ), |
| 7 | 7 | target, |
| 8 | 8 | opts | ... | ... |
app/helpers/manage_products_helper.rb
| ... | ... | @@ -49,12 +49,52 @@ module ManageProductsHelper |
| 49 | 49 | hierarchy.reverse.join(options[:separator] || ' → ') |
| 50 | 50 | end |
| 51 | 51 | |
| 52 | - def options_for_select_categories(categories) | |
| 52 | + def options_for_select_categories(categories, selected = nil) | |
| 53 | 53 | categories.sort_by{|cat| cat.name.transliterate}.map do |category| |
| 54 | - "<option value='#{category.id}'>#{category.name + (category.leaf? ? '': ' »')}</option>" | |
| 54 | + selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '') | |
| 55 | + "<option value='#{category.id}' #{selected_attribute}>#{category.name + (category.leaf? ? '': ' »')}</option>" | |
| 55 | 56 | end.join("\n") |
| 56 | 57 | end |
| 57 | 58 | |
| 59 | + def build_selects_for_ancestors(ancestors, last_level) | |
| 60 | + current_category = ancestors.shift | |
| 61 | + if current_category.nil? | |
| 62 | + content_tag('div', '<!-- no categories -->', | |
| 63 | + :class => 'categories_container', | |
| 64 | + :id => "categories_container_level#{ last_level }" | |
| 65 | + ) | |
| 66 | + else | |
| 67 | + content_tag('div', | |
| 68 | + select_tag('category_id', | |
| 69 | + options_for_select_categories(current_category.siblings + [current_category], current_category), | |
| 70 | + :size => 10, | |
| 71 | + :onchange => remote_function_to_update_categories_selection("categories_container_level#{ current_category.level + 1 }", :with => "'category_id=' + this.value") | |
| 72 | + ) + | |
| 73 | + build_selects_for_ancestors(ancestors, last_level), | |
| 74 | + :class => 'categories_container', | |
| 75 | + :id => "categories_container_level#{ current_category.level }" | |
| 76 | + ) | |
| 77 | + end | |
| 78 | + end | |
| 79 | + | |
| 80 | + def selects_for_all_ancestors(current_category) | |
| 81 | + build_selects_for_ancestors(current_category.ancestors.reverse + [current_category], current_category.level + 1) | |
| 82 | + end | |
| 83 | + | |
| 84 | + def select_for_new_category | |
| 85 | + content_tag('div', | |
| 86 | + render(:partial => 'categories_for_selection'), | |
| 87 | + :class => 'categories_container', | |
| 88 | + :id => 'categories_container_level0' | |
| 89 | + ) | |
| 90 | + end | |
| 91 | + | |
| 92 | + def categories_container(field_id_html, categories_selection_html, hierarchy_html = '') | |
| 93 | + field_id_html + | |
| 94 | + content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') + | |
| 95 | + content_tag('div', categories_selection_html, :id => 'categories_container_wrapper') | |
| 96 | + end | |
| 97 | + | |
| 58 | 98 | def select_for_categories(categories, level = 0) |
| 59 | 99 | if categories.empty? |
| 60 | 100 | content_tag('div', '', :id => 'no_subcategories') |
| ... | ... | @@ -68,4 +108,98 @@ module ManageProductsHelper |
| 68 | 108 | end |
| 69 | 109 | end |
| 70 | 110 | |
| 111 | + def edit_product_link(product, field, label, html_options = {}) | |
| 112 | + return '' unless (user && user.has_permission?('manage_products', profile)) | |
| 113 | + options = html_options.merge(:id => 'link-edit-product-' + field) | |
| 114 | + | |
| 115 | + link_to_remote(label, | |
| 116 | + {:update => "product-#{field}", | |
| 117 | + :url => { :controller => 'manage_products', :action => "edit", :id => product.id, :field => field }, | |
| 118 | + :method => :get}, | |
| 119 | + options) | |
| 120 | + end | |
| 121 | + | |
| 122 | + def edit_product_button(product, field, label, html_options = {}) | |
| 123 | + the_class = 'button with-text icon-edit' | |
| 124 | + if html_options.has_key?(:class) | |
| 125 | + the_class << ' ' << html_options[:class] | |
| 126 | + end | |
| 127 | + edit_product_link(product, field, label, html_options.merge(:class => the_class)) | |
| 128 | + end | |
| 129 | + | |
| 130 | + def edit_product_ui_button(product, field, label, html_options = {}) | |
| 131 | + return '' unless (user && user.has_permission?('manage_products', profile)) | |
| 132 | + options = html_options.merge(:id => 'edit-product-button-ui-' + field) | |
| 133 | + | |
| 134 | + ui_button_to_remote(label, | |
| 135 | + {:update => "product-#{field}", | |
| 136 | + :url => { :controller => 'manage_products', :action => "edit", :id => product.id, :field => field }, | |
| 137 | + :complete => "$('edit-product-button-ui-#{field}').hide()", | |
| 138 | + :method => :get}, | |
| 139 | + options) | |
| 140 | + end | |
| 141 | + | |
| 142 | + def cancel_edit_product_link(product, field, html_options = {}) | |
| 143 | + return '' unless (user && user.has_permission?('manage_products', profile)) | |
| 144 | + button_to_function(:cancel, _('Cancel'), nil, html_options) do |page| | |
| 145 | + page.replace_html "product-#{field}", :partial => "display_#{field}", :locals => {:product => product} | |
| 146 | + end | |
| 147 | + end | |
| 148 | + | |
| 149 | + def edit_product_category_link(product, html_options = {}) | |
| 150 | + return '' unless (user && user.has_permission?('manage_products', profile)) | |
| 151 | + options = html_options.merge(:id => 'link-edit-product-category') | |
| 152 | + link_to(_('Change category'), { :action => 'edit_category', :id => product.id}, options) | |
| 153 | + end | |
| 154 | + | |
| 155 | + def float_to_currency(value) | |
| 156 | + number_to_currency(value, :unit => environment.currency_unit, :separator => environment.currency_separator, :delimiter => environment.currency_delimiter, :format => "%u %n") | |
| 157 | + end | |
| 158 | + | |
| 159 | + def display_value(product) | |
| 160 | + price = product.price | |
| 161 | + unless price.blank? || price.zero? | |
| 162 | + unit = product.unit | |
| 163 | + return '' if unit.blank? | |
| 164 | + discount = product.discount | |
| 165 | + if discount.blank? || discount.zero? | |
| 166 | + display_price(_('Price: '), price, unit) | |
| 167 | + else | |
| 168 | + display_price_with_discount(price, unit, product.price_with_discount) | |
| 169 | + end | |
| 170 | + else | |
| 171 | + '' | |
| 172 | + end | |
| 173 | + end | |
| 174 | + | |
| 175 | + def display_price(label, price, unit) | |
| 176 | + content_tag('span', label, :class => 'field-name') + | |
| 177 | + content_tag('span', float_to_currency(price), :class => 'field-value') + | |
| 178 | + ' (%s)' % unit | |
| 179 | + end | |
| 180 | + | |
| 181 | + def display_price_with_discount(price, unit, price_with_discount) | |
| 182 | + original_value = content_tag('span', float_to_currency(price), :class => 'field-value') | |
| 183 | + discount_value = display_price(_('On sale: '), price_with_discount, unit) | |
| 184 | + content_tag('span', _('List price: '), :class => 'field-name') + original_value + "<p/>" + discount_value | |
| 185 | + end | |
| 186 | + | |
| 187 | + def display_qualifiers(product) | |
| 188 | + data = '' | |
| 189 | + product.product_qualifiers.each do |pq| | |
| 190 | + certified_by = pq.certifier ? _(' certified by %s') % link_to(pq.certifier.name, pq.certifier.link) : '' | |
| 191 | + data << content_tag('li', '✔ ' + pq.qualifier.name + certified_by, :class => 'product-qualifiers-item') | |
| 192 | + end | |
| 193 | + content_tag('ul', data, :id => 'product-qualifiers') | |
| 194 | + end | |
| 195 | + | |
| 196 | + def checkboxes_qualifiers(product, qualifier) | |
| 197 | + check_box_tag("product[qualifiers_list][#{qualifier.id}][qualifier_id]", qualifier.id, product.qualifiers.include?(qualifier)) + qualifier.name | |
| 198 | + end | |
| 199 | + | |
| 200 | + def select_certifiers(product, qualifier, certifiers) | |
| 201 | + relation = product.product_qualifiers.find(:first, :conditions => {:qualifier_id => qualifier.id}) | |
| 202 | + selected = relation.nil? ? 0 : relation.certifier_id | |
| 203 | + select_tag("product[qualifiers_list][#{qualifier.id}][certifier_id]", options_for_select([[_('Select...') , 0 ]] + certifiers.map {|c|[c.name, c.id]}, selected)) | |
| 204 | + end | |
| 71 | 205 | end | ... | ... |
app/models/environment.rb
| ... | ... | @@ -152,6 +152,9 @@ class Environment < ActiveRecord::Base |
| 152 | 152 | |
| 153 | 153 | has_many :roles |
| 154 | 154 | |
| 155 | + has_many :qualifiers | |
| 156 | + has_many :certifiers | |
| 157 | + | |
| 155 | 158 | acts_as_accessible |
| 156 | 159 | |
| 157 | 160 | def superior_intances |
| ... | ... | @@ -209,6 +212,10 @@ class Environment < ActiveRecord::Base |
| 209 | 212 | settings_items :help_message_to_add_enterprise, :type => String, :default => '' |
| 210 | 213 | settings_items :tip_message_enterprise_activation_question, :type => String, :default => '' |
| 211 | 214 | |
| 215 | + settings_items :currency_unit, :type => String, :default => '$' | |
| 216 | + settings_items :currency_separator, :type => String, :default => '.' | |
| 217 | + settings_items :currency_delimiter, :type => String, :default => ',' | |
| 218 | + | |
| 212 | 219 | def news_amount_by_folder=(amount) |
| 213 | 220 | settings[:news_amount_by_folder] = amount.to_i |
| 214 | 221 | end | ... | ... |
app/models/product.rb
| ... | ... | @@ -2,10 +2,14 @@ class Product < ActiveRecord::Base |
| 2 | 2 | belongs_to :enterprise |
| 3 | 3 | belongs_to :product_category |
| 4 | 4 | has_many :product_categorizations |
| 5 | + has_many :product_qualifiers | |
| 6 | + has_many :qualifiers, :through => :product_qualifiers | |
| 5 | 7 | |
| 6 | 8 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true |
| 7 | 9 | validates_presence_of :product_category |
| 10 | + | |
| 8 | 11 | validates_numericality_of :price, :allow_nil => true |
| 12 | + validates_numericality_of :discount, :allow_nil => true | |
| 9 | 13 | |
| 10 | 14 | after_update :save_image |
| 11 | 15 | |
| ... | ... | @@ -31,10 +35,36 @@ class Product < ActiveRecord::Base |
| 31 | 35 | |
| 32 | 36 | acts_as_searchable :fields => [ :name, :description, :category_full_name ] |
| 33 | 37 | |
| 34 | - xss_terminate :only => [ :name, :description ], :on => 'validation' | |
| 38 | + xss_terminate :only => [ :name ], :on => 'validation' | |
| 39 | + xss_terminate :only => [ :description ], :with => 'white_list', :on => 'validation' | |
| 35 | 40 | |
| 36 | 41 | acts_as_mappable |
| 37 | - | |
| 42 | + | |
| 43 | + def self.units | |
| 44 | + { | |
| 45 | + _('Litre') => 'litre', | |
| 46 | + _('Kilo') => 'kilo', | |
| 47 | + _('Meter') => 'meter', | |
| 48 | + _('Unit') => 'unit', | |
| 49 | + } | |
| 50 | + end | |
| 51 | + | |
| 52 | + def name | |
| 53 | + self[:name].blank? ? category_name : self[:name] | |
| 54 | + end | |
| 55 | + | |
| 56 | + def name=(value) | |
| 57 | + if (value == category_name) | |
| 58 | + self[:name] = nil | |
| 59 | + else | |
| 60 | + self[:name] = value | |
| 61 | + end | |
| 62 | + end | |
| 63 | + | |
| 64 | + def default_image(size='thumb') | |
| 65 | + '/images/icons-app/product-default-pic-%s.png' % size | |
| 66 | + end | |
| 67 | + | |
| 38 | 68 | def category_full_name |
| 39 | 69 | product_category ? product_category.full_name.split('/') : nil |
| 40 | 70 | end |
| ... | ... | @@ -60,13 +90,21 @@ class Product < ActiveRecord::Base |
| 60 | 90 | end |
| 61 | 91 | |
| 62 | 92 | def url |
| 63 | - enterprise.public_profile_url.merge(:controller => 'catalog', :action => 'show', :id => id) | |
| 93 | + enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => id) | |
| 64 | 94 | end |
| 65 | 95 | |
| 66 | 96 | def public? |
| 67 | 97 | enterprise.public_profile |
| 68 | 98 | end |
| 69 | 99 | |
| 100 | + def formatted_value(value) | |
| 101 | + ("%.2f" % self[value]).to_s.gsub('.', enterprise.environment.currency_separator) if self[value] | |
| 102 | + end | |
| 103 | + | |
| 104 | + def price_with_discount | |
| 105 | + price - discount if discount | |
| 106 | + end | |
| 107 | + | |
| 70 | 108 | def price=(value) |
| 71 | 109 | if value.is_a?(String) |
| 72 | 110 | super(currency_to_float(value)) |
| ... | ... | @@ -75,6 +113,14 @@ class Product < ActiveRecord::Base |
| 75 | 113 | end |
| 76 | 114 | end |
| 77 | 115 | |
| 116 | + def discount=(value) | |
| 117 | + if value.is_a?(String) | |
| 118 | + super(currency_to_float(value)) | |
| 119 | + else | |
| 120 | + super(value) | |
| 121 | + end | |
| 122 | + end | |
| 123 | + | |
| 78 | 124 | def currency_to_float( num ) |
| 79 | 125 | if num.count('.') == 1 && num.count(',') == 0 |
| 80 | 126 | # number like "12.34" |
| ... | ... | @@ -99,4 +145,17 @@ class Product < ActiveRecord::Base |
| 99 | 145 | return num.tr(',.','').to_f |
| 100 | 146 | end |
| 101 | 147 | |
| 148 | + def has_basic_info? | |
| 149 | + %w[description price].each do |field| | |
| 150 | + return true if !self.send(field).blank? | |
| 151 | + end | |
| 152 | + false | |
| 153 | + end | |
| 154 | + | |
| 155 | + def qualifiers_list=(qualifiers) | |
| 156 | + self.product_qualifiers.delete_all | |
| 157 | + qualifiers.each do |item| | |
| 158 | + self.product_qualifiers.create(item[1]) if item[1].has_key?('qualifier_id') | |
| 159 | + end | |
| 160 | + end | |
| 102 | 161 | end | ... | ... |
app/models/products_block.rb
| ... | ... | @@ -20,7 +20,7 @@ class ProductsBlock < Block |
| 20 | 20 | block_title(title) + |
| 21 | 21 | content_tag( |
| 22 | 22 | 'ul', |
| 23 | - products.map {|product| content_tag('li', link_to(product.name, product.url, :style => 'background-image:url(%s)' % ( product.image ? product.image.public_filename(:minor) : '/images/icons-app/product-default-pic-minor.png' )), :class => 'product' )} | |
| 23 | + products.map {|product| content_tag('li', link_to(product.name, product.url, :style => 'background-image:url(%s)' % ( product.image ? product.image.public_filename(:minor) : product.default_image('minor'))), :class => 'product' )} | |
| 24 | 24 | ) |
| 25 | 25 | end |
| 26 | 26 | ... | ... |
app/models/profile.rb
| ... | ... | @@ -386,7 +386,7 @@ class Profile < ActiveRecord::Base |
| 386 | 386 | |
| 387 | 387 | def url_options |
| 388 | 388 | options = { :host => default_hostname, :profile => (own_hostname ? nil : self.identifier) } |
| 389 | - Noosfero.url_options.merge(options) | |
| 389 | + options.merge(Noosfero.url_options.merge(options)) | |
| 390 | 390 | end |
| 391 | 391 | |
| 392 | 392 | private :generate_url, :url_options | ... | ... |
app/views/catalog/show.rhtml
| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | -<div id="show_product"> | |
| 2 | - | |
| 3 | -<h1> <%= @product.name %> </h1> | |
| 4 | - | |
| 5 | -<%= image_tag @product.image.public_filename, :class => 'product-pic' if @product.image %> | |
| 6 | - | |
| 7 | -<div class="product_description"> | |
| 8 | -<%= txt2html @product.description if @product.description %> | |
| 9 | -</div> | |
| 10 | - | |
| 11 | -<% if @product.price %> | |
| 12 | - <p class="product_price"> | |
| 13 | - <%= _('Price: %s') % ( "<strong>%.2f</strong>" % @product.price) %> | |
| 14 | - </p> | |
| 15 | -<% end %> | |
| 16 | - | |
| 17 | -<p class="product_category"> | |
| 18 | -<%= _('Category: %s ') % link_to_product_category(@product.product_category) %> | |
| 19 | -</p> | |
| 20 | - | |
| 21 | -<% button_bar do %> | |
| 22 | - <%= button :back, _("%s's products/services listing") % profile.name, :action => 'index', :id => nil %> | |
| 23 | -<% end %> | |
| 24 | - | |
| 25 | -</div> |
app/views/cms/_upload_file_form.rhtml
app/views/layouts/_javascript.rhtml
| 1 | -<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'colorpicker', 'colorpicker-noosfero', 'reflection', :cache => 'cache-general' %> | |
| 1 | +<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'colorpicker', 'colorpicker-noosfero', 'reflection', :cache => 'cache-general' %> | ... | ... |
app/views/layouts/application.rhtml
| ... | ... | @@ -15,7 +15,6 @@ |
| 15 | 15 | <%= |
| 16 | 16 | # Load the principal css files: |
| 17 | 17 | stylesheet_link_tag(noosfero_stylesheets, :cache => 'cache') + |
| 18 | - stylesheet_link_tag('jquery.ui/smoothness/jquery-ui-1.8.2.custom') + | |
| 19 | 18 | stylesheet_import( %w( common help menu article button search blocks forms login-box ), |
| 20 | 19 | :themed_source => true ) + "\n" + |
| 21 | 20 | import_blocks_stylesheets(:themed_source => true) + "\n" + |
| ... | ... | @@ -126,5 +125,10 @@ |
| 126 | 125 | app/views/shared/noosfero_layout_features.rhtml! %> |
| 127 | 126 | <%= noosfero_layout_features %> |
| 128 | 127 | |
| 128 | + <script type='text/javascript'> | |
| 129 | + // transform all element with class ui_button in a jQuery UI button | |
| 130 | + render_jquery_ui_buttons() | |
| 131 | + </script> | |
| 132 | + | |
| 129 | 133 | </body> |
| 130 | 134 | </html> | ... | ... |
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %> | |
| 2 | +<div id='display-product-info'> | |
| 3 | + <%= display_value(@product) %> | |
| 4 | + <%= display_qualifiers(@product) %> | |
| 5 | +</div> | |
| 6 | + | |
| 7 | +<div id='display-product-description'><%= @product.description %></div> | |
| 8 | + | |
| 9 | +<% if @product.has_basic_info? %> | |
| 10 | + <%= edit_product_button(@product, 'info', _('Edit basic information')) %> | |
| 11 | +<% else %> | |
| 12 | + <%= edit_product_ui_button(@product, 'info', _('Add description, price and other basic information'), :title => _('Click here to add description, price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers'), 'data-primary-icon' => 'ui-icon-pencil', 'data-secondary-icon' => 'ui-icon-triangle-1-s') %> | |
| 13 | + <%= javascript_tag("render_jquery_ui_buttons('edit-product-button-ui-info')") %> | |
| 14 | +<% end%> | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +<div id='display-product-image'> | |
| 2 | + <%= image_tag (@product.reload.image ? @product.image.public_filename : @product.default_image('thumb')), :class => 'product-pic' %> | |
| 3 | +</div> | |
| 4 | + | |
| 5 | +<% form_for(:product, :url => { :controller => 'manage_products', :action => 'edit', :id => @product, :field => 'image' }, :html => { :method => 'post', :id => 'uploadForm', :multipart => true}) do |f| %> | |
| 6 | + <% f.fields_for :image_builder, @product.image do |i| %> | |
| 7 | + <%= i.file_field( :uploaded_data, { :size => 10 } ) %> | |
| 8 | + <p><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %></p> | |
| 9 | + <% end %> | |
| 10 | + | |
| 11 | + <%= submit_button 'save', _('Save') %> | |
| 12 | + <%= cancel_edit_product_link(@product, 'image') %> | |
| 13 | +<% end %> | |
| 14 | + | |
| 15 | +<script type="text/javascript"> | |
| 16 | + jQuery("#uploadForm").ajaxForm({ | |
| 17 | + beforeSubmit: function(a,f,o) { | |
| 18 | + o.loading = open_loading('<%= _('loading... ') %>'); | |
| 19 | + o.loaded = close_loading(); | |
| 20 | + }, | |
| 21 | + target: '#product-image' | |
| 22 | + }); | |
| 23 | +</script> | |
| 24 | + | |
| 25 | +<% if errors %> | |
| 26 | + <%= render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } %> | |
| 27 | +<% end %> | ... | ... |
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +<% if errors %> | |
| 2 | + <%= render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } %> | |
| 3 | +<% end %> | |
| 4 | + | |
| 5 | +<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %> | |
| 6 | +<% remote_form_for(@product, | |
| 7 | + :loading => "open_loading('#{ _('loading...') }')", | |
| 8 | + :loaded => 'close_loading()', | |
| 9 | + :before => ("tinyMCE.triggerSave()" unless Rails.env == 'test'), | |
| 10 | + :update => 'product-info', | |
| 11 | + :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'info'}, | |
| 12 | + :html => {:id => 'product-info-form', :method => 'post'}) do |f| %> | |
| 13 | + <%= labelled_form_field(_('Description:'), f.text_area(:description, :rows => 15, :style => 'width: 90%;')) %> | |
| 14 | + <%= labelled_form_field(_('Price (%s):') % environment.currency_unit, f.text_field(:price, :value => @product.formatted_value(:price), :onKeyPress => "return numbersonly(event, '#{environment.currency_separator}');")) %> | |
| 15 | + <%= labelled_form_field(_('Unit:'), f.select(:unit, Product.units)) %> | |
| 16 | + <%= labelled_form_field(_('Discount (%s):') % environment.currency_unit, f.text_field(:discount, :value => @product.formatted_value(:discount), :onKeyPress => "return numbersonly(event, '#{environment.currency_separator}');")) %> | |
| 17 | + <div class='formlabel'><%= _('Available:') %></div> | |
| 18 | + <div class='formfield'> | |
| 19 | + <%= labelled_radio_button( _('Yes'), 'product[available]', 'true', @product.available) %> | |
| 20 | + <%= labelled_radio_button( _('No'), 'product[available]', 'false', !@product.available) %> | |
| 21 | + </div> | |
| 22 | + | |
| 23 | + | |
| 24 | + <% if !environment.qualifiers.empty? %> | |
| 25 | + <table id='product-qualifiers-list'> | |
| 26 | + <tr> | |
| 27 | + <th><%= _('Qualifier') %></th> | |
| 28 | + <th><%= _('Certifier') %></th> | |
| 29 | + </tr> | |
| 30 | + <% environment.qualifiers.each do |qualifier| %> | |
| 31 | + <tr> | |
| 32 | + <td> | |
| 33 | + <%= checkboxes_qualifiers(@product, qualifier) %> | |
| 34 | + </td> | |
| 35 | + <td> | |
| 36 | + <%= select_certifiers(@product, qualifier, environment.certifiers) %> | |
| 37 | + </td> | |
| 38 | + </tr> | |
| 39 | + <% end %> | |
| 40 | + </table> | |
| 41 | + <% end %> | |
| 42 | + | |
| 43 | + <% button_bar do %> | |
| 44 | + <%= submit_button :save, _('Save') %> | |
| 45 | + <%= cancel_edit_product_link(@product, 'info') %> | |
| 46 | + <% end %> | |
| 47 | +<% end %> | |
| 48 | + | |
| 49 | +<br style='clear:both'> | ... | ... |
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<% remote_form_for(@product, | |
| 2 | + :loading => "open_loading('#{ _('loading...') }')", | |
| 3 | + :loaded => 'close_loading()', | |
| 4 | + :update => 'product-name', | |
| 5 | + :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'name'}, | |
| 6 | + :html => {:method => 'post'}) do |f| %> | |
| 7 | + <%= f.text_field(:name, :value => @product.name, :class => 'name_edition') %> | |
| 8 | + | |
| 9 | + <% button_bar do %> | |
| 10 | + <%= submit_button :save, _('Save') %> | |
| 11 | + <%= cancel_edit_product_link(@product, 'name') %> | |
| 12 | + <% end %> | |
| 13 | +<% end %> | |
| 14 | + | |
| 15 | +<script type="text/javascript"> | |
| 16 | + jQuery('#product_name').focus().select(); | |
| 17 | +</script> | |
| 18 | + | |
| 19 | +<% if errors %> | |
| 20 | + <%= render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } %> | |
| 21 | +<% end %> | ... | ... |
| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | +<div class=product-category-hierarchy> | |
| 2 | + <%= hierarchy_category_navigation(@product.product_category, :make_links => false)%> | |
| 3 | +</div> | |
| 4 | + | |
| 5 | +<div id="category-product-edition"> | |
| 6 | + | |
| 7 | + <h2><%= @product.name %></h2> | |
| 8 | + | |
| 9 | + <div id='request_result_message' style='display: none'></div> | |
| 10 | + | |
| 11 | + <% remote_form_for(:product, @product, | |
| 12 | + :loading => "open_loading('#{ _('loading...') }')", | |
| 13 | + :loaded => "close_loading()", | |
| 14 | + :update => "request_result_message", | |
| 15 | + :url => {:action => 'edit_category', :id => @product, :field => 'category'}, | |
| 16 | + :html => {:method => 'post', :id => 'product_category_form'}) do |f| %> | |
| 17 | + | |
| 18 | + <h3><%= _('Edit category of this product:') %></h3> | |
| 19 | + | |
| 20 | + <%= categories_container(f.hidden_field('product_category_id'), selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true)) %> | |
| 21 | + | |
| 22 | + <div id='categories_selection_actionbar'> | |
| 23 | + <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %> | |
| 24 | + <span id='save_and_continue_wrapper'> | |
| 25 | + <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %> | |
| 26 | + <span class='tooltip' id='save_and_continue_disabled_tooltip'> | |
| 27 | + <%= ui_icon(:alert) %> | |
| 28 | + <%= _('This category does not allow registration of products, select a more specific category') %> | |
| 29 | + </span> | |
| 30 | + </span> | |
| 31 | + </div> | |
| 32 | + | |
| 33 | + <% end %> | |
| 34 | +</div> | ... | ... |
app/views/manage_products/index.rhtml
| ... | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | <td><strong><%= link_to product.name, :action => 'show', :id => product %></strong></td> |
| 17 | 17 | <td><%= product.price %></td> |
| 18 | 18 | <td> |
| 19 | - <%= button :edit, _('Edit'), :action => 'edit', :id => product %> | |
| 20 | 19 | <%= button :delete, _('Destroy'), :action => 'destroy', :id => product %> |
| 21 | 20 | </td> |
| 22 | 21 | </tr> | ... | ... |
app/views/manage_products/new.rhtml
| ... | ... | @@ -6,19 +6,11 @@ |
| 6 | 6 | :loading => "open_loading('#{ _('loading...') }')", |
| 7 | 7 | :update => "request_result_message", |
| 8 | 8 | :url => {:action => 'new'}, |
| 9 | - :html => {:method => 'post', :id => 'new_product_form'} do |f| %> | |
| 9 | + :html => {:method => 'post', :id => 'product_category_form'} do |f| %> | |
| 10 | 10 | |
| 11 | 11 | <h3><%= _('Select the category of the new product or service') %></h3> |
| 12 | 12 | |
| 13 | - <%= f.hidden_field 'product_category_id' %> | |
| 14 | - | |
| 15 | - <div id='hierarchy_navigation'> </div> | |
| 16 | - | |
| 17 | - <div id='categories_container_wrapper'> | |
| 18 | - <div class='categories_container' id='categories_container_level0'> | |
| 19 | - <%= render :partial => 'categories_for_selection' %> | |
| 20 | - </div> | |
| 21 | - </div> | |
| 13 | + <%= categories_container(f.hidden_field('product_category_id'), select_for_new_category) %> | |
| 22 | 14 | |
| 23 | 15 | <div id='categories_selection_actionbar'> |
| 24 | 16 | <%= button :back, _('Back to the product listing'), :action => 'index' %> | ... | ... |
app/views/manage_products/show.rhtml
| 1 | -<h3> <%= @product.name %> </h3> | |
| 1 | +<div id="product-category"> | |
| 2 | + <%= render :partial => 'manage_products/display_category', :locals => {:product => @product} %> | |
| 3 | +</div> | |
| 2 | 4 | |
| 3 | -<p> <%= image_tag @product.image.public_filename if @product.image %> </p> | |
| 4 | -<p> <strong><%= _('Price:') %></strong> <%= @product.price %> </p> | |
| 5 | -<p> <strong><%= _('Description:') %></strong> <%= txt2html @product.description if @product.description %> </p> | |
| 6 | -<p> <strong><%= _('Category:') %></strong> <%= link_to_product_category(@product.product_category) %> </p> | |
| 5 | +<div id="show_product"> | |
| 7 | 6 | |
| 8 | -<%= button :back, _('Back'), :action => 'index' %> | |
| 9 | - | |
| 10 | -<%= button :delete, _('Destroy'), :action => 'destroy', :id => @product %> | |
| 11 | -<%= button :edit, _('Edit'), :action => 'edit', :id => @product %> | |
| 7 | + <div id='product-name'> | |
| 8 | + <%= render :partial => 'manage_products/display_name', :locals => {:product => @product} %> | |
| 9 | + </div> | |
| 12 | 10 | |
| 11 | + <div id='product-details'> | |
| 12 | + <div id='product-image'> | |
| 13 | + <%= render :partial => 'manage_products/display_image', :locals => {:product => @product} %> | |
| 14 | + </div> | |
| 15 | + | |
| 16 | + <div id='product-info'> | |
| 17 | + <%= render :partial => 'manage_products/display_info', :locals => {:product => @product} %> | |
| 18 | + </div> | |
| 19 | + | |
| 20 | + </div> | |
| 21 | +</div> | |
| 22 | + | |
| 23 | +<% button_bar do %> | |
| 24 | + <%= button :back, _('Back to the product listing'), :action => 'index' %> | |
| 25 | + <%= button :delete, _('Remove product or service'), {:action => 'destroy', :id => @product}, :class => 'requires-permission-manage_products', :style => 'display:none;' %> | |
| 26 | +<% end %> | ... | ... |
app/views/shared/_dialog_error_messages.rhtml
app/views/shared/tiny_mce.rhtml
| 1 | 1 | <%= javascript_include_tag 'tinymce/jscripts/tiny_mce/tiny_mce.js' %> |
| 2 | 2 | <script type="text/javascript"> |
| 3 | 3 | var myplugins = "searchreplace,print,table"; |
| 4 | + var first_line, second_line; | |
| 5 | + var mode = '<%= mode ||= false %>' | |
| 6 | + <% if mode %> | |
| 7 | + first_line = "fontsizeselect,bold,italic,underline,bullist,numlist,justifyleft,justifycenter,justifyright,link,unlink" | |
| 8 | + second_line = "" | |
| 9 | + <% else %> | |
| 10 | + first_line = "print,separator,copy,paste,separator,undo,redo,separator,search,replace,separator,fontsizeselect,formatselect" | |
| 11 | + second_line = "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,link,unlink,image,table,separator,cleanup,code" | |
| 12 | + <% end %> | |
| 13 | + | |
| 4 | 14 | if (tinymce.isIE) { |
| 5 | 15 | // the paste plugin is only useful in Internet Explorer |
| 6 | 16 | myplugins = "paste," + myplugins; |
| ... | ... | @@ -14,8 +24,8 @@ tinyMCE.init({ |
| 14 | 24 | plugins: myplugins, |
| 15 | 25 | theme_advanced_toolbar_location : "top", |
| 16 | 26 | theme_advanced_layout_manager: 'SimpleLayout', |
| 17 | - theme_advanced_buttons1 : "print,separator,copy,paste,separator,undo,redo,separator,search,replace,separator,fontsizeselect,formatselect", | |
| 18 | - theme_advanced_buttons2 : "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,link,unlink,image,table,separator,cleanup,code", | |
| 27 | + theme_advanced_buttons1 : first_line, | |
| 28 | + theme_advanced_buttons2 : second_line, | |
| 19 | 29 | theme_advanced_buttons3 : "", |
| 20 | 30 | theme_advanced_blockformats :"p,address,pre,h2,h3,h4,h5,h6", |
| 21 | 31 | paste_auto_cleanup_on_paste : true, | ... | ... |
config/routes.rb
| ... | ... | @@ -60,7 +60,6 @@ ActionController::Routing::Routes.draw do |map| |
| 60 | 60 | |
| 61 | 61 | # catalog |
| 62 | 62 | map.catalog 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format}/ |
| 63 | - map.product 'catalog/:profile/:id', :controller => 'catalog', :action => 'show', :profile => /#{Noosfero.identifier_format}/ | |
| 64 | 63 | |
| 65 | 64 | # invite |
| 66 | 65 | map.invite 'profile/:profile/invite/:action', :controller => 'invite', :profile => /#{Noosfero.identifier_format}/ | ... | ... |
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +class AddColumnsToProducts < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + add_column :products, :unit, :string | |
| 4 | + add_column :products, :discount, :float | |
| 5 | + add_column :products, :available, :boolean | |
| 6 | + end | |
| 7 | + | |
| 8 | + def self.down | |
| 9 | + remove_column :products, :unit | |
| 10 | + remove_column :products, :discount | |
| 11 | + remove_column :products, :available | |
| 12 | + end | |
| 13 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +class CreateProductQualifiers < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + create_table :product_qualifiers do |t| | |
| 4 | + t.references :product | |
| 5 | + t.references :qualifier | |
| 6 | + t.references :certifier | |
| 7 | + t.timestamps | |
| 8 | + end | |
| 9 | + end | |
| 10 | + | |
| 11 | + def self.down | |
| 12 | + drop_table :product_qualifiers | |
| 13 | + end | |
| 14 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +class CreateCertifiers < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + create_table :certifiers do |t| | |
| 4 | + t.string :name | |
| 5 | + t.string :description | |
| 6 | + t.string :link | |
| 7 | + t.references :environment | |
| 8 | + | |
| 9 | + t.timestamps | |
| 10 | + end | |
| 11 | + end | |
| 12 | + | |
| 13 | + def self.down | |
| 14 | + drop_table :certifiers | |
| 15 | + end | |
| 16 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -141,6 +141,15 @@ ActiveRecord::Schema.define(:version => 20100621235235) do |
| 141 | 141 | add_index "categories_profiles", ["category_id"], :name => "index_categories_profiles_on_category_id" |
| 142 | 142 | add_index "categories_profiles", ["profile_id"], :name => "index_categories_profiles_on_profile_id" |
| 143 | 143 | |
| 144 | + create_table "certifiers", :force => true do |t| | |
| 145 | + t.string "name" | |
| 146 | + t.string "description" | |
| 147 | + t.string "link" | |
| 148 | + t.integer "environment_id" | |
| 149 | + t.datetime "created_at" | |
| 150 | + t.datetime "updated_at" | |
| 151 | + end | |
| 152 | + | |
| 144 | 153 | create_table "comments", :force => true do |t| |
| 145 | 154 | t.string "title" |
| 146 | 155 | t.text "body" |
| ... | ... | @@ -230,6 +239,14 @@ ActiveRecord::Schema.define(:version => 20100621235235) do |
| 230 | 239 | add_index "product_categorizations", ["category_id"], :name => "index_product_categorizations_on_category_id" |
| 231 | 240 | add_index "product_categorizations", ["product_id"], :name => "index_product_categorizations_on_product_id" |
| 232 | 241 | |
| 242 | + create_table "product_qualifiers", :force => true do |t| | |
| 243 | + t.integer "product_id" | |
| 244 | + t.integer "qualifier_id" | |
| 245 | + t.integer "certifier_id" | |
| 246 | + t.datetime "created_at" | |
| 247 | + t.datetime "updated_at" | |
| 248 | + end | |
| 249 | + | |
| 233 | 250 | create_table "products", :force => true do |t| |
| 234 | 251 | t.integer "enterprise_id" |
| 235 | 252 | t.integer "product_category_id" |
| ... | ... | @@ -241,6 +258,9 @@ ActiveRecord::Schema.define(:version => 20100621235235) do |
| 241 | 258 | t.datetime "updated_at" |
| 242 | 259 | t.float "lat" |
| 243 | 260 | t.float "lng" |
| 261 | + t.string "unit" | |
| 262 | + t.float "discount" | |
| 263 | + t.boolean "available" | |
| 244 | 264 | t.boolean "highlighted" |
| 245 | 265 | end |
| 246 | 266 | |
| ... | ... | @@ -276,6 +296,13 @@ ActiveRecord::Schema.define(:version => 20100621235235) do |
| 276 | 296 | |
| 277 | 297 | add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id" |
| 278 | 298 | |
| 299 | + create_table "qualifiers", :force => true do |t| | |
| 300 | + t.string "name" | |
| 301 | + t.integer "environment_id" | |
| 302 | + t.datetime "created_at" | |
| 303 | + t.datetime "updated_at" | |
| 304 | + end | |
| 305 | + | |
| 279 | 306 | create_table "refused_join_community", :id => false, :force => true do |t| |
| 280 | 307 | t.integer "person_id" |
| 281 | 308 | t.integer "community_id" | ... | ... |
features/manage_products.feature
| ... | ... | @@ -10,18 +10,28 @@ Feature: manage products |
| 10 | 10 | | identifier | owner | name | enabled | |
| 11 | 11 | | redemoinho | joaosilva | Rede Moinho | true | |
| 12 | 12 | And feature "disable_products_for_enterprises" is disabled on environment |
| 13 | - And I am logged in as "joaosilva" | |
| 14 | - And I am on Rede Moinho's control panel | |
| 15 | - And I follow "Manage Products and Services" | |
| 16 | 13 | |
| 17 | 14 | Scenario: listing products and services |
| 15 | + Given I am logged in as "joaosilva" | |
| 16 | + And I am on Rede Moinho's control panel | |
| 17 | + And I follow "Manage Products and Services" | |
| 18 | 18 | Then I should see "Listing products and services" |
| 19 | 19 | |
| 20 | + Scenario: see button to back in categories hierarchy | |
| 21 | + Given I am logged in as "joaosilva" | |
| 22 | + And I am on Rede Moinho's control panel | |
| 23 | + And I follow "Manage Products and Services" | |
| 24 | + When I follow "New product or service" | |
| 25 | + Then I should see "Back to the product listing" link | |
| 26 | + | |
| 20 | 27 | Scenario: see toplevel categories |
| 21 | 28 | Given the following product_categories |
| 22 | 29 | | name | |
| 23 | 30 | | Products | |
| 24 | 31 | | Services | |
| 32 | + Given I am logged in as "joaosilva" | |
| 33 | + And I am on Rede Moinho's control panel | |
| 34 | + And I follow "Manage Products and Services" | |
| 25 | 35 | When I follow "New product or service" |
| 26 | 36 | Then I should see "Products" |
| 27 | 37 | And I should see "Service" |
| ... | ... | @@ -35,6 +45,9 @@ Feature: manage products |
| 35 | 45 | | name | parent | |
| 36 | 46 | | Computers level1 | products-level0 | |
| 37 | 47 | | DVDs level1 | products-level0 | |
| 48 | + Given I am logged in as "joaosilva" | |
| 49 | + And I am on Rede Moinho's control panel | |
| 50 | + And I follow "Manage Products and Services" | |
| 38 | 51 | When I follow "New product or service" |
| 39 | 52 | And I select "Products level0 »" |
| 40 | 53 | Then I should see "Computers level1" |
| ... | ... | @@ -50,6 +63,9 @@ Feature: manage products |
| 50 | 63 | | name | parent | |
| 51 | 64 | | Computers level1 | products-level0 | |
| 52 | 65 | | Software development level1 | services-level0 | |
| 66 | + Given I am logged in as "joaosilva" | |
| 67 | + And I am on Rede Moinho's control panel | |
| 68 | + And I follow "Manage Products and Services" | |
| 53 | 69 | When I follow "New product or service" |
| 54 | 70 | And I select "Products level0 »" |
| 55 | 71 | And I select "Computers level1" |
| ... | ... | @@ -65,6 +81,9 @@ Feature: manage products |
| 65 | 81 | And the following product_category |
| 66 | 82 | | name | parent | |
| 67 | 83 | | Computers | products | |
| 84 | + Given I am logged in as "joaosilva" | |
| 85 | + And I am on Rede Moinho's control panel | |
| 86 | + And I follow "Manage Products and Services" | |
| 68 | 87 | When I follow "New product or service" |
| 69 | 88 | And I select "Products »" |
| 70 | 89 | And I select "Computers" |
| ... | ... | @@ -78,6 +97,9 @@ Feature: manage products |
| 78 | 97 | Given the following product_category |
| 79 | 98 | | name | parent | |
| 80 | 99 | | Category Level 1 | toplevel-product-categories | |
| 100 | + Given I am logged in as "joaosilva" | |
| 101 | + And I am on Rede Moinho's control panel | |
| 102 | + And I follow "Manage Products and Services" | |
| 81 | 103 | When I follow "New product or service" |
| 82 | 104 | And I select "Toplevel Product Categories »" |
| 83 | 105 | And I select "Category Level 1" |
| ... | ... | @@ -89,6 +111,7 @@ Feature: manage products |
| 89 | 111 | Given the following product_category |
| 90 | 112 | | name | |
| 91 | 113 | | Only for test | |
| 114 | + And I am logged in as "joaosilva" | |
| 92 | 115 | When I go to /myprofile/redemoinho/manage_products/new |
| 93 | 116 | Then the "#save_and_continue" button should not be enabled |
| 94 | 117 | |
| ... | ... | @@ -97,6 +120,9 @@ Feature: manage products |
| 97 | 120 | Given the following product_category |
| 98 | 121 | | name | |
| 99 | 122 | | Browsers (accept categories) | |
| 123 | + Given I am logged in as "joaosilva" | |
| 124 | + And I am on Rede Moinho's control panel | |
| 125 | + And I follow "Manage Products and Services" | |
| 100 | 126 | When I follow "New product or service" |
| 101 | 127 | And I select "Browsers (accept categories)" |
| 102 | 128 | Then the "Save and continue" button should be enabled |
| ... | ... | @@ -106,6 +132,9 @@ Feature: manage products |
| 106 | 132 | Given the following product_category |
| 107 | 133 | | name | accept_products | |
| 108 | 134 | | Browsers | false | |
| 135 | + Given I am logged in as "joaosilva" | |
| 136 | + And I am on Rede Moinho's control panel | |
| 137 | + And I follow "Manage Products and Services" | |
| 109 | 138 | When I follow "New product or service" |
| 110 | 139 | And I select "Browsers" |
| 111 | 140 | Then the "#save_and_continue" button should not be enabled |
| ... | ... | @@ -115,16 +144,23 @@ Feature: manage products |
| 115 | 144 | Given the following product_category |
| 116 | 145 | | name | |
| 117 | 146 | | Bicycle | |
| 147 | + Given I am logged in as "joaosilva" | |
| 148 | + And I am on Rede Moinho's control panel | |
| 149 | + And I follow "Manage Products and Services" | |
| 118 | 150 | When I follow "New product or service" |
| 119 | 151 | And I select "Bicycle" |
| 120 | 152 | And I press "Save and continue" |
| 121 | - Then I should see "Category: Bicycle" | |
| 153 | + Then I should see "Bicycle" | |
| 154 | + And I should see "Change category" | |
| 122 | 155 | |
| 123 | 156 | @selenium |
| 124 | 157 | Scenario: stay on the same place after error on save |
| 125 | 158 | Given the following product_category |
| 126 | 159 | | name | |
| 127 | 160 | | Bicycle | |
| 161 | + Given I am logged in as "joaosilva" | |
| 162 | + And I am on Rede Moinho's control panel | |
| 163 | + And I follow "Manage Products and Services" | |
| 128 | 164 | And I follow "New product or service" |
| 129 | 165 | And I select "Bicycle" |
| 130 | 166 | And I press "Save and continue" |
| ... | ... | @@ -134,3 +170,184 @@ Feature: manage products |
| 134 | 170 | And I press "Save and continue" |
| 135 | 171 | Then I should be on Rede Moinho's new product page |
| 136 | 172 | And I should see "Bicycle" |
| 173 | + | |
| 174 | + Scenario: a user with permission can see edit links | |
| 175 | + Given the following product_category | |
| 176 | + | name | | |
| 177 | + | Bicycle | | |
| 178 | + And the following products | |
| 179 | + | owner | category | name | description | | |
| 180 | + | redemoinho | bicycle | Bike | Red bicycle | | |
| 181 | + And I am logged in as "joaosilva" | |
| 182 | + When I go to Rede Moinho's page of product Bike | |
| 183 | + Then I should see "Change category" | |
| 184 | + And I should see "Edit name" | |
| 185 | + And I should see "Edit basic information" | |
| 186 | + And I should see "Change image" | |
| 187 | + | |
| 188 | + Scenario: an allowed user will see a different button when has no basic info | |
| 189 | + Given the following product_category | |
| 190 | + | name | | |
| 191 | + | Bicycle | | |
| 192 | + And the following products | |
| 193 | + | owner | category | name | | |
| 194 | + | redemoinho | bicycle | Bike | | |
| 195 | + And I am logged in as "joaosilva" | |
| 196 | + When I go to Rede Moinho's page of product Bike | |
| 197 | + Then I should see "Change category" | |
| 198 | + And I should see "Edit name" | |
| 199 | + And I should see "Add description, price and other basic information" | |
| 200 | + And I should see "Change image" | |
| 201 | + | |
| 202 | + Scenario: a not logged user cannot see edit links | |
| 203 | + Given I am not logged in | |
| 204 | + And the following product_category | |
| 205 | + | name | | |
| 206 | + | Bicycle | | |
| 207 | + And the following products | |
| 208 | + | owner | category | name | description | | |
| 209 | + | redemoinho | bicycle | Bike | Red bicycle | | |
| 210 | + When I go to Rede Moinho's page of product Bike | |
| 211 | + Then I should not see "Change category" | |
| 212 | + And I should not see "Edit name" | |
| 213 | + And I should not see "Edit basic information" | |
| 214 | + And I should not see "Change image" | |
| 215 | + | |
| 216 | + Scenario: a not allowed user cannot see edit links | |
| 217 | + Given the following users | |
| 218 | + | login | name | | |
| 219 | + | mariasantos | Maria Santos | | |
| 220 | + And the following product_category | |
| 221 | + | name | | |
| 222 | + | Bicycle | | |
| 223 | + And the following products | |
| 224 | + | owner | category | name | description | | |
| 225 | + | redemoinho | bicycle | Bike | Red bicycle | | |
| 226 | + And I am logged in as "mariasantos" | |
| 227 | + When I go to Rede Moinho's page of product Bike | |
| 228 | + Then I should not see "Change category" | |
| 229 | + And I should not see "Edit name" | |
| 230 | + And I should not see "Edit basic information" | |
| 231 | + And I should not see "Change image" | |
| 232 | + | |
| 233 | + @selenium | |
| 234 | + Scenario: edit name of a product | |
| 235 | + Given the following product_category | |
| 236 | + | name | | |
| 237 | + | Bicycle | | |
| 238 | + And the following products | |
| 239 | + | owner | category | name | | |
| 240 | + | redemoinho | bicycle | Bike | | |
| 241 | + And I am logged in as "joaosilva" | |
| 242 | + When I go to Rede Moinho's page of product Bike | |
| 243 | + And I follow "Edit name" | |
| 244 | + And I fill in "product_name" with "Red bicycle" | |
| 245 | + And I press "Save" | |
| 246 | + Then I should see "Red bicycle" | |
| 247 | + And I should be on Rede Moinho's page of product Red bicycle | |
| 248 | + | |
| 249 | + @selenium | |
| 250 | + Scenario: cancel edition of a product name | |
| 251 | + Given the following product_category | |
| 252 | + | name | | |
| 253 | + | Bicycle | | |
| 254 | + And the following products | |
| 255 | + | owner | category | name | | |
| 256 | + | redemoinho | bicycle | Bike | | |
| 257 | + And I am logged in as "joaosilva" | |
| 258 | + When I go to Rede Moinho's page of product Bike | |
| 259 | + And I follow "Edit name" | |
| 260 | + When I follow "Cancel" | |
| 261 | + Then I should see "Bike" | |
| 262 | + | |
| 263 | + @selenium | |
| 264 | + Scenario: edit category of a product | |
| 265 | + Given the following product_category | |
| 266 | + | name | | |
| 267 | + | Eletronics | | |
| 268 | + And the following product_categories | |
| 269 | + | name | parent | | |
| 270 | + | Computers | eletronics | | |
| 271 | + | DVDs | eletronics | | |
| 272 | + And the following products | |
| 273 | + | owner | category | name | | |
| 274 | + | redemoinho | computers | Generic pc | | |
| 275 | + And I am logged in as "joaosilva" | |
| 276 | + When I go to Rede Moinho's page of product Generic pc | |
| 277 | + And I follow "Change category" | |
| 278 | + And I select "Eletronics »" | |
| 279 | + Then I select "DVDs" | |
| 280 | + And I press "Save and continue" | |
| 281 | + Then I should see "Eletronics → DVDs" | |
| 282 | + | |
| 283 | + @selenium | |
| 284 | + Scenario: cancel edition of a product category | |
| 285 | + Given the following product_category | |
| 286 | + | name | | |
| 287 | + | Eletronics | | |
| 288 | + And the following product_categories | |
| 289 | + | name | parent | | |
| 290 | + | Computers | eletronics | | |
| 291 | + | DVDs | eletronics | | |
| 292 | + And the following products | |
| 293 | + | owner | category | name | | |
| 294 | + | redemoinho | computers | Generic pc | | |
| 295 | + And I am logged in as "joaosilva" | |
| 296 | + When I go to Rede Moinho's page of product Generic pc | |
| 297 | + And I follow "Change category" | |
| 298 | + When I follow "Back to product" | |
| 299 | + Then I should see "Eletronics → Computers" | |
| 300 | + | |
| 301 | + | |
| 302 | + @selenium | |
| 303 | + Scenario: edit image of a product | |
| 304 | + Given the following product_category | |
| 305 | + | name | | |
| 306 | + | Eletronics | | |
| 307 | + And the following product_categories | |
| 308 | + | name | parent | | |
| 309 | + | Computers | eletronics | | |
| 310 | + | DVDs | eletronics | | |
| 311 | + And the following products | |
| 312 | + | owner | category | name | | |
| 313 | + | redemoinho | computers | Generic pc | | |
| 314 | + And I am logged in as "joaosilva" | |
| 315 | + When I go to Rede Moinho's page of product Generic pc | |
| 316 | + And I follow "Change image" | |
| 317 | + When I follow "Cancel" | |
| 318 | + Then I should be on Rede Moinho's page of product Generic pc | |
| 319 | + | |
| 320 | + # FIXME Not working because of tinyMCE plus selenium | |
| 321 | + # @selenium | |
| 322 | + # Scenario: edit description of a product | |
| 323 | + # Given the following product_category | |
| 324 | + # | name | | |
| 325 | + # | Bicycle | | |
| 326 | + # And the following products | |
| 327 | + # | owner | category | name | description | | |
| 328 | + # | redemoinho | bicycle | Bike | A new red bicycle | | |
| 329 | + # And I am logged in as "joaosilva" | |
| 330 | + # When I go to Rede Moinho's page of product Bike | |
| 331 | + # Then I should see "A new red bicycle" | |
| 332 | + # And I follow "Edit basic information" | |
| 333 | + # And I type in tinyMCE field "Description" the text "An used red bicycle" | |
| 334 | + # And I press "Save" | |
| 335 | + # Then I should not see "A new red bicycle" | |
| 336 | + # And I should see "An used red bicycle" | |
| 337 | + # And I should be on Rede Moinho's page of product Bike | |
| 338 | + | |
| 339 | + @selenium | |
| 340 | + Scenario: cancel edition of a product description | |
| 341 | + Given the following product_category | |
| 342 | + | name | | |
| 343 | + | Bicycle | | |
| 344 | + And the following products | |
| 345 | + | owner | category | name | description | | |
| 346 | + | redemoinho | bicycle | Bike | A new red bicycle | | |
| 347 | + And I am logged in as "joaosilva" | |
| 348 | + When I go to Rede Moinho's page of product Bike | |
| 349 | + Then I should see "A new red bicycle" | |
| 350 | + And I follow "Edit basic information" | |
| 351 | + When I follow "Cancel" | |
| 352 | + Then I should see "A new red bicycle" | |
| 353 | + And I should be on Rede Moinho's page of product Bike | ... | ... |
features/step_definitions/noosfero_steps.rb
features/support/paths.rb
| ... | ... | @@ -54,6 +54,14 @@ module NavigationHelpers |
| 54 | 54 | when /^(.+)'s new product page/ |
| 55 | 55 | '/myprofile/%s/manage_products/new' % Profile.find_by_name($1).identifier |
| 56 | 56 | |
| 57 | + when /^(.+)'s page of product (.*)$/ | |
| 58 | + enterprise = Profile.find_by_name($1) | |
| 59 | + product = enterprise.products.find_by_name($2) | |
| 60 | + '/myprofile/%s/manage_products/show/%s' % [enterprise.identifier, product.id] | |
| 61 | + | |
| 62 | + when /^(.*)'s products page$/ | |
| 63 | + '/catalog/%s' % Profile.find_by_name($1).identifier | |
| 64 | + | |
| 57 | 65 | # Add more mappings here. |
| 58 | 66 | # Here is a more fancy example: |
| 59 | 67 | # | ... | ... |
public/designs/templates/leftbar/stylesheets/style.css
public/designs/templates/rightbar/stylesheets/style.css
public/javascripts/application.js
| ... | ... | @@ -138,3 +138,58 @@ function update_loading(message) { |
| 138 | 138 | function redirect_to(url) { |
| 139 | 139 | document.location=url; |
| 140 | 140 | } |
| 141 | + | |
| 142 | +/* Products edition */ | |
| 143 | + | |
| 144 | +function numbersonly(e, separator) { | |
| 145 | + var key; | |
| 146 | + var keychar; | |
| 147 | + | |
| 148 | + if (window.event) { | |
| 149 | + key = window.event.keyCode; | |
| 150 | + } | |
| 151 | + else if (e) { | |
| 152 | + key = e.which; | |
| 153 | + } | |
| 154 | + else { | |
| 155 | + return true; | |
| 156 | + } | |
| 157 | + keychar = String.fromCharCode(key); | |
| 158 | + | |
| 159 | + if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) ) { | |
| 160 | + return true; | |
| 161 | + } | |
| 162 | + else if ((("0123456789").indexOf(keychar) > -1)) { | |
| 163 | + return true; | |
| 164 | + } | |
| 165 | + else if (keychar == separator) { | |
| 166 | + return true; | |
| 167 | + } | |
| 168 | + else | |
| 169 | + return false; | |
| 170 | +} | |
| 171 | + | |
| 172 | +// transform all element with class ui_button in a jQuery UI button | |
| 173 | +function render_jquery_ui_buttons(element_id) { | |
| 174 | + if (element_id) { | |
| 175 | + element_id = '#' + element_id | |
| 176 | + jQuery(element_id).button({ | |
| 177 | + icons: { | |
| 178 | + primary: jQuery(element_id).attr('data-primary-icon'), | |
| 179 | + secondary: jQuery(element_id).attr('data-secondary-icon') | |
| 180 | + } | |
| 181 | + } | |
| 182 | + ) | |
| 183 | + } | |
| 184 | + else { | |
| 185 | + jQuery('.ui_button').each(function() { | |
| 186 | + jQuery(this).button({ | |
| 187 | + icons: { | |
| 188 | + primary: this.getAttribute('data-primary-icon'), | |
| 189 | + secondary: this.getAttribute('data-secondary-icon') | |
| 190 | + } | |
| 191 | + } | |
| 192 | + ) | |
| 193 | + }) | |
| 194 | + } | |
| 195 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,675 @@ |
| 1 | +/*! | |
| 2 | + * jQuery Form Plugin | |
| 3 | + * version: 2.43 (12-MAR-2010) | |
| 4 | + * @requires jQuery v1.3.2 or later | |
| 5 | + * | |
| 6 | + * Examples and documentation at: http://malsup.com/jquery/form/ | |
| 7 | + * Dual licensed under the MIT and GPL licenses: | |
| 8 | + * http://www.opensource.org/licenses/mit-license.php | |
| 9 | + * http://www.gnu.org/licenses/gpl.html | |
| 10 | + */ | |
| 11 | +;(function($) { | |
| 12 | + | |
| 13 | +/* | |
| 14 | + Usage Note: | |
| 15 | + ----------- | |
| 16 | + Do not use both ajaxSubmit and ajaxForm on the same form. These | |
| 17 | + functions are intended to be exclusive. Use ajaxSubmit if you want | |
| 18 | + to bind your own submit handler to the form. For example, | |
| 19 | + | |
| 20 | + $(document).ready(function() { | |
| 21 | + $('#myForm').bind('submit', function() { | |
| 22 | + $(this).ajaxSubmit({ | |
| 23 | + target: '#output' | |
| 24 | + }); | |
| 25 | + return false; // <-- important! | |
| 26 | + }); | |
| 27 | + }); | |
| 28 | + | |
| 29 | + Use ajaxForm when you want the plugin to manage all the event binding | |
| 30 | + for you. For example, | |
| 31 | + | |
| 32 | + $(document).ready(function() { | |
| 33 | + $('#myForm').ajaxForm({ | |
| 34 | + target: '#output' | |
| 35 | + }); | |
| 36 | + }); | |
| 37 | + | |
| 38 | + When using ajaxForm, the ajaxSubmit function will be invoked for you | |
| 39 | + at the appropriate time. | |
| 40 | +*/ | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * ajaxSubmit() provides a mechanism for immediately submitting | |
| 44 | + * an HTML form using AJAX. | |
| 45 | + */ | |
| 46 | +$.fn.ajaxSubmit = function(options) { | |
| 47 | + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) | |
| 48 | + if (!this.length) { | |
| 49 | + log('ajaxSubmit: skipping submit process - no element selected'); | |
| 50 | + return this; | |
| 51 | + } | |
| 52 | + | |
| 53 | + if (typeof options == 'function') | |
| 54 | + options = { success: options }; | |
| 55 | + | |
| 56 | + var url = $.trim(this.attr('action')); | |
| 57 | + if (url) { | |
| 58 | + // clean url (don't include hash vaue) | |
| 59 | + url = (url.match(/^([^#]+)/)||[])[1]; | |
| 60 | + } | |
| 61 | + url = url || window.location.href || ''; | |
| 62 | + | |
| 63 | + options = $.extend({ | |
| 64 | + url: url, | |
| 65 | + type: this.attr('method') || 'GET', | |
| 66 | + iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' | |
| 67 | + }, options || {}); | |
| 68 | + | |
| 69 | + // hook for manipulating the form data before it is extracted; | |
| 70 | + // convenient for use with rich editors like tinyMCE or FCKEditor | |
| 71 | + var veto = {}; | |
| 72 | + this.trigger('form-pre-serialize', [this, options, veto]); | |
| 73 | + if (veto.veto) { | |
| 74 | + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); | |
| 75 | + return this; | |
| 76 | + } | |
| 77 | + | |
| 78 | + // provide opportunity to alter form data before it is serialized | |
| 79 | + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { | |
| 80 | + log('ajaxSubmit: submit aborted via beforeSerialize callback'); | |
| 81 | + return this; | |
| 82 | + } | |
| 83 | + | |
| 84 | + var a = this.formToArray(options.semantic); | |
| 85 | + if (options.data) { | |
| 86 | + options.extraData = options.data; | |
| 87 | + for (var n in options.data) { | |
| 88 | + if(options.data[n] instanceof Array) { | |
| 89 | + for (var k in options.data[n]) | |
| 90 | + a.push( { name: n, value: options.data[n][k] } ); | |
| 91 | + } | |
| 92 | + else | |
| 93 | + a.push( { name: n, value: options.data[n] } ); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + // give pre-submit callback an opportunity to abort the submit | |
| 98 | + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { | |
| 99 | + log('ajaxSubmit: submit aborted via beforeSubmit callback'); | |
| 100 | + return this; | |
| 101 | + } | |
| 102 | + | |
| 103 | + // fire vetoable 'validate' event | |
| 104 | + this.trigger('form-submit-validate', [a, this, options, veto]); | |
| 105 | + if (veto.veto) { | |
| 106 | + log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); | |
| 107 | + return this; | |
| 108 | + } | |
| 109 | + | |
| 110 | + var q = $.param(a); | |
| 111 | + | |
| 112 | + if (options.type.toUpperCase() == 'GET') { | |
| 113 | + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; | |
| 114 | + options.data = null; // data is null for 'get' | |
| 115 | + } | |
| 116 | + else | |
| 117 | + options.data = q; // data is the query string for 'post' | |
| 118 | + | |
| 119 | + var $form = this, callbacks = []; | |
| 120 | + if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); | |
| 121 | + if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); | |
| 122 | + | |
| 123 | + // perform a load on the target only if dataType is not provided | |
| 124 | + if (!options.dataType && options.target) { | |
| 125 | + var oldSuccess = options.success || function(){}; | |
| 126 | + callbacks.push(function(data) { | |
| 127 | + var fn = options.replaceTarget ? 'replaceWith' : 'html'; | |
| 128 | + $(options.target)[fn](data).each(oldSuccess, arguments); | |
| 129 | + }); | |
| 130 | + } | |
| 131 | + else if (options.success) | |
| 132 | + callbacks.push(options.success); | |
| 133 | + | |
| 134 | + options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg | |
| 135 | + for (var i=0, max=callbacks.length; i < max; i++) | |
| 136 | + callbacks[i].apply(options, [data, status, xhr || $form, $form]); | |
| 137 | + }; | |
| 138 | + | |
| 139 | + // are there files to upload? | |
| 140 | + var files = $('input:file', this).fieldValue(); | |
| 141 | + var found = false; | |
| 142 | + for (var j=0; j < files.length; j++) | |
| 143 | + if (files[j]) | |
| 144 | + found = true; | |
| 145 | + | |
| 146 | + var multipart = false; | |
| 147 | +// var mp = 'multipart/form-data'; | |
| 148 | +// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); | |
| 149 | + | |
| 150 | + // options.iframe allows user to force iframe mode | |
| 151 | + // 06-NOV-09: now defaulting to iframe mode if file input is detected | |
| 152 | + if ((files.length && options.iframe !== false) || options.iframe || found || multipart) { | |
| 153 | + // hack to fix Safari hang (thanks to Tim Molendijk for this) | |
| 154 | + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d | |
| 155 | + if (options.closeKeepAlive) | |
| 156 | + $.get(options.closeKeepAlive, fileUpload); | |
| 157 | + else | |
| 158 | + fileUpload(); | |
| 159 | + } | |
| 160 | + else | |
| 161 | + $.ajax(options); | |
| 162 | + | |
| 163 | + // fire 'notify' event | |
| 164 | + this.trigger('form-submit-notify', [this, options]); | |
| 165 | + return this; | |
| 166 | + | |
| 167 | + | |
| 168 | + // private function for handling file uploads (hat tip to YAHOO!) | |
| 169 | + function fileUpload() { | |
| 170 | + var form = $form[0]; | |
| 171 | + | |
| 172 | + if ($(':input[name=submit]', form).length) { | |
| 173 | + alert('Error: Form elements must not be named "submit".'); | |
| 174 | + return; | |
| 175 | + } | |
| 176 | + | |
| 177 | + var opts = $.extend({}, $.ajaxSettings, options); | |
| 178 | + var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); | |
| 179 | + | |
| 180 | + var id = 'jqFormIO' + (new Date().getTime()); | |
| 181 | + var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" onload="(jQuery(this).data(\'form-plugin-onload\'))()" />'); | |
| 182 | + var io = $io[0]; | |
| 183 | + | |
| 184 | + $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); | |
| 185 | + | |
| 186 | + var xhr = { // mock object | |
| 187 | + aborted: 0, | |
| 188 | + responseText: null, | |
| 189 | + responseXML: null, | |
| 190 | + status: 0, | |
| 191 | + statusText: 'n/a', | |
| 192 | + getAllResponseHeaders: function() {}, | |
| 193 | + getResponseHeader: function() {}, | |
| 194 | + setRequestHeader: function() {}, | |
| 195 | + abort: function() { | |
| 196 | + this.aborted = 1; | |
| 197 | + $io.attr('src', opts.iframeSrc); // abort op in progress | |
| 198 | + } | |
| 199 | + }; | |
| 200 | + | |
| 201 | + var g = opts.global; | |
| 202 | + // trigger ajax global events so that activity/block indicators work like normal | |
| 203 | + if (g && ! $.active++) $.event.trigger("ajaxStart"); | |
| 204 | + if (g) $.event.trigger("ajaxSend", [xhr, opts]); | |
| 205 | + | |
| 206 | + if (s.beforeSend && s.beforeSend(xhr, s) === false) { | |
| 207 | + s.global && $.active--; | |
| 208 | + return; | |
| 209 | + } | |
| 210 | + if (xhr.aborted) | |
| 211 | + return; | |
| 212 | + | |
| 213 | + var cbInvoked = false; | |
| 214 | + var timedOut = 0; | |
| 215 | + | |
| 216 | + // add submitting element to data if we know it | |
| 217 | + var sub = form.clk; | |
| 218 | + if (sub) { | |
| 219 | + var n = sub.name; | |
| 220 | + if (n && !sub.disabled) { | |
| 221 | + opts.extraData = opts.extraData || {}; | |
| 222 | + opts.extraData[n] = sub.value; | |
| 223 | + if (sub.type == "image") { | |
| 224 | + opts.extraData[n+'.x'] = form.clk_x; | |
| 225 | + opts.extraData[n+'.y'] = form.clk_y; | |
| 226 | + } | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + // take a breath so that pending repaints get some cpu time before the upload starts | |
| 231 | + function doSubmit() { | |
| 232 | + // make sure form attrs are set | |
| 233 | + var t = $form.attr('target'), a = $form.attr('action'); | |
| 234 | + | |
| 235 | + // update form attrs in IE friendly way | |
| 236 | + form.setAttribute('target',id); | |
| 237 | + if (form.getAttribute('method') != 'POST') | |
| 238 | + form.setAttribute('method', 'POST'); | |
| 239 | + if (form.getAttribute('action') != opts.url) | |
| 240 | + form.setAttribute('action', opts.url); | |
| 241 | + | |
| 242 | + // ie borks in some cases when setting encoding | |
| 243 | + if (! opts.skipEncodingOverride) { | |
| 244 | + $form.attr({ | |
| 245 | + encoding: 'multipart/form-data', | |
| 246 | + enctype: 'multipart/form-data' | |
| 247 | + }); | |
| 248 | + } | |
| 249 | + | |
| 250 | + // support timout | |
| 251 | + if (opts.timeout) | |
| 252 | + setTimeout(function() { timedOut = true; cb(); }, opts.timeout); | |
| 253 | + | |
| 254 | + // add "extra" data to form if provided in options | |
| 255 | + var extraInputs = []; | |
| 256 | + try { | |
| 257 | + if (opts.extraData) | |
| 258 | + for (var n in opts.extraData) | |
| 259 | + extraInputs.push( | |
| 260 | + $('<input type="hidden" name="'+n+'" value="'+opts.extraData[n]+'" />') | |
| 261 | + .appendTo(form)[0]); | |
| 262 | + | |
| 263 | + // add iframe to doc and submit the form | |
| 264 | + $io.appendTo('body'); | |
| 265 | + $io.data('form-plugin-onload', cb); | |
| 266 | + form.submit(); | |
| 267 | + } | |
| 268 | + finally { | |
| 269 | + // reset attrs and remove "extra" input elements | |
| 270 | + form.setAttribute('action',a); | |
| 271 | + t ? form.setAttribute('target', t) : $form.removeAttr('target'); | |
| 272 | + $(extraInputs).remove(); | |
| 273 | + } | |
| 274 | + }; | |
| 275 | + | |
| 276 | + if (opts.forceSync) | |
| 277 | + doSubmit(); | |
| 278 | + else | |
| 279 | + setTimeout(doSubmit, 10); // this lets dom updates render | |
| 280 | + | |
| 281 | + var domCheckCount = 100; | |
| 282 | + | |
| 283 | + function cb() { | |
| 284 | + if (cbInvoked) | |
| 285 | + return; | |
| 286 | + | |
| 287 | + var ok = true; | |
| 288 | + try { | |
| 289 | + if (timedOut) throw 'timeout'; | |
| 290 | + // extract the server response from the iframe | |
| 291 | + var data, doc; | |
| 292 | + | |
| 293 | + doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; | |
| 294 | + | |
| 295 | + var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); | |
| 296 | + log('isXml='+isXml); | |
| 297 | + if (!isXml && (doc.body == null || doc.body.innerHTML == '')) { | |
| 298 | + if (--domCheckCount) { | |
| 299 | + // in some browsers (Opera) the iframe DOM is not always traversable when | |
| 300 | + // the onload callback fires, so we loop a bit to accommodate | |
| 301 | + log('requeing onLoad callback, DOM not available'); | |
| 302 | + setTimeout(cb, 250); | |
| 303 | + return; | |
| 304 | + } | |
| 305 | + log('Could not access iframe DOM after 100 tries.'); | |
| 306 | + return; | |
| 307 | + } | |
| 308 | + | |
| 309 | + log('response detected'); | |
| 310 | + cbInvoked = true; | |
| 311 | + xhr.responseText = doc.body ? doc.body.innerHTML : null; | |
| 312 | + xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; | |
| 313 | + xhr.getResponseHeader = function(header){ | |
| 314 | + var headers = {'content-type': opts.dataType}; | |
| 315 | + return headers[header]; | |
| 316 | + }; | |
| 317 | + | |
| 318 | + if (opts.dataType == 'json' || opts.dataType == 'script') { | |
| 319 | + // see if user embedded response in textarea | |
| 320 | + var ta = doc.getElementsByTagName('textarea')[0]; | |
| 321 | + if (ta) | |
| 322 | + xhr.responseText = ta.value; | |
| 323 | + else { | |
| 324 | + // account for browsers injecting pre around json response | |
| 325 | + var pre = doc.getElementsByTagName('pre')[0]; | |
| 326 | + if (pre) | |
| 327 | + xhr.responseText = pre.innerHTML; | |
| 328 | + } | |
| 329 | + } | |
| 330 | + else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { | |
| 331 | + xhr.responseXML = toXml(xhr.responseText); | |
| 332 | + } | |
| 333 | + data = $.httpData(xhr, opts.dataType); | |
| 334 | + } | |
| 335 | + catch(e){ | |
| 336 | + log('error caught:',e); | |
| 337 | + ok = false; | |
| 338 | + xhr.error = e; | |
| 339 | + $.handleError(opts, xhr, 'error', e); | |
| 340 | + } | |
| 341 | + | |
| 342 | + // ordering of these callbacks/triggers is odd, but that's how $.ajax does it | |
| 343 | + if (ok) { | |
| 344 | + opts.success(data, 'success'); | |
| 345 | + if (g) $.event.trigger("ajaxSuccess", [xhr, opts]); | |
| 346 | + } | |
| 347 | + if (g) $.event.trigger("ajaxComplete", [xhr, opts]); | |
| 348 | + if (g && ! --$.active) $.event.trigger("ajaxStop"); | |
| 349 | + if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error'); | |
| 350 | + | |
| 351 | + // clean up | |
| 352 | + setTimeout(function() { | |
| 353 | + $io.removeData('form-plugin-onload'); | |
| 354 | + $io.remove(); | |
| 355 | + xhr.responseXML = null; | |
| 356 | + }, 100); | |
| 357 | + }; | |
| 358 | + | |
| 359 | + function toXml(s, doc) { | |
| 360 | + if (window.ActiveXObject) { | |
| 361 | + doc = new ActiveXObject('Microsoft.XMLDOM'); | |
| 362 | + doc.async = 'false'; | |
| 363 | + doc.loadXML(s); | |
| 364 | + } | |
| 365 | + else | |
| 366 | + doc = (new DOMParser()).parseFromString(s, 'text/xml'); | |
| 367 | + return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null; | |
| 368 | + }; | |
| 369 | + }; | |
| 370 | +}; | |
| 371 | + | |
| 372 | +/** | |
| 373 | + * ajaxForm() provides a mechanism for fully automating form submission. | |
| 374 | + * | |
| 375 | + * The advantages of using this method instead of ajaxSubmit() are: | |
| 376 | + * | |
| 377 | + * 1: This method will include coordinates for <input type="image" /> elements (if the element | |
| 378 | + * is used to submit the form). | |
| 379 | + * 2. This method will include the submit element's name/value data (for the element that was | |
| 380 | + * used to submit the form). | |
| 381 | + * 3. This method binds the submit() method to the form for you. | |
| 382 | + * | |
| 383 | + * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely | |
| 384 | + * passes the options argument along after properly binding events for submit elements and | |
| 385 | + * the form itself. | |
| 386 | + */ | |
| 387 | +$.fn.ajaxForm = function(options) { | |
| 388 | + return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { | |
| 389 | + e.preventDefault(); | |
| 390 | + $(this).ajaxSubmit(options); | |
| 391 | + }).bind('click.form-plugin', function(e) { | |
| 392 | + var target = e.target; | |
| 393 | + var $el = $(target); | |
| 394 | + if (!($el.is(":submit,input:image"))) { | |
| 395 | + // is this a child element of the submit el? (ex: a span within a button) | |
| 396 | + var t = $el.closest(':submit'); | |
| 397 | + if (t.length == 0) | |
| 398 | + return; | |
| 399 | + target = t[0]; | |
| 400 | + } | |
| 401 | + var form = this; | |
| 402 | + form.clk = target; | |
| 403 | + if (target.type == 'image') { | |
| 404 | + if (e.offsetX != undefined) { | |
| 405 | + form.clk_x = e.offsetX; | |
| 406 | + form.clk_y = e.offsetY; | |
| 407 | + } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin | |
| 408 | + var offset = $el.offset(); | |
| 409 | + form.clk_x = e.pageX - offset.left; | |
| 410 | + form.clk_y = e.pageY - offset.top; | |
| 411 | + } else { | |
| 412 | + form.clk_x = e.pageX - target.offsetLeft; | |
| 413 | + form.clk_y = e.pageY - target.offsetTop; | |
| 414 | + } | |
| 415 | + } | |
| 416 | + // clear form vars | |
| 417 | + setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); | |
| 418 | + }); | |
| 419 | +}; | |
| 420 | + | |
| 421 | +// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm | |
| 422 | +$.fn.ajaxFormUnbind = function() { | |
| 423 | + return this.unbind('submit.form-plugin click.form-plugin'); | |
| 424 | +}; | |
| 425 | + | |
| 426 | +/** | |
| 427 | + * formToArray() gathers form element data into an array of objects that can | |
| 428 | + * be passed to any of the following ajax functions: $.get, $.post, or load. | |
| 429 | + * Each object in the array has both a 'name' and 'value' property. An example of | |
| 430 | + * an array for a simple login form might be: | |
| 431 | + * | |
| 432 | + * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] | |
| 433 | + * | |
| 434 | + * It is this array that is passed to pre-submit callback functions provided to the | |
| 435 | + * ajaxSubmit() and ajaxForm() methods. | |
| 436 | + */ | |
| 437 | +$.fn.formToArray = function(semantic) { | |
| 438 | + var a = []; | |
| 439 | + if (this.length == 0) return a; | |
| 440 | + | |
| 441 | + var form = this[0]; | |
| 442 | + var els = semantic ? form.getElementsByTagName('*') : form.elements; | |
| 443 | + if (!els) return a; | |
| 444 | + for(var i=0, max=els.length; i < max; i++) { | |
| 445 | + var el = els[i]; | |
| 446 | + var n = el.name; | |
| 447 | + if (!n) continue; | |
| 448 | + | |
| 449 | + if (semantic && form.clk && el.type == "image") { | |
| 450 | + // handle image inputs on the fly when semantic == true | |
| 451 | + if(!el.disabled && form.clk == el) { | |
| 452 | + a.push({name: n, value: $(el).val()}); | |
| 453 | + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); | |
| 454 | + } | |
| 455 | + continue; | |
| 456 | + } | |
| 457 | + | |
| 458 | + var v = $.fieldValue(el, true); | |
| 459 | + if (v && v.constructor == Array) { | |
| 460 | + for(var j=0, jmax=v.length; j < jmax; j++) | |
| 461 | + a.push({name: n, value: v[j]}); | |
| 462 | + } | |
| 463 | + else if (v !== null && typeof v != 'undefined') | |
| 464 | + a.push({name: n, value: v}); | |
| 465 | + } | |
| 466 | + | |
| 467 | + if (!semantic && form.clk) { | |
| 468 | + // input type=='image' are not found in elements array! handle it here | |
| 469 | + var $input = $(form.clk), input = $input[0], n = input.name; | |
| 470 | + if (n && !input.disabled && input.type == 'image') { | |
| 471 | + a.push({name: n, value: $input.val()}); | |
| 472 | + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); | |
| 473 | + } | |
| 474 | + } | |
| 475 | + return a; | |
| 476 | +}; | |
| 477 | + | |
| 478 | +/** | |
| 479 | + * Serializes form data into a 'submittable' string. This method will return a string | |
| 480 | + * in the format: name1=value1&name2=value2 | |
| 481 | + */ | |
| 482 | +$.fn.formSerialize = function(semantic) { | |
| 483 | + //hand off to jQuery.param for proper encoding | |
| 484 | + return $.param(this.formToArray(semantic)); | |
| 485 | +}; | |
| 486 | + | |
| 487 | +/** | |
| 488 | + * Serializes all field elements in the jQuery object into a query string. | |
| 489 | + * This method will return a string in the format: name1=value1&name2=value2 | |
| 490 | + */ | |
| 491 | +$.fn.fieldSerialize = function(successful) { | |
| 492 | + var a = []; | |
| 493 | + this.each(function() { | |
| 494 | + var n = this.name; | |
| 495 | + if (!n) return; | |
| 496 | + var v = $.fieldValue(this, successful); | |
| 497 | + if (v && v.constructor == Array) { | |
| 498 | + for (var i=0,max=v.length; i < max; i++) | |
| 499 | + a.push({name: n, value: v[i]}); | |
| 500 | + } | |
| 501 | + else if (v !== null && typeof v != 'undefined') | |
| 502 | + a.push({name: this.name, value: v}); | |
| 503 | + }); | |
| 504 | + //hand off to jQuery.param for proper encoding | |
| 505 | + return $.param(a); | |
| 506 | +}; | |
| 507 | + | |
| 508 | +/** | |
| 509 | + * Returns the value(s) of the element in the matched set. For example, consider the following form: | |
| 510 | + * | |
| 511 | + * <form><fieldset> | |
| 512 | + * <input name="A" type="text" /> | |
| 513 | + * <input name="A" type="text" /> | |
| 514 | + * <input name="B" type="checkbox" value="B1" /> | |
| 515 | + * <input name="B" type="checkbox" value="B2"/> | |
| 516 | + * <input name="C" type="radio" value="C1" /> | |
| 517 | + * <input name="C" type="radio" value="C2" /> | |
| 518 | + * </fieldset></form> | |
| 519 | + * | |
| 520 | + * var v = $(':text').fieldValue(); | |
| 521 | + * // if no values are entered into the text inputs | |
| 522 | + * v == ['',''] | |
| 523 | + * // if values entered into the text inputs are 'foo' and 'bar' | |
| 524 | + * v == ['foo','bar'] | |
| 525 | + * | |
| 526 | + * var v = $(':checkbox').fieldValue(); | |
| 527 | + * // if neither checkbox is checked | |
| 528 | + * v === undefined | |
| 529 | + * // if both checkboxes are checked | |
| 530 | + * v == ['B1', 'B2'] | |
| 531 | + * | |
| 532 | + * var v = $(':radio').fieldValue(); | |
| 533 | + * // if neither radio is checked | |
| 534 | + * v === undefined | |
| 535 | + * // if first radio is checked | |
| 536 | + * v == ['C1'] | |
| 537 | + * | |
| 538 | + * The successful argument controls whether or not the field element must be 'successful' | |
| 539 | + * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). | |
| 540 | + * The default value of the successful argument is true. If this value is false the value(s) | |
| 541 | + * for each element is returned. | |
| 542 | + * | |
| 543 | + * Note: This method *always* returns an array. If no valid value can be determined the | |
| 544 | + * array will be empty, otherwise it will contain one or more values. | |
| 545 | + */ | |
| 546 | +$.fn.fieldValue = function(successful) { | |
| 547 | + for (var val=[], i=0, max=this.length; i < max; i++) { | |
| 548 | + var el = this[i]; | |
| 549 | + var v = $.fieldValue(el, successful); | |
| 550 | + if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) | |
| 551 | + continue; | |
| 552 | + v.constructor == Array ? $.merge(val, v) : val.push(v); | |
| 553 | + } | |
| 554 | + return val; | |
| 555 | +}; | |
| 556 | + | |
| 557 | +/** | |
| 558 | + * Returns the value of the field element. | |
| 559 | + */ | |
| 560 | +$.fieldValue = function(el, successful) { | |
| 561 | + var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); | |
| 562 | + if (typeof successful == 'undefined') successful = true; | |
| 563 | + | |
| 564 | + if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || | |
| 565 | + (t == 'checkbox' || t == 'radio') && !el.checked || | |
| 566 | + (t == 'submit' || t == 'image') && el.form && el.form.clk != el || | |
| 567 | + tag == 'select' && el.selectedIndex == -1)) | |
| 568 | + return null; | |
| 569 | + | |
| 570 | + if (tag == 'select') { | |
| 571 | + var index = el.selectedIndex; | |
| 572 | + if (index < 0) return null; | |
| 573 | + var a = [], ops = el.options; | |
| 574 | + var one = (t == 'select-one'); | |
| 575 | + var max = (one ? index+1 : ops.length); | |
| 576 | + for(var i=(one ? index : 0); i < max; i++) { | |
| 577 | + var op = ops[i]; | |
| 578 | + if (op.selected) { | |
| 579 | + var v = op.value; | |
| 580 | + if (!v) // extra pain for IE... | |
| 581 | + v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; | |
| 582 | + if (one) return v; | |
| 583 | + a.push(v); | |
| 584 | + } | |
| 585 | + } | |
| 586 | + return a; | |
| 587 | + } | |
| 588 | + return el.value; | |
| 589 | +}; | |
| 590 | + | |
| 591 | +/** | |
| 592 | + * Clears the form data. Takes the following actions on the form's input fields: | |
| 593 | + * - input text fields will have their 'value' property set to the empty string | |
| 594 | + * - select elements will have their 'selectedIndex' property set to -1 | |
| 595 | + * - checkbox and radio inputs will have their 'checked' property set to false | |
| 596 | + * - inputs of type submit, button, reset, and hidden will *not* be effected | |
| 597 | + * - button elements will *not* be effected | |
| 598 | + */ | |
| 599 | +$.fn.clearForm = function() { | |
| 600 | + return this.each(function() { | |
| 601 | + $('input,select,textarea', this).clearFields(); | |
| 602 | + }); | |
| 603 | +}; | |
| 604 | + | |
| 605 | +/** | |
| 606 | + * Clears the selected form elements. | |
| 607 | + */ | |
| 608 | +$.fn.clearFields = $.fn.clearInputs = function() { | |
| 609 | + return this.each(function() { | |
| 610 | + var t = this.type, tag = this.tagName.toLowerCase(); | |
| 611 | + if (t == 'text' || t == 'password' || tag == 'textarea') | |
| 612 | + this.value = ''; | |
| 613 | + else if (t == 'checkbox' || t == 'radio') | |
| 614 | + this.checked = false; | |
| 615 | + else if (tag == 'select') | |
| 616 | + this.selectedIndex = -1; | |
| 617 | + }); | |
| 618 | +}; | |
| 619 | + | |
| 620 | +/** | |
| 621 | + * Resets the form data. Causes all form elements to be reset to their original value. | |
| 622 | + */ | |
| 623 | +$.fn.resetForm = function() { | |
| 624 | + return this.each(function() { | |
| 625 | + // guard against an input with the name of 'reset' | |
| 626 | + // note that IE reports the reset function as an 'object' | |
| 627 | + if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) | |
| 628 | + this.reset(); | |
| 629 | + }); | |
| 630 | +}; | |
| 631 | + | |
| 632 | +/** | |
| 633 | + * Enables or disables any matching elements. | |
| 634 | + */ | |
| 635 | +$.fn.enable = function(b) { | |
| 636 | + if (b == undefined) b = true; | |
| 637 | + return this.each(function() { | |
| 638 | + this.disabled = !b; | |
| 639 | + }); | |
| 640 | +}; | |
| 641 | + | |
| 642 | +/** | |
| 643 | + * Checks/unchecks any matching checkboxes or radio buttons and | |
| 644 | + * selects/deselects and matching option elements. | |
| 645 | + */ | |
| 646 | +$.fn.selected = function(select) { | |
| 647 | + if (select == undefined) select = true; | |
| 648 | + return this.each(function() { | |
| 649 | + var t = this.type; | |
| 650 | + if (t == 'checkbox' || t == 'radio') | |
| 651 | + this.checked = select; | |
| 652 | + else if (this.tagName.toLowerCase() == 'option') { | |
| 653 | + var $sel = $(this).parent('select'); | |
| 654 | + if (select && $sel[0] && $sel[0].type == 'select-one') { | |
| 655 | + // deselect all other options | |
| 656 | + $sel.find('option').selected(false); | |
| 657 | + } | |
| 658 | + this.selected = select; | |
| 659 | + } | |
| 660 | + }); | |
| 661 | +}; | |
| 662 | + | |
| 663 | +// helper fn for console logging | |
| 664 | +// set $.fn.ajaxSubmit.debug to true to enable debug logging | |
| 665 | +function log() { | |
| 666 | + if ($.fn.ajaxSubmit.debug) { | |
| 667 | + var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); | |
| 668 | + if (window.console && window.console.log) | |
| 669 | + window.console.log(msg); | |
| 670 | + else if (window.opera && window.opera.postError) | |
| 671 | + window.opera.postError(msg); | |
| 672 | + } | |
| 673 | +}; | |
| 674 | + | |
| 675 | +})(jQuery); | ... | ... |
public/stylesheets/application.css
| ... | ... | @@ -97,7 +97,7 @@ div#profile-disabled { |
| 97 | 97 | padding-left: 60px; |
| 98 | 98 | min-height: 40px; |
| 99 | 99 | width: 400px; |
| 100 | - background: url("../images/icons-app/alert.png") no-repeat 5px #ffffa9; | |
| 100 | + background: url('/images/icons-app/alert.png') no-repeat 5px #ffffa9; | |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | div#profile-disabled .unlock-button{ |
| ... | ... | @@ -2503,20 +2503,158 @@ div#activation_enterprise div { |
| 2503 | 2503 | |
| 2504 | 2504 | /* * * Show Product * * * * * * * * * * * * */ |
| 2505 | 2505 | |
| 2506 | -#show_product .product-pic { | |
| 2506 | +.controller-catalog #show_product .product-pic { | |
| 2507 | + border: 1px solid #D3D7CF; | |
| 2508 | +} | |
| 2509 | + | |
| 2510 | +#show_product, | |
| 2511 | +#category-product-edition { | |
| 2512 | + background-color: transparent; | |
| 2513 | + position: relative; | |
| 2514 | + padding: 5px; | |
| 2515 | + -moz-border-radius: 5px; | |
| 2516 | + -webkit-border-radius: 5px; | |
| 2517 | +} | |
| 2518 | + | |
| 2519 | +#show_product h2, | |
| 2520 | +#category-product-edition h2 { | |
| 2521 | + margin-top: 0px; | |
| 2522 | +} | |
| 2523 | + | |
| 2524 | +#show_product .field-value { | |
| 2525 | + font-weight: bold; | |
| 2526 | +} | |
| 2527 | + | |
| 2528 | +#product-category, | |
| 2529 | +.product-category-hierarchy { | |
| 2530 | + margin-top: 40px; | |
| 2531 | + margin-bottom: 12px; | |
| 2532 | + padding-left: 7px; | |
| 2533 | +} | |
| 2534 | + | |
| 2535 | +#product-category { | |
| 2536 | + height: 18px; | |
| 2537 | +} | |
| 2538 | + | |
| 2539 | +#product-category p { | |
| 2540 | + display: inline; | |
| 2541 | +} | |
| 2542 | + | |
| 2543 | +#category-product-edition { | |
| 2544 | + padding-left: 10px; | |
| 2545 | + padding-right: 10px; | |
| 2546 | +} | |
| 2547 | + | |
| 2548 | +#display-product-name, | |
| 2549 | +#display-product-category { | |
| 2507 | 2550 | float: left; |
| 2508 | - margin-right: 15px; | |
| 2509 | - border: 1px solid #444; | |
| 2510 | - padding: 2px; | |
| 2511 | - background: #FFF; | |
| 2512 | 2551 | } |
| 2513 | 2552 | |
| 2514 | -#show_product .product_category { | |
| 2553 | +#product-details { | |
| 2515 | 2554 | padding-top: 10px; |
| 2555 | + padding-bottom: 10px; | |
| 2556 | + position: relative; | |
| 2557 | +} | |
| 2558 | + | |
| 2559 | +#product-name h2 { | |
| 2560 | + display: inline; | |
| 2561 | +} | |
| 2562 | + | |
| 2563 | +#product_name { | |
| 2564 | + width: 90%; | |
| 2565 | +} | |
| 2566 | + | |
| 2567 | +#edit-product-name { | |
| 2568 | + margin-top: 10px; | |
| 2569 | +} | |
| 2570 | + | |
| 2571 | +#product-name, | |
| 2572 | +#product-details { | |
| 2573 | + position: relative; | |
| 2516 | 2574 | clear: left; |
| 2517 | 2575 | } |
| 2518 | 2576 | |
| 2577 | +#display-product-info { | |
| 2578 | + left: 290px; | |
| 2579 | + top: 10px; | |
| 2580 | + width: 360px; | |
| 2581 | + text-align: left; | |
| 2582 | + position: absolute; | |
| 2583 | + overflow: hidden; | |
| 2584 | +} | |
| 2585 | + | |
| 2586 | +#product-info-form { | |
| 2587 | + margin-top: 20px; | |
| 2588 | +} | |
| 2519 | 2589 | |
| 2590 | +#edit-product-category { | |
| 2591 | + padding: 15px 5px 10px; | |
| 2592 | +} | |
| 2593 | + | |
| 2594 | +#product-info .field-name { | |
| 2595 | + margin-top: 5px; | |
| 2596 | + margin-bottom: 15px; | |
| 2597 | +} | |
| 2598 | + | |
| 2599 | +#product-info .type-text input, | |
| 2600 | +#product-info select { | |
| 2601 | + width: 150px; | |
| 2602 | +} | |
| 2603 | + | |
| 2604 | +#product-info .section-title { | |
| 2605 | + display: none; | |
| 2606 | +} | |
| 2607 | + | |
| 2608 | +#product-qualifiers { | |
| 2609 | + padding-left: 0px; | |
| 2610 | +} | |
| 2611 | + | |
| 2612 | +#product-qualifiers li { | |
| 2613 | + list-style: none; | |
| 2614 | +} | |
| 2615 | + | |
| 2616 | +#edit-product-button-ui-info { | |
| 2617 | + margin-top: 40px; | |
| 2618 | +} | |
| 2619 | + | |
| 2620 | +#product-image { | |
| 2621 | + text-align: center; | |
| 2622 | + padding: 10px; | |
| 2623 | + width: 250px; | |
| 2624 | + margin-right: 10px; | |
| 2625 | + margin-bottom: 5px; | |
| 2626 | + border: 1px solid #AAA; | |
| 2627 | +} | |
| 2628 | + | |
| 2629 | +#product-image p { | |
| 2630 | + font-size: 11px; | |
| 2631 | + font-style: italic; | |
| 2632 | + margin-top: 0px; | |
| 2633 | + color: #555; | |
| 2634 | +} | |
| 2635 | + | |
| 2636 | +#display-product-image { | |
| 2637 | + margin-bottom: 10px; | |
| 2638 | + overflow: hidden; | |
| 2639 | +} | |
| 2640 | + | |
| 2641 | +#edit-product-image { | |
| 2642 | + position: relative; | |
| 2643 | + margin-top: 5px; | |
| 2644 | +} | |
| 2645 | + | |
| 2646 | +#product-qualifiers-list { | |
| 2647 | + padding: 0px; | |
| 2648 | +} | |
| 2649 | + | |
| 2650 | +#product-qualifiers-list li { | |
| 2651 | + list-style: none; | |
| 2652 | +} | |
| 2653 | + | |
| 2654 | +#product-qualifiers-list .product-qualifier-title, | |
| 2655 | +#product-qualifiers-list .product-certifier-title { | |
| 2656 | + margin-right: 20px; | |
| 2657 | +} | |
| 2520 | 2658 | /* ==> public/stylesheets/controller_cms.css <== */ |
| 2521 | 2659 | |
| 2522 | 2660 | .controller-cms #article_types li { |
| ... | ... | @@ -3007,7 +3145,7 @@ h1#agenda-title { |
| 3007 | 3145 | #new_product_title { |
| 3008 | 3146 | text-align: center; |
| 3009 | 3147 | } |
| 3010 | -#new_product_form { | |
| 3148 | +#product_category_form { | |
| 3011 | 3149 | border: 1px solid #AABB88; |
| 3012 | 3150 | -moz-border-radius: 5px; |
| 3013 | 3151 | -webkit-border-radius: 5px; |
| ... | ... | @@ -3063,7 +3201,7 @@ h1#agenda-title { |
| 3063 | 3201 | display: block; |
| 3064 | 3202 | } |
| 3065 | 3203 | #hierarchy_navigation { |
| 3066 | - min-height: 1em; | |
| 3204 | + min-height: 1.3em; | |
| 3067 | 3205 | } |
| 3068 | 3206 | .msie #hierarchy_navigation { |
| 3069 | 3207 | font-size: small; |
| ... | ... | @@ -3903,7 +4041,8 @@ h1#agenda-title { |
| 3903 | 4041 | /* jquery.ui custom styles */ |
| 3904 | 4042 | |
| 3905 | 4043 | .fg-button span { |
| 3906 | - padding: 0.1em 1em !important; | |
| 4044 | + padding-top: 0.1em !important; | |
| 4045 | + padding-bottom: 0.1em !important; | |
| 3907 | 4046 | } |
| 3908 | 4047 | |
| 3909 | 4048 | .treeitem .button{ | ... | ... |
public/stylesheets/jquery.ui/south-street/images/ui-anim_basic_16x16.gif
0 → 100644
1.52 KB
public/stylesheets/jquery.ui/south-street/images/ui-bg_glass_55_fcf0ba_1x400.png
0 → 100644
127 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_gloss-wave_100_ece8da_500x100.png
0 → 100644
2.08 KB
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-hard_100_f5f3e5_1x100.png
0 → 100644
110 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-hard_100_fafaf4_1x100.png
0 → 100644
96 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-hard_15_459e00_1x100.png
0 → 100644
153 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-hard_95_cccccc_1x100.png
0 → 100644
105 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-soft_25_67b021_1x100.png
0 → 100644
124 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_highlight-soft_95_ffedad_1x100.png
0 → 100644
165 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-bg_inset-soft_15_2b2922_1x100.png
0 → 100644
119 Bytes
public/stylesheets/jquery.ui/south-street/images/ui-icons_808080_256x240.png
0 → 100644
4.27 KB
public/stylesheets/jquery.ui/south-street/images/ui-icons_847e71_256x240.png
0 → 100644
4.27 KB
public/stylesheets/jquery.ui/south-street/images/ui-icons_8dc262_256x240.png
0 → 100644
5.23 KB
public/stylesheets/jquery.ui/south-street/images/ui-icons_cd0a0a_256x240.png
0 → 100644
4.27 KB
public/stylesheets/jquery.ui/south-street/images/ui-icons_eeeeee_256x240.png
0 → 100644
4.27 KB
public/stylesheets/jquery.ui/south-street/images/ui-icons_ffffff_256x240.png
0 → 100644
4.27 KB
public/stylesheets/jquery.ui/south-street/jquery-ui-1.8.2.custom.css
0 → 100644
| ... | ... | @@ -0,0 +1,489 @@ |
| 1 | +/* | |
| 2 | +* jQuery UI CSS Framework | |
| 3 | +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) | |
| 4 | +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. | |
| 5 | +*/ | |
| 6 | + | |
| 7 | +/* Layout helpers | |
| 8 | +----------------------------------*/ | |
| 9 | +.ui-helper-hidden { display: none; } | |
| 10 | +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } | |
| 11 | +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } | |
| 12 | +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } | |
| 13 | +.ui-helper-clearfix { display: inline-block; } | |
| 14 | +/* required comment for clearfix to work in Opera \*/ | |
| 15 | +* html .ui-helper-clearfix { height:1%; } | |
| 16 | +.ui-helper-clearfix { display:block; } | |
| 17 | +/* end clearfix */ | |
| 18 | +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } | |
| 19 | + | |
| 20 | + | |
| 21 | +/* Interaction Cues | |
| 22 | +----------------------------------*/ | |
| 23 | +.ui-state-disabled { cursor: default !important; } | |
| 24 | + | |
| 25 | + | |
| 26 | +/* Icons | |
| 27 | +----------------------------------*/ | |
| 28 | + | |
| 29 | +/* states and images */ | |
| 30 | +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } | |
| 31 | + | |
| 32 | + | |
| 33 | +/* Misc visuals | |
| 34 | +----------------------------------*/ | |
| 35 | + | |
| 36 | +/* Overlays */ | |
| 37 | +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } | |
| 38 | + | |
| 39 | + | |
| 40 | +/* | |
| 41 | +* jQuery UI CSS Framework | |
| 42 | +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) | |
| 43 | +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. | |
| 44 | +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=segoe%20ui,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=ece8da&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=100&borderColorHeader=d4ccb0&fcHeader=433f38&iconColorHeader=847e71&bgColorContent=f5f3e5&bgTextureContent=04_highlight_hard.png&bgImgOpacityContent=100&borderColorContent=dfd9c3&fcContent=312e25&iconColorContent=808080&bgColorDefault=459e00&bgTextureDefault=04_highlight_hard.png&bgImgOpacityDefault=15&borderColorDefault=327E04&fcDefault=ffffff&iconColorDefault=eeeeee&bgColorHover=67b021&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=327E04&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=fafaf4&bgTextureActive=04_highlight_hard.png&bgImgOpacityActive=100&borderColorActive=d4ccb0&fcActive=459e00&iconColorActive=8DC262&bgColorHighlight=fcf0ba&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=e8e1b5&fcHighlight=363636&iconColorHighlight=8DC262&bgColorError=ffedad&bgTextureError=03_highlight_soft.png&bgImgOpacityError=95&borderColorError=e3a345&fcError=cd5c0a&iconColorError=cd0a0a&bgColorOverlay=2b2922&bgTextureOverlay=05_inset_soft.png&bgImgOpacityOverlay=15&opacityOverlay=90&bgColorShadow=cccccc&bgTextureShadow=04_highlight_hard.png&bgImgOpacityShadow=95&opacityShadow=20&thicknessShadow=12px&offsetTopShadow=-12px&offsetLeftShadow=-12px&cornerRadiusShadow=10px | |
| 45 | +*/ | |
| 46 | + | |
| 47 | + | |
| 48 | +/* Component containers | |
| 49 | +----------------------------------*/ | |
| 50 | +.ui-widget { font-family: segoe ui, Arial, sans-serif; font-size: 1.1em; } | |
| 51 | +.ui-widget .ui-widget { font-size: 1em; } | |
| 52 | +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: segoe ui, Arial, sans-serif; font-size: 1em; } | |
| 53 | +.ui-widget-content { border: 1px solid #dfd9c3; background: #f5f3e5 url(images/ui-bg_highlight-hard_100_f5f3e5_1x100.png) 50% top repeat-x; color: #312e25; } | |
| 54 | +.ui-widget-content a { color: #312e25; } | |
| 55 | +.ui-widget-header { border: 1px solid #d4ccb0; background: #ece8da url(images/ui-bg_gloss-wave_100_ece8da_500x100.png) 50% 50% repeat-x; color: #433f38; font-weight: bold; } | |
| 56 | +.ui-widget-header a { color: #433f38; } | |
| 57 | + | |
| 58 | +/* Interaction states | |
| 59 | +----------------------------------*/ | |
| 60 | +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #327e04; background: #459e00 url(images/ui-bg_highlight-hard_15_459e00_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; } | |
| 61 | +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #ffffff; text-decoration: none; } | |
| 62 | +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #327e04; background: #67b021 url(images/ui-bg_highlight-soft_25_67b021_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; } | |
| 63 | +.ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; } | |
| 64 | +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #d4ccb0; background: #fafaf4 url(images/ui-bg_highlight-hard_100_fafaf4_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #459e00; } | |
| 65 | +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #459e00; text-decoration: none; } | |
| 66 | +.ui-widget :active { outline: none; } | |
| 67 | + | |
| 68 | +/* Interaction Cues | |
| 69 | +----------------------------------*/ | |
| 70 | +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #e8e1b5; background: #fcf0ba url(images/ui-bg_glass_55_fcf0ba_1x400.png) 50% 50% repeat-x; color: #363636; } | |
| 71 | +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } | |
| 72 | +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #e3a345; background: #ffedad url(images/ui-bg_highlight-soft_95_ffedad_1x100.png) 50% top repeat-x; color: #cd5c0a; } | |
| 73 | +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd5c0a; } | |
| 74 | +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd5c0a; } | |
| 75 | +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } | |
| 76 | +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } | |
| 77 | +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } | |
| 78 | + | |
| 79 | +/* Icons | |
| 80 | +----------------------------------*/ | |
| 81 | + | |
| 82 | +/* states and images */ | |
| 83 | +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_808080_256x240.png); } | |
| 84 | +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_808080_256x240.png); } | |
| 85 | +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_847e71_256x240.png); } | |
| 86 | +.ui-state-default .ui-icon { background-image: url(images/ui-icons_eeeeee_256x240.png); } | |
| 87 | +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } | |
| 88 | +.ui-state-active .ui-icon {background-image: url(images/ui-icons_8dc262_256x240.png); } | |
| 89 | +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_8dc262_256x240.png); } | |
| 90 | +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } | |
| 91 | + | |
| 92 | +/* positioning */ | |
| 93 | +.ui-icon-carat-1-n { background-position: 0 0; } | |
| 94 | +.ui-icon-carat-1-ne { background-position: -16px 0; } | |
| 95 | +.ui-icon-carat-1-e { background-position: -32px 0; } | |
| 96 | +.ui-icon-carat-1-se { background-position: -48px 0; } | |
| 97 | +.ui-icon-carat-1-s { background-position: -64px 0; } | |
| 98 | +.ui-icon-carat-1-sw { background-position: -80px 0; } | |
| 99 | +.ui-icon-carat-1-w { background-position: -96px 0; } | |
| 100 | +.ui-icon-carat-1-nw { background-position: -112px 0; } | |
| 101 | +.ui-icon-carat-2-n-s { background-position: -128px 0; } | |
| 102 | +.ui-icon-carat-2-e-w { background-position: -144px 0; } | |
| 103 | +.ui-icon-triangle-1-n { background-position: 0 -16px; } | |
| 104 | +.ui-icon-triangle-1-ne { background-position: -16px -16px; } | |
| 105 | +.ui-icon-triangle-1-e { background-position: -32px -16px; } | |
| 106 | +.ui-icon-triangle-1-se { background-position: -48px -16px; } | |
| 107 | +.ui-icon-triangle-1-s { background-position: -64px -16px; } | |
| 108 | +.ui-icon-triangle-1-sw { background-position: -80px -16px; } | |
| 109 | +.ui-icon-triangle-1-w { background-position: -96px -16px; } | |
| 110 | +.ui-icon-triangle-1-nw { background-position: -112px -16px; } | |
| 111 | +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } | |
| 112 | +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } | |
| 113 | +.ui-icon-arrow-1-n { background-position: 0 -32px; } | |
| 114 | +.ui-icon-arrow-1-ne { background-position: -16px -32px; } | |
| 115 | +.ui-icon-arrow-1-e { background-position: -32px -32px; } | |
| 116 | +.ui-icon-arrow-1-se { background-position: -48px -32px; } | |
| 117 | +.ui-icon-arrow-1-s { background-position: -64px -32px; } | |
| 118 | +.ui-icon-arrow-1-sw { background-position: -80px -32px; } | |
| 119 | +.ui-icon-arrow-1-w { background-position: -96px -32px; } | |
| 120 | +.ui-icon-arrow-1-nw { background-position: -112px -32px; } | |
| 121 | +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } | |
| 122 | +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } | |
| 123 | +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } | |
| 124 | +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } | |
| 125 | +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } | |
| 126 | +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } | |
| 127 | +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } | |
| 128 | +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } | |
| 129 | +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } | |
| 130 | +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } | |
| 131 | +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } | |
| 132 | +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } | |
| 133 | +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } | |
| 134 | +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } | |
| 135 | +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } | |
| 136 | +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } | |
| 137 | +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } | |
| 138 | +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } | |
| 139 | +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } | |
| 140 | +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } | |
| 141 | +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } | |
| 142 | +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } | |
| 143 | +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } | |
| 144 | +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } | |
| 145 | +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } | |
| 146 | +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } | |
| 147 | +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } | |
| 148 | +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } | |
| 149 | +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } | |
| 150 | +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } | |
| 151 | +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } | |
| 152 | +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } | |
| 153 | +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } | |
| 154 | +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } | |
| 155 | +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } | |
| 156 | +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } | |
| 157 | +.ui-icon-arrow-4 { background-position: 0 -80px; } | |
| 158 | +.ui-icon-arrow-4-diag { background-position: -16px -80px; } | |
| 159 | +.ui-icon-extlink { background-position: -32px -80px; } | |
| 160 | +.ui-icon-newwin { background-position: -48px -80px; } | |
| 161 | +.ui-icon-refresh { background-position: -64px -80px; } | |
| 162 | +.ui-icon-shuffle { background-position: -80px -80px; } | |
| 163 | +.ui-icon-transfer-e-w { background-position: -96px -80px; } | |
| 164 | +.ui-icon-transferthick-e-w { background-position: -112px -80px; } | |
| 165 | +.ui-icon-folder-collapsed { background-position: 0 -96px; } | |
| 166 | +.ui-icon-folder-open { background-position: -16px -96px; } | |
| 167 | +.ui-icon-document { background-position: -32px -96px; } | |
| 168 | +.ui-icon-document-b { background-position: -48px -96px; } | |
| 169 | +.ui-icon-note { background-position: -64px -96px; } | |
| 170 | +.ui-icon-mail-closed { background-position: -80px -96px; } | |
| 171 | +.ui-icon-mail-open { background-position: -96px -96px; } | |
| 172 | +.ui-icon-suitcase { background-position: -112px -96px; } | |
| 173 | +.ui-icon-comment { background-position: -128px -96px; } | |
| 174 | +.ui-icon-person { background-position: -144px -96px; } | |
| 175 | +.ui-icon-print { background-position: -160px -96px; } | |
| 176 | +.ui-icon-trash { background-position: -176px -96px; } | |
| 177 | +.ui-icon-locked { background-position: -192px -96px; } | |
| 178 | +.ui-icon-unlocked { background-position: -208px -96px; } | |
| 179 | +.ui-icon-bookmark { background-position: -224px -96px; } | |
| 180 | +.ui-icon-tag { background-position: -240px -96px; } | |
| 181 | +.ui-icon-home { background-position: 0 -112px; } | |
| 182 | +.ui-icon-flag { background-position: -16px -112px; } | |
| 183 | +.ui-icon-calendar { background-position: -32px -112px; } | |
| 184 | +.ui-icon-cart { background-position: -48px -112px; } | |
| 185 | +.ui-icon-pencil { background-position: -64px -112px; } | |
| 186 | +.ui-icon-clock { background-position: -80px -112px; } | |
| 187 | +.ui-icon-disk { background-position: -96px -112px; } | |
| 188 | +.ui-icon-calculator { background-position: -112px -112px; } | |
| 189 | +.ui-icon-zoomin { background-position: -128px -112px; } | |
| 190 | +.ui-icon-zoomout { background-position: -144px -112px; } | |
| 191 | +.ui-icon-search { background-position: -160px -112px; } | |
| 192 | +.ui-icon-wrench { background-position: -176px -112px; } | |
| 193 | +.ui-icon-gear { background-position: -192px -112px; } | |
| 194 | +.ui-icon-heart { background-position: -208px -112px; } | |
| 195 | +.ui-icon-star { background-position: -224px -112px; } | |
| 196 | +.ui-icon-link { background-position: -240px -112px; } | |
| 197 | +.ui-icon-cancel { background-position: 0 -128px; } | |
| 198 | +.ui-icon-plus { background-position: -16px -128px; } | |
| 199 | +.ui-icon-plusthick { background-position: -32px -128px; } | |
| 200 | +.ui-icon-minus { background-position: -48px -128px; } | |
| 201 | +.ui-icon-minusthick { background-position: -64px -128px; } | |
| 202 | +.ui-icon-close { background-position: -80px -128px; } | |
| 203 | +.ui-icon-closethick { background-position: -96px -128px; } | |
| 204 | +.ui-icon-key { background-position: -112px -128px; } | |
| 205 | +.ui-icon-lightbulb { background-position: -128px -128px; } | |
| 206 | +.ui-icon-scissors { background-position: -144px -128px; } | |
| 207 | +.ui-icon-clipboard { background-position: -160px -128px; } | |
| 208 | +.ui-icon-copy { background-position: -176px -128px; } | |
| 209 | +.ui-icon-contact { background-position: -192px -128px; } | |
| 210 | +.ui-icon-image { background-position: -208px -128px; } | |
| 211 | +.ui-icon-video { background-position: -224px -128px; } | |
| 212 | +.ui-icon-script { background-position: -240px -128px; } | |
| 213 | +.ui-icon-alert { background-position: 0 -144px; } | |
| 214 | +.ui-icon-info { background-position: -16px -144px; } | |
| 215 | +.ui-icon-notice { background-position: -32px -144px; } | |
| 216 | +.ui-icon-help { background-position: -48px -144px; } | |
| 217 | +.ui-icon-check { background-position: -64px -144px; } | |
| 218 | +.ui-icon-bullet { background-position: -80px -144px; } | |
| 219 | +.ui-icon-radio-off { background-position: -96px -144px; } | |
| 220 | +.ui-icon-radio-on { background-position: -112px -144px; } | |
| 221 | +.ui-icon-pin-w { background-position: -128px -144px; } | |
| 222 | +.ui-icon-pin-s { background-position: -144px -144px; } | |
| 223 | +.ui-icon-play { background-position: 0 -160px; } | |
| 224 | +.ui-icon-pause { background-position: -16px -160px; } | |
| 225 | +.ui-icon-seek-next { background-position: -32px -160px; } | |
| 226 | +.ui-icon-seek-prev { background-position: -48px -160px; } | |
| 227 | +.ui-icon-seek-end { background-position: -64px -160px; } | |
| 228 | +.ui-icon-seek-start { background-position: -80px -160px; } | |
| 229 | +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ | |
| 230 | +.ui-icon-seek-first { background-position: -80px -160px; } | |
| 231 | +.ui-icon-stop { background-position: -96px -160px; } | |
| 232 | +.ui-icon-eject { background-position: -112px -160px; } | |
| 233 | +.ui-icon-volume-off { background-position: -128px -160px; } | |
| 234 | +.ui-icon-volume-on { background-position: -144px -160px; } | |
| 235 | +.ui-icon-power { background-position: 0 -176px; } | |
| 236 | +.ui-icon-signal-diag { background-position: -16px -176px; } | |
| 237 | +.ui-icon-signal { background-position: -32px -176px; } | |
| 238 | +.ui-icon-battery-0 { background-position: -48px -176px; } | |
| 239 | +.ui-icon-battery-1 { background-position: -64px -176px; } | |
| 240 | +.ui-icon-battery-2 { background-position: -80px -176px; } | |
| 241 | +.ui-icon-battery-3 { background-position: -96px -176px; } | |
| 242 | +.ui-icon-circle-plus { background-position: 0 -192px; } | |
| 243 | +.ui-icon-circle-minus { background-position: -16px -192px; } | |
| 244 | +.ui-icon-circle-close { background-position: -32px -192px; } | |
| 245 | +.ui-icon-circle-triangle-e { background-position: -48px -192px; } | |
| 246 | +.ui-icon-circle-triangle-s { background-position: -64px -192px; } | |
| 247 | +.ui-icon-circle-triangle-w { background-position: -80px -192px; } | |
| 248 | +.ui-icon-circle-triangle-n { background-position: -96px -192px; } | |
| 249 | +.ui-icon-circle-arrow-e { background-position: -112px -192px; } | |
| 250 | +.ui-icon-circle-arrow-s { background-position: -128px -192px; } | |
| 251 | +.ui-icon-circle-arrow-w { background-position: -144px -192px; } | |
| 252 | +.ui-icon-circle-arrow-n { background-position: -160px -192px; } | |
| 253 | +.ui-icon-circle-zoomin { background-position: -176px -192px; } | |
| 254 | +.ui-icon-circle-zoomout { background-position: -192px -192px; } | |
| 255 | +.ui-icon-circle-check { background-position: -208px -192px; } | |
| 256 | +.ui-icon-circlesmall-plus { background-position: 0 -208px; } | |
| 257 | +.ui-icon-circlesmall-minus { background-position: -16px -208px; } | |
| 258 | +.ui-icon-circlesmall-close { background-position: -32px -208px; } | |
| 259 | +.ui-icon-squaresmall-plus { background-position: -48px -208px; } | |
| 260 | +.ui-icon-squaresmall-minus { background-position: -64px -208px; } | |
| 261 | +.ui-icon-squaresmall-close { background-position: -80px -208px; } | |
| 262 | +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } | |
| 263 | +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } | |
| 264 | +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } | |
| 265 | +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } | |
| 266 | +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } | |
| 267 | +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } | |
| 268 | + | |
| 269 | + | |
| 270 | +/* Misc visuals | |
| 271 | +----------------------------------*/ | |
| 272 | + | |
| 273 | +/* Corner radius */ | |
| 274 | +.ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; } | |
| 275 | +.ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; } | |
| 276 | +.ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; } | |
| 277 | +.ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; } | |
| 278 | +.ui-corner-top { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; } | |
| 279 | +.ui-corner-bottom { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; } | |
| 280 | +.ui-corner-right { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; } | |
| 281 | +.ui-corner-left { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; } | |
| 282 | +.ui-corner-all { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; } | |
| 283 | + | |
| 284 | +/* Overlays */ | |
| 285 | +.ui-widget-overlay { background: #2b2922 url(images/ui-bg_inset-soft_15_2b2922_1x100.png) 50% bottom repeat-x; opacity: .90;filter:Alpha(Opacity=90); } | |
| 286 | +.ui-widget-shadow { margin: -12px 0 0 -12px; padding: 12px; background: #cccccc url(images/ui-bg_highlight-hard_95_cccccc_1x100.png) 50% top repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; }/* Resizable | |
| 287 | +----------------------------------*/ | |
| 288 | +.ui-resizable { position: relative;} | |
| 289 | +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} | |
| 290 | +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } | |
| 291 | +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } | |
| 292 | +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } | |
| 293 | +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } | |
| 294 | +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } | |
| 295 | +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } | |
| 296 | +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } | |
| 297 | +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } | |
| 298 | +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Selectable | |
| 299 | +----------------------------------*/ | |
| 300 | +.ui-selectable-helper { border:1px dotted black } | |
| 301 | +/* Accordion | |
| 302 | +----------------------------------*/ | |
| 303 | +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } | |
| 304 | +.ui-accordion .ui-accordion-li-fix { display: inline; } | |
| 305 | +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } | |
| 306 | +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } | |
| 307 | +/* IE7-/Win - Fix extra vertical space in lists */ | |
| 308 | +.ui-accordion a { zoom: 1; } | |
| 309 | +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } | |
| 310 | +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } | |
| 311 | +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } | |
| 312 | +.ui-accordion .ui-accordion-content-active { display: block; }/* Autocomplete | |
| 313 | +----------------------------------*/ | |
| 314 | +.ui-autocomplete { position: absolute; cursor: default; } | |
| 315 | +.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; } | |
| 316 | + | |
| 317 | +/* workarounds */ | |
| 318 | +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ | |
| 319 | + | |
| 320 | +/* Menu | |
| 321 | +----------------------------------*/ | |
| 322 | +.ui-menu { | |
| 323 | + list-style:none; | |
| 324 | + padding: 2px; | |
| 325 | + margin: 0; | |
| 326 | + display:block; | |
| 327 | +} | |
| 328 | +.ui-menu .ui-menu { | |
| 329 | + margin-top: -3px; | |
| 330 | +} | |
| 331 | +.ui-menu .ui-menu-item { | |
| 332 | + margin:0; | |
| 333 | + padding: 0; | |
| 334 | + zoom: 1; | |
| 335 | + float: left; | |
| 336 | + clear: left; | |
| 337 | + width: 100%; | |
| 338 | +} | |
| 339 | +.ui-menu .ui-menu-item a { | |
| 340 | + text-decoration:none; | |
| 341 | + display:block; | |
| 342 | + padding:.2em .4em; | |
| 343 | + line-height:1.5; | |
| 344 | + zoom:1; | |
| 345 | +} | |
| 346 | +.ui-menu .ui-menu-item a.ui-state-hover, | |
| 347 | +.ui-menu .ui-menu-item a.ui-state-active { | |
| 348 | + font-weight: normal; | |
| 349 | + margin: -1px; | |
| 350 | +} | |
| 351 | +/* Button | |
| 352 | +----------------------------------*/ | |
| 353 | + | |
| 354 | +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ | |
| 355 | +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ | |
| 356 | +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ | |
| 357 | +.ui-button-icons-only { width: 3.4em; } | |
| 358 | +button.ui-button-icons-only { width: 3.7em; } | |
| 359 | + | |
| 360 | +/*button text element */ | |
| 361 | +.ui-button .ui-button-text { display: block; line-height: 1.4; } | |
| 362 | +.ui-button-text-only .ui-button-text { padding: .4em 1em; } | |
| 363 | +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } | |
| 364 | +.ui-button-text-icon .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } | |
| 365 | +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } | |
| 366 | +/* no icon support for input elements, provide padding by default */ | |
| 367 | +input.ui-button { padding: .4em 1em; } | |
| 368 | + | |
| 369 | +/*button icon element(s) */ | |
| 370 | +.ui-button-icon-only .ui-icon, .ui-button-text-icon .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } | |
| 371 | +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } | |
| 372 | +.ui-button-text-icon .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } | |
| 373 | +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } | |
| 374 | + | |
| 375 | +/*button sets*/ | |
| 376 | +.ui-buttonset { margin-right: 7px; } | |
| 377 | +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } | |
| 378 | + | |
| 379 | +/* workarounds */ | |
| 380 | +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | +/* Dialog | |
| 387 | +----------------------------------*/ | |
| 388 | +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } | |
| 389 | +.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } | |
| 390 | +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } | |
| 391 | +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } | |
| 392 | +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } | |
| 393 | +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } | |
| 394 | +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } | |
| 395 | +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } | |
| 396 | +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } | |
| 397 | +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } | |
| 398 | +.ui-draggable .ui-dialog-titlebar { cursor: move; } | |
| 399 | +/* Slider | |
| 400 | +----------------------------------*/ | |
| 401 | +.ui-slider { position: relative; text-align: left; } | |
| 402 | +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } | |
| 403 | +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } | |
| 404 | + | |
| 405 | +.ui-slider-horizontal { height: .8em; } | |
| 406 | +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } | |
| 407 | +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } | |
| 408 | +.ui-slider-horizontal .ui-slider-range-min { left: 0; } | |
| 409 | +.ui-slider-horizontal .ui-slider-range-max { right: 0; } | |
| 410 | + | |
| 411 | +.ui-slider-vertical { width: .8em; height: 100px; } | |
| 412 | +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } | |
| 413 | +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } | |
| 414 | +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } | |
| 415 | +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs | |
| 416 | +----------------------------------*/ | |
| 417 | +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ | |
| 418 | +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } | |
| 419 | +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } | |
| 420 | +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } | |
| 421 | +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } | |
| 422 | +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } | |
| 423 | +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ | |
| 424 | +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } | |
| 425 | +.ui-tabs .ui-tabs-hide { display: none !important; } | |
| 426 | +/* Datepicker | |
| 427 | +----------------------------------*/ | |
| 428 | +.ui-datepicker { width: 17em; padding: .2em .2em 0; } | |
| 429 | +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } | |
| 430 | +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } | |
| 431 | +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } | |
| 432 | +.ui-datepicker .ui-datepicker-prev { left:2px; } | |
| 433 | +.ui-datepicker .ui-datepicker-next { right:2px; } | |
| 434 | +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } | |
| 435 | +.ui-datepicker .ui-datepicker-next-hover { right:1px; } | |
| 436 | +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } | |
| 437 | +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } | |
| 438 | +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } | |
| 439 | +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} | |
| 440 | +.ui-datepicker select.ui-datepicker-month, | |
| 441 | +.ui-datepicker select.ui-datepicker-year { width: 49%;} | |
| 442 | +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } | |
| 443 | +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } | |
| 444 | +.ui-datepicker td { border: 0; padding: 1px; } | |
| 445 | +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } | |
| 446 | +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } | |
| 447 | +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } | |
| 448 | +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } | |
| 449 | + | |
| 450 | +/* with multiple calendars */ | |
| 451 | +.ui-datepicker.ui-datepicker-multi { width:auto; } | |
| 452 | +.ui-datepicker-multi .ui-datepicker-group { float:left; } | |
| 453 | +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } | |
| 454 | +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } | |
| 455 | +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } | |
| 456 | +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } | |
| 457 | +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } | |
| 458 | +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } | |
| 459 | +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } | |
| 460 | +.ui-datepicker-row-break { clear:both; width:100%; } | |
| 461 | + | |
| 462 | +/* RTL support */ | |
| 463 | +.ui-datepicker-rtl { direction: rtl; } | |
| 464 | +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } | |
| 465 | +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } | |
| 466 | +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } | |
| 467 | +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } | |
| 468 | +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } | |
| 469 | +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } | |
| 470 | +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } | |
| 471 | +.ui-datepicker-rtl .ui-datepicker-group { float:right; } | |
| 472 | +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } | |
| 473 | +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } | |
| 474 | + | |
| 475 | +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ | |
| 476 | +.ui-datepicker-cover { | |
| 477 | + display: none; /*sorry for IE5*/ | |
| 478 | + display/**/: block; /*sorry for IE5*/ | |
| 479 | + position: absolute; /*must have*/ | |
| 480 | + z-index: -1; /*must have*/ | |
| 481 | + filter: mask(); /*must have*/ | |
| 482 | + top: -4px; /*must have*/ | |
| 483 | + left: -4px; /*must have*/ | |
| 484 | + width: 200px; /*must have*/ | |
| 485 | + height: 200px; /*must have*/ | |
| 486 | +}/* Progressbar | |
| 487 | +----------------------------------*/ | |
| 488 | +.ui-progressbar { height:2em; text-align: left; } | |
| 489 | +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } | |
| 0 | 490 | \ No newline at end of file | ... | ... |
1.52 KB
public/stylesheets/jquery.ui/sunny/images/ui-bg_diagonals-medium_20_d34d17_40x40.png
0 → 100644
199 Bytes
public/stylesheets/jquery.ui/sunny/images/ui-bg_flat_30_cccccc_40x100.png
0 → 100644
180 Bytes
public/stylesheets/jquery.ui/sunny/images/ui-bg_flat_50_5c5c5c_40x100.png
0 → 100644
180 Bytes
public/stylesheets/jquery.ui/sunny/images/ui-bg_gloss-wave_45_817865_500x100.png
0 → 100644
3.88 KB
public/stylesheets/jquery.ui/sunny/images/ui-bg_gloss-wave_60_fece2f_500x100.png
0 → 100644
3.43 KB
public/stylesheets/jquery.ui/sunny/images/ui-bg_gloss-wave_70_ffdd57_500x100.png
0 → 100644
3.05 KB
public/stylesheets/jquery.ui/sunny/images/ui-bg_gloss-wave_90_fff9e5_500x100.png
0 → 100644
2.2 KB
public/stylesheets/jquery.ui/sunny/images/ui-bg_highlight-soft_100_feeebd_1x100.png
0 → 100644
108 Bytes
public/stylesheets/jquery.ui/sunny/images/ui-bg_inset-soft_30_ffffff_1x100.png
0 → 100644
100 Bytes
4.27 KB
5.23 KB
4.27 KB
4.27 KB
4.27 KB
4.27 KB
5.23 KB
public/stylesheets/jquery.ui/sunny/jquery-ui-1.8.2.custom.css
0 → 100644
| ... | ... | @@ -0,0 +1,489 @@ |
| 1 | +/* | |
| 2 | +* jQuery UI CSS Framework | |
| 3 | +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) | |
| 4 | +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. | |
| 5 | +*/ | |
| 6 | + | |
| 7 | +/* Layout helpers | |
| 8 | +----------------------------------*/ | |
| 9 | +.ui-helper-hidden { display: none; } | |
| 10 | +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } | |
| 11 | +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } | |
| 12 | +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } | |
| 13 | +.ui-helper-clearfix { display: inline-block; } | |
| 14 | +/* required comment for clearfix to work in Opera \*/ | |
| 15 | +* html .ui-helper-clearfix { height:1%; } | |
| 16 | +.ui-helper-clearfix { display:block; } | |
| 17 | +/* end clearfix */ | |
| 18 | +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } | |
| 19 | + | |
| 20 | + | |
| 21 | +/* Interaction Cues | |
| 22 | +----------------------------------*/ | |
| 23 | +.ui-state-disabled { cursor: default !important; } | |
| 24 | + | |
| 25 | + | |
| 26 | +/* Icons | |
| 27 | +----------------------------------*/ | |
| 28 | + | |
| 29 | +/* states and images */ | |
| 30 | +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } | |
| 31 | + | |
| 32 | + | |
| 33 | +/* Misc visuals | |
| 34 | +----------------------------------*/ | |
| 35 | + | |
| 36 | +/* Overlays */ | |
| 37 | +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } | |
| 38 | + | |
| 39 | + | |
| 40 | +/* | |
| 41 | +* jQuery UI CSS Framework | |
| 42 | +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) | |
| 43 | +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. | |
| 44 | +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Segoe%20UI,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=8px&bgColorHeader=817865&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=45&borderColorHeader=494437&fcHeader=ffffff&iconColorHeader=fadc7a&bgColorContent=feeebd&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=8e846b&fcContent=383838&iconColorContent=d19405&bgColorDefault=fece2f&bgTextureDefault=12_gloss_wave.png&bgImgOpacityDefault=60&borderColorDefault=d19405&fcDefault=4c3000&iconColorDefault=3d3d3d&bgColorHover=ffdd57&bgTextureHover=12_gloss_wave.png&bgImgOpacityHover=70&borderColorHover=a45b13&fcHover=381f00&iconColorHover=bd7b00&bgColorActive=ffffff&bgTextureActive=05_inset_soft.png&bgImgOpacityActive=30&borderColorActive=655e4e&fcActive=0074c7&iconColorActive=eb990f&bgColorHighlight=fff9e5&bgTextureHighlight=12_gloss_wave.png&bgImgOpacityHighlight=90&borderColorHighlight=eeb420&fcHighlight=1f1f1f&iconColorHighlight=ed9f26&bgColorError=d34d17&bgTextureError=07_diagonals_medium.png&bgImgOpacityError=20&borderColorError=ffb73d&fcError=ffffff&iconColorError=ffe180&bgColorOverlay=5c5c5c&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=50&opacityOverlay=80&bgColorShadow=cccccc&bgTextureShadow=01_flat.png&bgImgOpacityShadow=30&opacityShadow=60&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px | |
| 45 | +*/ | |
| 46 | + | |
| 47 | + | |
| 48 | +/* Component containers | |
| 49 | +----------------------------------*/ | |
| 50 | +.ui-widget { font-family: Segoe UI, Arial, sans-serif; font-size: 1.1em; } | |
| 51 | +.ui-widget .ui-widget { font-size: 1em; } | |
| 52 | +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Segoe UI, Arial, sans-serif; font-size: 1em; } | |
| 53 | +.ui-widget-content { border: 1px solid #8e846b; background: #feeebd url(images/ui-bg_highlight-soft_100_feeebd_1x100.png) 50% top repeat-x; color: #383838; } | |
| 54 | +.ui-widget-content a { color: #383838; } | |
| 55 | +.ui-widget-header { border: 1px solid #494437; background: #817865 url(images/ui-bg_gloss-wave_45_817865_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } | |
| 56 | +.ui-widget-header a { color: #ffffff; } | |
| 57 | + | |
| 58 | +/* Interaction states | |
| 59 | +----------------------------------*/ | |
| 60 | +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d19405; background: #fece2f url(images/ui-bg_gloss-wave_60_fece2f_500x100.png) 50% 50% repeat-x; font-weight: bold; color: #4c3000; } | |
| 61 | +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4c3000; text-decoration: none; } | |
| 62 | +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #a45b13; background: #ffdd57 url(images/ui-bg_gloss-wave_70_ffdd57_500x100.png) 50% 50% repeat-x; font-weight: bold; color: #381f00; } | |
| 63 | +.ui-state-hover a, .ui-state-hover a:hover { color: #381f00; text-decoration: none; } | |
| 64 | +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #655e4e; background: #ffffff url(images/ui-bg_inset-soft_30_ffffff_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #0074c7; } | |
| 65 | +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #0074c7; text-decoration: none; } | |
| 66 | +.ui-widget :active { outline: none; } | |
| 67 | + | |
| 68 | +/* Interaction Cues | |
| 69 | +----------------------------------*/ | |
| 70 | +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #eeb420; background: #fff9e5 url(images/ui-bg_gloss-wave_90_fff9e5_500x100.png) 50% top repeat-x; color: #1f1f1f; } | |
| 71 | +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #1f1f1f; } | |
| 72 | +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #ffb73d; background: #d34d17 url(images/ui-bg_diagonals-medium_20_d34d17_40x40.png) 50% 50% repeat; color: #ffffff; } | |
| 73 | +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } | |
| 74 | +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } | |
| 75 | +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } | |
| 76 | +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } | |
| 77 | +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } | |
| 78 | + | |
| 79 | +/* Icons | |
| 80 | +----------------------------------*/ | |
| 81 | + | |
| 82 | +/* states and images */ | |
| 83 | +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_d19405_256x240.png); } | |
| 84 | +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_d19405_256x240.png); } | |
| 85 | +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_fadc7a_256x240.png); } | |
| 86 | +.ui-state-default .ui-icon { background-image: url(images/ui-icons_3d3d3d_256x240.png); } | |
| 87 | +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_bd7b00_256x240.png); } | |
| 88 | +.ui-state-active .ui-icon {background-image: url(images/ui-icons_eb990f_256x240.png); } | |
| 89 | +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_ed9f26_256x240.png); } | |
| 90 | +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffe180_256x240.png); } | |
| 91 | + | |
| 92 | +/* positioning */ | |
| 93 | +.ui-icon-carat-1-n { background-position: 0 0; } | |
| 94 | +.ui-icon-carat-1-ne { background-position: -16px 0; } | |
| 95 | +.ui-icon-carat-1-e { background-position: -32px 0; } | |
| 96 | +.ui-icon-carat-1-se { background-position: -48px 0; } | |
| 97 | +.ui-icon-carat-1-s { background-position: -64px 0; } | |
| 98 | +.ui-icon-carat-1-sw { background-position: -80px 0; } | |
| 99 | +.ui-icon-carat-1-w { background-position: -96px 0; } | |
| 100 | +.ui-icon-carat-1-nw { background-position: -112px 0; } | |
| 101 | +.ui-icon-carat-2-n-s { background-position: -128px 0; } | |
| 102 | +.ui-icon-carat-2-e-w { background-position: -144px 0; } | |
| 103 | +.ui-icon-triangle-1-n { background-position: 0 -16px; } | |
| 104 | +.ui-icon-triangle-1-ne { background-position: -16px -16px; } | |
| 105 | +.ui-icon-triangle-1-e { background-position: -32px -16px; } | |
| 106 | +.ui-icon-triangle-1-se { background-position: -48px -16px; } | |
| 107 | +.ui-icon-triangle-1-s { background-position: -64px -16px; } | |
| 108 | +.ui-icon-triangle-1-sw { background-position: -80px -16px; } | |
| 109 | +.ui-icon-triangle-1-w { background-position: -96px -16px; } | |
| 110 | +.ui-icon-triangle-1-nw { background-position: -112px -16px; } | |
| 111 | +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } | |
| 112 | +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } | |
| 113 | +.ui-icon-arrow-1-n { background-position: 0 -32px; } | |
| 114 | +.ui-icon-arrow-1-ne { background-position: -16px -32px; } | |
| 115 | +.ui-icon-arrow-1-e { background-position: -32px -32px; } | |
| 116 | +.ui-icon-arrow-1-se { background-position: -48px -32px; } | |
| 117 | +.ui-icon-arrow-1-s { background-position: -64px -32px; } | |
| 118 | +.ui-icon-arrow-1-sw { background-position: -80px -32px; } | |
| 119 | +.ui-icon-arrow-1-w { background-position: -96px -32px; } | |
| 120 | +.ui-icon-arrow-1-nw { background-position: -112px -32px; } | |
| 121 | +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } | |
| 122 | +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } | |
| 123 | +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } | |
| 124 | +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } | |
| 125 | +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } | |
| 126 | +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } | |
| 127 | +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } | |
| 128 | +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } | |
| 129 | +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } | |
| 130 | +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } | |
| 131 | +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } | |
| 132 | +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } | |
| 133 | +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } | |
| 134 | +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } | |
| 135 | +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } | |
| 136 | +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } | |
| 137 | +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } | |
| 138 | +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } | |
| 139 | +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } | |
| 140 | +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } | |
| 141 | +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } | |
| 142 | +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } | |
| 143 | +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } | |
| 144 | +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } | |
| 145 | +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } | |
| 146 | +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } | |
| 147 | +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } | |
| 148 | +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } | |
| 149 | +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } | |
| 150 | +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } | |
| 151 | +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } | |
| 152 | +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } | |
| 153 | +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } | |
| 154 | +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } | |
| 155 | +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } | |
| 156 | +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } | |
| 157 | +.ui-icon-arrow-4 { background-position: 0 -80px; } | |
| 158 | +.ui-icon-arrow-4-diag { background-position: -16px -80px; } | |
| 159 | +.ui-icon-extlink { background-position: -32px -80px; } | |
| 160 | +.ui-icon-newwin { background-position: -48px -80px; } | |
| 161 | +.ui-icon-refresh { background-position: -64px -80px; } | |
| 162 | +.ui-icon-shuffle { background-position: -80px -80px; } | |
| 163 | +.ui-icon-transfer-e-w { background-position: -96px -80px; } | |
| 164 | +.ui-icon-transferthick-e-w { background-position: -112px -80px; } | |
| 165 | +.ui-icon-folder-collapsed { background-position: 0 -96px; } | |
| 166 | +.ui-icon-folder-open { background-position: -16px -96px; } | |
| 167 | +.ui-icon-document { background-position: -32px -96px; } | |
| 168 | +.ui-icon-document-b { background-position: -48px -96px; } | |
| 169 | +.ui-icon-note { background-position: -64px -96px; } | |
| 170 | +.ui-icon-mail-closed { background-position: -80px -96px; } | |
| 171 | +.ui-icon-mail-open { background-position: -96px -96px; } | |
| 172 | +.ui-icon-suitcase { background-position: -112px -96px; } | |
| 173 | +.ui-icon-comment { background-position: -128px -96px; } | |
| 174 | +.ui-icon-person { background-position: -144px -96px; } | |
| 175 | +.ui-icon-print { background-position: -160px -96px; } | |
| 176 | +.ui-icon-trash { background-position: -176px -96px; } | |
| 177 | +.ui-icon-locked { background-position: -192px -96px; } | |
| 178 | +.ui-icon-unlocked { background-position: -208px -96px; } | |
| 179 | +.ui-icon-bookmark { background-position: -224px -96px; } | |
| 180 | +.ui-icon-tag { background-position: -240px -96px; } | |
| 181 | +.ui-icon-home { background-position: 0 -112px; } | |
| 182 | +.ui-icon-flag { background-position: -16px -112px; } | |
| 183 | +.ui-icon-calendar { background-position: -32px -112px; } | |
| 184 | +.ui-icon-cart { background-position: -48px -112px; } | |
| 185 | +.ui-icon-pencil { background-position: -64px -112px; } | |
| 186 | +.ui-icon-clock { background-position: -80px -112px; } | |
| 187 | +.ui-icon-disk { background-position: -96px -112px; } | |
| 188 | +.ui-icon-calculator { background-position: -112px -112px; } | |
| 189 | +.ui-icon-zoomin { background-position: -128px -112px; } | |
| 190 | +.ui-icon-zoomout { background-position: -144px -112px; } | |
| 191 | +.ui-icon-search { background-position: -160px -112px; } | |
| 192 | +.ui-icon-wrench { background-position: -176px -112px; } | |
| 193 | +.ui-icon-gear { background-position: -192px -112px; } | |
| 194 | +.ui-icon-heart { background-position: -208px -112px; } | |
| 195 | +.ui-icon-star { background-position: -224px -112px; } | |
| 196 | +.ui-icon-link { background-position: -240px -112px; } | |
| 197 | +.ui-icon-cancel { background-position: 0 -128px; } | |
| 198 | +.ui-icon-plus { background-position: -16px -128px; } | |
| 199 | +.ui-icon-plusthick { background-position: -32px -128px; } | |
| 200 | +.ui-icon-minus { background-position: -48px -128px; } | |
| 201 | +.ui-icon-minusthick { background-position: -64px -128px; } | |
| 202 | +.ui-icon-close { background-position: -80px -128px; } | |
| 203 | +.ui-icon-closethick { background-position: -96px -128px; } | |
| 204 | +.ui-icon-key { background-position: -112px -128px; } | |
| 205 | +.ui-icon-lightbulb { background-position: -128px -128px; } | |
| 206 | +.ui-icon-scissors { background-position: -144px -128px; } | |
| 207 | +.ui-icon-clipboard { background-position: -160px -128px; } | |
| 208 | +.ui-icon-copy { background-position: -176px -128px; } | |
| 209 | +.ui-icon-contact { background-position: -192px -128px; } | |
| 210 | +.ui-icon-image { background-position: -208px -128px; } | |
| 211 | +.ui-icon-video { background-position: -224px -128px; } | |
| 212 | +.ui-icon-script { background-position: -240px -128px; } | |
| 213 | +.ui-icon-alert { background-position: 0 -144px; } | |
| 214 | +.ui-icon-info { background-position: -16px -144px; } | |
| 215 | +.ui-icon-notice { background-position: -32px -144px; } | |
| 216 | +.ui-icon-help { background-position: -48px -144px; } | |
| 217 | +.ui-icon-check { background-position: -64px -144px; } | |
| 218 | +.ui-icon-bullet { background-position: -80px -144px; } | |
| 219 | +.ui-icon-radio-off { background-position: -96px -144px; } | |
| 220 | +.ui-icon-radio-on { background-position: -112px -144px; } | |
| 221 | +.ui-icon-pin-w { background-position: -128px -144px; } | |
| 222 | +.ui-icon-pin-s { background-position: -144px -144px; } | |
| 223 | +.ui-icon-play { background-position: 0 -160px; } | |
| 224 | +.ui-icon-pause { background-position: -16px -160px; } | |
| 225 | +.ui-icon-seek-next { background-position: -32px -160px; } | |
| 226 | +.ui-icon-seek-prev { background-position: -48px -160px; } | |
| 227 | +.ui-icon-seek-end { background-position: -64px -160px; } | |
| 228 | +.ui-icon-seek-start { background-position: -80px -160px; } | |
| 229 | +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ | |
| 230 | +.ui-icon-seek-first { background-position: -80px -160px; } | |
| 231 | +.ui-icon-stop { background-position: -96px -160px; } | |
| 232 | +.ui-icon-eject { background-position: -112px -160px; } | |
| 233 | +.ui-icon-volume-off { background-position: -128px -160px; } | |
| 234 | +.ui-icon-volume-on { background-position: -144px -160px; } | |
| 235 | +.ui-icon-power { background-position: 0 -176px; } | |
| 236 | +.ui-icon-signal-diag { background-position: -16px -176px; } | |
| 237 | +.ui-icon-signal { background-position: -32px -176px; } | |
| 238 | +.ui-icon-battery-0 { background-position: -48px -176px; } | |
| 239 | +.ui-icon-battery-1 { background-position: -64px -176px; } | |
| 240 | +.ui-icon-battery-2 { background-position: -80px -176px; } | |
| 241 | +.ui-icon-battery-3 { background-position: -96px -176px; } | |
| 242 | +.ui-icon-circle-plus { background-position: 0 -192px; } | |
| 243 | +.ui-icon-circle-minus { background-position: -16px -192px; } | |
| 244 | +.ui-icon-circle-close { background-position: -32px -192px; } | |
| 245 | +.ui-icon-circle-triangle-e { background-position: -48px -192px; } | |
| 246 | +.ui-icon-circle-triangle-s { background-position: -64px -192px; } | |
| 247 | +.ui-icon-circle-triangle-w { background-position: -80px -192px; } | |
| 248 | +.ui-icon-circle-triangle-n { background-position: -96px -192px; } | |
| 249 | +.ui-icon-circle-arrow-e { background-position: -112px -192px; } | |
| 250 | +.ui-icon-circle-arrow-s { background-position: -128px -192px; } | |
| 251 | +.ui-icon-circle-arrow-w { background-position: -144px -192px; } | |
| 252 | +.ui-icon-circle-arrow-n { background-position: -160px -192px; } | |
| 253 | +.ui-icon-circle-zoomin { background-position: -176px -192px; } | |
| 254 | +.ui-icon-circle-zoomout { background-position: -192px -192px; } | |
| 255 | +.ui-icon-circle-check { background-position: -208px -192px; } | |
| 256 | +.ui-icon-circlesmall-plus { background-position: 0 -208px; } | |
| 257 | +.ui-icon-circlesmall-minus { background-position: -16px -208px; } | |
| 258 | +.ui-icon-circlesmall-close { background-position: -32px -208px; } | |
| 259 | +.ui-icon-squaresmall-plus { background-position: -48px -208px; } | |
| 260 | +.ui-icon-squaresmall-minus { background-position: -64px -208px; } | |
| 261 | +.ui-icon-squaresmall-close { background-position: -80px -208px; } | |
| 262 | +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } | |
| 263 | +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } | |
| 264 | +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } | |
| 265 | +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } | |
| 266 | +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } | |
| 267 | +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } | |
| 268 | + | |
| 269 | + | |
| 270 | +/* Misc visuals | |
| 271 | +----------------------------------*/ | |
| 272 | + | |
| 273 | +/* Corner radius */ | |
| 274 | +.ui-corner-tl { -moz-border-radius-topleft: 8px; -webkit-border-top-left-radius: 8px; border-top-left-radius: 8px; } | |
| 275 | +.ui-corner-tr { -moz-border-radius-topright: 8px; -webkit-border-top-right-radius: 8px; border-top-right-radius: 8px; } | |
| 276 | +.ui-corner-bl { -moz-border-radius-bottomleft: 8px; -webkit-border-bottom-left-radius: 8px; border-bottom-left-radius: 8px; } | |
| 277 | +.ui-corner-br { -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px; border-bottom-right-radius: 8px; } | |
| 278 | +.ui-corner-top { -moz-border-radius-topleft: 8px; -webkit-border-top-left-radius: 8px; border-top-left-radius: 8px; -moz-border-radius-topright: 8px; -webkit-border-top-right-radius: 8px; border-top-right-radius: 8px; } | |
| 279 | +.ui-corner-bottom { -moz-border-radius-bottomleft: 8px; -webkit-border-bottom-left-radius: 8px; border-bottom-left-radius: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px; border-bottom-right-radius: 8px; } | |
| 280 | +.ui-corner-right { -moz-border-radius-topright: 8px; -webkit-border-top-right-radius: 8px; border-top-right-radius: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px; border-bottom-right-radius: 8px; } | |
| 281 | +.ui-corner-left { -moz-border-radius-topleft: 8px; -webkit-border-top-left-radius: 8px; border-top-left-radius: 8px; -moz-border-radius-bottomleft: 8px; -webkit-border-bottom-left-radius: 8px; border-bottom-left-radius: 8px; } | |
| 282 | +.ui-corner-all { -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } | |
| 283 | + | |
| 284 | +/* Overlays */ | |
| 285 | +.ui-widget-overlay { background: #5c5c5c url(images/ui-bg_flat_50_5c5c5c_40x100.png) 50% 50% repeat-x; opacity: .80;filter:Alpha(Opacity=80); } | |
| 286 | +.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; background: #cccccc url(images/ui-bg_flat_30_cccccc_40x100.png) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* Resizable | |
| 287 | +----------------------------------*/ | |
| 288 | +.ui-resizable { position: relative;} | |
| 289 | +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} | |
| 290 | +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } | |
| 291 | +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } | |
| 292 | +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } | |
| 293 | +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } | |
| 294 | +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } | |
| 295 | +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } | |
| 296 | +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } | |
| 297 | +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } | |
| 298 | +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Selectable | |
| 299 | +----------------------------------*/ | |
| 300 | +.ui-selectable-helper { border:1px dotted black } | |
| 301 | +/* Accordion | |
| 302 | +----------------------------------*/ | |
| 303 | +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } | |
| 304 | +.ui-accordion .ui-accordion-li-fix { display: inline; } | |
| 305 | +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } | |
| 306 | +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } | |
| 307 | +/* IE7-/Win - Fix extra vertical space in lists */ | |
| 308 | +.ui-accordion a { zoom: 1; } | |
| 309 | +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } | |
| 310 | +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } | |
| 311 | +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } | |
| 312 | +.ui-accordion .ui-accordion-content-active { display: block; }/* Autocomplete | |
| 313 | +----------------------------------*/ | |
| 314 | +.ui-autocomplete { position: absolute; cursor: default; } | |
| 315 | +.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; } | |
| 316 | + | |
| 317 | +/* workarounds */ | |
| 318 | +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ | |
| 319 | + | |
| 320 | +/* Menu | |
| 321 | +----------------------------------*/ | |
| 322 | +.ui-menu { | |
| 323 | + list-style:none; | |
| 324 | + padding: 2px; | |
| 325 | + margin: 0; | |
| 326 | + display:block; | |
| 327 | +} | |
| 328 | +.ui-menu .ui-menu { | |
| 329 | + margin-top: -3px; | |
| 330 | +} | |
| 331 | +.ui-menu .ui-menu-item { | |
| 332 | + margin:0; | |
| 333 | + padding: 0; | |
| 334 | + zoom: 1; | |
| 335 | + float: left; | |
| 336 | + clear: left; | |
| 337 | + width: 100%; | |
| 338 | +} | |
| 339 | +.ui-menu .ui-menu-item a { | |
| 340 | + text-decoration:none; | |
| 341 | + display:block; | |
| 342 | + padding:.2em .4em; | |
| 343 | + line-height:1.5; | |
| 344 | + zoom:1; | |
| 345 | +} | |
| 346 | +.ui-menu .ui-menu-item a.ui-state-hover, | |
| 347 | +.ui-menu .ui-menu-item a.ui-state-active { | |
| 348 | + font-weight: normal; | |
| 349 | + margin: -1px; | |
| 350 | +} | |
| 351 | +/* Button | |
| 352 | +----------------------------------*/ | |
| 353 | + | |
| 354 | +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ | |
| 355 | +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ | |
| 356 | +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ | |
| 357 | +.ui-button-icons-only { width: 3.4em; } | |
| 358 | +button.ui-button-icons-only { width: 3.7em; } | |
| 359 | + | |
| 360 | +/*button text element */ | |
| 361 | +.ui-button .ui-button-text { display: block; line-height: 1.4; } | |
| 362 | +.ui-button-text-only .ui-button-text { padding: .4em 1em; } | |
| 363 | +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } | |
| 364 | +.ui-button-text-icon .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } | |
| 365 | +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } | |
| 366 | +/* no icon support for input elements, provide padding by default */ | |
| 367 | +input.ui-button { padding: .4em 1em; } | |
| 368 | + | |
| 369 | +/*button icon element(s) */ | |
| 370 | +.ui-button-icon-only .ui-icon, .ui-button-text-icon .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } | |
| 371 | +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } | |
| 372 | +.ui-button-text-icon .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } | |
| 373 | +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } | |
| 374 | + | |
| 375 | +/*button sets*/ | |
| 376 | +.ui-buttonset { margin-right: 7px; } | |
| 377 | +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } | |
| 378 | + | |
| 379 | +/* workarounds */ | |
| 380 | +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | +/* Dialog | |
| 387 | +----------------------------------*/ | |
| 388 | +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } | |
| 389 | +.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } | |
| 390 | +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } | |
| 391 | +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } | |
| 392 | +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } | |
| 393 | +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } | |
| 394 | +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } | |
| 395 | +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } | |
| 396 | +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } | |
| 397 | +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } | |
| 398 | +.ui-draggable .ui-dialog-titlebar { cursor: move; } | |
| 399 | +/* Slider | |
| 400 | +----------------------------------*/ | |
| 401 | +.ui-slider { position: relative; text-align: left; } | |
| 402 | +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } | |
| 403 | +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } | |
| 404 | + | |
| 405 | +.ui-slider-horizontal { height: .8em; } | |
| 406 | +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } | |
| 407 | +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } | |
| 408 | +.ui-slider-horizontal .ui-slider-range-min { left: 0; } | |
| 409 | +.ui-slider-horizontal .ui-slider-range-max { right: 0; } | |
| 410 | + | |
| 411 | +.ui-slider-vertical { width: .8em; height: 100px; } | |
| 412 | +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } | |
| 413 | +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } | |
| 414 | +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } | |
| 415 | +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs | |
| 416 | +----------------------------------*/ | |
| 417 | +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ | |
| 418 | +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } | |
| 419 | +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } | |
| 420 | +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } | |
| 421 | +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } | |
| 422 | +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } | |
| 423 | +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ | |
| 424 | +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } | |
| 425 | +.ui-tabs .ui-tabs-hide { display: none !important; } | |
| 426 | +/* Datepicker | |
| 427 | +----------------------------------*/ | |
| 428 | +.ui-datepicker { width: 17em; padding: .2em .2em 0; } | |
| 429 | +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } | |
| 430 | +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } | |
| 431 | +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } | |
| 432 | +.ui-datepicker .ui-datepicker-prev { left:2px; } | |
| 433 | +.ui-datepicker .ui-datepicker-next { right:2px; } | |
| 434 | +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } | |
| 435 | +.ui-datepicker .ui-datepicker-next-hover { right:1px; } | |
| 436 | +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } | |
| 437 | +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } | |
| 438 | +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } | |
| 439 | +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} | |
| 440 | +.ui-datepicker select.ui-datepicker-month, | |
| 441 | +.ui-datepicker select.ui-datepicker-year { width: 49%;} | |
| 442 | +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } | |
| 443 | +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } | |
| 444 | +.ui-datepicker td { border: 0; padding: 1px; } | |
| 445 | +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } | |
| 446 | +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } | |
| 447 | +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } | |
| 448 | +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } | |
| 449 | + | |
| 450 | +/* with multiple calendars */ | |
| 451 | +.ui-datepicker.ui-datepicker-multi { width:auto; } | |
| 452 | +.ui-datepicker-multi .ui-datepicker-group { float:left; } | |
| 453 | +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } | |
| 454 | +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } | |
| 455 | +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } | |
| 456 | +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } | |
| 457 | +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } | |
| 458 | +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } | |
| 459 | +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } | |
| 460 | +.ui-datepicker-row-break { clear:both; width:100%; } | |
| 461 | + | |
| 462 | +/* RTL support */ | |
| 463 | +.ui-datepicker-rtl { direction: rtl; } | |
| 464 | +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } | |
| 465 | +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } | |
| 466 | +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } | |
| 467 | +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } | |
| 468 | +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } | |
| 469 | +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } | |
| 470 | +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } | |
| 471 | +.ui-datepicker-rtl .ui-datepicker-group { float:right; } | |
| 472 | +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } | |
| 473 | +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } | |
| 474 | + | |
| 475 | +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ | |
| 476 | +.ui-datepicker-cover { | |
| 477 | + display: none; /*sorry for IE5*/ | |
| 478 | + display/**/: block; /*sorry for IE5*/ | |
| 479 | + position: absolute; /*must have*/ | |
| 480 | + z-index: -1; /*must have*/ | |
| 481 | + filter: mask(); /*must have*/ | |
| 482 | + top: -4px; /*must have*/ | |
| 483 | + left: -4px; /*must have*/ | |
| 484 | + width: 200px; /*must have*/ | |
| 485 | + height: 200px; /*must have*/ | |
| 486 | +}/* Progressbar | |
| 487 | +----------------------------------*/ | |
| 488 | +.ui-progressbar { height:2em; text-align: left; } | |
| 489 | +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } | |
| 0 | 490 | \ No newline at end of file | ... | ... |
test/functional/catalog_controller_test.rb
| ... | ... | @@ -39,31 +39,6 @@ class CatalogControllerTest < Test::Unit::TestCase |
| 39 | 39 | assert_kind_of Array, assigns(:products) |
| 40 | 40 | end |
| 41 | 41 | |
| 42 | - should 'show product of enterprise' do | |
| 43 | - prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | |
| 44 | - get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 45 | - assert_tag :tag => 'h1', :content => /#{prod.name}/ | |
| 46 | - end | |
| 47 | - | |
| 48 | - should 'link back to index from product show' do | |
| 49 | - enterprise = Enterprise.create!(:name => 'test_enterprise_1', :identifier => 'test_enterprise_1', :environment => Environment.default) | |
| 50 | - prod = enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | |
| 51 | - get :show, :id => prod.id, :profile => enterprise.identifier | |
| 52 | - assert_tag({ | |
| 53 | - :tag => 'div', | |
| 54 | - :attributes => { | |
| 55 | - :class => /main-block/ | |
| 56 | - }, | |
| 57 | - :descendant => { | |
| 58 | - :tag => 'a', | |
| 59 | - :attributes => { | |
| 60 | - :href => "/catalog/#{enterprise.identifier}" | |
| 61 | - } | |
| 62 | - } | |
| 63 | - }) | |
| 64 | - | |
| 65 | - end | |
| 66 | - | |
| 67 | 42 | should 'not give access if environment do not let' do |
| 68 | 43 | env = Environment.default |
| 69 | 44 | env.enable('disable_products_for_enterprises') |
| ... | ... | @@ -86,20 +61,6 @@ class CatalogControllerTest < Test::Unit::TestCase |
| 86 | 61 | assert_tag :tag => 'li', :attributes => { :class => 'product_price' }, :content => /Price:/ |
| 87 | 62 | end |
| 88 | 63 | |
| 89 | - should 'not show product price when showing product if not informed' do | |
| 90 | - prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | |
| 91 | - get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 92 | - | |
| 93 | - assert_no_tag :tag => 'p', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
| 94 | - end | |
| 95 | - | |
| 96 | - should 'show product price when showing product if informed' do | |
| 97 | - prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category) | |
| 98 | - get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 99 | - | |
| 100 | - assert_tag :tag => 'p', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
| 101 | - end | |
| 102 | - | |
| 103 | 64 | should 'link to assets products wiht product category in the link to product category on index' do |
| 104 | 65 | pc = ProductCategory.create!(:name => 'some product', :environment => enterprise.environment) |
| 105 | 66 | prod = enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => pc) |
| ... | ... | @@ -108,12 +69,4 @@ class CatalogControllerTest < Test::Unit::TestCase |
| 108 | 69 | assert_tag :tag => 'a', :attributes => {:href => /assets\/products\?product_category=#{pc.id}/} |
| 109 | 70 | end |
| 110 | 71 | |
| 111 | - should 'link to assets products wiht product category in the link to product category on show' do | |
| 112 | - pc = ProductCategory.create!(:name => 'some product', :environment => enterprise.environment) | |
| 113 | - prod = enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => pc) | |
| 114 | - | |
| 115 | - get :show, :id => prod.id, :profile => enterprise.identifier | |
| 116 | - assert_tag :tag => 'a', :attributes => {:href => /assets\/products\?product_category=#{pc.id}/} | |
| 117 | - end | |
| 118 | - | |
| 119 | 72 | end | ... | ... |
test/functional/manage_products_controller_test.rb
| ... | ... | @@ -65,27 +65,60 @@ class ManageProductsControllerTest < Test::Unit::TestCase |
| 65 | 65 | end |
| 66 | 66 | end |
| 67 | 67 | |
| 68 | - should "get edit form" do | |
| 69 | - p = @enterprise.products.create!(:name => 'test product', :product_category => @product_category) | |
| 70 | - get 'edit', :profile => @enterprise.identifier, :id => p.id | |
| 68 | + should "get edit name form" do | |
| 69 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 70 | + get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'name' | |
| 71 | 71 | assert_response :success |
| 72 | 72 | assert assigns(:product) |
| 73 | - assert_template 'edit' | |
| 74 | - assert_tag :tag => 'form', :attributes => { :action => /edit/ } | |
| 73 | + assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=name/ } | |
| 75 | 74 | end |
| 76 | 75 | |
| 77 | - should "edit product" do | |
| 78 | - p = @enterprise.products.create!(:name => 'test product', :product_category => @product_category) | |
| 79 | - post 'edit', :profile => @enterprise.identifier, :product => {:name => 'new test product'}, :id => p.id | |
| 80 | - assert_response :redirect | |
| 76 | + should "get edit info form" do | |
| 77 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 78 | + get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'info' | |
| 79 | + assert_response :success | |
| 80 | + assert assigns(:product) | |
| 81 | + assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=info/ } | |
| 82 | + end | |
| 83 | + | |
| 84 | + should "get edit image form" do | |
| 85 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 86 | + get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'image' | |
| 87 | + assert_response :success | |
| 88 | + assert assigns(:product) | |
| 89 | + assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=image/ } | |
| 90 | + end | |
| 91 | + | |
| 92 | + should "edit product name" do | |
| 93 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 94 | + post :edit, :profile => @enterprise.identifier, :product => {:name => 'new test product'}, :id => product.id, :field => 'name' | |
| 95 | + assert_response :success | |
| 81 | 96 | assert assigns(:product) |
| 82 | 97 | assert ! assigns(:product).new_record? |
| 83 | - assert_equal p, Product.find_by_name('new test product') | |
| 98 | + assert_equal product, Product.find_by_name('new test product') | |
| 99 | + end | |
| 100 | + | |
| 101 | + should "edit product description" do | |
| 102 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id, :description => 'My product is very good') | |
| 103 | + post :edit, :profile => @enterprise.identifier, :product => {:description => 'A very good product!'}, :id => product.id, :field => 'info' | |
| 104 | + assert_response :success | |
| 105 | + assert assigns(:product) | |
| 106 | + assert ! assigns(:product).new_record? | |
| 107 | + assert_equal 'A very good product!', Product.find_by_name('test product').description | |
| 108 | + end | |
| 109 | + | |
| 110 | + should "edit product image" do | |
| 111 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 112 | + post :edit, :profile => @enterprise.identifier, :product => { :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') } }, :id => product.id, :field => 'image' | |
| 113 | + assert_response :success | |
| 114 | + assert assigns(:product) | |
| 115 | + assert ! assigns(:product).new_record? | |
| 116 | + assert_equal 'rails.png', Product.find_by_name('test product').image.filename | |
| 84 | 117 | end |
| 85 | 118 | |
| 86 | 119 | should "not edit to invalid parameters" do |
| 87 | - p = @enterprise.products.create!(:name => 'test product', :product_category => @product_category) | |
| 88 | - post 'edit', :profile => @enterprise.identifier, :product => {:product_category => nil}, :id => p.id | |
| 120 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 121 | + post 'edit_category', :profile => @enterprise.identifier, :product => {:product_category => nil}, :id => product.id | |
| 89 | 122 | assert_response :success |
| 90 | 123 | assert assigns(:product) |
| 91 | 124 | assert ! assigns(:product).valid? |
| ... | ... | @@ -131,32 +164,16 @@ class ManageProductsControllerTest < Test::Unit::TestCase |
| 131 | 164 | end |
| 132 | 165 | end |
| 133 | 166 | |
| 134 | - should 'show thumbnail image when edit product' do | |
| 135 | - p = @enterprise.products.create!(:name => 'test product1', :product_category => @product_category, :image_builder => { | |
| 136 | - :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') | |
| 137 | - }) | |
| 138 | - get 'edit', :profile => @enterprise.identifier, :id => p.id | |
| 139 | - assert_tag :tag => 'img', :attributes => { :src => /#{p.image.public_filename(:thumb)}/ } | |
| 140 | - end | |
| 141 | - | |
| 142 | - should 'show change image link above thumbnail image' do | |
| 143 | - p = @enterprise.products.create!(:name => 'test product1', :product_category => @product_category, :image_builder => { | |
| 144 | - :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') | |
| 145 | - }) | |
| 146 | - get 'edit', :profile => @enterprise.identifier, :id => p.id | |
| 147 | - assert_tag :tag => 'a', :attributes => { :href => '#' }, :content => 'Change image' | |
| 148 | - end | |
| 149 | - | |
| 150 | 167 | should 'filter html from name of product' do |
| 151 | 168 | category = fast_create(ProductCategory, :name => 'Category 1') |
| 152 | 169 | post 'new', :profile => @enterprise.identifier, :product => { :name => "<b id='html_name'>name bold</b>", :product_category_id => category.id } |
| 153 | 170 | assert_sanitized assigns(:product).name |
| 154 | 171 | end |
| 155 | 172 | |
| 156 | - should 'filter html from description of product' do | |
| 173 | + should 'filter html with whit list from description of product' do | |
| 157 | 174 | category = fast_create(ProductCategory, :name => 'Category 1') |
| 158 | 175 | post 'new', :profile => @enterprise.identifier, :product => { :name => 'name', :description => "<b id='html_descr'>descr bold</b>", :product_category_id => category.id } |
| 159 | - assert_sanitized assigns(:product).description | |
| 176 | + assert_equal "<b>descr bold</b>", assigns(:product).description | |
| 160 | 177 | end |
| 161 | 178 | |
| 162 | 179 | should 'not let users in if environment do not let' do |
| ... | ... | @@ -179,15 +196,6 @@ class ManageProductsControllerTest < Test::Unit::TestCase |
| 179 | 196 | assert_equivalent ProductCategory.top_level_for(pc1.environment), assigns(:categories) |
| 180 | 197 | end |
| 181 | 198 | |
| 182 | - should 'links to products asset for product category link when showing' do | |
| 183 | - pc = fast_create(ProductCategory, :name => 'test_category') | |
| 184 | - p = @enterprise.products.create!(:name => 'test product', :product_category => pc) | |
| 185 | - | |
| 186 | - get :show, :profile => @enterprise.identifier, :id => p.id | |
| 187 | - | |
| 188 | - assert_tag :tag => 'a', :attributes => {:href => /assets\/products\?product_category=#{pc.id}/} | |
| 189 | - end | |
| 190 | - | |
| 191 | 199 | should 'increase level while navigate on hierarchy categories' do |
| 192 | 200 | category_level0 = fast_create(ProductCategory, :name => 'Products', :environment_id => @environment.id) |
| 193 | 201 | category_level1 = fast_create(ProductCategory, :parent_id => category_level0.id, :name => 'Shoes', :environment_id => @environment.id) |
| ... | ... | @@ -232,4 +240,58 @@ class ManageProductsControllerTest < Test::Unit::TestCase |
| 232 | 240 | end |
| 233 | 241 | end |
| 234 | 242 | |
| 243 | + should 'show product of enterprise' do | |
| 244 | + prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | |
| 245 | + get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 246 | + assert_tag :tag => 'h2', :content => /#{prod.name}/ | |
| 247 | + end | |
| 248 | + | |
| 249 | + should 'link back to index from product show' do | |
| 250 | + enterprise = Enterprise.create!(:name => 'test_enterprise_1', :identifier => 'test_enterprise_1', :environment => Environment.default) | |
| 251 | + prod = enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | |
| 252 | + get :show, :id => prod.id, :profile => enterprise.identifier | |
| 253 | + assert_tag({ | |
| 254 | + :tag => 'div', | |
| 255 | + :attributes => { | |
| 256 | + :class => /main-block/ | |
| 257 | + }, | |
| 258 | + :descendant => { | |
| 259 | + :tag => 'a', | |
| 260 | + :attributes => { | |
| 261 | + :href => "/myprofile/#{enterprise.identifier}/manage_products", | |
| 262 | + }, | |
| 263 | + :content => /Back to the product listing/ | |
| 264 | + } | |
| 265 | + }) | |
| 266 | + end | |
| 267 | + | |
| 268 | + should 'not show product price when showing product if not informed' do | |
| 269 | + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
| 270 | + get :show, :id => product.id, :profile => @enterprise.identifier | |
| 271 | + | |
| 272 | + assert_no_tag :tag => 'span', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
| 273 | + end | |
| 274 | + | |
| 275 | + should 'show product price when showing product if unit was informed' do | |
| 276 | + prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :unit => 'unit', :product_category => @product_category) | |
| 277 | + get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 278 | + | |
| 279 | + assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/ | |
| 280 | + end | |
| 281 | + | |
| 282 | + should 'show product price when showing product if discount was informed' do | |
| 283 | + prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :discount => 3.50, :unit => 'unit', :product_category => @product_category) | |
| 284 | + get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 285 | + | |
| 286 | + assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /List price:/ | |
| 287 | + assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /On sale:/ | |
| 288 | + end | |
| 289 | + | |
| 290 | + should 'not show product price when showing product if unit not informed' do | |
| 291 | + prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category) | |
| 292 | + get :show, :id => prod.id, :profile => @enterprise.identifier | |
| 293 | + | |
| 294 | + assert_no_tag :tag => 'span', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
| 295 | + end | |
| 296 | + | |
| 235 | 297 | end | ... | ... |
test/integration/routing_test.rb
| ... | ... | @@ -160,12 +160,6 @@ class RoutingTest < ActionController::IntegrationTest |
| 160 | 160 | |
| 161 | 161 | def test_catalog_routing |
| 162 | 162 | assert_routing('/catalog/colivre', :controller => 'catalog', :action => 'index', :profile => 'colivre') |
| 163 | - assert_routing('/catalog/colivre/1234', :controller => 'catalog', :action => 'show', :profile => 'colivre', :id => '1234') | |
| 164 | - end | |
| 165 | - | |
| 166 | - def test_catalog_with_dot_routing | |
| 167 | - assert_routing('/catalog/profile.withdot', :controller => 'catalog', :action => 'index', :profile => 'profile.withdot') | |
| 168 | - assert_routing('/catalog/profile.withdot/1234', :controller => 'catalog', :action => 'show', :profile => 'profile.withdot', :id => '1234') | |
| 169 | 163 | end |
| 170 | 164 | |
| 171 | 165 | def test_hosted_domain_routing | ... | ... |
test/unit/application_helper_test.rb
| ... | ... | @@ -579,11 +579,6 @@ class ApplicationHelperTest < Test::Unit::TestCase |
| 579 | 579 | assert_equal 'filename.mp3', short_filename('filename.mp3') |
| 580 | 580 | end |
| 581 | 581 | |
| 582 | - include ActionView::Helpers::NumberHelper | |
| 583 | - should 'format float to money as Brazillian currency' do | |
| 584 | - assert_equal 'R$10,00', float_to_currency(10.0) | |
| 585 | - end | |
| 586 | - | |
| 587 | 582 | protected |
| 588 | 583 | |
| 589 | 584 | def url_for(args = {}) | ... | ... |
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | |
| 2 | + | |
| 3 | +class CertifierTest < Test::Unit::TestCase | |
| 4 | + | |
| 5 | + should 'have link' do | |
| 6 | + certifier = Certifier.new | |
| 7 | + | |
| 8 | + assert_equal '', certifier.link | |
| 9 | + | |
| 10 | + certifier.link = 'http://noosfero.org' | |
| 11 | + assert_equal 'http://noosfero.org', certifier.link | |
| 12 | + end | |
| 13 | + | |
| 14 | +end | ... | ... |
test/unit/enterprise_homepage_test.rb
| ... | ... | @@ -52,7 +52,7 @@ class EnterpriseHomepageTest < Test::Unit::TestCase |
| 52 | 52 | a = EnterpriseHomepage.new(:name => 'article homepage') |
| 53 | 53 | ent.articles << a |
| 54 | 54 | result = a.to_html |
| 55 | - assert_match /catalog\/test_enterprise\/#{prod.id}/, result | |
| 55 | + assert_match /\/test_enterprise\/manage_products\/show\/#{prod.id}/, result | |
| 56 | 56 | end |
| 57 | 57 | |
| 58 | 58 | should 'can display hits' do | ... | ... |
test/unit/environment_test.rb
| ... | ... | @@ -948,4 +948,28 @@ class EnvironmentTest < Test::Unit::TestCase |
| 948 | 948 | assert !v.has_terms_of_use? |
| 949 | 949 | end |
| 950 | 950 | |
| 951 | + should 'have currency unit attribute' do | |
| 952 | + env = Environment.new | |
| 953 | + assert_equal env.currency_unit, '$' | |
| 954 | + | |
| 955 | + env.currency_unit = 'R$' | |
| 956 | + assert_equal 'R$', env.currency_unit | |
| 957 | + end | |
| 958 | + | |
| 959 | + should 'have currency separator attribute' do | |
| 960 | + env = Environment.new | |
| 961 | + assert_equal env.currency_separator, '.' | |
| 962 | + | |
| 963 | + env.currency_separator = ',' | |
| 964 | + assert_equal ',', env.currency_separator | |
| 965 | + end | |
| 966 | + | |
| 967 | + should 'have currency delimiter attribute' do | |
| 968 | + env = Environment.new | |
| 969 | + assert_equal env.currency_delimiter, ',' | |
| 970 | + | |
| 971 | + env.currency_delimiter = '.' | |
| 972 | + assert_equal '.', env.currency_delimiter | |
| 973 | + end | |
| 974 | + | |
| 951 | 975 | end | ... | ... |
test/unit/manage_products_helper_test.rb
| ... | ... | @@ -38,6 +38,63 @@ class ManageProductsHelperTest < Test::Unit::TestCase |
| 38 | 38 | assert_tag_in_string select_for_categories(category_1.children(true), 1), :tag => 'select', :attributes => {:id => 'category_id'} |
| 39 | 39 | end |
| 40 | 40 | |
| 41 | + include ActionView::Helpers::NumberHelper | |
| 42 | + should 'format price to environment currency' do | |
| 43 | + @environment.currency_unit = "R$" | |
| 44 | + @environment.currency_separator = "," | |
| 45 | + @environment.currency_delimiter = "." | |
| 46 | + @environment.save | |
| 47 | + assert_equal 'R$ 10,00', float_to_currency(10.0) | |
| 48 | + end | |
| 49 | + | |
| 50 | + should 'not display link to edit product when user does not have permission' do | |
| 51 | + user = mock | |
| 52 | + user.expects(:has_permission?).with(anything, anything).returns(false) | |
| 53 | + @controller = mock | |
| 54 | + @controller.expects(:user).returns(user).at_least_once | |
| 55 | + @controller.expects(:profile).returns(mock) | |
| 56 | + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) | |
| 57 | + product = fast_create(Product, :product_category_id => category.id) | |
| 58 | + assert_equal '', edit_product_link(product, 'field', 'link to edit') | |
| 59 | + end | |
| 60 | + | |
| 61 | + should 'display link to edit product when user has permission' do | |
| 62 | + user = mock | |
| 63 | + user.expects(:has_permission?).with(anything, anything).returns(true) | |
| 64 | + @controller = mock | |
| 65 | + @controller.expects(:user).returns(user).at_least_once | |
| 66 | + @controller.expects(:profile).returns(mock) | |
| 67 | + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) | |
| 68 | + product = fast_create(Product, :product_category_id => category.id) | |
| 69 | + | |
| 70 | + expects(:link_to_remote).with('link to edit', {:update => "product-name", :url => {:controller => 'manage_products', :action => 'edit', :id => product.id, :field => 'name'}, :method => :get}, anything).returns('LINK') | |
| 71 | + | |
| 72 | + assert_equal 'LINK', edit_product_link(product, 'name', 'link to edit') | |
| 73 | + end | |
| 74 | + | |
| 75 | + should 'not display link to edit product category when user does not have permission' do | |
| 76 | + user = mock | |
| 77 | + user.expects(:has_permission?).with(anything, anything).returns(false) | |
| 78 | + @controller = mock | |
| 79 | + @controller.expects(:user).returns(user).at_least_once | |
| 80 | + @controller.expects(:profile).returns(mock) | |
| 81 | + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) | |
| 82 | + product = fast_create(Product, :product_category_id => category.id) | |
| 83 | + assert_equal '', edit_product_category_link(product) | |
| 84 | + end | |
| 85 | + | |
| 86 | + should 'display link to edit product category when user has permission' do | |
| 87 | + user = mock | |
| 88 | + user.expects(:has_permission?).with(anything, anything).returns(true) | |
| 89 | + @controller = mock | |
| 90 | + @controller.expects(:user).returns(user).at_least_once | |
| 91 | + @controller.expects(:profile).returns(mock) | |
| 92 | + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) | |
| 93 | + product = fast_create(Product, :product_category_id => category.id) | |
| 94 | + | |
| 95 | + assert_tag_in_string edit_product_category_link(product), {:tag => 'a', :content => 'Change category'} | |
| 96 | + end | |
| 97 | + | |
| 41 | 98 | protected |
| 42 | 99 | include NoosferoTestHelper |
| 43 | 100 | ... | ... |
test/unit/product_test.rb
| ... | ... | @@ -20,6 +20,27 @@ class ProductTest < Test::Unit::TestCase |
| 20 | 20 | end |
| 21 | 21 | end |
| 22 | 22 | |
| 23 | + should 'display category name if name is nil' do | |
| 24 | + p = fast_create(Product, :name => nil) | |
| 25 | + p.expects(:category_name).returns('Software') | |
| 26 | + assert_equal 'Software', p.name | |
| 27 | + end | |
| 28 | + | |
| 29 | + should 'display category name if name is blank' do | |
| 30 | + p = fast_create(Product, :name => '') | |
| 31 | + p.expects(:category_name).returns('Software') | |
| 32 | + assert_equal 'Software', p.name | |
| 33 | + end | |
| 34 | + | |
| 35 | + should 'set nil to name if name is equal to category name' do | |
| 36 | + p = fast_create(Product) | |
| 37 | + p.expects(:category_name).returns('Software').at_least_once | |
| 38 | + p.name = 'Software' | |
| 39 | + p.save | |
| 40 | + assert_equal 'Software', p.name | |
| 41 | + assert_equal nil, p[:name] | |
| 42 | + end | |
| 43 | + | |
| 23 | 44 | should 'list recent products' do |
| 24 | 45 | enterprise = fast_create(Enterprise, :name => "My enterprise", :identifier => 'my-enterprise') |
| 25 | 46 | Product.delete_all |
| ... | ... | @@ -113,7 +134,7 @@ class ProductTest < Test::Unit::TestCase |
| 113 | 134 | |
| 114 | 135 | product.expects(:id).returns(999) |
| 115 | 136 | product.expects(:enterprise).returns(enterprise) |
| 116 | - assert_equal({:controller => 'catalog', :action => 'show', :id => 999}, product.url) | |
| 137 | + assert_equal({:controller => 'manage_products', :action => 'show', :id => 999}, product.url) | |
| 117 | 138 | end |
| 118 | 139 | |
| 119 | 140 | should 'categorize also with product categorization' do |
| ... | ... | @@ -178,12 +199,27 @@ class ProductTest < Test::Unit::TestCase |
| 178 | 199 | end |
| 179 | 200 | end |
| 180 | 201 | |
| 202 | + should 'accept discount in american\'s or brazilian\'s currency format' do | |
| 203 | + [ | |
| 204 | + [12.34, 12.34], | |
| 205 | + ["12.34", 12.34], | |
| 206 | + ["12,34", 12.34], | |
| 207 | + ["12.345.678,90", 12345678.90], | |
| 208 | + ["12,345,678.90", 12345678.90], | |
| 209 | + ["12.345.678", 12345678.00], | |
| 210 | + ["12,345,678", 12345678.00] | |
| 211 | + ].each do |input, output| | |
| 212 | + product = Product.new(:discount => input) | |
| 213 | + assert_equal output, product.discount | |
| 214 | + end | |
| 215 | + end | |
| 216 | + | |
| 181 | 217 | should 'strip name with malformed HTML when sanitize' do |
| 182 | 218 | product = Product.new(:product_category => @product_category) |
| 183 | 219 | product.name = "<h1 Bla </h1>" |
| 184 | 220 | product.valid? |
| 185 | 221 | |
| 186 | - assert_equal '', product.name | |
| 222 | + assert_equal @product_category.name, product.name | |
| 187 | 223 | end |
| 188 | 224 | |
| 189 | 225 | should 'escape malformed html tags' do |
| ... | ... | @@ -208,4 +244,23 @@ class ProductTest < Test::Unit::TestCase |
| 208 | 244 | assert product.errors.invalid?(:product_category) |
| 209 | 245 | end |
| 210 | 246 | |
| 247 | + should 'format values to float with 2 decimals' do | |
| 248 | + ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') | |
| 249 | + product = fast_create(Product, :enterprise_id => ent.id, :price => 12.994, :discount => 1.994) | |
| 250 | + | |
| 251 | + assert_equal "12.99", product.formatted_value(:price) | |
| 252 | + assert_equal "1.99", product.formatted_value(:discount) | |
| 253 | + end | |
| 254 | + | |
| 255 | + should 'calculate price with discount' do | |
| 256 | + ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') | |
| 257 | + product = fast_create(Product, :enterprise_id => ent.id, :price => 12.994, :discount => 1.994) | |
| 258 | + | |
| 259 | + assert_equal 11.00, product.price_with_discount | |
| 260 | + end | |
| 261 | + | |
| 262 | + should 'have default image' do | |
| 263 | + product = Product.new | |
| 264 | + assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image | |
| 265 | + end | |
| 211 | 266 | end | ... | ... |