diff --git a/Project, b/Project, new file mode 100644 index 0000000..e69de29 diff --git a/Task, b/Task, new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8e93168..fa075d6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,6 +2,8 @@ # Likewise, all the methods added will be available for all controllers. class ApplicationController < ActionController::Base + before_filter :authenticate + include Clearance::Authentication #helper :all # include all helpers, all the time protect_from_forgery # See ActionController::RequestForgeryProtection for details diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 766b4d1..5cf0b2d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,8 +1,9 @@ class ProjectsController < ApplicationController + before_filter :authenticate # GET /projects # GET /projects.xml def index - @projects = Project.all + @projects = Project.active.paginate :per_page => 30, :page => params[:page] respond_to do |format| format.html # index.html.erb @@ -13,8 +14,8 @@ class ProjectsController < ApplicationController # GET /projects/1 # GET /projects/1.xml def show - @project = Project.find(params[:id]) - + @project = Project.find(params[:id], :include => [:users]) + @tasks = @project.tasks.parents.paginate(:per_page => 30, :page => params[:page], :include => :tasks) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @project } diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..73f8b0c --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,25 @@ +class UsersController < Clearance::UsersController + + def dashboard + @user = current_user + @projects = @user.projects.active.paginate(:per_page => 30, :page => params[:page]) + end + + def show + @user = User.find_by_short_name(params[:id]) + end + + def inline + + user = current_user + old = user.send(params[:id]) + user.update_attribute(params[:id], params['value']) + if user.save + value = user.send(params[:id]) + else + value = old + end + render :text => value , :layout => false + end + +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 48f74d7..ae7fc75 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -7,4 +7,5 @@ module ApplicationHelper out << tag(:meta, :name => 'csrf-param', :content => 'authenticity_token') end + end diff --git a/app/models/project.rb b/app/models/project.rb index f8e90d2..75eedc7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,4 +1,11 @@ class Project < ActiveRecord::Base has_many :tasks + belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" validates_presence_of :name + has_and_belongs_to_many :users + validates_uniqueness_of :name + + named_scope :archived, :conditions => {:archived => true} + named_scope :active, :conditions => {:archived => false} + end diff --git a/app/models/task.rb b/app/models/task.rb index d7d38a0..314be49 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1,9 +1,31 @@ class Task < ActiveRecord::Base belongs_to :project has_many :tasks, :foreign_key => :parent - + belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" + belongs_to :assignee, :class_name => "User", :foreign_key => 'assigned_id' + #named scopes named_scope :parents, :conditions => {:parent => nil} - + #validations validates_presence_of :name, :description, :project_id validates_associated :project + validate :assignee_validation, :owner_validation + + def assignee_validation + unless assigned_id.blank? + unless User.exists?(assigned_id) + errors.add :assignee, "Assignee doesn't exist" + end + end + end + + def owner_validation + unless owner_id.blank? + unless User.exists?(owner_id) + errors.add :owner, "Owner doesn't exist" + end + end + end + + + end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..dbcf911 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,17 @@ +class User < ActiveRecord::Base + include Clearance::User + has_and_belongs_to_many :projects + has_many :owned_projects, :class_name => "Project", :foreign_key => "owner_id" + has_many :owned_tasks, :class_name => "Task", :foreign_key => "owner_id" + has_many :assigned_tasks, :class_name => "Task", :foreign_key => "assigned_id" + validates_uniqueness_of :short_name + validates_presence_of :short_name + validates_format_of :phone, :with => /^[0-9]{3}-[0-9]{3}-[0-9]{4}$/, :if => Proc.new {|user| !user.phone.blank?} + validates_format_of :mobile, :with => /^[0-9]{3}-[0-9]{3}-[0-9]{4}$/, :if => Proc.new {|user| !user.mobile.blank?} + + def gravatar(size = 48) + hash = Digest::MD5.hexdigest email + "http://www.gravatar.com/avatar/#{hash}.jpg?s=#{size}" + end + +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a2e3ec8..fa75efa 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,13 +7,18 @@ <%= stylesheet_link_tag 'scaffold', 'style' %> - + <% flash.each_key do |flash_key| %> -
- <%= flash[flash_key] %> +
+ <%=h flash[flash_key] %>
<% end %> - - <%= yield %> +
+
+ <%= yield %> +
+
\ No newline at end of file diff --git a/app/views/passwords/edit.html.erb b/app/views/passwords/edit.html.erb new file mode 100644 index 0000000..c206ca0 --- /dev/null +++ b/app/views/passwords/edit.html.erb @@ -0,0 +1,21 @@ +

