├── app ├── helpers │ └── worktimelog_helper.rb ├── views │ ├── worktimelog │ │ ├── _widget_timer.html.erb │ │ ├── index.html.erb │ │ ├── snapup.html.erb │ │ ├── intercept.html.erb │ │ ├── take_over.html.erb │ │ ├── archive.html.erb │ │ ├── summary.html.erb │ │ ├── worklog.html.erb │ │ ├── _sentinel.html.erb │ │ ├── _widget_issue_toolbar.html.erb │ │ ├── issue_summary.html.erb │ │ ├── user_summary.html.erb │ │ └── project_summary.html.erb │ ├── stopwatch │ │ ├── timer.html.erb │ │ ├── timer.json.erb │ │ └── _widget_timer.html.erb │ └── settings │ │ ├── _worktime_license.html.erb │ │ ├── _worktime.html.erb │ │ ├── _worktime_credits.html.erb │ │ ├── _worktime_about.html.erb │ │ └── _worktime_general.html.erb ├── models │ └── worktimelog.rb └── controllers │ ├── stopwatch_controller.rb │ └── worktimelog_controller.rb ├── assets ├── scss │ ├── _settings.scss │ ├── redmine_worktime_log.scss │ ├── _mixins.scss │ ├── _table.scss │ ├── _main.scss │ ├── _widget.scss │ └── vendor │ │ └── chosen.scss ├── images │ ├── chosen-sprite.png │ └── chosen-sprite@2x.png ├── javascripts │ ├── timer.js │ └── vendor │ │ └── jquery │ │ ├── jquery.stopwatch.js │ │ └── jquery.chosen.js └── stylesheets │ ├── redmine_worktime_log.css.map │ └── redmine_worktime_log.css ├── test ├── test_helper.rb ├── unit │ └── worklog_test.rb └── functional │ └── worklog_controller_test.rb ├── lib ├── redmine_worktime │ ├── hooks │ │ ├── view_layout_hook.rb │ │ ├── view_issue_hook.rb │ │ └── view_sidebar_hook.rb │ ├── helpers │ │ └── worktime_helper.rb │ └── patches │ │ └── view_sidebar_patch.rb └── redmine_worktime.rb ├── db └── migrate │ └── 001_create_worktimelogs.rb ├── config ├── routes.rb └── locales │ ├── en.yml │ ├── uk.yml │ ├── fr.yml │ └── ru.yml ├── init.rb ├── README.rdoc └── README.md /app/helpers/worktimelog_helper.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/_settings.scss: -------------------------------------------------------------------------------- 1 | $span-margin: 1.2rem; -------------------------------------------------------------------------------- /app/views/worktimelog/_widget_timer.html.erb: -------------------------------------------------------------------------------- 1 | SILENCE IS GOLD -------------------------------------------------------------------------------- /app/views/worktimelog/index.html.erb: -------------------------------------------------------------------------------- 1 |

Silence is gold

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/snapup.html.erb: -------------------------------------------------------------------------------- 1 |

Silence is gold

2 | -------------------------------------------------------------------------------- /app/views/stopwatch/timer.html.erb: -------------------------------------------------------------------------------- 1 |

WorklogController#timer

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/intercept.html.erb: -------------------------------------------------------------------------------- 1 |

Silence is gold

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/take_over.html.erb: -------------------------------------------------------------------------------- 1 |

Silence is gold

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/archive.html.erb: -------------------------------------------------------------------------------- 1 |

WorklogController#archive

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/summary.html.erb: -------------------------------------------------------------------------------- 1 |

WorklogController#summary

2 | -------------------------------------------------------------------------------- /app/views/worktimelog/worklog.html.erb: -------------------------------------------------------------------------------- 1 |

WorklogController#worklog

2 | -------------------------------------------------------------------------------- /app/views/stopwatch/timer.json.erb: -------------------------------------------------------------------------------- 1 | {success: <%= @success %>, params: '<%= params %>'} -------------------------------------------------------------------------------- /assets/images/chosen-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themondays/redmine_worktime_log/HEAD/assets/images/chosen-sprite.png -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Load the Redmine helper 2 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper') 3 | -------------------------------------------------------------------------------- /assets/images/chosen-sprite@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themondays/redmine_worktime_log/HEAD/assets/images/chosen-sprite@2x.png -------------------------------------------------------------------------------- /app/views/worktimelog/_sentinel.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :header_tags do %> 2 | <%= javascript_include_tag 'vendor/jquery/jquery.chosen.js', 'vendor/jquery/jquery.stopwatch.js', 'timer', :plugin => 'redmine_worktime_log' %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /test/unit/worklog_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class WorklogTest < ActiveSupport::TestCase 4 | 5 | # Replace this with your real tests. 6 | def test_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/redmine_worktime/hooks/view_layout_hook.rb: -------------------------------------------------------------------------------- 1 | module RedmineWorktime 2 | module Hooks 3 | class ViewLayoutHook < Redmine::Hook::ViewListener 4 | render_on :view_layouts_base_html_head, :partial => "worktimelog/sentinel" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/functional/worklog_controller_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class WorklogControllerTest < ActionController::TestCase 4 | # Replace this with your real tests. 5 | def test_truth 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /assets/scss/redmine_worktime_log.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Redmine Worktime Log Plugin 3 | * @author: Jared Denison 4 | */ 5 | 6 | @import "_settings"; 7 | @import "_mixins"; 8 | @import "_widget"; 9 | @import "_main"; 10 | @import "_table"; 11 | @import "vendor/chosen.scss"; -------------------------------------------------------------------------------- /db/migrate/001_create_worktimelogs.rb: -------------------------------------------------------------------------------- 1 | class CreateWorktimelogs < ActiveRecord::Migration 2 | def change 3 | create_table :worktimelogs do |t| 4 | t.integer :issue_id 5 | t.integer :user_id 6 | t.timestamp :started 7 | t.timestamp :finished 8 | t.integer :total 9 | t.integer :flag 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/settings/_worktime_license.html.erb: -------------------------------------------------------------------------------- 1 | <% html_title l(:label_worktime_license) %> 2 |

<%= l(:label_worktime_license) %>

3 |
4 | This plugin is available under CC-BY 3.0 5 |
6 |
7 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 8 |
-------------------------------------------------------------------------------- /lib/redmine_worktime/helpers/worktime_helper.rb: -------------------------------------------------------------------------------- 1 | module RedmineWorktime 2 | module Helper 3 | def time_to_sec(t) 4 | s = t.split(":").map{|s| s.to_i} 5 | return (s[0]*3600) + (s[1]*60) + s[2] 6 | end 7 | # helper_method :to_time 8 | def to_time(t) 9 | seconds = t % 60 10 | minutes = (t / 60) % 60 11 | hours = t / (60 * 60) 12 | return format("%02d:%02d:%02d", hours, minutes, seconds) 13 | end 14 | end 15 | end 16 | 17 | ActionView::Base.send :include, RedmineWorktime::Helper -------------------------------------------------------------------------------- /app/views/settings/_worktime.html.erb: -------------------------------------------------------------------------------- 1 | <% worktime_tabs = [ 2 | {:name => 'general', :partial => 'settings/worktime_general', :label => :label_worktime_general}, 3 | {:name => 'about', :partial => 'settings/worktime_about', :label => :label_worktime_about}, 4 | {:name => 'credits', :partial => 'settings/worktime_credits', :label => :label_worktime_credits}, 5 | {:name => 'license', :partial => 'settings/worktime_license', :label => :label_worktime_license} 6 | ] %> 7 | 8 | <%= render_tabs worktime_tabs %> 9 | 10 | <% html_title l(:label_worktime) %> 11 | 12 | -------------------------------------------------------------------------------- /app/views/settings/_worktime_credits.html.erb: -------------------------------------------------------------------------------- 1 | <% html_title l(:label_worktime_credits) %> 2 |

<%= l(:label_worktime_credits) %>

3 |

Additional thanks to:

4 | 8 | 9 |
10 | If you found something unappropriate or I forgot mention someone please touch me and we fix it. 11 |
12 | 13 | -------------------------------------------------------------------------------- /assets/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin universe($property,$value) { 2 | -webkit-#{$property}: #{$value}; 3 | -moz-#{$property}: #{$value}; 4 | -ms-#{$property}: #{$value}; 5 | -o-#{$property}: #{$value}; 6 | #{$property}: #{$value}; 7 | } 8 | @mixin box-shadow($str) { 9 | @include universe(box-shadow, $str); 10 | } 11 | @mixin box-sizing($str) { 12 | @include universe(box-sizing, $str); 13 | } 14 | @mixin _border-box() { 15 | @include box-sizing(border-box); 16 | } 17 | @mixin -content-box { 18 | background:#fff; 19 | margin: 0; 20 | border: none; 21 | margin-bottom: $span-margin; 22 | padding: $span-margin; 23 | } -------------------------------------------------------------------------------- /app/models/worktimelog.rb: -------------------------------------------------------------------------------- 1 | class Worktimelog < ActiveRecord::Base 2 | unloadable 3 | has_one :issue 4 | belongs_to :issue 5 | belongs_to :project 6 | belongs_to :user 7 | end 8 | class Issue < ActiveRecord::Base 9 | has_one :project 10 | belongs_to :project 11 | end 12 | 13 | class Project < ActiveRecord::Base 14 | belongs_to :issue 15 | end 16 | 17 | class ContactsIssue < ActiveRecord::Base 18 | self.primary_key = "issue_id" 19 | self.inheritance_column = "issue_id" 20 | has_one :issue 21 | belongs_to :contact 22 | end 23 | 24 | class Contacts < ActiveRecord::Base 25 | belongs_to :contacts_issue 26 | end 27 | -------------------------------------------------------------------------------- /assets/scss/_table.scss: -------------------------------------------------------------------------------- 1 | table.worktime-log-table { 2 | th .day-total { 3 | font-weight: 300; 4 | font-size: 12px; 5 | border-radius: 3px; 6 | background-color: #ecf0f1; 7 | color: #7f8c8d; 8 | padding: 2px 3px; 9 | position: relative; 10 | display: inline-block; 11 | } 12 | th .day-total::before { 13 | content: ''; 14 | border: 5px transparent solid; 15 | width: 0; 16 | height: 0; 17 | display: block; 18 | padding: 0; 19 | margin: 0; 20 | top: -9px; 21 | margin-left: -5px; 22 | z-index: 2; 23 | left: 50%; 24 | line-height: 0; 25 | position: absolute; 26 | background-color: transparent; 27 | border-bottom-color: #ecf0f1; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/redmine_worktime.rb: -------------------------------------------------------------------------------- 1 | # Redmine Worktime Log Hooks 2 | # require 'redmine_worktime/patches/project_patch' 3 | require 'redmine_worktime/helpers/worktime_helper' 4 | require 'redmine_worktime/hooks/view_layout_hook' 5 | require 'redmine_worktime/hooks/view_sidebar_hook' 6 | if !!Setting.plugin_redmine_worktime_log[:show_toolbar_in_issue] 7 | require 'redmine_worktime/hooks/view_issue_hook' 8 | end 9 | 10 | module RedmineWorktime 11 | module Hooks 12 | class ViewLayoutsBaseHook < Redmine::Hook::ViewListener 13 | #<%= javascript_include_tag 'jquery.stopwatch.js', 'timer', :plugin => 'redmine_worktime_log' %> 14 | render_on :view_layouts_base_html_head, :inline => "<%= stylesheet_link_tag :redmine_worktime_log, :plugin => 'redmine_worktime_log' %>" 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | # Plugin"s routes 2 | get "worktime/stopwatch", :to => "stopwatch#timer" 3 | get "worktime/stopwatch/:id", :to => "stopwatch#timer" 4 | post "worktime/stopwatch/:id", :to => "stopwatch#timer" 5 | get "worktime/stopwatch/snapup/:id", :to => "stopwatch#snapup" 6 | get "users/:id/worktime", :to => "worktimelog#user_summary" 7 | 8 | match "users/:id/worktime" => "worktimelog#user_summary" 9 | match "issues/:issue_id/worktime" => "worktimelog#issue_summary" 10 | match "projects/:project_id/worktime" => "worktimelog#project_summary" 11 | 12 | 13 | resources :projects do 14 | resources :worktimelog, :only => [:project_summary] 15 | end 16 | 17 | resources :issues do 18 | resources :worktimelog, :only => [:issue_summary,:snapup] 19 | end 20 | 21 | resources :users do 22 | resources :worktimelog, :only => [:user_summary] 23 | end 24 | 25 | -------------------------------------------------------------------------------- /assets/scss/_main.scss: -------------------------------------------------------------------------------- 1 | .widget { 2 | &.worklog { 3 | .timer-container { 4 | .stopwatch { 5 | padding-left: 8px; 6 | font-size: 0.7rem; 7 | } 8 | } 9 | } 10 | h3 { 11 | .my-summary { 12 | float: right; 13 | &.small { 14 | font-size: 0.575em; 15 | } 16 | } 17 | } 18 | } 19 | 20 | .worktime-log.issue-toolbar { 21 | background-color: #F7F6EE; 22 | padding: 10px; 23 | } 24 | 25 | .worktimelog, .worktime-log { 26 | .issue-btn { 27 | display: inline-block; 28 | margin: 0 1px; 29 | height: 21px; 30 | line-height: 16px; 31 | border-radius: 2px; 32 | left: 0; 33 | padding: 0 10px; 34 | margin-left: 0; 35 | border: none; 36 | box-shadow: none; 37 | text-shadow: none; 38 | background: #179e7f; 39 | color: #fff; 40 | text-decoration: none; 41 | border: inset 0 -2px 0 0 rgba(0,0,0,.2); 42 | outline: none; 43 | line-height: 21px; 44 | } 45 | .issue-btn.nice { 46 | background-color: #CC5E2E; 47 | } 48 | } -------------------------------------------------------------------------------- /app/views/settings/_worktime_about.html.erb: -------------------------------------------------------------------------------- 1 | <% html_title l(:label_worktime_about) %> 2 | 3 |

<%= l(:label_worktime_inception) %>

4 | 5 |
6 | Hey there. Worktime Log built about 3 month ago and today I completely added missing things and prepare first release. 7 |
8 | 9 |
10 | Plugin built especially for internal and tested with PostgreSQL configuration ONLY and with base RoR knowledges, so suggestions welcomed. Feel free to make forks and touch me in case if you have some fixes and suggestions. 11 |
12 | 13 | 24 | 25 |
Developed by Jared Denison in 2014.
-------------------------------------------------------------------------------- /app/views/settings/_worktime_general.html.erb: -------------------------------------------------------------------------------- 1 |

<%= l(:fieldset_widget_title) %>

2 |

3 | 4 | <%= hidden_field_tag 'settings[show_in_projects]', 0, :id => nil %> 5 | <%= check_box_tag 'settings[show_in_projects]', 1, @settings[:show_in_projects] %> 6 |

7 | 8 |

9 | 10 | <%= hidden_field_tag 'settings[show_in_issues]', 0, :id => nil %> 11 | <%= check_box_tag 'settings[show_in_issues]', 1, @settings[:show_in_issues] %> 12 |

13 | 14 |

15 | 16 | <%= hidden_field_tag 'settings[show_in_welcome]', 0, :id => nil %> 17 | <%= check_box_tag 'settings[show_in_welcome]', 1, @settings[:show_in_welcome] %> 18 |

19 | 20 |

<%= l(:fieldset_smart_toolbar) %>

21 |

22 | 23 | <%= hidden_field_tag 'settings[show_toolbar_in_issue]', 0, :id => nil %> 24 | <%= check_box_tag 'settings[show_inshow_toolbar_in_issue_welcome]', 1, @settings[:show_toolbar_in_issue] %> 25 |

26 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'redmine' 2 | Redmine::Plugin.register :redmine_worktime_log do 3 | name 'Redmine Worktime Log' 4 | author 'Jared Denisov' 5 | description 'Worktime log will help arange spent time and prepare logs for each user.' 6 | version '0.0.3' 7 | url 'http://themondays.ca/redmine/plugins/worklog.git' 8 | author_url 'http://themondays.ca' 9 | 10 | requires_redmine :version_or_higher => '2.1.2' 11 | 12 | settings :default => { 13 | 'show_in_projects' => true, 14 | 'show_in_issues' => true, 15 | 'show_in_welcome' => false, 16 | 'show_toolbar_in_issue' => true, 17 | }, :partial => 'settings/worktime' 18 | 19 | permission :worktime, { :worktimelog => [:user_summary] }, :public => false 20 | 21 | project_module :worktime do 22 | permission :view_issue_summary, :worktimelog => :issue_summary 23 | permission :view_project_sumary, :worktimelog => :project_summary 24 | permission :view_user_sumary, :worktimelog => :user_summary 25 | permission :stopwatch_timer, :stopwatch => :timer 26 | end 27 | menu :project_menu, :worktime_log, {:controller => 'worktimelog', :action => 'project_summary'}, :caption => :label_worktime_project_nav, :param => :project_id 28 | end 29 | 30 | ActionDispatch::Callbacks.to_prepare do 31 | require 'redmine_worktime' 32 | end 33 | -------------------------------------------------------------------------------- /lib/redmine_worktime/hooks/view_issue_hook.rb: -------------------------------------------------------------------------------- 1 | module RedmineWorktime 2 | module Hooks 3 | class ViewIssueHook < Redmine::Hook::ViewListener 4 | def get_user_total(id) 5 | Worktimelog.where("user_id = #{User.current.id} AND issue_id = #{id} AND flag = 1").select("COUNT(id), SUM(total) as user_time").to_a 6 | end 7 | def get_issue_total(id) 8 | Worktimelog.where({:issue_id => id, :flag => 1}).select("COUNT(id), SUM(total) as issue_time").to_a 9 | end 10 | def running_issue 11 | Worktimelog.where({:user_id => User.current.id, :flag => 0}).limit(1).to_a 12 | end 13 | def running_array 14 | Worktimelog.where({:user_id => User.current.id, :flag => 0}).limit(1).pluck(:issue_id) 15 | end 16 | def view_issues_show_details_bottom(context) 17 | context[:user_total] = get_user_total(context[:issue].id) 18 | context[:issue_total] = get_issue_total(context[:issue].id) 19 | context[:running] = running_issue 20 | context[:me] = User.current.id 21 | context[:running_array] = running_array 22 | context[:controller].send(:render_to_string, { 23 | :partial => "worktimelog/widget_issue_toolbar", 24 | :locals => context 25 | }) 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/redmine_worktime/patches/view_sidebar_patch.rb: -------------------------------------------------------------------------------- 1 | module RedmineWorktime 2 | module Patches 3 | class ViewSidebarHook < Redmine::Hook::ViewListener 4 | include MyHelper 5 | 6 | require_dependency 'projects_helper' 7 | def projects_list 8 | Project. 9 | limit(10). 10 | to_a 11 | end 12 | def issues_list 13 | Issue.visible.open. 14 | select("id,subject,project_id,p.name as project_name"). 15 | where(:assigned_to_id => ([User.current.id] + User.current.group_ids)). 16 | includes(:status, :project, :tracker, :priority). 17 | order("#{Issue.table_name}.project_id ASC, #{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC"). 18 | to_a 19 | end 20 | def running_issue 21 | Worktimelog.where({:user_id => User.current.id, :flag => 0}).limit(1).to_a 22 | end 23 | def _widget(context) 24 | context[:iss] = issues_list 25 | context[:running] = running_issue 26 | context[:controller].send(:render_to_string, { 27 | :partial =>'stopwatch/widget_timer', 28 | :locals => context 29 | }) 30 | return context 31 | end 32 | def view_issues_sidebar_planning_bottom(context) 33 | #view_issues_sidebar_planning_bottom 34 | _widget(context) 35 | end 36 | def view_project_sidebar_planning_bottom(context) 37 | #view_issues_sidebar_planning_bottom 38 | _widget(context) 39 | end 40 | # def view_layouts_base_sidebar(context) 41 | # #view_issues_sidebar_planning_bottom 42 | # _widget(context) 43 | # end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # English strings go here for Rails i18n 2 | en: 3 | label_worktime: "Worktime Stopwatch" 4 | label_worktime_project_nav: "Work Time" 5 | label_worktime_general: "General" 6 | label_worktime_about: "About Plugin" 7 | label_worktime_credits: "Credit" 8 | label_worktime_license: "License" 9 | label_worktime_my_summary: "My Summary" 10 | fieldset_widget_title: "Widget Options" 11 | label_show_stopwatch_in_projects: "Show stopwatch widget in projects sidebar" 12 | label_show_stopwatch_in_issues: "Show stopwatch widget in issues sidebar" 13 | label_show_stopwatch_in_welcome: "Show stopwatch widget in welcome screen" 14 | fieldset_smart_toolbar: "Smart Toolbar Options" 15 | label_show_smart_toolbar_issue: "Show extra toolbar on issue page" 16 | label_worktime_start: "Start" 17 | label_worktime_stop: "Stop" 18 | label_worktime_switch: "Switch" 19 | label_worktime_snapup: "Snap Up" 20 | label_worktime_you_spent: "You spent" 21 | label_worktime_total_spent: "total" 22 | label_worktime_spent: "Spent" 23 | label_worktime_project_summary: "Project Worktime Summary" 24 | label_worktime_issue_summary: "Issue Worktime Summary" 25 | label_worktime_user_summary: "User Worktime Summary" 26 | label_worktime_summary: "Worktime Summary" 27 | label_worktime_filter: "Filter" 28 | label_worktime_filter_from: "From" 29 | label_worktime_filter_to: "To" 30 | label_worktime_filter_apply: "Apply" 31 | label_worktime_th_username: "User" 32 | label_worktime_th_project: "Project" 33 | label_worktime_th_issue: "Issue" 34 | label_worktime_th_id: "ID" 35 | label_worktime_th_start: "Started" 36 | label_worktime_th_end: "Finished" 37 | label_worktime_th_total: "Total" 38 | label_worktime_inception: "Inception" 39 | -------------------------------------------------------------------------------- /config/locales/uk.yml: -------------------------------------------------------------------------------- 1 | # Ukrainian strings go here for Rails i18n 2 | uk: 3 | label_worktime: "Час роботи" 4 | label_worktime_project_nav: "Час роботи" 5 | label_worktime_general: "Загальні" 6 | label_worktime_about: "Про додаток" 7 | label_worktime_credits: "Пошана" 8 | label_worktime_license: "Ліцензія" 9 | label_worktime_my_summary: "Моє резюме" 10 | fieldset_widget_title: "Опції Віджета" 11 | label_show_stopwatch_in_projects: "Показати секундомір у бічній панелі проектів" 12 | label_show_stopwatch_in_issues: "Показати секундомір у бічній панелі завдань" 13 | label_show_stopwatch_in_welcome: "Показати секундомір на екрані вітання" 14 | fieldset_smart_toolbar: "Додаткові інструменти" 15 | label_show_smart_toolbar_issue: "Показати додаткові інструменти на сторінці завдання" 16 | label_worktime_start: "Пуск" 17 | label_worktime_stop: "Стоп" 18 | label_worktime_switch: "Перехід" 19 | label_worktime_snapup: "Підхопити" 20 | label_worktime_you_spent: "Ви витратили" 21 | label_worktime_total_spent: "загально" 22 | label_worktime_spent: "витрачено" 23 | label_worktime_project_summary: "Часовий Підсумок Проекту" 24 | label_worktime_issue_summary: "Часовий Підсумок Завдання" 25 | label_worktime_user_summary: "Часовий Підсумок Користувача" 26 | label_worktime_summary: "Підсумок" 27 | label_worktime_filter: "Фільтр" 28 | label_worktime_filter_from: "Від" 29 | label_worktime_filter_to: "По" 30 | label_worktime_filter_apply: "Застосувати" 31 | label_worktime_th_username: "Користувач" 32 | label_worktime_th_project: "Проект" 33 | label_worktime_th_issue: "Завдання" 34 | label_worktime_th_id: "ID" 35 | label_worktime_th_start: "Початок" 36 | label_worktime_th_end: "Кінець" 37 | label_worktime_th_total: "Усього" 38 | label_worktime_inception: "Початок" -------------------------------------------------------------------------------- /config/locales/fr.yml: -------------------------------------------------------------------------------- 1 | # French strings go here for Rails i18n 2 | fr: 3 | label_worktime: "Chronomètre" 4 | label_worktime_project_nav: "Temps de travail" 5 | label_worktime_general: "Général" 6 | label_worktime_about: "A propos de Plugin" 7 | label_worktime_credits: "Crédit" 8 | label_worktime_license: "Licence" 9 | label_worktime_my_summary: "Mon résumé" 10 | fieldset_widget_title: "Widget Parametres" 11 | label_show_stopwatch_in_projects: "Montrer widget chronomètre dans des projets encadré" 12 | label_show_stopwatch_in_issues: "Montrer widget chronomètre questions encadré" 13 | label_show_stopwatch_in_welcome: "Show widget chronomètre écran de bienvenue" 14 | fieldset_smart_toolbar: "Options de barre d'outils intelligente" 15 | label_show_smart_toolbar_issue: "Afficher la barre supplémentaire à le billet page" 16 | label_worktime_start: "Démarrer" 17 | label_worktime_stop: "Stop" 18 | label_worktime_switch: "Switch" 19 | label_worktime_snapup: "Accepter" 20 | label_worktime_you_spent: "Vous avez passé" 21 | label_worktime_total_spent: "total" 22 | label_worktime_spent: "Passé" 23 | label_worktime_project_summary: "Résumé du Projet" 24 | label_worktime_issue_summary: "Résumé du Billet" 25 | label_worktime_user_summary: "Résumé du Utilisateur" 26 | label_worktime_summary: "Résumé du temps" 27 | label_worktime_filter: "Filtre" 28 | label_worktime_filter_from: "De" 29 | label_worktime_filter_to: "Pour" 30 | label_worktime_filter_apply: "Appliquer" 31 | label_worktime_th_username: "Utilisateur" 32 | label_worktime_th_project: "Projet" 33 | label_worktime_th_issue: "Billet" 34 | label_worktime_th_id: "ID" 35 | label_worktime_th_start: "Démarré" 36 | label_worktime_th_end: "Fini" 37 | label_worktime_th_total: "Total" 38 | label_worktime_inception: "La Introduction" -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | # Russian strings go here for Rails i18n 2 | ru: 3 | label_worktime: "Рабочее Время" 4 | label_worktime_project_nav: "Рабочее Время" 5 | label_worktime_general: "Общие" 6 | label_worktime_about: "О плагине" 7 | label_worktime_credits: "Признательность" 8 | label_worktime_license: "Лицензия" 9 | label_worktime_my_summary: "Мое резюме" 10 | fieldset_widget_title: "Настройки виджета" 11 | label_show_stopwatch_in_projects: "Показывать секундомер в боковой панеле проекта" 12 | label_show_stopwatch_in_issues: "Показывать секундомер в боковой панеле задачи" 13 | label_show_stopwatch_in_welcome: "Показывать секундомер на главной странице" 14 | fieldset_smart_toolbar: "Дополнительные инструменты" 15 | label_show_smart_toolbar_issue: "Показывать дополнительные инструменты на странице задачи" 16 | label_worktime_start: "Пуск" 17 | label_worktime_stop: "Стоп" 18 | label_worktime_switch: "Переход" 19 | label_worktime_snapup: "Подхватить" 20 | label_worktime_you_spent: "Потрачено вами" 21 | label_worktime_total_spent: "всего" 22 | label_worktime_spent: "потрачено" 23 | label_worktime_project_summary: "Временная сводка проекта" 24 | label_worktime_issue_summary: "Временная сводка задачи" 25 | label_worktime_user_summary: "Временная сводка пользователя" 26 | label_worktime_summary: "Сводка" 27 | label_worktime_filter: "Фильтр" 28 | label_worktime_filter_from: "С" 29 | label_worktime_filter_to: "По" 30 | label_worktime_filter_apply: "Применить" 31 | label_worktime_th_username: "Пользователь" 32 | label_worktime_th_project: "Проект" 33 | label_worktime_th_issue: "Задача" 34 | label_worktime_th_id: "ID задачи" 35 | label_worktime_th_start: "Начало" 36 | label_worktime_th_end: "Конец" 37 | label_worktime_th_total: "Всего" 38 | label_worktime_inception: "Начало" -------------------------------------------------------------------------------- /app/views/worktimelog/_widget_issue_toolbar.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <% if user_total != nil %> 3 | <% user_total.each do |my| %> 4 | <% if my.user_time != nil %> 5 | <% spent = to_time(my.user_time.to_f) %> 6 | <% else %> 7 | <% spent = '00:00:00' %> 8 | <% end %> 9 | <%= l(:label_worktime_you_spent) %>: <%= spent %> 10 | <% end %> 11 | <% end %> 12 | 13 | <% if issue_total != nil %> 14 | <% issue_total.each do |all| %> 15 | <% if all.issue_time != nil %> 16 | <%= l(:label_worktime_total_spent) %>: <%= to_time(all.issue_time.to_f) %> 17 | <% end %> 18 | <% end %> 19 | <% end %> 20 | <% if running_array[0] != nil %> 21 | <% running.each do |r| %> 22 | <% if r.issue_id == @issue.id %> 23 | <%= link_to(l(:label_worktime_stop), { controller: "stopwatch", action: "timer", id: issue.id, state: "stop", back: true}, class: "worktimelog issue-btn") %> 24 | 25 | <% elsif r.issue_id != @issue.id && r.issue_id != nil %> 26 | <%= link_to(l(:label_worktime_switch), { controller: "stopwatch", action: "timer", id: issue.id, state: "start", back: true}, class: "worktimelog issue-btn") %> 27 | <% else %> 28 | <%= link_to(l(:label_worktime_start), { controller: "stopwatch", action: "timer", id: issue.id, state: "start", back: true}, class: "worktimelog issue-btn") %> 29 | <% end %> 30 | <% end %> 31 | <% else %> 32 | <%= link_to(l(:label_worktime_start), { controller: "stopwatch", action: "timer", id: issue.id, state: "start", back: true}, class: "worktimelog issue-btn") %> 33 | <% end %> 34 | <% if @issue.assigned_to_id != me %> 35 | <%= link_to(l(:label_worktime_snapup), {controller: 'stopwatch', action: 'snapup', id: issue.id, back: "true"}, class: 'worktimelog issue-btn nice') %> 36 | <% end %> 37 |
-------------------------------------------------------------------------------- /lib/redmine_worktime/hooks/view_sidebar_hook.rb: -------------------------------------------------------------------------------- 1 | module RedmineWorktime 2 | module Hooks 3 | class ViewSidebarHook < Redmine::Hook::ViewListener 4 | include MyHelper 5 | 6 | require_dependency 'projects_helper' 7 | def projects_list 8 | Project. 9 | limit(10). 10 | to_a 11 | end 12 | def issues_list 13 | Issue.visible.open. 14 | select("id,subject,project_id,p.name as project_name"). 15 | where(:assigned_to_id => ([User.current.id] + User.current.group_ids)). 16 | includes(:status, :project, :tracker, :priority). 17 | order("#{Issue.table_name}.project_id ASC, #{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC"). 18 | to_a 19 | end 20 | def running_issue 21 | Worktimelog.where({:user_id => User.current.id, :flag => 0}).limit(1).to_a 22 | end 23 | def _widget(context) 24 | context[:iss] = issues_list 25 | context[:running] = running_issue 26 | context[:me] = User.current.id 27 | context[:controller].send(:render_to_string, { 28 | :partial =>'stopwatch/widget_timer', 29 | :locals => context 30 | }) 31 | end 32 | 33 | # Rendering widget to specified areas 34 | 35 | def view_welcome_index_left(context) 36 | if !!Setting.plugin_redmine_worktime_log[:show_in_welcome] 37 | _widget(context) 38 | end 39 | end 40 | 41 | def view_issues_sidebar_planning_bottom(context) 42 | if !!Setting.plugin_redmine_worktime_log[:show_in_issues] 43 | _widget(context) 44 | end 45 | end 46 | 47 | def view_projects_show_sidebar_bottom(context) 48 | if !!Setting.plugin_redmine_worktime_log[:show_in_projects] 49 | _widget(context) 50 | end 51 | end 52 | 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = Redmine Worktime Log Plugin 2 | 3 | Release Candidate: 0.0.1 4 | 5 | == Inception 6 | Stopwatch plugin with extended projects / users / issues summary will help you track your time without editing issue details. 7 | 8 | Hey there. Worktime Log built about 3 month ago and today I completely added missing things and prepare first release. 9 | 10 | Plugin built especially for internal and tested with PostgreSQL configuration ONLY and with base RoR knowledges, so suggestions welcomed. Feel free to make forks and touch me in case if you have some fixes and suggestions. 11 | 12 | == How it works? 13 | Push START button and continue working and don't forget to press STOP when you going on lunch :) 14 | 15 | == Installation 16 | * bundle install --without development test RAILS_ENV=production 17 | * Copy plugin files to ```/redmine/plugins``` and you will get something like that: ```redmine/plugins/redmine_worktime_log/init.rb``` 18 | * Run ```rake redmine:plugins NAME=redmine_worktime_log RAILS_ENV=production``` 19 | 20 | 21 | == Additional thanks to: 22 | * Stopwatch timer originally from CakePHP app called [project-manager] by [websightdesigns] 23 | * [jQuery.Chosen] - by [Harvest] 24 | 25 | == Project locations 26 | * [Project page on GitHub] 27 | * [Project page] 28 | * [Bring me a coffee] 29 | 30 | In case ff you found something unappropriate or I forgot mention someone please touch me and we fix it. 31 | Developed by [Jared Denison] in 2014. 32 | 33 | [Project page on GitHub]:https://github.com/themondays/redmine_worktime_log 34 | [Project page]:http://themondays.ca/redmine/plugins/worktimelog/ 35 | [Bring me a coffee]:http://themondays.ca/coffee/ 36 | [Jared Denison]:http://themondays.ca 37 | [project-manager]:https://github.com/websightdesigns/project-manager/blob/master/README.md 38 | [websightdesigns]:https://github.com/websightdesigns/project-manager/blob/master/README.md 39 | [jQuery.Chosen]:http://harvesthq.github.io/chosen/ 40 | [Harvest]:http://www.getharvest.com/ 41 | 42 | -------------------------------------------------------------------------------- /app/views/stopwatch/_widget_timer.html.erb: -------------------------------------------------------------------------------- 1 | <% runtime = 0 %> 2 | <% ac = "false" %> 3 | <% running_issue_id = "" %> 4 | <% running_issue = "" %> 5 | <% if running.count > 0 %> 6 | <% running.each do |r| %> 7 | <% if r.finished %> 8 | <% runtime = runtime+(r.finished - r.started) %> 9 | <% else %> 10 | <% runtime = runtime+(Time.now.getutc - r.started) %> 11 | <% ac = true %> 12 | <% running_issue_id = r.issue_id %> 13 | <% end %> 14 | <% end %> 15 | <% end %> 16 | 17 |
18 |

19 | <%= l(:label_worktime) %> 20 | <%= link_to(l(:label_worktime_my_summary), { controller: "worktimelog", action: "user_summary", id: me }, class: "my-summary small") %> 21 |

22 |
23 | 24 | 39 | 40 | 41 | 42 |
43 | <%= to_time(runtime) %> 44 | <%= link_to(running_issue, controller: 'issues', action: 'show', id: running_issue_id) %> 45 |
46 | 47 |
48 |
49 | -------------------------------------------------------------------------------- /app/views/worktimelog/issue_summary.html.erb: -------------------------------------------------------------------------------- 1 |

<%= l(:label_worktime_issue_summary) %>

2 | 3 |
4 |
<%= l(:label_worktime_filter) %> 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | <% daytotal = 0 %> 13 | <% subtotal = 0 %> 14 | <% date_listed = 0 %> 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | <% @summary.each do |log| %> 27 | <% if Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') != date_listed %> 28 | <% if date_listed != 0 %> 29 | <% daytotal1 = 0 %> 30 | <% end %> 31 | <% date_listed = Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') %> 32 | <% if daytotal > 0 %> 33 | 34 | 35 | 36 | 37 | <% daytotal = 0 %> 38 | <% end %> 39 | 40 | 41 | 42 | <% end %> 43 | class="assigned_to"<% end %>> 44 | 45 | 46 | 47 | 48 | 49 | <% daytotal += log.total %> 50 | <% subtotal += log.total %> 51 | <% end %> 52 | <% if daytotal > 0 %> 53 | 54 | 55 | 56 | 57 | <% daytotal = 0 %> 58 | <% end %> 59 | 60 | 61 |
<%= l(:label_worktime_th_username) %><%= l(:label_worktime_th_start) %><%= l(:label_worktime_th_end) %><%= l(:label_worktime_th_total) %>
 <%= to_time(daytotal) %>