Change your password

+ +

+ Your password has been reset. Choose a new password below. +

+ +<% semantic_form_for(:user, + :url => user_password_path(@user, :token => @user.confirmation_token), + :html => { :method => :put }) do |form| %> + <%= form.error_messages %> + <% form.inputs do -%> + <%= form.input :password, :as => :password, + :label => "Choose password" %> + <%= form.input :password_confirmation, :as => :password, + :label => "Confirm password" %> + <% end -%> + <% form.buttons do -%> + <%= form.commit_button "Save this password" %> + <% end -%> +<% end %> + diff --git a/app/views/passwords/new.html.erb b/app/views/passwords/new.html.erb new file mode 100644 index 0000000..4ac1269 --- /dev/null +++ b/app/views/passwords/new.html.erb @@ -0,0 +1,15 @@ +

Reset your password

+ +

+ We will email you a link to reset your password. +

+ +<% semantic_form_for :password, :url => passwords_path do |form| -%> + <% form.inputs do -%> + <%= form.input :email, :label => "Email address" %> + <% end -%> + <% form.buttons do -%> + <%= form.commit_button "Reset password" %> + <% end -%> +<% end -%> + diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb index cb43c94..0657dda 100644 --- a/app/views/projects/index.html.erb +++ b/app/views/projects/index.html.erb @@ -8,7 +8,7 @@ <% @projects.each do |project| %> <%=h project.name %> - <%= link_to 'Show', project %> + <%= link_to 'Show', project_path(project) %> <%= link_to 'Edit', edit_project_path(project) %> <%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %> @@ -17,4 +17,6 @@
+<%= will_paginate @projects %> + <%= link_to 'New project', new_project_path %> \ No newline at end of file diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb index ab0b305..0cac856 100644 --- a/app/views/projects/show.html.erb +++ b/app/views/projects/show.html.erb @@ -2,7 +2,14 @@ Name: <%=h @project.name %>

- - +
+ <% @project.users.each do |user| %> + <%= image_tag user.gravatar %> <%= link_to "@#{user.short_name}", user_path(user.short_name) %> + <% end %> +
+
+ <%= render :partial => 'tasks/task_list' %> +
+<%= will_paginate @tasks %> <%= link_to 'Edit', edit_project_path(@project) %> | <%= link_to 'Back', projects_path %> \ No newline at end of file diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000..440d03e --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,21 @@ +

Sign in

+ +<% semantic_form_for :session, :url => session_path do |form| %> + <% form.inputs do %> + <%= form.input :email %> + <%= form.input :password, :as => :password %> + <% end %> + <% form.buttons do %> + <%= form.commit_button "Sign in" %> + <% end %> +<% end %> + + + diff --git a/app/views/tasks/_task_list.html.erb b/app/views/tasks/_task_list.html.erb index 8a32267..95fe33c 100644 --- a/app/views/tasks/_task_list.html.erb +++ b/app/views/tasks/_task_list.html.erb @@ -21,5 +21,4 @@ <% else %>

No Dependet Tasks

-

<%= link_to 'Create One', new_project_task_path(@project, :parent => @task.id) %> <% end %> \ No newline at end of file diff --git a/app/views/users/_inputs.html.erb b/app/views/users/_inputs.html.erb new file mode 100644 index 0000000..e6e90c9 --- /dev/null +++ b/app/views/users/_inputs.html.erb @@ -0,0 +1,7 @@ +<% form.inputs do %> + <%= form.input :email %> + <%= form.input :password %> + <%= form.input :password_confirmation, :label => "Confirm password" %> + <%= form.input :short_name %> +<% end %> + diff --git a/app/views/users/dashboard.html.erb b/app/views/users/dashboard.html.erb new file mode 100644 index 0000000..ffd51a2 --- /dev/null +++ b/app/views/users/dashboard.html.erb @@ -0,0 +1,18 @@ +<%= javascript_include_tag 'jeditable.min'%> + +

Dashboard

+<%= image_tag @user.gravatar %> +
+ <% [:phone, :mobile, :im].each do |col| %> +

<%= col.to_s %>: <%=h @user.send(col) %>

+ <% end %> +
+<% @projects.each do |project| %> +

<%= link_to project.name, project %>

+<% end %> \ No newline at end of file diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..be7f1dc --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,10 @@ +

Sign up