<%= date_listed %>
<%= link_to(log.user, controller: 'users', action: 'show', id: log.user_id) %><%= Time.at(log.started).gmtime.strftime('%H:%M') %><%= Time.at(log.finished).gmtime.strftime('%H:%M') %><%= to_time(log.total) %>
 <%= to_time(daytotal) %>
62 |

<%= to_time(subtotal) %>

63 |
-------------------------------------------------------------------------------- /app/views/worktimelog/user_summary.html.erb: -------------------------------------------------------------------------------- 1 |

<%= @user %> <%= l(:label_worktime_summary) %>

2 | 3 |
4 |
<%= l(:label_worktime_filter) %> 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | <% daytotal = 0 %> 14 | <% subtotal = 0 %> 15 | <% date_listed = 0 %> 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <% @summary.each do |log| %> 30 | <% if Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') != date_listed %> 31 | <% date_listed = Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') %> 32 | 33 | <% if daytotal > 0 %> 34 | 35 | 36 | 37 | 38 | <% daytotal = 0 %> 39 | <% end %> 40 | 41 | 42 | 43 | 44 | 45 | <% end %> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | <% daytotal += log.total %> 56 | <% subtotal += log.total %> 57 | <% end %> 58 | 59 | <% if daytotal > 0 %> 60 | 61 | 62 | 63 | 64 | <% daytotal = 0 %> 65 | <% end %> 66 | 67 | 68 |
<%= l(:label_worktime_th_project) %><%= l(:label_worktime_th_issue) %><%= l(:label_worktime_th_id) %><%= l(:label_worktime_th_start) %><%= l(:label_worktime_th_end) %><%= l(:label_worktime_th_total) %>
 <%= to_time(daytotal) %>
<%= date_listed %>
<%= link_to(log.project_name, controller: 'projects', action: 'show', id: log.project_identifier) %><%= link_to(log.subject, controller: 'issues', action: 'show', id: log.issue_id) %><%= link_to(log.issue_id, controller: 'issues', action: 'show', id: log.issue_id) %><%= Time.at(log.started).gmtime.strftime('%H:%M:%S') %><%= Time.at(log.finished).gmtime.strftime('%H:%M:%S') %><%= to_time(log.total) %>
 <%= to_time(daytotal) %>
69 |

<%= to_time(subtotal) %>

70 |
-------------------------------------------------------------------------------- /app/controllers/stopwatch_controller.rb: -------------------------------------------------------------------------------- 1 | class StopwatchController < ApplicationController 2 | 3 | unloadable 4 | 5 | # before_filter :authorize 6 | 7 | respond_to :html, :js 8 | 9 | def get_started 10 | #Hope God will excuse me for using map this way 11 | Worktimelog.where({:user_id => User.current.id, :flag => 0}).limit(1).map { |w| {started: w.started, issue_id: w.issue_id} } 12 | end 13 | 14 | def get_old_started 15 | Worktimelog.where({:user_id => User.current.id, :flag => 0}) 16 | end 17 | 18 | def update_time_entry(t,id) 19 | now = Time.now.in_time_zone(User.current.time_zone).getutc 20 | project = Issue.where(:id => id).pluck(:project_id) 21 | te = TimeEntry.new( 22 | :project_id => project[0], 23 | :user_id => User.current.id, 24 | :issue_id => id, 25 | :hours => t.to_i/3600, 26 | :comments => 'Captured time', 27 | :activity_id => 1, 28 | :spent_on => User.current.today, 29 | :tyear => now.strftime('%Y'), 30 | :tmonth => now.strftime('%M'), 31 | :tweek => now.strftime('%U'), 32 | :created_on => now, 33 | :updated_on => now 34 | ) 35 | te.save 36 | end 37 | 38 | def time_to_sec(t) 39 | s = t.split(":").map{|s| s.to_i} 40 | return (s[0]*3600) + (s[1]*60) + s[2] 41 | end 42 | 43 | def _start 44 | query = { 45 | :issue_id => params[:id], 46 | :user_id => User.current.id, 47 | :started => Time.now.in_time_zone(User.current.time_zone).getutc, 48 | :flag => 0 49 | } 50 | Worktimelog.create(query) 51 | end 52 | def _stop 53 | target = get_started[0] 54 | if target[:issue_id] 55 | now = Time.now.in_time_zone(User.current.time_zone).getutc 56 | started = time_to_sec(Time.at(now-Time.parse(target[:started].to_s)).strftime('%H:%M:%S')) 57 | @worklog = Worktimelog.where({:user_id => User.current.id, :flag => 0}) 58 | spent_time = time_to_sec(Time.at(now-Time.at(Time.parse(target[:started].to_s))).utc.strftime('%R:%S')) 59 | @worklog.update_all("finished = '#{now}', total = '#{spent_time}', flag = 1") 60 | if target[:issue_id] 61 | update_time_entry(spent_time,target[:issue_id]) 62 | end 63 | end 64 | end 65 | 66 | def timer 67 | @success = false 68 | if params[:state] == "start" && params[:id] 69 | @success = true 70 | _start 71 | if params[:back] == "true" 72 | redirect_to :back 73 | end 74 | 75 | end 76 | 77 | if params[:state] == "stop" 78 | @success = true 79 | _stop 80 | if params[:back] == "true" 81 | redirect_to :back 82 | end 83 | end 84 | end 85 | def snapup 86 | _stop 87 | _start 88 | 89 | issue = Issue.find(params[:id]) 90 | issue.assigned_to_id = User.current.id 91 | issue.save 92 | 93 | if params[:back] == 'true' 94 | redirect_to :back 95 | end 96 | end 97 | 98 | end 99 | -------------------------------------------------------------------------------- /app/views/worktimelog/project_summary.html.erb: -------------------------------------------------------------------------------- 1 |

<%= l(:label_worktime_project_summary) %>

2 | 3 |
4 |
<%= l(:label_worktime_filter) %> 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | <% daytotal = 0 %> 13 | <% subtotal = 0 %> 14 | <% date_listed = 0 %> 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | <% @summary.each do |log| %> 29 | <% if Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') != date_listed %> 30 | <% if date_listed != 0 %> 31 | <% daytotal1 = 0 %> 32 | <% end %> 33 | <% date_listed = Time.at(log.finished).gmtime.strftime('%A, %B %e / %Y') %> 34 | <% if daytotal > 0 %> 35 | 36 | 37 | 38 | 39 | <% daytotal = 0 %> 40 | <% end %> 41 | 42 | 43 | 44 | 45 | 46 | <% end %> 47 | class="assigned_to"<% end %>> 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | <% daytotal += log.total %> 56 | <% subtotal += log.total %> 57 | <% end %> 58 | 59 | <% if daytotal > 0 %> 60 | 61 | 62 | 63 | 64 | <% daytotal = 0 %> 65 | <% end %> 66 | 67 | 68 |
<%= l(:label_worktime_th_username) %><%= l(:label_worktime_th_issue) %><%= l(:label_worktime_th_id) %><%= l(:label_worktime_th_start) %><%= l(:label_worktime_th_end) %><%= l(:label_worktime_th_total) %>
 <%= to_time(daytotal) %>
<%= date_listed %>
<%= link_to(log.user, controller: 'users', action: 'show', id: log.user_id) %><%= link_to(log.subject, controller: 'issues', action: 'show', id: log.issue_id) %><%= link_to(log.issue_id, controller: 'issues', action: 'show', id: log.issue_id) %><%= Time.at(log.started).gmtime.strftime('%H:%M:%S') %><%= Time.at(log.finished).gmtime.strftime('%H:%M:%S') %><%= to_time(log.total) %>
 <%= to_time(daytotal) %>
69 |

<%= to_time(subtotal) %>

70 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redmine Worktime Log Plugin 2 | Release Candidate: 0.0.2 3 | 4 | ### Inception 5 | Hey folks. 6 | 7 | If describe this plugin in couple words - Worktime Log is just a Stopwatch plugin with extended projects / users / issues summary. I'm pretty sure that plugin will help you track your team load without any additional inconvenience editing issue details and billion clicks. 8 | 9 | Worktime Log built about 3 month ago for internal use and today I decided to share firs public RC with you. 10 | 11 | In general plugin created and tested with Redmine 2.6 under PostgreSQL, by this reason some queries should be reviewed before push to production with MySQL database. 12 | 13 | Feel free to make forks and touch me in case if you have some fixes and suggestions. 14 | 15 | ### How it works? 16 | 1. Enable Worktime Log module in your project 17 | 2. Add couple tickets assigned to you 18 | 3. Push START button and continue working 19 | 4. Don't forget press STOP when you going on lunch :) 20 | 21 | ![Worktime Log Issue Stopwatch Widget](http://www.redmine.org/attachments/download/13033/rwtl-stopwatch.png) 22 | 23 | ### Extra Issue Toolbar 24 | To make life easier I have added additional toolbar to issue overview. In case if you don't need this tool you may change toolbar visibility inside plugin settings. 25 | 26 | ![Worktime Log Issue Extra Toolbar](http://www.redmine.org/attachments/download/13032/rwtl-issue-toolbar.png) 27 | 28 | ### Installation 29 | 1. Copy plugin files to ```/redmine/plugins``` and you will get something like that: ```redmine/plugins/redmine_worktime_log/init.rb``` 30 | 2. Run ```rake redmine:plugins NAME=redmine_worktime_log RAILS_ENV=production``` 31 | 32 | ### Settings 33 | Inside plugin settings you may change widgets visibility as well. 34 | 35 | ### Additional thanks to: 36 | * Stopwatch timer originally from CakePHP app called [project-manager] by [websightdesigns] 37 | * [jQuery.Chosen] - by [Harvest] 38 | 39 | ### License 40 | This plugin is available under [CC-BY 3.0] 41 | 42 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 43 | 44 | ### Project locations 45 | * [Project page on GitHub] 46 | * [Project page] 47 | * [Bring me a coffee] 48 | 49 | In case ff you found something unappropriate or I forgot mention someone please touch me and we fix it. 50 | 51 | Developed by [Jared Denison] in 2014. 52 | 53 | [Project page on GitHub]:https://github.com/themondays/redmine_worktime_log 54 | [Project page]:http://themondays.ca/redmine/plugins/worktimelog/ 55 | [Bring me a coffee]:http://themondays.ca/coffee/ 56 | [Jared Denison]:http://themondays.ca 57 | [project-manager]:https://github.com/websightdesigns/project-manager/blob/master/README.md 58 | [websightdesigns]:https://github.com/websightdesigns/project-manager/blob/master/README.md 59 | [jQuery.Chosen]:http://harvesthq.github.io/chosen/ 60 | [Harvest]:http://www.getharvest.com/ 61 | [CC-BY 3.0]:http://creativecommons.org/licenses/by/3.0/ 62 | 63 | ### Changelog 64 | 65 | #### Rev. 0.0.3 66 | * Added time helper 67 | * Fixed issue totals 68 | * Fixed summary totals 69 | 70 | #### Rev. 0.0.2 71 | * Fixed toolbar stylesheet 72 | * Fixed toolbar snap up button appearance 73 | * Added 3 new languages 74 | -------------------------------------------------------------------------------- /assets/javascripts/timer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Worktime Log Stopwatch 3 | * @version 0.1 4 | */ 5 | $(document).ready(function() { 6 | var RedmineWorktimeLog = { 7 | opts: { 8 | time: 0, 9 | active: false, 10 | elapsed: 0, 11 | running_issue: 0, 12 | formWidget: '', 13 | timer: null 14 | }, 15 | query: function(url,settings) { 16 | $.ajax({ 17 | url: url, 18 | type: "POST", 19 | data: settings, 20 | dataType: "json", 21 | beforeSend: function(){ 22 | }, 23 | 24 | complete: function(){ 25 | }, 26 | 27 | success: function( response ){ 28 | return true; 29 | }, 30 | error: function(){ 31 | return false; 32 | } 33 | }); 34 | }, 35 | widget: function() { 36 | var _this = this, 37 | btn = $("button", _this.opts.formWidget), 38 | Timer = _this.opts.timer.stopwatch({ 39 | startTime: _this.opts.runtime, 40 | format: '{HH}:{MM}:{SS}' 41 | }); 42 | _this.opts.runtime = _this.opts.timer.data('runtime')*1; 43 | if (this.opts.runtime > 1) { 44 | Timer.stopwatch({active: true,startTime: _this.opts.runtime}).stopwatch('start'); 45 | _this.opts.active = true; 46 | btn.text(btn.data("stop")).attr('value','stop'); 47 | } 48 | $("#stopwatch-ui select.dropdown").chosen({width:"80%",no_results_text: "Not found: "}); 49 | 50 | //.bind(callback,this) 51 | }, 52 | events: (function() { 53 | var _this = this; 54 | $(".widget.worklog #stopwatch-ui .dropdown").on('change',function(event){ 55 | var el = $(this), 56 | btn = $("button", el); 57 | // Fix it 58 | if ( _this.opts.running_issue > 0 && _this.opts.active === true && _this.opts.running_issue !== el.val() ) { 59 | btn.parent().text(btn.data("switch")); 60 | } else { 61 | btn.parent().text(btn.data("stop")); 62 | } 63 | }); 64 | }), 65 | launch: function(){ 66 | var _this = this; 67 | this.opts.formWidget.submit(function(event){ 68 | event.preventDefault(); 69 | var el = $(this), 70 | btn = $("button",el), 71 | params = { 72 | state: $('[name="state"]',el).val(), 73 | issue_id: $('[name="issue_id"]',el).val() 74 | }; 75 | url='/worktime/stopwatch/' + params.issue_id; 76 | _this.query(url,params); 77 | //var stopwatch = timer.stopwatch({startTime: time}); 78 | if ( _this.opts.active !== true ) { 79 | _this.opts.active = true; 80 | _this.opts.timer. 81 | stopwatch('start'); 82 | btn.text(btn.data("stop")).attr('value','stop'); 83 | _this.opts.running_issue = $(".dropdown",el).val(); 84 | } else { 85 | _this.opts.elapsed = _this.opts.timer.stopwatch('getTime'); 86 | _this.opts.timer. 87 | stopwatch('stop').stopwatch('reset'); 88 | _this.opts.timer.data('suntime',1); 89 | _this.opts.active = false; 90 | _this.opts.running_issue = 0; 91 | btn.text(btn.data("start")).attr('value','start'); 92 | } 93 | return false; 94 | }); 95 | 96 | }, 97 | init: function() { 98 | this.events(); 99 | this.widget(); 100 | this.launch(); 101 | } 102 | 103 | }; 104 | 105 | RedmineWorktimeLog.opts.formWidget = $(".widget.worklog #stopwatch-ui"); 106 | RedmineWorktimeLog.opts.timer = $('#timer'); 107 | RedmineWorktimeLog.opts.runtime = RedmineWorktimeLog.opts.timer.data('runtime')*1; 108 | 109 | RedmineWorktimeLog.init(); 110 | 111 | RedmineWorktimeLog.opts.timer.stopwatch({ 112 | startTime: RedmineWorktimeLog.opts.runtime, 113 | format: '{HH}:{MM}:{SS}' 114 | }); 115 | }); 116 | 117 | /** 118 | * To do: 119 | * - add bindings 120 | * - callback 121 | * - rewrite stopwatch 122 | * - cleanup 123 | */ -------------------------------------------------------------------------------- /assets/scss/_widget.scss: -------------------------------------------------------------------------------- 1 | $span-margin: 1.2rem; 2 | #sidebar, .splitcontentleft, .splitcontentright { 3 | .chosen-container { 4 | .chosen-single { 5 | border-radius: 0; 6 | @include box-shadow(none); 7 | } 8 | .chosen-drop { 9 | border-radius: 0; 10 | @include box-shadow(none); 11 | } 12 | } 13 | 14 | .widget.worklog { 15 | box-sizing: border-box; 16 | margin-top: $span-margin; 17 | background: #fafaf5; 18 | padding: $span-margin; 19 | h3 { 20 | margin: 0; 21 | padding: 0; 22 | border: none; 23 | } 24 | .chosen-container { 25 | &.chosen-container-active { 26 | .chosen-single { 27 | b { 28 | background-position: 3px 8px; 29 | } 30 | } 31 | 32 | } 33 | .chosen-search { 34 | input { 35 | box-shadow: none; 36 | border-color: #eee; 37 | } 38 | } 39 | .chosen-drop { 40 | border-color: #eee; 41 | } 42 | .chosen-results { 43 | color: #444; 44 | position: relative; 45 | overflow-x: hidden; 46 | overflow-y: auto; 47 | margin: 0 4px 4px 0; 48 | padding: 0 0 0 4px; 49 | max-height: 240px; 50 | -webkit-overflow-scrolling: touch; 51 | li { 52 | display: none; 53 | margin: 0; 54 | padding: 5px 6px; 55 | list-style: none; 56 | line-height: 15px; 57 | word-wrap: break-word; 58 | -webkit-touch-callout: none; 59 | &.active-result { 60 | display: list-item; 61 | cursor: pointer; 62 | } 63 | &.disabled-result { 64 | display: list-item; 65 | color: #ccc; 66 | cursor: default; 67 | } 68 | &.highlighted { 69 | background-color: #3875d7; 70 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); 71 | background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%); 72 | background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%); 73 | background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%); 74 | background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); 75 | color: #fff; 76 | } 77 | &.no-results { 78 | color: #777; 79 | display: list-item; 80 | background: #f4f4f4; 81 | } 82 | &.group-result { 83 | display: list-item; 84 | font-weight: bold; 85 | cursor: default; 86 | } 87 | &.group-option { 88 | padding-left: 15px; 89 | } 90 | .smart-link { 91 | clear: right; 92 | float: right; 93 | font-size: 9px; 94 | padding: 2px 4px; 95 | background-color: #4D85BD; 96 | color: #fff; 97 | line-height: 9px; 98 | border-radius: 2px; 99 | } 100 | em { 101 | font-style: normal; 102 | text-decoration: underline; 103 | } 104 | } 105 | } 106 | } 107 | 108 | } 109 | .widget.worklog .dropdown { 110 | width:80%; 111 | margin-bottom:10px; 112 | } 113 | .widget.worklog a.chosen-single { 114 | display: block; 115 | padding: 6px 10px; 116 | border-color: #eee; 117 | height: 36px; 118 | background: white; 119 | b { 120 | background-position: -15px 8px; 121 | } 122 | } 123 | .widget.worklog button.run { 124 | width: 20%; 125 | margin: 0; 126 | float: right; 127 | height: 36px; 128 | line-height: 16px; 129 | border-radius: 0 2px 2px 0; 130 | left: 0; 131 | padding: 6px 0; 132 | margin-left: 0; 133 | border: none; 134 | // border-color: #eee; 135 | box-shadow: none; 136 | text-shadow: none; 137 | &[value="start"] { 138 | background: #5dade2; 139 | color: #fff; 140 | } 141 | &[value="stop"] { 142 | background: #2ecc71; 143 | color: #fff; 144 | } 145 | outline: none; 146 | 147 | } 148 | .widget.worklog .stopwatch { 149 | } 150 | } -------------------------------------------------------------------------------- /app/controllers/worktimelog_controller.rb: -------------------------------------------------------------------------------- 1 | class WorktimelogController < ApplicationController 2 | 3 | unloadable 4 | 5 | layout 'base' 6 | 7 | before_filter :find_project, :authorize, :only => :project_summary 8 | 9 | respond_to :html, :js 10 | 11 | helper :issue_relations 12 | include IssueRelationsHelper 13 | include IssuesHelper 14 | 15 | def find_project 16 | @project = Project.find(params[:project_id]) 17 | end 18 | 19 | def find_issue 20 | @project = Issue.find(params[:id]) 21 | end 22 | 23 | def find_user 24 | @project = User.find(params[:user_id]) 25 | end 26 | 27 | def new 28 | @worklog = Worktimelog.new 29 | end 30 | 31 | def index 32 | end 33 | 34 | def worklog 35 | end 36 | 37 | def timer 38 | @success = false 39 | if params[:state] == "start" && params[:id] 40 | @success = true 41 | @lv = { 42 | :issue_id => params[:id], 43 | :user_id => User.current.id, 44 | :started => Time.now.getutc, 45 | :flag => 0 46 | } 47 | logger.debug(@lv) 48 | @worklog = Worktimelog.create(@lv) 49 | end 50 | 51 | if params[:state] == "stop" 52 | @success = true 53 | @worklog = Worktimelog.where({:user_id => User.current.id, :flag => 0}) 54 | @worklog.update_all(:finished => Time.now.getutc, :flag => 1) 55 | end 56 | end 57 | 58 | def get_worktime(query) 59 | end 60 | 61 | def issue_summary 62 | @date = Time.now 63 | 64 | where_query = "issue_id = #{params[:issue_id]} AND flag = 1" 65 | 66 | if (params[:started] && params[:finished]) 67 | where_query += "AND (started, finished) OVERLAPS ('#{params[:started]}'::DATE, '#{params[:finished]}'::DATE)" 68 | end 69 | 70 | @summary = Worktimelog.joins([{issue: :project},:user]).select(' 71 | issue_id, 72 | user_id, 73 | started, 74 | finished, 75 | total, 76 | flag, 77 | issues.project_id as project_id, 78 | issues.subject as subject, 79 | users.firstname as firstname, 80 | users.lastname as lastname 81 | '). 82 | where(where_query). 83 | order(" 84 | finished DESC 85 | ") 86 | if ( params[:started] || params[:finished] ) 87 | if ( params[:started] ) 88 | @summary.where("started::text LIKE '#{params[:started]}%'") 89 | end 90 | if ( params[:finished] ) 91 | @summary.where("finished::text LIKE '#{params[:finished]}%'") 92 | end 93 | else 94 | @summary.limit(100) 95 | end 96 | end 97 | 98 | def project_summary 99 | @date = Time.now 100 | 101 | where_query = "projects.identifier = '#{params[:project_id]}' AND flag = 1" 102 | 103 | if (params[:started] && params[:finished]) 104 | where_query += "AND (started, finished) OVERLAPS ('#{params[:started]}'::DATE, '#{params[:finished]}'::DATE)" 105 | end 106 | 107 | @summary = Worktimelog.joins([{issue: :project},:user]).select(' 108 | issue_id, 109 | user_id, 110 | started, 111 | finished, 112 | total, 113 | flag, 114 | issues.project_id as project_id, 115 | issues.subject as subject, 116 | users.firstname as firstname, 117 | users.lastname as lastname 118 | '). 119 | where(where_query). 120 | order(" 121 | finished DESC 122 | ") 123 | if ( params[:started] || params[:finished] ) 124 | if ( params[:started] ) 125 | @summary.where("started::text LIKE '#{params[:started]}%'") 126 | end 127 | if ( params[:finished] ) 128 | @summary.where("finished::text LIKE '#{params[:finished]}%'") 129 | end 130 | else 131 | @summary.limit(100) 132 | end end 133 | 134 | def user_summary 135 | @date = Time.now 136 | @where_query = "user_id = #{params[:id]} AND flag = 1" 137 | @user = User.find(params[:id]) 138 | if (params[:started] && params[:finished]) 139 | @where_query += "AND (started, finished) OVERLAPS ('#{params[:started]}'::DATE, '#{params[:finished]}'::DATE)" 140 | end 141 | @summary = Worktimelog.joins(issue: :project).select(' 142 | issue_id, 143 | user_id, 144 | started, 145 | finished, 146 | total, 147 | flag, 148 | issues.project_id as project_id, 149 | issues.subject as subject, 150 | projects.name as project_name, 151 | projects.identifier as project_identifier 152 | ').where(@where_query). 153 | order(" 154 | finished DESC 155 | ") 156 | if ( params[:started] || params[:finished] ) 157 | if ( params[:started] ) 158 | @summary.where("started::text LIKE '#{params[:started]}%'") 159 | end 160 | if ( params[:finished] ) 161 | @summary.where("finished::text LIKE '#{params[:finished]}%'") 162 | end 163 | else 164 | @summary.limit(100) 165 | end 166 | end 167 | 168 | def ranks 169 | end 170 | 171 | def time_to_sec(t) 172 | s = t.split(":").map{|s| s.to_i} 173 | return (s[0]*3600) + (s[1]*60) + s[2] 174 | end 175 | 176 | private 177 | def worklog_params 178 | params.require(:worklog).permit(:issue_id) 179 | end 180 | 181 | end 182 | -------------------------------------------------------------------------------- /assets/javascripts/vendor/jquery/jquery.stopwatch.js: -------------------------------------------------------------------------------- 1 | // Originally from: git https://bitbucket.org/websightdesigns/project-manager.git 2 | (function( $ ){ 3 | 4 | function incrementer(ct, increment) { 5 | return function() { ct+=increment; return ct; }; 6 | } 7 | 8 | function pad2(number) { 9 | return (number < 10 ? '0' : '') + number; 10 | } 11 | 12 | function defaultFormatMilliseconds(millis) { 13 | var x, seconds, minutes, hours; 14 | x = millis / 1000; 15 | seconds = Math.floor(x % 60); 16 | x /= 60; 17 | minutes = Math.floor(x % 60); 18 | x /= 60; 19 | hours = Math.floor(x % 24); 20 | // x /= 24; 21 | // days = Math.floor(x); 22 | return [pad2(hours), pad2(minutes), pad2(seconds)].join(':'); 23 | } 24 | 25 | function formatMilliseconds(millis, data) { 26 | var formatter; 27 | if (typeof jintervals == 'function') { 28 | formatter = function(millis, data){return jintervals(millis/1000, data.format);}; 29 | } else { 30 | formatter = defaultFormatMilliseconds; 31 | } 32 | formatMilliseconds = function(millis, data) { 33 | return formatter(millis, data); 34 | }; 35 | return formatMilliseconds(millis, data); 36 | } 37 | 38 | var methods = { 39 | 40 | init: function(options) { 41 | var defaults = { 42 | updateInterval: 1000, 43 | startTime: 0, 44 | format: '{HH}:{MM}:{SS}', 45 | formatter: formatMilliseconds 46 | }; 47 | 48 | // if (options) { $.extend(settings, options); } 49 | 50 | return this.each(function() { 51 | var $this = $(this), 52 | data = $this.data('stopwatch'); 53 | 54 | // If the plugin hasn't been initialized yet 55 | if (!data) { 56 | // Setup the stopwatch data 57 | var settings = $.extend({}, defaults, options); 58 | data = settings; 59 | data.active = false; 60 | data.target = $this; 61 | data.elapsed = settings.startTime; 62 | // create counter 63 | data.incrementer = incrementer(data.startTime, data.updateInterval); 64 | data.tick_function = function() { 65 | var millis = data.incrementer(); 66 | data.elapsed = millis; 67 | data.target.trigger('tick.stopwatch', [millis]); 68 | data.target.stopwatch('render'); 69 | }; 70 | $this.data('stopwatch', data); 71 | } 72 | 73 | }); 74 | }, 75 | 76 | start: function() { 77 | return this.each(function() { 78 | var $this = $(this), 79 | data = $this.data('stopwatch'); 80 | // Mark as active 81 | data.active = true; 82 | data.timerID = setInterval(data.tick_function, data.updateInterval); 83 | $this.data('stopwatch', data); 84 | }); 85 | }, 86 | 87 | stop: function() { 88 | return this.each(function() { 89 | var $this = $(this), 90 | data = $this.data('stopwatch'); 91 | clearInterval(data.timerID); 92 | data.active = false; 93 | $this.data('stopwatch', data); 94 | }); 95 | }, 96 | 97 | destroy: function() { 98 | return this.each(function(){ 99 | var $this = $(this), 100 | data = $this.data('stopwatch'); 101 | $this.stopwatch('stop').unbind('.stopwatch').removeData('stopwatch'); 102 | }); 103 | }, 104 | 105 | render: function() { 106 | var $this = $(this), 107 | data = $this.data('stopwatch'); 108 | $this.html(data.formatter(data.elapsed, data)); 109 | }, 110 | 111 | getTime: function() { 112 | var $this = $(this), 113 | data = $this.data('stopwatch'); 114 | return data.elapsed; 115 | }, 116 | 117 | toggle: function() { 118 | return this.each(function() { 119 | var $this = $(this); 120 | var data = $this.data('stopwatch'); 121 | if (data.active) { 122 | $this.stopwatch('stop'); 123 | } else { 124 | $this.stopwatch('start'); 125 | } 126 | }); 127 | }, 128 | 129 | reset: function() { 130 | return this.each(function() { 131 | var $this = $(this); 132 | data = $this.data('stopwatch'); 133 | data.incrementer = incrementer(data.startTime, data.updateInterval); 134 | data.elapsed = data.startTime; 135 | $this.data('stopwatch', data); 136 | }); 137 | } 138 | }; 139 | $.fn.stopwatch = function( method ) { 140 | if (methods[method]) { 141 | return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 142 | } else if (typeof method === 'object' || !method) { 143 | return methods.init.apply(this, arguments); 144 | } else { 145 | $.error( 'Method ' + method + ' does not exist on jQuery.stopwatch' ); 146 | } 147 | }; 148 | })( jQuery ); -------------------------------------------------------------------------------- /assets/stylesheets/redmine_worktime_log.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": ["../scss/_widget.scss","../scss/_mixins.scss","../scss/_main.scss","../scss/_table.scss","../scss/vendor/chosen.scss"], 5 | "names": [], 6 | "file": "redmine_worktime_log.css" 7 | } 8 | -------------------------------------------------------------------------------- /assets/scss/vendor/chosen.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | Chosen, a Select Box Enhancer for jQuery and Prototype 3 | by Patrick Filler for Harvest, http://getharvest.com 4 | 5 | Version 1.3.0 6 | Full source at https://github.com/harvesthq/chosen 7 | Copyright (c) 2011-2014 Harvest http://getharvest.com 8 | 9 | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md 10 | This file is generated by `grunt build`, do not edit it by hand. 11 | */ 12 | 13 | /* @group Base */ 14 | 15 | .chosen-container { 16 | position: relative; 17 | display: inline-block; 18 | vertical-align: middle; 19 | font-size: 13px; 20 | zoom: 1; 21 | *display: inline; 22 | -webkit-user-select: none; 23 | -moz-user-select: none; 24 | user-select: none; 25 | * { 26 | -webkit-box-sizing: border-box; 27 | -moz-box-sizing: border-box; 28 | box-sizing: border-box; 29 | } 30 | .chosen-drop { 31 | position: absolute; 32 | top: 100%; 33 | left: -9999px; 34 | z-index: 1010; 35 | width: 100%; 36 | border: 1px solid #aaa; 37 | border-top: 0; 38 | background: #fff; 39 | box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); 40 | } 41 | &.chosen-with-drop .chosen-drop { 42 | left: 0; 43 | } 44 | a { 45 | cursor: pointer; 46 | } 47 | } 48 | 49 | /* @end */ 50 | /* @group Single Chosen */ 51 | 52 | .chosen-container-single { 53 | .chosen-single { 54 | position: relative; 55 | display: block; 56 | overflow: hidden; 57 | padding: 0 0 0 8px; 58 | height: 25px; 59 | border: 1px solid #aaa; 60 | border-radius: 5px; 61 | background-color: #fff; 62 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4)); 63 | background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 64 | background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 65 | background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 66 | background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 67 | background-clip: padding-box; 68 | box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1); 69 | color: #444; 70 | text-decoration: none; 71 | white-space: nowrap; 72 | line-height: 24px; 73 | } 74 | .chosen-default { 75 | color: #999; 76 | } 77 | .chosen-single span { 78 | display: block; 79 | overflow: hidden; 80 | margin-right: 26px; 81 | text-overflow: ellipsis; 82 | white-space: nowrap; 83 | } 84 | .chosen-single-with-deselect span { 85 | margin-right: 38px; 86 | } 87 | .chosen-single abbr { 88 | position: absolute; 89 | top: 6px; 90 | right: 26px; 91 | display: block; 92 | width: 12px; 93 | height: 12px; 94 | background: url('../images/chosen-sprite.png') -42px 1px no-repeat; 95 | font-size: 1px; 96 | &:hover { 97 | background-position: -42px -10px; 98 | } 99 | } 100 | &.chosen-disabled .chosen-single abbr:hover { 101 | background-position: -42px -10px; 102 | } 103 | .chosen-single div { 104 | position: absolute; 105 | top: 0; 106 | right: 0; 107 | display: block; 108 | width: 18px; 109 | height: 100%; 110 | b { 111 | display: block; 112 | width: 100%; 113 | height: 100%; 114 | background: url('../images/chosen-sprite.png') no-repeat 0px 2px; 115 | } 116 | } 117 | .chosen-search { 118 | position: relative; 119 | z-index: 1010; 120 | margin: 0; 121 | padding: 3px 4px; 122 | white-space: nowrap; 123 | input[type="text"] { 124 | margin: 1px 0; 125 | padding: 4px 20px 4px 5px; 126 | width: 100%; 127 | height: auto; 128 | outline: 0; 129 | border: 1px solid #aaa; 130 | background: white url('../images/chosen-sprite.png') no-repeat 100% -20px; 131 | background: url('../images/chosen-sprite.png') no-repeat 100% -20px; 132 | font-size: 1em; 133 | font-family: sans-serif; 134 | line-height: normal; 135 | border-radius: 0; 136 | } 137 | } 138 | .chosen-drop { 139 | margin-top: -1px; 140 | border-radius: 0 0 4px 4px; 141 | background-clip: padding-box; 142 | } 143 | &.chosen-container-single-nosearch .chosen-search { 144 | position: absolute; 145 | left: -9999px; 146 | } 147 | } 148 | 149 | /* @end */ 150 | /* @group Results */ 151 | 152 | .chosen-container .chosen-results { 153 | color: #444; 154 | position: relative; 155 | overflow-x: hidden; 156 | overflow-y: auto; 157 | margin: 0 4px 4px 0; 158 | padding: 0 0 0 4px; 159 | max-height: 240px; 160 | -webkit-overflow-scrolling: touch; 161 | li { 162 | display: none; 163 | margin: 0; 164 | padding: 5px 6px; 165 | list-style: none; 166 | line-height: 15px; 167 | word-wrap: break-word; 168 | -webkit-touch-callout: none; 169 | &.active-result { 170 | display: list-item; 171 | cursor: pointer; 172 | .smart-link { 173 | z-index: 10; 174 | clear: right; 175 | float: right; 176 | font-size: 9px; 177 | padding: 2px 4px; 178 | background-color: #4D85BD; 179 | color: #fff; 180 | line-height: 9px; 181 | border-radius: 2px; 182 | } 183 | } 184 | &.disabled-result { 185 | display: list-item; 186 | color: #ccc; 187 | cursor: default; 188 | } 189 | &.highlighted { 190 | background-color: #3875d7; 191 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); 192 | background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%); 193 | background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%); 194 | background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%); 195 | background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); 196 | color: #fff; 197 | } 198 | &.no-results { 199 | color: #777; 200 | display: list-item; 201 | background: #f4f4f4; 202 | } 203 | &.group-result { 204 | display: list-item; 205 | font-weight: bold; 206 | cursor: default; 207 | } 208 | &.group-option { 209 | padding-left: 15px; 210 | } 211 | em { 212 | font-style: normal; 213 | text-decoration: underline; 214 | } 215 | } 216 | } 217 | 218 | /* @end */ 219 | /* @group Multi Chosen */ 220 | 221 | .chosen-container-multi { 222 | .chosen-choices { 223 | position: relative; 224 | overflow: hidden; 225 | margin: 0; 226 | padding: 0 5px; 227 | width: 100%; 228 | height: auto !important; 229 | height: 1%; 230 | border: 1px solid #aaa; 231 | background-color: #fff; 232 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); 233 | background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); 234 | background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); 235 | background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%); 236 | background-image: linear-gradient(#eeeeee 1%, #ffffff 15%); 237 | cursor: text; 238 | li { 239 | float: left; 240 | list-style: none; 241 | &.search-field { 242 | margin: 0; 243 | padding: 0; 244 | white-space: nowrap; 245 | input[type="text"] { 246 | margin: 1px 0; 247 | padding: 0; 248 | height: 25px; 249 | outline: 0; 250 | border: 0 !important; 251 | background: transparent !important; 252 | box-shadow: none; 253 | color: #999; 254 | font-size: 100%; 255 | font-family: sans-serif; 256 | line-height: normal; 257 | border-radius: 0; 258 | } 259 | } 260 | &.search-choice { 261 | position: relative; 262 | margin: 3px 5px 3px 0; 263 | padding: 3px 20px 3px 5px; 264 | border: 1px solid #aaa; 265 | max-width: 100%; 266 | border-radius: 3px; 267 | background-color: #eeeeee; 268 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); 269 | background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 270 | background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 271 | background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 272 | background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 273 | background-size: 100% 19px; 274 | background-repeat: repeat-x; 275 | background-clip: padding-box; 276 | box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05); 277 | color: #333; 278 | line-height: 13px; 279 | cursor: default; 280 | span { 281 | word-wrap: break-word; 282 | } 283 | .search-choice-close { 284 | position: absolute; 285 | top: 4px; 286 | right: 3px; 287 | display: block; 288 | width: 12px; 289 | height: 12px; 290 | background: url('../images/chosen-sprite.png') -42px 1px no-repeat; 291 | font-size: 1px; 292 | &:hover { 293 | background-position: -42px -10px; 294 | } 295 | } 296 | } 297 | &.search-choice-disabled { 298 | padding-right: 5px; 299 | border: 1px solid #ccc; 300 | background-color: #e4e4e4; 301 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); 302 | background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 303 | background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 304 | background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 305 | background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 306 | color: #666; 307 | } 308 | &.search-choice-focus { 309 | background: #d4d4d4; 310 | .search-choice-close { 311 | background-position: -42px -10px; 312 | } 313 | } 314 | } 315 | } 316 | .chosen-results { 317 | margin: 0; 318 | padding: 0; 319 | } 320 | .chosen-drop .result-selected { 321 | display: list-item; 322 | color: #ccc; 323 | cursor: default; 324 | } 325 | } 326 | 327 | /* @end */ 328 | /* @group Active */ 329 | 330 | .chosen-container-active { 331 | .chosen-single { 332 | border: 1px solid #5897fb; 333 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 334 | } 335 | &.chosen-with-drop .chosen-single { 336 | border: 1px solid #aaa; 337 | -moz-border-radius-bottomright: 0; 338 | border-bottom-right-radius: 0; 339 | -moz-border-radius-bottomleft: 0; 340 | border-bottom-left-radius: 0; 341 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff)); 342 | background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%); 343 | background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%); 344 | background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%); 345 | background-image: linear-gradient(#eeeeee 20%, #ffffff 80%); 346 | box-shadow: 0 1px 0 #fff inset; 347 | div { 348 | border-left: none; 349 | background: transparent; 350 | b { 351 | background-position: -18px 2px; 352 | } 353 | } 354 | } 355 | .chosen-choices { 356 | border: 1px solid #5897fb; 357 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 358 | li.search-field input[type="text"] { 359 | color: #222 !important; 360 | } 361 | } 362 | } 363 | 364 | /* @end */ 365 | /* @group Disabled Support */ 366 | 367 | .chosen-disabled { 368 | opacity: 0.5 !important; 369 | cursor: default; 370 | .chosen-single, .chosen-choices .search-choice .search-choice-close { 371 | cursor: default; 372 | } 373 | } 374 | 375 | /* @end */ 376 | /* @group Right to Left */ 377 | 378 | .chosen-rtl { 379 | text-align: right; 380 | .chosen-single { 381 | overflow: visible; 382 | padding: 0 8px 0 0; 383 | span { 384 | margin-right: 0; 385 | margin-left: 26px; 386 | direction: rtl; 387 | } 388 | } 389 | .chosen-single-with-deselect span { 390 | margin-left: 38px; 391 | } 392 | .chosen-single { 393 | div { 394 | right: auto; 395 | left: 3px; 396 | } 397 | abbr { 398 | right: auto; 399 | left: 26px; 400 | } 401 | } 402 | .chosen-choices li { 403 | float: right; 404 | &.search-field input[type="text"] { 405 | direction: rtl; 406 | } 407 | &.search-choice { 408 | margin: 3px 5px 3px 0; 409 | padding: 3px 5px 3px 19px; 410 | .search-choice-close { 411 | right: auto; 412 | left: 4px; 413 | } 414 | } 415 | } 416 | &.chosen-container-single-nosearch .chosen-search, .chosen-drop { 417 | left: 9999px; 418 | } 419 | &.chosen-container-single .chosen-results { 420 | margin: 0 0 4px 4px; 421 | padding: 0 4px 0 0; 422 | } 423 | .chosen-results li.group-option { 424 | padding-right: 15px; 425 | padding-left: 0; 426 | } 427 | &.chosen-container-active.chosen-with-drop .chosen-single div { 428 | border-right: none; 429 | } 430 | .chosen-search input[type="text"] { 431 | padding: 4px 5px 4px 20px; 432 | background: white url('../images/chosen-sprite.png') no-repeat -30px -20px; 433 | background: url('../images/chosen-sprite.png') no-repeat -30px -20px; 434 | direction: rtl; 435 | } 436 | &.chosen-container-single { 437 | .chosen-single div b { 438 | background-position: 6px 2px; 439 | } 440 | &.chosen-with-drop .chosen-single div b { 441 | background-position: -12px 2px; 442 | } 443 | } 444 | } 445 | 446 | /* @end */ 447 | /* @group Retina compatibility */ 448 | @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) { 449 | .chosen-rtl .chosen-search input[type="text"] { 450 | background-image: url('../images/chosen-sprite@2x.png') !important; 451 | background-size: 52px 37px !important; 452 | background-repeat: no-repeat !important; 453 | } 454 | .chosen-container-single { 455 | .chosen-single { 456 | abbr, div b { 457 | background-image: url('../images/chosen-sprite@2x.png') !important; 458 | background-size: 52px 37px !important; 459 | background-repeat: no-repeat !important; 460 | } 461 | } 462 | .chosen-search input[type="text"] { 463 | background-image: url('../images/chosen-sprite@2x.png') !important; 464 | background-size: 52px 37px !important; 465 | background-repeat: no-repeat !important; 466 | } 467 | } 468 | .chosen-container-multi .chosen-choices .search-choice .search-choice-close { 469 | background-image: url('../images/chosen-sprite@2x.png') !important; 470 | background-size: 52px 37px !important; 471 | background-repeat: no-repeat !important; 472 | } 473 | .chosen-container { 474 | .chosen-results-scroll-down span, .chosen-results-scroll-up span { 475 | background-image: url('../images/chosen-sprite@2x.png') !important; 476 | background-size: 52px 37px !important; 477 | background-repeat: no-repeat !important; 478 | } 479 | } 480 | } 481 | 482 | /* @end */ 483 | -------------------------------------------------------------------------------- /assets/stylesheets/redmine_worktime_log.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Redmine Worktime Log Plugin 3 | * @author: Jared Denison 4 | */ 5 | #sidebar .chosen-container .chosen-single, .splitcontentleft .chosen-container .chosen-single, .splitcontentright .chosen-container .chosen-single { 6 | border-radius: 0; 7 | -webkit-box-shadow: none; 8 | -moz-box-shadow: none; 9 | -ms-box-shadow: none; 10 | -o-box-shadow: none; 11 | box-shadow: none; } 12 | #sidebar .chosen-container .chosen-drop, .splitcontentleft .chosen-container .chosen-drop, .splitcontentright .chosen-container .chosen-drop { 13 | border-radius: 0; 14 | -webkit-box-shadow: none; 15 | -moz-box-shadow: none; 16 | -ms-box-shadow: none; 17 | -o-box-shadow: none; 18 | box-shadow: none; } 19 | #sidebar .widget.worklog, .splitcontentleft .widget.worklog, .splitcontentright .widget.worklog { 20 | box-sizing: border-box; 21 | margin-top: 1.2rem; 22 | background: #fafaf5; 23 | padding: 1.2rem; } 24 | #sidebar .widget.worklog h3, .splitcontentleft .widget.worklog h3, .splitcontentright .widget.worklog h3 { 25 | margin: 0; 26 | padding: 0; 27 | border: none; } 28 | #sidebar .widget.worklog .chosen-container.chosen-container-active .chosen-single b, .splitcontentleft .widget.worklog .chosen-container.chosen-container-active .chosen-single b, .splitcontentright .widget.worklog .chosen-container.chosen-container-active .chosen-single b { 29 | background-position: 3px 8px; } 30 | #sidebar .widget.worklog .chosen-container .chosen-search input, .splitcontentleft .widget.worklog .chosen-container .chosen-search input, .splitcontentright .widget.worklog .chosen-container .chosen-search input { 31 | box-shadow: none; 32 | border-color: #eee; } 33 | #sidebar .widget.worklog .chosen-container .chosen-drop, .splitcontentleft .widget.worklog .chosen-container .chosen-drop, .splitcontentright .widget.worklog .chosen-container .chosen-drop { 34 | border-color: #eee; } 35 | #sidebar .widget.worklog .chosen-container .chosen-results, .splitcontentleft .widget.worklog .chosen-container .chosen-results, .splitcontentright .widget.worklog .chosen-container .chosen-results { 36 | color: #444; 37 | position: relative; 38 | overflow-x: hidden; 39 | overflow-y: auto; 40 | margin: 0 4px 4px 0; 41 | padding: 0 0 0 4px; 42 | max-height: 240px; 43 | -webkit-overflow-scrolling: touch; } 44 | #sidebar .widget.worklog .chosen-container .chosen-results li, .splitcontentleft .widget.worklog .chosen-container .chosen-results li, .splitcontentright .widget.worklog .chosen-container .chosen-results li { 45 | display: none; 46 | margin: 0; 47 | padding: 5px 6px; 48 | list-style: none; 49 | line-height: 15px; 50 | word-wrap: break-word; 51 | -webkit-touch-callout: none; } 52 | #sidebar .widget.worklog .chosen-container .chosen-results li.active-result, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.active-result, .splitcontentright .widget.worklog .chosen-container .chosen-results li.active-result { 53 | display: list-item; 54 | cursor: pointer; } 55 | #sidebar .widget.worklog .chosen-container .chosen-results li.disabled-result, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.disabled-result, .splitcontentright .widget.worklog .chosen-container .chosen-results li.disabled-result { 56 | display: list-item; 57 | color: #ccc; 58 | cursor: default; } 59 | #sidebar .widget.worklog .chosen-container .chosen-results li.highlighted, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.highlighted, .splitcontentright .widget.worklog .chosen-container .chosen-results li.highlighted { 60 | background-color: #3875d7; 61 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); 62 | background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%); 63 | background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%); 64 | background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%); 65 | background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); 66 | color: #fff; } 67 | #sidebar .widget.worklog .chosen-container .chosen-results li.no-results, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.no-results, .splitcontentright .widget.worklog .chosen-container .chosen-results li.no-results { 68 | color: #777; 69 | display: list-item; 70 | background: #f4f4f4; } 71 | #sidebar .widget.worklog .chosen-container .chosen-results li.group-result, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.group-result, .splitcontentright .widget.worklog .chosen-container .chosen-results li.group-result { 72 | display: list-item; 73 | font-weight: bold; 74 | cursor: default; } 75 | #sidebar .widget.worklog .chosen-container .chosen-results li.group-option, .splitcontentleft .widget.worklog .chosen-container .chosen-results li.group-option, .splitcontentright .widget.worklog .chosen-container .chosen-results li.group-option { 76 | padding-left: 15px; } 77 | #sidebar .widget.worklog .chosen-container .chosen-results li .smart-link, .splitcontentleft .widget.worklog .chosen-container .chosen-results li .smart-link, .splitcontentright .widget.worklog .chosen-container .chosen-results li .smart-link { 78 | clear: right; 79 | float: right; 80 | font-size: 9px; 81 | padding: 2px 4px; 82 | background-color: #4D85BD; 83 | color: #fff; 84 | line-height: 9px; 85 | border-radius: 2px; } 86 | #sidebar .widget.worklog .chosen-container .chosen-results li em, .splitcontentleft .widget.worklog .chosen-container .chosen-results li em, .splitcontentright .widget.worklog .chosen-container .chosen-results li em { 87 | font-style: normal; 88 | text-decoration: underline; } 89 | #sidebar .widget.worklog .dropdown, .splitcontentleft .widget.worklog .dropdown, .splitcontentright .widget.worklog .dropdown { 90 | width: 80%; 91 | margin-bottom: 10px; } 92 | #sidebar .widget.worklog a.chosen-single, .splitcontentleft .widget.worklog a.chosen-single, .splitcontentright .widget.worklog a.chosen-single { 93 | display: block; 94 | padding: 6px 10px; 95 | border-color: #eee; 96 | height: 36px; 97 | background: white; } 98 | #sidebar .widget.worklog a.chosen-single b, .splitcontentleft .widget.worklog a.chosen-single b, .splitcontentright .widget.worklog a.chosen-single b { 99 | background-position: -15px 8px; } 100 | #sidebar .widget.worklog button.run, .splitcontentleft .widget.worklog button.run, .splitcontentright .widget.worklog button.run { 101 | width: 20%; 102 | margin: 0; 103 | float: right; 104 | height: 36px; 105 | line-height: 16px; 106 | border-radius: 0 2px 2px 0; 107 | left: 0; 108 | padding: 6px 0; 109 | margin-left: 0; 110 | border: none; 111 | box-shadow: none; 112 | text-shadow: none; 113 | outline: none; } 114 | #sidebar .widget.worklog button.run[value="start"], .splitcontentleft .widget.worklog button.run[value="start"], .splitcontentright .widget.worklog button.run[value="start"] { 115 | background: #5dade2; 116 | color: #fff; } 117 | #sidebar .widget.worklog button.run[value="stop"], .splitcontentleft .widget.worklog button.run[value="stop"], .splitcontentright .widget.worklog button.run[value="stop"] { 118 | background: #2ecc71; 119 | color: #fff; } 120 | 121 | .widget.worklog .timer-container .stopwatch { 122 | padding-left: 8px; 123 | font-size: 0.7rem; } 124 | .widget h3 .my-summary { 125 | float: right; } 126 | .widget h3 .my-summary.small { 127 | font-size: 0.575em; } 128 | 129 | .worktime-log.issue-toolbar { 130 | background-color: #F7F6EE; 131 | padding: 10px; } 132 | 133 | .worktimelog .issue-btn, .worktime-log .issue-btn { 134 | display: inline-block; 135 | margin: 0 1px; 136 | height: 21px; 137 | line-height: 16px; 138 | border-radius: 2px; 139 | left: 0; 140 | padding: 0 10px; 141 | margin-left: 0; 142 | border: none; 143 | box-shadow: none; 144 | text-shadow: none; 145 | background: #179e7f; 146 | color: #fff; 147 | text-decoration: none; 148 | border: inset 0 -2px 0 0 rgba(0, 0, 0, 0.2); 149 | outline: none; 150 | line-height: 21px; } 151 | .worktimelog .issue-btn.nice, .worktime-log .issue-btn.nice { 152 | background-color: #CC5E2E; } 153 | 154 | table.worktime-log-table th .day-total { 155 | font-weight: 300; 156 | font-size: 12px; 157 | border-radius: 3px; 158 | background-color: #ecf0f1; 159 | color: #7f8c8d; 160 | padding: 2px 3px; 161 | position: relative; 162 | display: inline-block; } 163 | table.worktime-log-table th .day-total::before { 164 | content: ''; 165 | border: 5px transparent solid; 166 | width: 0; 167 | height: 0; 168 | display: block; 169 | padding: 0; 170 | margin: 0; 171 | top: -9px; 172 | margin-left: -5px; 173 | z-index: 2; 174 | left: 50%; 175 | line-height: 0; 176 | position: absolute; 177 | background-color: transparent; 178 | border-bottom-color: #ecf0f1; } 179 | 180 | /*! 181 | Chosen, a Select Box Enhancer for jQuery and Prototype 182 | by Patrick Filler for Harvest, http://getharvest.com 183 | 184 | Version 1.3.0 185 | Full source at https://github.com/harvesthq/chosen 186 | Copyright (c) 2011-2014 Harvest http://getharvest.com 187 | 188 | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md 189 | This file is generated by `grunt build`, do not edit it by hand. 190 | */ 191 | /* @group Base */ 192 | .chosen-container { 193 | position: relative; 194 | display: inline-block; 195 | vertical-align: middle; 196 | font-size: 13px; 197 | zoom: 1; 198 | *display: inline; 199 | -webkit-user-select: none; 200 | -moz-user-select: none; 201 | user-select: none; } 202 | .chosen-container * { 203 | -webkit-box-sizing: border-box; 204 | -moz-box-sizing: border-box; 205 | box-sizing: border-box; } 206 | .chosen-container .chosen-drop { 207 | position: absolute; 208 | top: 100%; 209 | left: -9999px; 210 | z-index: 1010; 211 | width: 100%; 212 | border: 1px solid #aaa; 213 | border-top: 0; 214 | background: #fff; 215 | box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); } 216 | .chosen-container.chosen-with-drop .chosen-drop { 217 | left: 0; } 218 | .chosen-container a { 219 | cursor: pointer; } 220 | 221 | /* @end */ 222 | /* @group Single Chosen */ 223 | .chosen-container-single .chosen-single { 224 | position: relative; 225 | display: block; 226 | overflow: hidden; 227 | padding: 0 0 0 8px; 228 | height: 25px; 229 | border: 1px solid #aaa; 230 | border-radius: 5px; 231 | background-color: #fff; 232 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4)); 233 | background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 234 | background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 235 | background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 236 | background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 237 | background-clip: padding-box; 238 | box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1); 239 | color: #444; 240 | text-decoration: none; 241 | white-space: nowrap; 242 | line-height: 24px; } 243 | .chosen-container-single .chosen-default { 244 | color: #999; } 245 | .chosen-container-single .chosen-single span { 246 | display: block; 247 | overflow: hidden; 248 | margin-right: 26px; 249 | text-overflow: ellipsis; 250 | white-space: nowrap; } 251 | .chosen-container-single .chosen-single-with-deselect span { 252 | margin-right: 38px; } 253 | .chosen-container-single .chosen-single abbr { 254 | position: absolute; 255 | top: 6px; 256 | right: 26px; 257 | display: block; 258 | width: 12px; 259 | height: 12px; 260 | background: url("../images/chosen-sprite.png") -42px 1px no-repeat; 261 | font-size: 1px; } 262 | .chosen-container-single .chosen-single abbr:hover { 263 | background-position: -42px -10px; } 264 | .chosen-container-single.chosen-disabled .chosen-single abbr:hover { 265 | background-position: -42px -10px; } 266 | .chosen-container-single .chosen-single div { 267 | position: absolute; 268 | top: 0; 269 | right: 0; 270 | display: block; 271 | width: 18px; 272 | height: 100%; } 273 | .chosen-container-single .chosen-single div b { 274 | display: block; 275 | width: 100%; 276 | height: 100%; 277 | background: url("../images/chosen-sprite.png") no-repeat 0px 2px; } 278 | .chosen-container-single .chosen-search { 279 | position: relative; 280 | z-index: 1010; 281 | margin: 0; 282 | padding: 3px 4px; 283 | white-space: nowrap; } 284 | .chosen-container-single .chosen-search input[type="text"] { 285 | margin: 1px 0; 286 | padding: 4px 20px 4px 5px; 287 | width: 100%; 288 | height: auto; 289 | outline: 0; 290 | border: 1px solid #aaa; 291 | background: white url("../images/chosen-sprite.png") no-repeat 100% -20px; 292 | background: url("../images/chosen-sprite.png") no-repeat 100% -20px; 293 | font-size: 1em; 294 | font-family: sans-serif; 295 | line-height: normal; 296 | border-radius: 0; } 297 | .chosen-container-single .chosen-drop { 298 | margin-top: -1px; 299 | border-radius: 0 0 4px 4px; 300 | background-clip: padding-box; } 301 | .chosen-container-single.chosen-container-single-nosearch .chosen-search { 302 | position: absolute; 303 | left: -9999px; } 304 | 305 | /* @end */ 306 | /* @group Results */ 307 | .chosen-container .chosen-results { 308 | color: #444; 309 | position: relative; 310 | overflow-x: hidden; 311 | overflow-y: auto; 312 | margin: 0 4px 4px 0; 313 | padding: 0 0 0 4px; 314 | max-height: 240px; 315 | -webkit-overflow-scrolling: touch; } 316 | .chosen-container .chosen-results li { 317 | display: none; 318 | margin: 0; 319 | padding: 5px 6px; 320 | list-style: none; 321 | line-height: 15px; 322 | word-wrap: break-word; 323 | -webkit-touch-callout: none; } 324 | .chosen-container .chosen-results li.active-result { 325 | display: list-item; 326 | cursor: pointer; } 327 | .chosen-container .chosen-results li.active-result .smart-link { 328 | z-index: 10; 329 | clear: right; 330 | float: right; 331 | font-size: 9px; 332 | padding: 2px 4px; 333 | background-color: #4D85BD; 334 | color: #fff; 335 | line-height: 9px; 336 | border-radius: 2px; } 337 | .chosen-container .chosen-results li.disabled-result { 338 | display: list-item; 339 | color: #ccc; 340 | cursor: default; } 341 | .chosen-container .chosen-results li.highlighted { 342 | background-color: #3875d7; 343 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); 344 | background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%); 345 | background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%); 346 | background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%); 347 | background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); 348 | color: #fff; } 349 | .chosen-container .chosen-results li.no-results { 350 | color: #777; 351 | display: list-item; 352 | background: #f4f4f4; } 353 | .chosen-container .chosen-results li.group-result { 354 | display: list-item; 355 | font-weight: bold; 356 | cursor: default; } 357 | .chosen-container .chosen-results li.group-option { 358 | padding-left: 15px; } 359 | .chosen-container .chosen-results li em { 360 | font-style: normal; 361 | text-decoration: underline; } 362 | 363 | /* @end */ 364 | /* @group Multi Chosen */ 365 | .chosen-container-multi .chosen-choices { 366 | position: relative; 367 | overflow: hidden; 368 | margin: 0; 369 | padding: 0 5px; 370 | width: 100%; 371 | height: auto !important; 372 | height: 1%; 373 | border: 1px solid #aaa; 374 | background-color: #fff; 375 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); 376 | background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); 377 | background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); 378 | background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%); 379 | background-image: linear-gradient(#eeeeee 1%, #ffffff 15%); 380 | cursor: text; } 381 | .chosen-container-multi .chosen-choices li { 382 | float: left; 383 | list-style: none; } 384 | .chosen-container-multi .chosen-choices li.search-field { 385 | margin: 0; 386 | padding: 0; 387 | white-space: nowrap; } 388 | .chosen-container-multi .chosen-choices li.search-field input[type="text"] { 389 | margin: 1px 0; 390 | padding: 0; 391 | height: 25px; 392 | outline: 0; 393 | border: 0 !important; 394 | background: transparent !important; 395 | box-shadow: none; 396 | color: #999; 397 | font-size: 100%; 398 | font-family: sans-serif; 399 | line-height: normal; 400 | border-radius: 0; } 401 | .chosen-container-multi .chosen-choices li.search-choice { 402 | position: relative; 403 | margin: 3px 5px 3px 0; 404 | padding: 3px 20px 3px 5px; 405 | border: 1px solid #aaa; 406 | max-width: 100%; 407 | border-radius: 3px; 408 | background-color: #eeeeee; 409 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); 410 | background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 411 | background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 412 | background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 413 | background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 414 | background-size: 100% 19px; 415 | background-repeat: repeat-x; 416 | background-clip: padding-box; 417 | box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05); 418 | color: #333; 419 | line-height: 13px; 420 | cursor: default; } 421 | .chosen-container-multi .chosen-choices li.search-choice span { 422 | word-wrap: break-word; } 423 | .chosen-container-multi .chosen-choices li.search-choice .search-choice-close { 424 | position: absolute; 425 | top: 4px; 426 | right: 3px; 427 | display: block; 428 | width: 12px; 429 | height: 12px; 430 | background: url("../images/chosen-sprite.png") -42px 1px no-repeat; 431 | font-size: 1px; } 432 | .chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover { 433 | background-position: -42px -10px; } 434 | .chosen-container-multi .chosen-choices li.search-choice-disabled { 435 | padding-right: 5px; 436 | border: 1px solid #ccc; 437 | background-color: #e4e4e4; 438 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); 439 | background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 440 | background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 441 | background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 442 | background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 443 | color: #666; } 444 | .chosen-container-multi .chosen-choices li.search-choice-focus { 445 | background: #d4d4d4; } 446 | .chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close { 447 | background-position: -42px -10px; } 448 | .chosen-container-multi .chosen-results { 449 | margin: 0; 450 | padding: 0; } 451 | .chosen-container-multi .chosen-drop .result-selected { 452 | display: list-item; 453 | color: #ccc; 454 | cursor: default; } 455 | 456 | /* @end */ 457 | /* @group Active */ 458 | .chosen-container-active .chosen-single { 459 | border: 1px solid #5897fb; 460 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } 461 | .chosen-container-active.chosen-with-drop .chosen-single { 462 | border: 1px solid #aaa; 463 | -moz-border-radius-bottomright: 0; 464 | border-bottom-right-radius: 0; 465 | -moz-border-radius-bottomleft: 0; 466 | border-bottom-left-radius: 0; 467 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff)); 468 | background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%); 469 | background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%); 470 | background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%); 471 | background-image: linear-gradient(#eeeeee 20%, #ffffff 80%); 472 | box-shadow: 0 1px 0 #fff inset; } 473 | .chosen-container-active.chosen-with-drop .chosen-single div { 474 | border-left: none; 475 | background: transparent; } 476 | .chosen-container-active.chosen-with-drop .chosen-single div b { 477 | background-position: -18px 2px; } 478 | .chosen-container-active .chosen-choices { 479 | border: 1px solid #5897fb; 480 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } 481 | .chosen-container-active .chosen-choices li.search-field input[type="text"] { 482 | color: #222 !important; } 483 | 484 | /* @end */ 485 | /* @group Disabled Support */ 486 | .chosen-disabled { 487 | opacity: 0.5 !important; 488 | cursor: default; } 489 | .chosen-disabled .chosen-single, .chosen-disabled .chosen-choices .search-choice .search-choice-close { 490 | cursor: default; } 491 | 492 | /* @end */ 493 | /* @group Right to Left */ 494 | .chosen-rtl { 495 | text-align: right; } 496 | .chosen-rtl .chosen-single { 497 | overflow: visible; 498 | padding: 0 8px 0 0; } 499 | .chosen-rtl .chosen-single span { 500 | margin-right: 0; 501 | margin-left: 26px; 502 | direction: rtl; } 503 | .chosen-rtl .chosen-single-with-deselect span { 504 | margin-left: 38px; } 505 | .chosen-rtl .chosen-single div { 506 | right: auto; 507 | left: 3px; } 508 | .chosen-rtl .chosen-single abbr { 509 | right: auto; 510 | left: 26px; } 511 | .chosen-rtl .chosen-choices li { 512 | float: right; } 513 | .chosen-rtl .chosen-choices li.search-field input[type="text"] { 514 | direction: rtl; } 515 | .chosen-rtl .chosen-choices li.search-choice { 516 | margin: 3px 5px 3px 0; 517 | padding: 3px 5px 3px 19px; } 518 | .chosen-rtl .chosen-choices li.search-choice .search-choice-close { 519 | right: auto; 520 | left: 4px; } 521 | .chosen-rtl.chosen-container-single-nosearch .chosen-search, .chosen-rtl .chosen-drop { 522 | left: 9999px; } 523 | .chosen-rtl.chosen-container-single .chosen-results { 524 | margin: 0 0 4px 4px; 525 | padding: 0 4px 0 0; } 526 | .chosen-rtl .chosen-results li.group-option { 527 | padding-right: 15px; 528 | padding-left: 0; } 529 | .chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div { 530 | border-right: none; } 531 | .chosen-rtl .chosen-search input[type="text"] { 532 | padding: 4px 5px 4px 20px; 533 | background: white url("../images/chosen-sprite.png") no-repeat -30px -20px; 534 | background: url("../images/chosen-sprite.png") no-repeat -30px -20px; 535 | direction: rtl; } 536 | .chosen-rtl.chosen-container-single .chosen-single div b { 537 | background-position: 6px 2px; } 538 | .chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b { 539 | background-position: -12px 2px; } 540 | 541 | /* @end */ 542 | /* @group Retina compatibility */ 543 | @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) { 544 | .chosen-rtl .chosen-search input[type="text"] { 545 | background-image: url("../images/chosen-sprite@2x.png") !important; 546 | background-size: 52px 37px !important; 547 | background-repeat: no-repeat !important; } 548 | 549 | .chosen-container-single .chosen-single abbr, .chosen-container-single .chosen-single div b { 550 | background-image: url("../images/chosen-sprite@2x.png") !important; 551 | background-size: 52px 37px !important; 552 | background-repeat: no-repeat !important; } 553 | .chosen-container-single .chosen-search input[type="text"] { 554 | background-image: url("../images/chosen-sprite@2x.png") !important; 555 | background-size: 52px 37px !important; 556 | background-repeat: no-repeat !important; } 557 | 558 | .chosen-container-multi .chosen-choices .search-choice .search-choice-close { 559 | background-image: url("../images/chosen-sprite@2x.png") !important; 560 | background-size: 52px 37px !important; 561 | background-repeat: no-repeat !important; } 562 | 563 | .chosen-container .chosen-results-scroll-down span, .chosen-container .chosen-results-scroll-up span { 564 | background-image: url("../images/chosen-sprite@2x.png") !important; 565 | background-size: 52px 37px !important; 566 | background-repeat: no-repeat !important; } } 567 | /* @end */ 568 | 569 | /*# sourceMappingURL=redmine_worktime_log.css.map */ 570 | -------------------------------------------------------------------------------- /assets/javascripts/vendor/jquery/jquery.chosen.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Chosen, a Select Box Enhancer for jQuery and Prototype 3 | by Patrick Filler for Harvest, http://getharvest.com 4 | 5 | Version 1.3.0 6 | Full source at https://github.com/harvesthq/chosen 7 | Copyright (c) 2011-2014 Harvest http://getharvest.com 8 | 9 | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md 10 | This file is generated by `grunt build`, do not edit it by hand. 11 | */ 12 | 13 | (function() { 14 | var $, AbstractChosen, Chosen, SelectParser, _ref, 15 | __hasProp = {}.hasOwnProperty, 16 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 17 | 18 | SelectParser = (function() { 19 | function SelectParser() { 20 | this.options_index = 0; 21 | this.parsed = []; 22 | } 23 | 24 | SelectParser.prototype.add_node = function(child) { 25 | if (child.nodeName.toUpperCase() === "OPTGROUP") { 26 | return this.add_group(child); 27 | } else { 28 | return this.add_option(child); 29 | } 30 | }; 31 | 32 | SelectParser.prototype.add_group = function(group) { 33 | var group_position, option, _i, _len, _ref, _results; 34 | group_position = this.parsed.length; 35 | this.parsed.push({ 36 | array_index: group_position, 37 | group: true, 38 | label: this.escapeExpression(group.label), 39 | children: 0, 40 | disabled: group.disabled, 41 | classes: group.className 42 | }); 43 | _ref = group.childNodes; 44 | _results = []; 45 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 46 | option = _ref[_i]; 47 | _results.push(this.add_option(option, group_position, group.disabled)); 48 | } 49 | return _results; 50 | }; 51 | 52 | SelectParser.prototype.add_option = function(option, group_position, group_disabled) { 53 | if (option.nodeName.toUpperCase() === "OPTION") { 54 | if (option.text !== "") { 55 | if (group_position != null) { 56 | this.parsed[group_position].children += 1; 57 | } 58 | this.parsed.push({ 59 | array_index: this.parsed.length, 60 | options_index: this.options_index, 61 | value: option.value, 62 | text: option.text, 63 | html: option.innerHTML, 64 | selected: option.selected, 65 | disabled: group_disabled === true ? group_disabled : option.disabled, 66 | group_array_index: group_position, 67 | classes: option.className, 68 | style: option.style.cssText 69 | }); 70 | } else { 71 | this.parsed.push({ 72 | array_index: this.parsed.length, 73 | options_index: this.options_index, 74 | empty: true 75 | }); 76 | } 77 | return this.options_index += 1; 78 | } 79 | }; 80 | 81 | SelectParser.prototype.escapeExpression = function(text) { 82 | var map, unsafe_chars; 83 | if ((text == null) || text === false) { 84 | return ""; 85 | } 86 | if (!/[\&\<\>\"\'\`]/.test(text)) { 87 | return text; 88 | } 89 | map = { 90 | "<": "<", 91 | ">": ">", 92 | '"': """, 93 | "'": "'", 94 | "`": "`" 95 | }; 96 | unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g; 97 | return text.replace(unsafe_chars, function(chr) { 98 | return map[chr] || "&"; 99 | }); 100 | }; 101 | 102 | return SelectParser; 103 | 104 | })(); 105 | 106 | SelectParser.select_to_array = function(select) { 107 | var child, parser, _i, _len, _ref; 108 | parser = new SelectParser(); 109 | _ref = select.childNodes; 110 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 111 | child = _ref[_i]; 112 | parser.add_node(child); 113 | } 114 | return parser.parsed; 115 | }; 116 | 117 | AbstractChosen = (function() { 118 | function AbstractChosen(form_field, options) { 119 | this.form_field = form_field; 120 | this.options = options != null ? options : {}; 121 | if (!AbstractChosen.browser_is_supported()) { 122 | return; 123 | } 124 | this.is_multiple = this.form_field.multiple; 125 | this.set_default_text(); 126 | this.set_default_values(); 127 | this.setup(); 128 | this.set_up_html(); 129 | this.register_observers(); 130 | this.on_ready(); 131 | } 132 | 133 | AbstractChosen.prototype.set_default_values = function() { 134 | var _this = this; 135 | this.click_test_action = function(evt) { 136 | return _this.test_active_click(evt); 137 | }; 138 | this.activate_action = function(evt) { 139 | return _this.activate_field(evt); 140 | }; 141 | this.active_field = false; 142 | this.mouse_on_container = false; 143 | this.results_showing = false; 144 | this.result_highlighted = null; 145 | this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false; 146 | this.disable_search_threshold = this.options.disable_search_threshold || 0; 147 | this.disable_search = this.options.disable_search || false; 148 | this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true; 149 | this.group_search = this.options.group_search != null ? this.options.group_search : true; 150 | this.search_contains = this.options.search_contains || false; 151 | this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true; 152 | this.max_selected_options = this.options.max_selected_options || Infinity; 153 | this.inherit_select_classes = this.options.inherit_select_classes || false; 154 | this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true; 155 | return this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true; 156 | }; 157 | 158 | AbstractChosen.prototype.set_default_text = function() { 159 | if (this.form_field.getAttribute("data-placeholder")) { 160 | this.default_text = this.form_field.getAttribute("data-placeholder"); 161 | } else if (this.is_multiple) { 162 | this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text; 163 | } else { 164 | this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text; 165 | } 166 | return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text; 167 | }; 168 | 169 | AbstractChosen.prototype.mouse_enter = function() { 170 | return this.mouse_on_container = true; 171 | }; 172 | 173 | AbstractChosen.prototype.mouse_leave = function() { 174 | return this.mouse_on_container = false; 175 | }; 176 | 177 | AbstractChosen.prototype.input_focus = function(evt) { 178 | var _this = this; 179 | if (this.is_multiple) { 180 | if (!this.active_field) { 181 | return setTimeout((function() { 182 | return _this.container_mousedown(); 183 | }), 50); 184 | } 185 | } else { 186 | if (!this.active_field) { 187 | return this.activate_field(); 188 | } 189 | } 190 | }; 191 | 192 | AbstractChosen.prototype.input_blur = function(evt) { 193 | var _this = this; 194 | if (!this.mouse_on_container) { 195 | this.active_field = false; 196 | return setTimeout((function() { 197 | return _this.blur_test(); 198 | }), 100); 199 | } 200 | }; 201 | 202 | AbstractChosen.prototype.results_option_build = function(options) { 203 | var content, data, _i, _len, _ref; 204 | content = ''; 205 | _ref = this.results_data; 206 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 207 | data = _ref[_i]; 208 | if (data.group) { 209 | content += this.result_add_group(data); 210 | } else { 211 | content += this.result_add_option(data); 212 | } 213 | if (options != null ? options.first : void 0) { 214 | if (data.selected && this.is_multiple) { 215 | this.choice_build(data); 216 | } else if (data.selected && !this.is_multiple) { 217 | this.single_set_selected_text(data.text); 218 | } 219 | } 220 | } 221 | return content; 222 | }; 223 | 224 | AbstractChosen.prototype.result_add_option = function(option) { 225 | var classes, option_el; 226 | if (!option.search_match) { 227 | return ''; 228 | } 229 | if (!this.include_option_in_results(option)) { 230 | return ''; 231 | } 232 | classes = []; 233 | if (!option.disabled && !(option.selected && this.is_multiple)) { 234 | classes.push("active-result"); 235 | } 236 | if (option.disabled && !(option.selected && this.is_multiple)) { 237 | classes.push("disabled-result"); 238 | } 239 | if (option.selected) { 240 | classes.push("result-selected"); 241 | } 242 | if (option.group_array_index != null) { 243 | classes.push("group-option"); 244 | } 245 | if (option.classes !== "") { 246 | classes.push(option.classes); 247 | } 248 | var option_obj = this.form_field.options[option.array_index]; 249 | option_el = document.createElement("li"); 250 | option_el.className = classes.join(" "); 251 | option_el.style.cssText = option.style; 252 | option_el.setAttribute("data-option-array-index", option.array_index); 253 | option_el.innerHTML = option.search_text; 254 | if ($(option_obj).data('href')) { 255 | link_el = document.createElement("a"); 256 | link_el.className = "smart-link"; 257 | link_el.href = $(option_obj).data('href'); 258 | link_el.innerHTML = "L"; 259 | link_el.onclick = function(event){ 260 | event.stopPropagation(); 261 | return window.location.href = $(option_obj).data('href'); 262 | }; 263 | 264 | option_el.appendChild(link_el); 265 | } 266 | return this.outerHTML(option_el); 267 | }; 268 | 269 | AbstractChosen.prototype.result_add_group = function(group) { 270 | var classes, group_el; 271 | if (!(group.search_match || group.group_match)) { 272 | return ''; 273 | } 274 | if (!(group.active_options > 0)) { 275 | return ''; 276 | } 277 | classes = []; 278 | classes.push("group-result"); 279 | if (group.classes) { 280 | classes.push(group.classes); 281 | } 282 | group_el = document.createElement("li"); 283 | group_el.className = classes.join(" "); 284 | group_el.innerHTML = group.search_text; 285 | return this.outerHTML(group_el); 286 | }; 287 | 288 | AbstractChosen.prototype.results_update_field = function() { 289 | this.set_default_text(); 290 | if (!this.is_multiple) { 291 | this.results_reset_cleanup(); 292 | } 293 | this.result_clear_highlight(); 294 | this.results_build(); 295 | if (this.results_showing) { 296 | return this.winnow_results(); 297 | } 298 | }; 299 | 300 | AbstractChosen.prototype.reset_single_select_options = function() { 301 | var result, _i, _len, _ref, _results; 302 | _ref = this.results_data; 303 | _results = []; 304 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 305 | result = _ref[_i]; 306 | if (result.selected) { 307 | _results.push(result.selected = false); 308 | } else { 309 | _results.push(void 0); 310 | } 311 | } 312 | return _results; 313 | }; 314 | 315 | AbstractChosen.prototype.results_toggle = function() { 316 | if (this.results_showing) { 317 | return this.results_hide(); 318 | } else { 319 | return this.results_show(); 320 | } 321 | }; 322 | 323 | AbstractChosen.prototype.results_search = function(evt) { 324 | if (this.results_showing) { 325 | return this.winnow_results(); 326 | } else { 327 | return this.results_show(); 328 | } 329 | }; 330 | 331 | AbstractChosen.prototype.winnow_results = function() { 332 | var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref; 333 | this.no_results_clear(); 334 | results = 0; 335 | searchText = this.get_search_text(); 336 | escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 337 | zregex = new RegExp(escapedSearchText, 'i'); 338 | regex = this.get_search_regex(escapedSearchText); 339 | _ref = this.results_data; 340 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 341 | option = _ref[_i]; 342 | option.search_match = false; 343 | results_group = null; 344 | if (this.include_option_in_results(option)) { 345 | if (option.group) { 346 | option.group_match = false; 347 | option.active_options = 0; 348 | } 349 | if ((option.group_array_index != null) && this.results_data[option.group_array_index]) { 350 | results_group = this.results_data[option.group_array_index]; 351 | if (results_group.active_options === 0 && results_group.search_match) { 352 | results += 1; 353 | } 354 | results_group.active_options += 1; 355 | } 356 | if (!(option.group && !this.group_search)) { 357 | option.search_text = option.group ? option.label : option.text; 358 | option.search_match = this.search_string_match(option.search_text, regex); 359 | if (option.search_match && !option.group) { 360 | results += 1; 361 | } 362 | if (option.search_match) { 363 | if (searchText.length) { 364 | startpos = option.search_text.search(zregex); 365 | text = option.search_text.substr(0, startpos + searchText.length) + '' + option.search_text.substr(startpos + searchText.length); 366 | option.search_text = text.substr(0, startpos) + '' + text.substr(startpos); 367 | } 368 | if (results_group != null) { 369 | results_group.group_match = true; 370 | } 371 | } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) { 372 | option.search_match = true; 373 | } 374 | } 375 | } 376 | } 377 | this.result_clear_highlight(); 378 | if (results < 1 && searchText.length) { 379 | this.update_results_content(""); 380 | return this.no_results(searchText); 381 | } else { 382 | this.update_results_content(this.results_option_build()); 383 | return this.winnow_results_set_highlight(); 384 | } 385 | }; 386 | 387 | AbstractChosen.prototype.get_search_regex = function(escaped_search_string) { 388 | var regex_anchor; 389 | regex_anchor = this.search_contains ? "" : "^"; 390 | return new RegExp(regex_anchor + escaped_search_string, 'i'); 391 | }; 392 | 393 | AbstractChosen.prototype.search_string_match = function(search_string, regex) { 394 | var part, parts, _i, _len; 395 | if (regex.test(search_string)) { 396 | return true; 397 | } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) { 398 | parts = search_string.replace(/\[|\]/g, "").split(" "); 399 | if (parts.length) { 400 | for (_i = 0, _len = parts.length; _i < _len; _i++) { 401 | part = parts[_i]; 402 | if (regex.test(part)) { 403 | return true; 404 | } 405 | } 406 | } 407 | } 408 | }; 409 | 410 | AbstractChosen.prototype.choices_count = function() { 411 | var option, _i, _len, _ref; 412 | if (this.selected_option_count != null) { 413 | return this.selected_option_count; 414 | } 415 | this.selected_option_count = 0; 416 | _ref = this.form_field.options; 417 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 418 | option = _ref[_i]; 419 | if (option.selected) { 420 | this.selected_option_count += 1; 421 | } 422 | } 423 | return this.selected_option_count; 424 | }; 425 | 426 | AbstractChosen.prototype.choices_click = function(evt) { 427 | evt.preventDefault(); 428 | if (!(this.results_showing || this.is_disabled)) { 429 | return this.results_show(); 430 | } 431 | }; 432 | 433 | AbstractChosen.prototype.keyup_checker = function(evt) { 434 | var stroke, _ref; 435 | stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; 436 | this.search_field_scale(); 437 | switch (stroke) { 438 | case 8: 439 | if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) { 440 | return this.keydown_backstroke(); 441 | } else if (!this.pending_backstroke) { 442 | this.result_clear_highlight(); 443 | return this.results_search(); 444 | } 445 | break; 446 | case 13: 447 | evt.preventDefault(); 448 | if (this.results_showing) { 449 | return this.result_select(evt); 450 | } 451 | break; 452 | case 27: 453 | if (this.results_showing) { 454 | this.results_hide(); 455 | } 456 | return true; 457 | case 9: 458 | case 38: 459 | case 40: 460 | case 16: 461 | case 91: 462 | case 17: 463 | break; 464 | default: 465 | return this.results_search(); 466 | } 467 | }; 468 | 469 | AbstractChosen.prototype.clipboard_event_checker = function(evt) { 470 | var _this = this; 471 | return setTimeout((function() { 472 | return _this.results_search(); 473 | }), 50); 474 | }; 475 | 476 | AbstractChosen.prototype.container_width = function() { 477 | if (this.options.width != null) { 478 | return this.options.width; 479 | } else { 480 | return "" + this.form_field.offsetWidth + "px"; 481 | } 482 | }; 483 | 484 | AbstractChosen.prototype.include_option_in_results = function(option) { 485 | if (this.is_multiple && (!this.display_selected_options && option.selected)) { 486 | return false; 487 | } 488 | if (!this.display_disabled_options && option.disabled) { 489 | return false; 490 | } 491 | if (option.empty) { 492 | return false; 493 | } 494 | return true; 495 | }; 496 | 497 | AbstractChosen.prototype.search_results_touchstart = function(evt) { 498 | this.touch_started = true; 499 | return this.search_results_mouseover(evt); 500 | }; 501 | 502 | AbstractChosen.prototype.search_results_touchmove = function(evt) { 503 | this.touch_started = false; 504 | return this.search_results_mouseout(evt); 505 | }; 506 | 507 | AbstractChosen.prototype.search_results_touchend = function(evt) { 508 | if (this.touch_started) { 509 | return this.search_results_mouseup(evt); 510 | } 511 | }; 512 | 513 | AbstractChosen.prototype.outerHTML = function(element) { 514 | var tmp; 515 | if (element.outerHTML) { 516 | return element.outerHTML; 517 | } 518 | tmp = document.createElement("div"); 519 | tmp.appendChild(element); 520 | return tmp.innerHTML; 521 | }; 522 | 523 | AbstractChosen.browser_is_supported = function() { 524 | if (window.navigator.appName === "Microsoft Internet Explorer") { 525 | return document.documentMode >= 8; 526 | } 527 | if (/iP(od|hone)/i.test(window.navigator.userAgent)) { 528 | return false; 529 | } 530 | if (/Android/i.test(window.navigator.userAgent)) { 531 | if (/Mobile/i.test(window.navigator.userAgent)) { 532 | return false; 533 | } 534 | } 535 | return true; 536 | }; 537 | 538 | AbstractChosen.default_multiple_text = "Select Some Options"; 539 | 540 | AbstractChosen.default_single_text = "Select an Option"; 541 | 542 | AbstractChosen.default_no_result_text = "No results match"; 543 | 544 | return AbstractChosen; 545 | 546 | })(); 547 | 548 | $ = jQuery; 549 | 550 | $.fn.extend({ 551 | chosen: function(options) { 552 | if (!AbstractChosen.browser_is_supported()) { 553 | return this; 554 | } 555 | return this.each(function(input_field) { 556 | var $this, chosen; 557 | $this = $(this); 558 | chosen = $this.data('chosen'); 559 | if (options === 'destroy' && chosen instanceof Chosen) { 560 | chosen.destroy(); 561 | } else if (!(chosen instanceof Chosen)) { 562 | $this.data('chosen', new Chosen(this, options)); 563 | } 564 | }); 565 | } 566 | }); 567 | 568 | Chosen = (function(_super) { 569 | __extends(Chosen, _super); 570 | 571 | function Chosen() { 572 | _ref = Chosen.__super__.constructor.apply(this, arguments); 573 | return _ref; 574 | } 575 | 576 | Chosen.prototype.setup = function() { 577 | this.form_field_jq = $(this.form_field); 578 | this.current_selectedIndex = this.form_field.selectedIndex; 579 | return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl"); 580 | }; 581 | 582 | Chosen.prototype.set_up_html = function() { 583 | var container_classes, container_props; 584 | container_classes = ["chosen-container"]; 585 | container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single")); 586 | if (this.inherit_select_classes && this.form_field.className) { 587 | container_classes.push(this.form_field.className); 588 | } 589 | if (this.is_rtl) { 590 | container_classes.push("chosen-rtl"); 591 | } 592 | container_props = { 593 | 'class': container_classes.join(' '), 594 | 'style': "width: " + (this.container_width()) + ";", 595 | 'title': this.form_field.title 596 | }; 597 | if (this.form_field.id.length) { 598 | container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen"; 599 | } 600 | this.container = $("
", container_props); 601 | if (this.is_multiple) { 602 | this.container.html('
    '); 603 | } else { 604 | this.container.html('' + this.default_text + '
      '); 605 | } 606 | this.form_field_jq.hide().after(this.container); 607 | this.dropdown = this.container.find('div.chosen-drop').first(); 608 | this.search_field = this.container.find('input').first(); 609 | this.search_results = this.container.find('ul.chosen-results').first(); 610 | this.search_field_scale(); 611 | this.search_no_results = this.container.find('li.no-results').first(); 612 | if (this.is_multiple) { 613 | this.search_choices = this.container.find('ul.chosen-choices').first(); 614 | this.search_container = this.container.find('li.search-field').first(); 615 | } else { 616 | this.search_container = this.container.find('div.chosen-search').first(); 617 | this.selected_item = this.container.find('.chosen-single').first(); 618 | } 619 | this.results_build(); 620 | this.set_tab_index(); 621 | return this.set_label_behavior(); 622 | }; 623 | 624 | Chosen.prototype.on_ready = function() { 625 | return this.form_field_jq.trigger("chosen:ready", { 626 | chosen: this 627 | }); 628 | }; 629 | 630 | Chosen.prototype.register_observers = function() { 631 | var _this = this; 632 | this.container.bind('touchstart.chosen', function(evt) { 633 | _this.container_mousedown(evt); 634 | }); 635 | this.container.bind('touchend.chosen', function(evt) { 636 | _this.container_mouseup(evt); 637 | }); 638 | this.container.bind('mousedown.chosen', function(evt) { 639 | _this.container_mousedown(evt); 640 | }); 641 | this.container.bind('mouseup.chosen', function(evt) { 642 | _this.container_mouseup(evt); 643 | }); 644 | this.container.bind('mouseenter.chosen', function(evt) { 645 | _this.mouse_enter(evt); 646 | }); 647 | this.container.bind('mouseleave.chosen', function(evt) { 648 | _this.mouse_leave(evt); 649 | }); 650 | this.search_results.bind('mouseup.chosen', function(evt) { 651 | _this.search_results_mouseup(evt); 652 | }); 653 | this.search_results.bind('mouseover.chosen', function(evt) { 654 | _this.search_results_mouseover(evt); 655 | }); 656 | this.search_results.bind('mouseout.chosen', function(evt) { 657 | _this.search_results_mouseout(evt); 658 | }); 659 | this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) { 660 | _this.search_results_mousewheel(evt); 661 | }); 662 | this.search_results.bind('touchstart.chosen', function(evt) { 663 | _this.search_results_touchstart(evt); 664 | }); 665 | this.search_results.bind('touchmove.chosen', function(evt) { 666 | _this.search_results_touchmove(evt); 667 | }); 668 | this.search_results.bind('touchend.chosen', function(evt) { 669 | _this.search_results_touchend(evt); 670 | }); 671 | this.form_field_jq.bind("chosen:updated.chosen", function(evt) { 672 | _this.results_update_field(evt); 673 | }); 674 | this.form_field_jq.bind("chosen:activate.chosen", function(evt) { 675 | _this.activate_field(evt); 676 | }); 677 | this.form_field_jq.bind("chosen:open.chosen", function(evt) { 678 | _this.container_mousedown(evt); 679 | }); 680 | this.form_field_jq.bind("chosen:close.chosen", function(evt) { 681 | _this.input_blur(evt); 682 | }); 683 | this.search_field.bind('blur.chosen', function(evt) { 684 | _this.input_blur(evt); 685 | }); 686 | this.search_field.bind('keyup.chosen', function(evt) { 687 | _this.keyup_checker(evt); 688 | }); 689 | this.search_field.bind('keydown.chosen', function(evt) { 690 | _this.keydown_checker(evt); 691 | }); 692 | this.search_field.bind('focus.chosen', function(evt) { 693 | _this.input_focus(evt); 694 | }); 695 | this.search_field.bind('cut.chosen', function(evt) { 696 | _this.clipboard_event_checker(evt); 697 | }); 698 | this.search_field.bind('paste.chosen', function(evt) { 699 | _this.clipboard_event_checker(evt); 700 | }); 701 | if (this.is_multiple) { 702 | return this.search_choices.bind('click.chosen', function(evt) { 703 | _this.choices_click(evt); 704 | }); 705 | } else { 706 | return this.container.bind('click.chosen', function(evt) { 707 | evt.preventDefault(); 708 | }); 709 | } 710 | }; 711 | 712 | Chosen.prototype.destroy = function() { 713 | $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); 714 | if (this.search_field[0].tabIndex) { 715 | this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex; 716 | } 717 | this.container.remove(); 718 | this.form_field_jq.removeData('chosen'); 719 | return this.form_field_jq.show(); 720 | }; 721 | 722 | Chosen.prototype.search_field_disabled = function() { 723 | this.is_disabled = this.form_field_jq[0].disabled; 724 | if (this.is_disabled) { 725 | this.container.addClass('chosen-disabled'); 726 | this.search_field[0].disabled = true; 727 | if (!this.is_multiple) { 728 | this.selected_item.unbind("focus.chosen", this.activate_action); 729 | } 730 | return this.close_field(); 731 | } else { 732 | this.container.removeClass('chosen-disabled'); 733 | this.search_field[0].disabled = false; 734 | if (!this.is_multiple) { 735 | return this.selected_item.bind("focus.chosen", this.activate_action); 736 | } 737 | } 738 | }; 739 | 740 | Chosen.prototype.container_mousedown = function(evt) { 741 | if (!this.is_disabled) { 742 | if (evt && evt.type === "mousedown" && !this.results_showing) { 743 | evt.preventDefault(); 744 | } 745 | if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) { 746 | if (!this.active_field) { 747 | if (this.is_multiple) { 748 | this.search_field.val(""); 749 | } 750 | $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action); 751 | this.results_show(); 752 | } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) { 753 | evt.preventDefault(); 754 | this.results_toggle(); 755 | } 756 | return this.activate_field(); 757 | } 758 | } 759 | }; 760 | 761 | Chosen.prototype.container_mouseup = function(evt) { 762 | if (evt.target.nodeName === "ABBR" && !this.is_disabled) { 763 | return this.results_reset(evt); 764 | } 765 | }; 766 | 767 | Chosen.prototype.search_results_mousewheel = function(evt) { 768 | var delta; 769 | if (evt.originalEvent) { 770 | delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail; 771 | } 772 | if (delta != null) { 773 | evt.preventDefault(); 774 | if (evt.type === 'DOMMouseScroll') { 775 | delta = delta * 40; 776 | } 777 | return this.search_results.scrollTop(delta + this.search_results.scrollTop()); 778 | } 779 | }; 780 | 781 | Chosen.prototype.blur_test = function(evt) { 782 | if (!this.active_field && this.container.hasClass("chosen-container-active")) { 783 | return this.close_field(); 784 | } 785 | }; 786 | 787 | Chosen.prototype.close_field = function() { 788 | $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); 789 | this.active_field = false; 790 | this.results_hide(); 791 | this.container.removeClass("chosen-container-active"); 792 | this.clear_backstroke(); 793 | this.show_search_field_default(); 794 | return this.search_field_scale(); 795 | }; 796 | 797 | Chosen.prototype.activate_field = function() { 798 | this.container.addClass("chosen-container-active"); 799 | this.active_field = true; 800 | this.search_field.val(this.search_field.val()); 801 | return this.search_field.focus(); 802 | }; 803 | 804 | Chosen.prototype.test_active_click = function(evt) { 805 | var active_container; 806 | active_container = $(evt.target).closest('.chosen-container'); 807 | if (active_container.length && this.container[0] === active_container[0]) { 808 | return this.active_field = true; 809 | } else { 810 | return this.close_field(); 811 | } 812 | }; 813 | 814 | Chosen.prototype.results_build = function() { 815 | this.parsing = true; 816 | this.selected_option_count = null; 817 | this.results_data = SelectParser.select_to_array(this.form_field); 818 | if (this.is_multiple) { 819 | this.search_choices.find("li.search-choice").remove(); 820 | } else if (!this.is_multiple) { 821 | this.single_set_selected_text(); 822 | if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) { 823 | this.search_field[0].readOnly = true; 824 | this.container.addClass("chosen-container-single-nosearch"); 825 | } else { 826 | this.search_field[0].readOnly = false; 827 | this.container.removeClass("chosen-container-single-nosearch"); 828 | } 829 | } 830 | this.update_results_content(this.results_option_build({ 831 | first: true 832 | })); 833 | this.search_field_disabled(); 834 | this.show_search_field_default(); 835 | this.search_field_scale(); 836 | return this.parsing = false; 837 | }; 838 | 839 | Chosen.prototype.result_do_highlight = function(el) { 840 | var high_bottom, high_top, maxHeight, visible_bottom, visible_top; 841 | if (el.length) { 842 | this.result_clear_highlight(); 843 | this.result_highlight = el; 844 | this.result_highlight.addClass("highlighted"); 845 | maxHeight = parseInt(this.search_results.css("maxHeight"), 10); 846 | visible_top = this.search_results.scrollTop(); 847 | visible_bottom = maxHeight + visible_top; 848 | high_top = this.result_highlight.position().top + this.search_results.scrollTop(); 849 | high_bottom = high_top + this.result_highlight.outerHeight(); 850 | if (high_bottom >= visible_bottom) { 851 | return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); 852 | } else if (high_top < visible_top) { 853 | return this.search_results.scrollTop(high_top); 854 | } 855 | } 856 | }; 857 | 858 | Chosen.prototype.result_clear_highlight = function() { 859 | if (this.result_highlight) { 860 | this.result_highlight.removeClass("highlighted"); 861 | } 862 | return this.result_highlight = null; 863 | }; 864 | 865 | Chosen.prototype.results_show = function() { 866 | if (this.is_multiple && this.max_selected_options <= this.choices_count()) { 867 | this.form_field_jq.trigger("chosen:maxselected", { 868 | chosen: this 869 | }); 870 | return false; 871 | } 872 | this.container.addClass("chosen-with-drop"); 873 | this.results_showing = true; 874 | this.search_field.focus(); 875 | this.search_field.val(this.search_field.val()); 876 | this.winnow_results(); 877 | return this.form_field_jq.trigger("chosen:showing_dropdown", { 878 | chosen: this 879 | }); 880 | }; 881 | 882 | Chosen.prototype.update_results_content = function(content) { 883 | return this.search_results.html(content); 884 | }; 885 | 886 | Chosen.prototype.results_hide = function() { 887 | if (this.results_showing) { 888 | this.result_clear_highlight(); 889 | this.container.removeClass("chosen-with-drop"); 890 | this.form_field_jq.trigger("chosen:hiding_dropdown", { 891 | chosen: this 892 | }); 893 | } 894 | return this.results_showing = false; 895 | }; 896 | 897 | Chosen.prototype.set_tab_index = function(el) { 898 | var ti; 899 | if (this.form_field.tabIndex) { 900 | ti = this.form_field.tabIndex; 901 | this.form_field.tabIndex = -1; 902 | return this.search_field[0].tabIndex = ti; 903 | } 904 | }; 905 | 906 | Chosen.prototype.set_label_behavior = function() { 907 | var _this = this; 908 | this.form_field_label = this.form_field_jq.parents("label"); 909 | if (!this.form_field_label.length && this.form_field.id.length) { 910 | this.form_field_label = $("label[for='" + this.form_field.id + "']"); 911 | } 912 | if (this.form_field_label.length > 0) { 913 | return this.form_field_label.bind('click.chosen', function(evt) { 914 | if (_this.is_multiple) { 915 | return _this.container_mousedown(evt); 916 | } else { 917 | return _this.activate_field(); 918 | } 919 | }); 920 | } 921 | }; 922 | 923 | Chosen.prototype.show_search_field_default = function() { 924 | if (this.is_multiple && this.choices_count() < 1 && !this.active_field) { 925 | this.search_field.val(this.default_text); 926 | return this.search_field.addClass("default"); 927 | } else { 928 | this.search_field.val(""); 929 | return this.search_field.removeClass("default"); 930 | } 931 | }; 932 | 933 | Chosen.prototype.search_results_mouseup = function(evt) { 934 | var target; 935 | target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 936 | if (target.length) { 937 | this.result_highlight = target; 938 | this.result_select(evt); 939 | return this.search_field.focus(); 940 | } 941 | }; 942 | 943 | Chosen.prototype.search_results_mouseover = function(evt) { 944 | var target; 945 | target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 946 | if (target) { 947 | return this.result_do_highlight(target); 948 | } 949 | }; 950 | 951 | Chosen.prototype.search_results_mouseout = function(evt) { 952 | if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { 953 | return this.result_clear_highlight(); 954 | } 955 | }; 956 | 957 | Chosen.prototype.choice_build = function(item) { 958 | var choice, close_link, 959 | _this = this; 960 | choice = $('
    • ', { 961 | "class": "search-choice" 962 | }).html("" + item.html + ""); 963 | if (item.disabled) { 964 | choice.addClass('search-choice-disabled'); 965 | } else { 966 | close_link = $('', { 967 | "class": 'search-choice-close', 968 | 'data-option-array-index': item.array_index 969 | }); 970 | close_link.bind('click.chosen', function(evt) { 971 | return _this.choice_destroy_link_click(evt); 972 | }); 973 | choice.append(close_link); 974 | } 975 | return this.search_container.before(choice); 976 | }; 977 | 978 | Chosen.prototype.choice_destroy_link_click = function(evt) { 979 | evt.preventDefault(); 980 | evt.stopPropagation(); 981 | if (!this.is_disabled) { 982 | return this.choice_destroy($(evt.target)); 983 | } 984 | }; 985 | 986 | Chosen.prototype.choice_destroy = function(link) { 987 | if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) { 988 | this.show_search_field_default(); 989 | if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) { 990 | this.results_hide(); 991 | } 992 | link.parents('li').first().remove(); 993 | return this.search_field_scale(); 994 | } 995 | }; 996 | 997 | Chosen.prototype.results_reset = function() { 998 | this.reset_single_select_options(); 999 | this.form_field.options[0].selected = true; 1000 | this.single_set_selected_text(); 1001 | this.show_search_field_default(); 1002 | this.results_reset_cleanup(); 1003 | this.form_field_jq.trigger("change"); 1004 | if (this.active_field) { 1005 | return this.results_hide(); 1006 | } 1007 | }; 1008 | 1009 | Chosen.prototype.results_reset_cleanup = function() { 1010 | this.current_selectedIndex = this.form_field.selectedIndex; 1011 | return this.selected_item.find("abbr").remove(); 1012 | }; 1013 | 1014 | Chosen.prototype.result_select = function(evt) { 1015 | var high, item; 1016 | if (this.result_highlight) { 1017 | high = this.result_highlight; 1018 | this.result_clear_highlight(); 1019 | if (this.is_multiple && this.max_selected_options <= this.choices_count()) { 1020 | this.form_field_jq.trigger("chosen:maxselected", { 1021 | chosen: this 1022 | }); 1023 | return false; 1024 | } 1025 | if (this.is_multiple) { 1026 | high.removeClass("active-result"); 1027 | } else { 1028 | this.reset_single_select_options(); 1029 | } 1030 | item = this.results_data[high[0].getAttribute("data-option-array-index")]; 1031 | item.selected = true; 1032 | this.form_field.options[item.options_index].selected = true; 1033 | this.selected_option_count = null; 1034 | if (this.is_multiple) { 1035 | this.choice_build(item); 1036 | } else { 1037 | this.single_set_selected_text(item.text); 1038 | } 1039 | if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) { 1040 | this.results_hide(); 1041 | } 1042 | this.search_field.val(""); 1043 | if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) { 1044 | this.form_field_jq.trigger("change", { 1045 | 'selected': this.form_field.options[item.options_index].value 1046 | }); 1047 | } 1048 | this.current_selectedIndex = this.form_field.selectedIndex; 1049 | return this.search_field_scale(); 1050 | } 1051 | }; 1052 | 1053 | Chosen.prototype.single_set_selected_text = function(text) { 1054 | if (text == null) { 1055 | text = this.default_text; 1056 | } 1057 | if (text === this.default_text) { 1058 | this.selected_item.addClass("chosen-default"); 1059 | } else { 1060 | this.single_deselect_control_build(); 1061 | this.selected_item.removeClass("chosen-default"); 1062 | } 1063 | return this.selected_item.find("span").text(text); 1064 | }; 1065 | 1066 | Chosen.prototype.result_deselect = function(pos) { 1067 | var result_data; 1068 | result_data = this.results_data[pos]; 1069 | if (!this.form_field.options[result_data.options_index].disabled) { 1070 | result_data.selected = false; 1071 | this.form_field.options[result_data.options_index].selected = false; 1072 | this.selected_option_count = null; 1073 | this.result_clear_highlight(); 1074 | if (this.results_showing) { 1075 | this.winnow_results(); 1076 | } 1077 | this.form_field_jq.trigger("change", { 1078 | deselected: this.form_field.options[result_data.options_index].value 1079 | }); 1080 | this.search_field_scale(); 1081 | return true; 1082 | } else { 1083 | return false; 1084 | } 1085 | }; 1086 | 1087 | Chosen.prototype.single_deselect_control_build = function() { 1088 | if (!this.allow_single_deselect) { 1089 | return; 1090 | } 1091 | if (!this.selected_item.find("abbr").length) { 1092 | this.selected_item.find("span").first().after(""); 1093 | } 1094 | return this.selected_item.addClass("chosen-single-with-deselect"); 1095 | }; 1096 | 1097 | Chosen.prototype.get_search_text = function() { 1098 | if (this.search_field.val() === this.default_text) { 1099 | return ""; 1100 | } else { 1101 | return $('
      ').text($.trim(this.search_field.val())).html(); 1102 | } 1103 | }; 1104 | 1105 | Chosen.prototype.winnow_results_set_highlight = function() { 1106 | var do_high, selected_results; 1107 | selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; 1108 | do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); 1109 | if (do_high != null) { 1110 | return this.result_do_highlight(do_high); 1111 | } 1112 | }; 1113 | 1114 | Chosen.prototype.no_results = function(terms) { 1115 | var no_results_html; 1116 | no_results_html = $('
    • ' + this.results_none_found + ' ""
    • '); 1117 | no_results_html.find("span").first().html(terms); 1118 | this.search_results.append(no_results_html); 1119 | return this.form_field_jq.trigger("chosen:no_results", { 1120 | chosen: this 1121 | }); 1122 | }; 1123 | 1124 | Chosen.prototype.no_results_clear = function() { 1125 | return this.search_results.find(".no-results").remove(); 1126 | }; 1127 | 1128 | Chosen.prototype.keydown_arrow = function() { 1129 | var next_sib; 1130 | if (this.results_showing && this.result_highlight) { 1131 | next_sib = this.result_highlight.nextAll("li.active-result").first(); 1132 | if (next_sib) { 1133 | return this.result_do_highlight(next_sib); 1134 | } 1135 | } else { 1136 | return this.results_show(); 1137 | } 1138 | }; 1139 | 1140 | Chosen.prototype.keyup_arrow = function() { 1141 | var prev_sibs; 1142 | if (!this.results_showing && !this.is_multiple) { 1143 | return this.results_show(); 1144 | } else if (this.result_highlight) { 1145 | prev_sibs = this.result_highlight.prevAll("li.active-result"); 1146 | if (prev_sibs.length) { 1147 | return this.result_do_highlight(prev_sibs.first()); 1148 | } else { 1149 | if (this.choices_count() > 0) { 1150 | this.results_hide(); 1151 | } 1152 | return this.result_clear_highlight(); 1153 | } 1154 | } 1155 | }; 1156 | 1157 | Chosen.prototype.keydown_backstroke = function() { 1158 | var next_available_destroy; 1159 | if (this.pending_backstroke) { 1160 | this.choice_destroy(this.pending_backstroke.find("a").first()); 1161 | return this.clear_backstroke(); 1162 | } else { 1163 | next_available_destroy = this.search_container.siblings("li.search-choice").last(); 1164 | if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) { 1165 | this.pending_backstroke = next_available_destroy; 1166 | if (this.single_backstroke_delete) { 1167 | return this.keydown_backstroke(); 1168 | } else { 1169 | return this.pending_backstroke.addClass("search-choice-focus"); 1170 | } 1171 | } 1172 | } 1173 | }; 1174 | 1175 | Chosen.prototype.clear_backstroke = function() { 1176 | if (this.pending_backstroke) { 1177 | this.pending_backstroke.removeClass("search-choice-focus"); 1178 | } 1179 | return this.pending_backstroke = null; 1180 | }; 1181 | 1182 | Chosen.prototype.keydown_checker = function(evt) { 1183 | var stroke, _ref1; 1184 | stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode; 1185 | this.search_field_scale(); 1186 | if (stroke !== 8 && this.pending_backstroke) { 1187 | this.clear_backstroke(); 1188 | } 1189 | switch (stroke) { 1190 | case 8: 1191 | this.backstroke_length = this.search_field.val().length; 1192 | break; 1193 | case 9: 1194 | if (this.results_showing && !this.is_multiple) { 1195 | this.result_select(evt); 1196 | } 1197 | this.mouse_on_container = false; 1198 | break; 1199 | case 13: 1200 | if (this.results_showing) { 1201 | evt.preventDefault(); 1202 | } 1203 | break; 1204 | case 32: 1205 | if (this.disable_search) { 1206 | evt.preventDefault(); 1207 | } 1208 | break; 1209 | case 38: 1210 | evt.preventDefault(); 1211 | this.keyup_arrow(); 1212 | break; 1213 | case 40: 1214 | evt.preventDefault(); 1215 | this.keydown_arrow(); 1216 | break; 1217 | } 1218 | }; 1219 | 1220 | Chosen.prototype.search_field_scale = function() { 1221 | var div, f_width, h, style, style_block, styles, w, _i, _len; 1222 | if (this.is_multiple) { 1223 | h = 0; 1224 | w = 0; 1225 | style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"; 1226 | styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing']; 1227 | for (_i = 0, _len = styles.length; _i < _len; _i++) { 1228 | style = styles[_i]; 1229 | style_block += style + ":" + this.search_field.css(style) + ";"; 1230 | } 1231 | div = $('
      ', { 1232 | 'style': style_block 1233 | }); 1234 | div.text(this.search_field.val()); 1235 | $('body').append(div); 1236 | w = div.width() + 25; 1237 | div.remove(); 1238 | f_width = this.container.outerWidth(); 1239 | if (w > f_width - 10) { 1240 | w = f_width - 10; 1241 | } 1242 | return this.search_field.css({ 1243 | 'width': w + 'px' 1244 | }); 1245 | } 1246 | }; 1247 | 1248 | return Chosen; 1249 | 1250 | })(AbstractChosen); 1251 | 1252 | }).call(this); 1253 | --------------------------------------------------------------------------------