+ +<% semantic_form_for @user do |form| %> + <%= form.error_messages %> + <%= render :partial => "/users/inputs", :locals => { :form => form } %> + <% form.buttons do %> + <%= form.commit_button "Sign up" %> + <% end %> +<% end %> + diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000..0b31a59 --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1 @@ +

User Activity

\ No newline at end of file diff --git a/assigned_id b/assigned_id new file mode 100644 index 0000000..e69de29 diff --git a/config/environment.rb b/config/environment.rb index 585bf34..f3e6026 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -25,8 +25,8 @@ Rails::Initializer.run do |config| config.gem 'paperclip' config.gem 'formtastic' config.gem 'faker' - config.gem 'postgres' config.gem 'mysql' + config.gem "matthuhiggins-foreigner", :lib => "foreigner", :source => "http://gemcutter.org" # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named diff --git a/config/environments/development.rb b/config/environments/development.rb index 85c9a60..43762f2 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -14,4 +14,6 @@ config.action_view.debug_rjs = true config.action_controller.perform_caching = false # Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false \ No newline at end of file +config.action_mailer.raise_delivery_errors = false + +config.action_mailer.default_url_options = { :host => 'localhost:3000' } \ No newline at end of file diff --git a/config/environments/test.rb b/config/environments/test.rb index d6f80a4..8d3a911 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -25,4 +25,6 @@ config.action_mailer.delivery_method = :test # Use SQL instead of Active Record's schema dumper when creating the test database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types -# config.active_record.schema_format = :sql \ No newline at end of file +# config.active_record.schema_format = :sql + +config.action_mailer.default_url_options = { :host => 'localhost:3000' } \ No newline at end of file diff --git a/config/initializers/clearance.rb b/config/initializers/clearance.rb new file mode 100644 index 0000000..80f480b --- /dev/null +++ b/config/initializers/clearance.rb @@ -0,0 +1,3 @@ +Clearance.configure do |config| + config.mailer_sender = 'donotreply@example.com' +end diff --git a/config/routes.rb b/config/routes.rb index 1b86422..12d6e9d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,40 +1,10 @@ ActionController::Routing::Routes.draw do |map| - # The priority is based upon order of creation: first created -> highest priority. + Clearance::Routes.draw(map) + map.user '/users/:id', :controller => :users, :action => :show + map.user_inline_edit '/users/:id/inline', :controller => :users, :action => :inline, :conditions => { :method => :post } + #map.dashboard '/dashboard', :controller => :users, :action => :dashboard - # Sample of regular route: - # map.connect 'products/:id', :controller => 'catalog', :action => 'view' - # Keep in mind you can assign values other than :controller and :action - - # Sample of named route: - # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' - # This route can be invoked with purchase_url(:id => product.id) - - # Sample resource route (maps HTTP verbs to controller actions automatically): - # map.resources :products - - # Sample resource route with options: - # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get } - - # Sample resource route with sub-resources: - # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller - # Sample resource route with more complex sub-resources - # map.resources :products do |products| - # products.resources :comments - # products.resources :sales, :collection => { :recent => :get } - # end - - # Sample resource route within a namespace: - # map.namespace :admin do |admin| - # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb) - # admin.resources :products - # end - - # You can have the root of your site routed with map.root -- just remember to delete public/index.html. - # map.root :controller => "welcome" - - # See how all your routes lay out with "rake routes" - map.resources :projects do |projects| projects.resources :tasks end @@ -45,5 +15,5 @@ ActionController::Routing::Routes.draw do |map| # consider removing or commenting them out if you're using named routes and resources. #map.connect ':controller/:action/:id' #map.connect ':controller/:action/:id.:format' - map.root :controller => :projects, :action =>:index + map.root :controller => :users, :action => :dashboard end diff --git a/db/migrate/20100305002309_clearance_create_users.rb b/db/migrate/20100305002309_clearance_create_users.rb new file mode 100644 index 0000000..4f7e62f --- /dev/null +++ b/db/migrate/20100305002309_clearance_create_users.rb @@ -0,0 +1,21 @@ +class ClearanceCreateUsers < ActiveRecord::Migration + def self.up + create_table(:users) do |t| + t.string :email + t.string :encrypted_password, :limit => 128 + t.string :salt, :limit => 128 + t.string :confirmation_token, :limit => 128 + t.string :remember_token, :limit => 128 + t.boolean :email_confirmed, :default => false, :null => false + t.timestamps + end + + add_index :users, [:id, :confirmation_token] + add_index :users, :email + add_index :users, :remember_token + end + + def self.down + drop_table :users + end +end diff --git a/db/migrate/20100305010025_projects_users.rb b/db/migrate/20100305010025_projects_users.rb new file mode 100644 index 0000000..1ed3c9b --- /dev/null +++ b/db/migrate/20100305010025_projects_users.rb @@ -0,0 +1,15 @@ +class ProjectsUsers < ActiveRecord::Migration + def self.up + create_table :projects_users, :id => false do |t| + t.integer :project_id + t.integer :user_id + t.foreign_key :projects + t.foreign_key :users + t.index :project_id, :user_id + end + end + + def self.down + drop_table :projects_users + end +end diff --git a/db/migrate/20100305013414_add_shorname_to_users.rb b/db/migrate/20100305013414_add_shorname_to_users.rb new file mode 100644 index 0000000..ee95afa --- /dev/null +++ b/db/migrate/20100305013414_add_shorname_to_users.rb @@ -0,0 +1,9 @@ +class AddShornameToUsers < ActiveRecord::Migration + def self.up + add_column :users, :short_name, :string + end + + def self.down + remove_column :users, :short_name + end +end diff --git a/db/migrate/20100305020706_add_owner_to_tasks_and_projects.rb b/db/migrate/20100305020706_add_owner_to_tasks_and_projects.rb new file mode 100644 index 0000000..af82641 --- /dev/null +++ b/db/migrate/20100305020706_add_owner_to_tasks_and_projects.rb @@ -0,0 +1,21 @@ +class AddOwnerToTasksAndProjects < ActiveRecord::Migration + @tables = [:tasks, :projects] + + def self.up + @tables.each do |table| + add_column table, :owner_id, :integer + add_index table, :owner_id + add_foreign_key table, :users, :column => :owner_id + end + add_column :tasks, :assigned_id, :integer + add_index :tasks, :assigned_id + end + + def self.down + @tables.each do |t| + remove_column t, :owner_id + remove_foreign_key t, :column => :owner_id + end + remove_column :tasks, :assigned_id + end +end diff --git a/db/migrate/20100305035342_add_archived_to_projects.rb b/db/migrate/20100305035342_add_archived_to_projects.rb new file mode 100644 index 0000000..e492437 --- /dev/null +++ b/db/migrate/20100305035342_add_archived_to_projects.rb @@ -0,0 +1,9 @@ +class AddArchivedToProjects < ActiveRecord::Migration + def self.up + add_column :projects, :archived, :boolean, :default => false + end + + def self.down + remove_column :projects, :archived + end +end diff --git a/db/migrate/20100305060621_add_contact_info_to_users.rb b/db/migrate/20100305060621_add_contact_info_to_users.rb new file mode 100644 index 0000000..bd4330b --- /dev/null +++ b/db/migrate/20100305060621_add_contact_info_to_users.rb @@ -0,0 +1,13 @@ +class AddContactInfoToUsers < ActiveRecord::Migration + def self.up + add_column :users, :phone, :string + add_column :users, :mobile, :string + add_column :users, :im, :string + end + + def self.down + remove_column :users, :im + remove_column :users, :mobile + remove_column :users, :phone + end +end diff --git a/db/schema.rb b/db/schema.rb index d143fc1..401963e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,12 +9,21 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20100304040201) do +ActiveRecord::Schema.define(:version => 20100305060621) do create_table "projects", :force => true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" + t.integer "owner_id" + t.boolean "archived", :default => false + end + + add_index "projects", ["owner_id"], :name => "index_projects_on_owner_id" + + create_table "projects_users", :id => false, :force => true do |t| + t.integer "project_id" + t.integer "user_id" end create_table "tasks", :force => true do |t| @@ -24,6 +33,34 @@ ActiveRecord::Schema.define(:version => 20100304040201) do t.integer "parent" t.datetime "created_at" t.datetime "updated_at" + t.integer "owner_id" + t.integer "assigned_id" end + add_index "tasks", ["assigned_id"], :name => "index_tasks_on_assigned_id" + add_index "tasks", ["owner_id"], :name => "index_tasks_on_owner_id" + + create_table "users", :force => true do |t| + t.string "email" + t.string "encrypted_password", :limit => 128 + t.string "salt", :limit => 128 + t.string "confirmation_token", :limit => 128 + t.string "remember_token", :limit => 128 + t.boolean "email_confirmed", :default => false, :null => false + t.datetime "created_at" + t.datetime "updated_at" + t.string "short_name" + t.string "phone" + t.string "mobile" + t.string "im" + end + + add_index "users", ["email"], :name => "index_users_on_email" + add_index "users", ["id", "confirmation_token"], :name => "index_users_on_id_and_confirmation_token" + add_index "users", ["remember_token"], :name => "index_users_on_remember_token" + + add_foreign_key "projects", "users", :name => "projects_owner_id_fk", :column => "owner_id" + + add_foreign_key "tasks", "users", :name => "tasks_owner_id_fk", :column => "owner_id" + end diff --git a/factories/factory_loader.rb b/factories/factory_loader.rb index db3caf2..89f9b42 100644 --- a/factories/factory_loader.rb +++ b/factories/factory_loader.rb @@ -1,32 +1,46 @@ path = File.join(RAILS_ROOT, 'factories') require 'factory_girl' -require File.join(path, 'task_factory') -require File.join(path, 'project_factory') +["user", "task", "project"].each {|factory| require File.join(path, "#{factory}_factory")} + class FactoryLoader def self.up + self.create_users self.create_projects + puts "Factories Loaded!" end def self.down - [Task, Project].each {|klass| klass.delete_all} + [Task, Project, User].each(&:delete_all) + puts "Factories Unloaded!" + end + + + def self.create_users + 5.times do |n| + u = Factory.create(:user) + u.confirm_email! + end end def self.create_projects - 101.times do |i| - p = Factory.create(:project) - self.create_tasks(p) + users = User.all + users.each do |user| + 10.times do |i| + p = Factory.create(:project, :owner => user, :users => [user]) + self.create_tasks(p, user) + end end end - def self.create_tasks(project) + def self.create_tasks(project, user) 5.times do |i| - task = Factory.create(:task, :project => project) + task = Factory.create(:task, :project => project, :owner => user, :assignee => user) 5.times do |n| - t = Factory.create(:task, :project => project, :parent => task.id) + t = Factory.create(:task, :project => project, :parent => task.id, :owner => user, :assignee => user) 2.times do |nn| - Factory.create(:task, :project => project, :parent => t.id) + Factory.create(:task, :project => project, :parent => t.id, :owner => user, :assignee => user) end end end diff --git a/factories/user_factory.rb b/factories/user_factory.rb new file mode 100644 index 0000000..4f5a2ab --- /dev/null +++ b/factories/user_factory.rb @@ -0,0 +1,8 @@ +require 'factory_girl' + + +Factory.define :user do |f| + f.sequence(:email) { |n| "email_#{n}@localhost.com" } + f.sequence(:password) { |n| "password#{n}" } + f.sequence(:short_name) { |n| "short_#{n}" } +end \ No newline at end of file diff --git a/lib/tasks/factory.rake b/lib/tasks/factory.rake new file mode 100644 index 0000000..c52dde0 --- /dev/null +++ b/lib/tasks/factory.rake @@ -0,0 +1,18 @@ +namespace :db do + namespace :factory do + desc "Load the factory data" + task :load => [:environment, :load_class] do + FactoryLoader.up + end + desc "Unload all the stories" + task :unload => [:environment, :load_class] do + FactoryLoader.down + end + desc "Reload Factories" + task :reload => [:environment, :load_class, :unload, :load] + + task :load_class do + require File.join(RAILS_ROOT, 'factories', 'factory_loader') + end + end +end \ No newline at end of file diff --git a/owner_id b/owner_id new file mode 100644 index 0000000..e69de29 diff --git a/public/javascripts/jeditable.min.js b/public/javascripts/jeditable.min.js new file mode 100644 index 0000000..40da694 --- /dev/null +++ b/public/javascripts/jeditable.min.js @@ -0,0 +1,37 @@ +(function($){$.fn.editable=function(target,options){if('disable'==target){$(this).data('disabled.editable',true);return;} +if('enable'==target){$(this).data('disabled.editable',false);return;} +if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;} +var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);} +settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);} +$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;} +if(self.editing){return;} +if(false===onedit.apply(this,[settings,self])){return;} +e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');} +if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;} +if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}} +if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');} +self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('
');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}} +if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}} +var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);} +$.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;} +content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();} +input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});} +form.submit(function(e){if(t){clearTimeout(t);} +e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);} +if('PUT'==settings.method){submitdata['_method']='put';} +$(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);} +self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}} +$(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);} +if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('