├── .gitignore ├── .rspec ├── .travis.yml ├── CONTRIBUTORS.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Makefile ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ ├── error.png │ │ ├── gravatar.png │ │ ├── jscolor │ │ │ ├── arrow.gif │ │ │ ├── cross.gif │ │ │ ├── hs.png │ │ │ └── hv.png │ │ ├── options.png │ │ ├── rails.png │ │ ├── shit.png │ │ ├── success.png │ │ └── trophy.png │ ├── javascripts │ │ ├── application.js │ │ ├── board.js │ │ ├── bootstrap-alerts.js │ │ ├── bootstrap-dropdown.js │ │ ├── bootstrap-modal.js │ │ ├── jquery.tokeninput.js │ │ └── jscolor │ │ │ └── jscolor.js │ └── stylesheets │ │ ├── .gitkeep │ │ ├── application.css │ │ ├── bootstrap.min.css │ │ └── token-input-facebook.css ├── controllers │ ├── application_controller.rb │ ├── boards_controller.rb │ ├── categories_controller.rb │ ├── comments_controller.rb │ ├── contributors_controller.rb │ ├── projects_controller.rb │ └── tasks_controller.rb ├── helpers │ ├── application_helper.rb │ └── boards_helper.rb ├── models │ ├── board.rb │ ├── category.rb │ ├── comment.rb │ ├── contributor.rb │ ├── project.rb │ └── task.rb └── views │ ├── boards │ └── show.html.slim │ ├── categories │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ └── new.html.slim │ ├── comments │ ├── _form.html.slim │ ├── _list.html.slim │ └── edit.html.slim │ ├── contributors │ └── dashboard.html.slim │ ├── devise │ ├── confirmations │ │ └── new.html.slim │ ├── mailer │ │ ├── confirmation_instructions.html.slim │ │ ├── reset_password_instructions.html.slim │ │ └── unlock_instructions.html.slim │ ├── passwords │ │ ├── edit.html.slim │ │ └── new.html.slim │ ├── registrations │ │ ├── edit.html.slim │ │ └── new.html.slim │ ├── sessions │ │ └── new.html.slim │ └── shared │ │ └── _links.slim │ ├── layouts │ └── application.html.erb │ ├── projects │ ├── _form.html.slim │ ├── edit.html.slim │ └── new.html.slim │ └── tasks │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim ├── autotest └── discover.rb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cucumber.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── devise.rb │ ├── escape_rack.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── secret_token.rb │ ├── session_store.rb │ └── simple_form.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml └── routes.rb ├── db ├── migrate │ ├── 20100921004233_create_projects.rb │ ├── 20100921012401_create_contributors.rb │ ├── 20100925143455_contributors_tasks.rb │ ├── 20101031223531_create_tasks.rb │ ├── 20110106023051_create_comments.rb │ ├── 20110128222606_create_categories.rb │ ├── 20110421121043_contributors_projects.rb │ └── 20110821185450_add_author_id_to_task.rb └── seeds.rb ├── direction.md ├── doc └── README_FOR_APP ├── features ├── board.feature ├── comments.feature ├── step_definitions │ ├── board_steps.rb │ ├── categories_steps.rb │ ├── comments_steps.rb │ ├── contributor_steps.rb │ ├── my_web_steps.rb │ ├── project_steps.rb │ ├── task_steps.rb │ └── web_steps.rb ├── support │ ├── env.rb │ ├── paths.rb │ └── selectors.rb └── tasks.feature ├── heroku-deploy.sh ├── lib ├── albino_render.rb ├── tasks │ └── .gitkeep └── templates │ └── slim │ └── scaffold │ └── _form.html.slim ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── script ├── cucumber └── rails ├── spec ├── acceptance │ ├── authentication_spec.rb │ ├── category_spec.rb │ ├── comments_spec.rb │ ├── contributors_spec.rb │ └── projects_spec.rb ├── controllers │ └── tasks_controller_spec.rb ├── factories │ ├── categories.rb │ ├── comments.rb │ ├── contributors.rb │ ├── projects.rb │ └── tasks.rb ├── helpers │ └── boards_helper_spec.rb ├── lib │ └── albino_render_spec.rb ├── models │ ├── category_spec.rb │ ├── comment_spec.rb │ ├── contributor_spec.rb │ ├── project_spec.rb │ └── task_spec.rb ├── routing │ ├── board_routing_spec.rb │ ├── categories_routing_spec.rb │ ├── comments_routing_spec.rb │ ├── contributors_routing_spec.rb │ ├── projects_routing_spec.rb │ └── tasks_routing_spec.rb └── spec_helper.rb └── vendor └── plugins └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | .rvmrc 3 | db/schema.rb 4 | db/*.sqlite3* 5 | log/*.log 6 | tmp/**/* 7 | Capfile 8 | config/deploy.rb 9 | .sass-cache/ -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | --format nested 3 | --drb 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | bundler_args: --binstubs 2 | 3 | rvm: 4 | - 1.9.2 5 | 6 | env: "RAILS_ENV='test'" 7 | 8 | script: "bundle exec rake travis" 9 | 10 | notifications: 11 | recipients: 12 | - hugomaiavieira@gmail.com 13 | 14 | branches: 15 | only: 16 | - master 17 | 18 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | 4 | * Hugo Maia Vieira 5 | * Rodrigo Manhães 6 | * Eduardo Hertz 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'rails', '3.2.1' 4 | gem 'mysql2', '~>0.3' 5 | 6 | gem 'slim', '~>1.0' 7 | gem 'simple_form', '~>1.5' 8 | gem 'inherited_resources', '~>1.2' 9 | gem 'escape_utils', '~>0.2' 10 | gem 'devise', '~>2.0' 11 | gem 'redcarpet', '~>2.1' # Markdown 12 | gem 'albino', '~>1.3' # Markdown syntax highlighting 13 | gem 'nokogiri', '~>1.5' # Parse the html for markdown syntax highlighting 14 | gem 'jquery-rails', '~>2.0' 15 | gem 'ruby-json', '~>1.1' 16 | 17 | group :assets do 18 | gem 'therubyracer' # JavaScript runtime. uglifier dependence 19 | gem 'uglifier' 20 | end 21 | 22 | group :development, :test do 23 | gem 'sqlite3-ruby' 24 | gem 'factory_girl_rails', '~>1.1' 25 | gem 'rspec', '~>2.6' 26 | gem 'rspec-rails', '~>2.6' 27 | gem 'valid_attribute', '~>1.1' 28 | gem 'capybara', '~>1.0' 29 | gem 'launchy', '>=2.0' # save_and_open_page 30 | gem 'cucumber-rails', '~>1.0', :require => false 31 | gem 'database_cleaner', '~>0.6' 32 | 33 | # Just a faster web server 34 | gem 'thin' 35 | # Speedy test iterations 36 | gem 'spork', '~> 0.9.0.rc' # See: http://www.rubyinside.com/how-to-rails-3-and-rspec-2-4336.html 37 | end 38 | 39 | group :development do 40 | gem 'rails3-generators' 41 | gem 'pry' 42 | gem 'pry-doc' 43 | end -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.1) 5 | actionpack (= 3.2.1) 6 | mail (~> 2.4.0) 7 | actionpack (3.2.1) 8 | activemodel (= 3.2.1) 9 | activesupport (= 3.2.1) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.1) 13 | rack (~> 1.4.0) 14 | rack-cache (~> 1.1) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.1.2) 17 | activemodel (3.2.1) 18 | activesupport (= 3.2.1) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.1) 21 | activemodel (= 3.2.1) 22 | activesupport (= 3.2.1) 23 | arel (~> 3.0.0) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.1) 26 | activemodel (= 3.2.1) 27 | activesupport (= 3.2.1) 28 | activesupport (3.2.1) 29 | i18n (~> 0.6) 30 | multi_json (~> 1.0) 31 | addressable (2.2.7) 32 | albino (1.3.3) 33 | posix-spawn (>= 0.3.6) 34 | arel (3.0.0) 35 | bcrypt-ruby (3.0.1) 36 | builder (3.0.0) 37 | capybara (1.1.2) 38 | mime-types (>= 1.16) 39 | nokogiri (>= 1.3.3) 40 | rack (>= 1.0.0) 41 | rack-test (>= 0.5.4) 42 | selenium-webdriver (~> 2.0) 43 | xpath (~> 0.1.4) 44 | childprocess (0.3.1) 45 | ffi (~> 1.0.6) 46 | coderay (1.0.5) 47 | cucumber (1.1.4) 48 | builder (>= 2.1.2) 49 | diff-lcs (>= 1.1.2) 50 | gherkin (~> 2.7.1) 51 | json (>= 1.4.6) 52 | term-ansicolor (>= 1.0.6) 53 | cucumber-rails (1.2.1) 54 | capybara (>= 1.1.2) 55 | cucumber (>= 1.1.3) 56 | nokogiri (>= 1.5.0) 57 | daemons (1.1.8) 58 | database_cleaner (0.7.1) 59 | devise (2.0.4) 60 | bcrypt-ruby (~> 3.0) 61 | orm_adapter (~> 0.0.3) 62 | railties (~> 3.1) 63 | warden (~> 1.1.1) 64 | diff-lcs (1.1.3) 65 | erubis (2.7.0) 66 | escape_utils (0.2.4) 67 | eventmachine (0.12.10) 68 | execjs (1.3.0) 69 | multi_json (~> 1.0) 70 | factory_girl (2.6.0) 71 | activesupport (>= 2.3.9) 72 | factory_girl_rails (1.7.0) 73 | factory_girl (~> 2.6.0) 74 | railties (>= 3.0.0) 75 | ffi (1.0.11) 76 | gherkin (2.7.7) 77 | json (>= 1.4.6) 78 | has_scope (0.5.1) 79 | hike (1.2.1) 80 | i18n (0.6.0) 81 | inherited_resources (1.3.0) 82 | has_scope (~> 0.5.0) 83 | responders (~> 0.6.0) 84 | journey (1.0.1) 85 | jquery-rails (2.0.0) 86 | railties (>= 3.2.0.beta, < 5.0) 87 | thor (~> 0.14) 88 | json (1.6.5) 89 | launchy (2.0.5) 90 | addressable (~> 2.2.6) 91 | libv8 (3.3.10.4) 92 | mail (2.4.1) 93 | i18n (>= 0.4.0) 94 | mime-types (~> 1.16) 95 | treetop (~> 1.4.8) 96 | method_source (0.7.0) 97 | mime-types (1.17.2) 98 | multi_json (1.0.4) 99 | mysql2 (0.3.11) 100 | nokogiri (1.5.0) 101 | orm_adapter (0.0.6) 102 | polyglot (0.3.3) 103 | posix-spawn (0.3.6) 104 | pry (0.9.8.2) 105 | coderay (~> 1.0.5) 106 | method_source (~> 0.7) 107 | slop (>= 2.4.4, < 3) 108 | pry-doc (0.4.0) 109 | pry (>= 0.9.0) 110 | yard (~> 0.7.4) 111 | rack (1.4.1) 112 | rack-cache (1.1) 113 | rack (>= 0.4) 114 | rack-ssl (1.3.2) 115 | rack 116 | rack-test (0.6.1) 117 | rack (>= 1.0) 118 | rails (3.2.1) 119 | actionmailer (= 3.2.1) 120 | actionpack (= 3.2.1) 121 | activerecord (= 3.2.1) 122 | activeresource (= 3.2.1) 123 | activesupport (= 3.2.1) 124 | bundler (~> 1.0) 125 | railties (= 3.2.1) 126 | rails3-generators (0.17.4) 127 | railties (>= 3.0.0) 128 | railties (3.2.1) 129 | actionpack (= 3.2.1) 130 | activesupport (= 3.2.1) 131 | rack-ssl (~> 1.3.2) 132 | rake (>= 0.8.7) 133 | rdoc (~> 3.4) 134 | thor (~> 0.14.6) 135 | rake (0.9.2.2) 136 | rdoc (3.12) 137 | json (~> 1.4) 138 | redcarpet (2.1.0) 139 | responders (0.6.5) 140 | rspec (2.8.0) 141 | rspec-core (~> 2.8.0) 142 | rspec-expectations (~> 2.8.0) 143 | rspec-mocks (~> 2.8.0) 144 | rspec-core (2.8.0) 145 | rspec-expectations (2.8.0) 146 | diff-lcs (~> 1.1.2) 147 | rspec-mocks (2.8.0) 148 | rspec-rails (2.8.1) 149 | actionpack (>= 3.0) 150 | activesupport (>= 3.0) 151 | railties (>= 3.0) 152 | rspec (~> 2.8.0) 153 | ruby-json (1.1.2) 154 | rubyzip (0.9.6.1) 155 | selenium-webdriver (2.19.0) 156 | childprocess (>= 0.2.5) 157 | ffi (~> 1.0.9) 158 | multi_json (~> 1.0.4) 159 | rubyzip 160 | simple_form (1.5.2) 161 | actionpack (~> 3.0) 162 | activemodel (~> 3.0) 163 | slim (1.1.0) 164 | temple (~> 0.3.5) 165 | tilt (~> 1.3.2) 166 | slop (2.4.4) 167 | spork (0.9.0) 168 | sprockets (2.1.2) 169 | hike (~> 1.2) 170 | rack (~> 1.0) 171 | tilt (~> 1.1, != 1.3.0) 172 | sqlite3 (1.3.5) 173 | sqlite3-ruby (1.3.3) 174 | sqlite3 (>= 1.3.3) 175 | temple (0.3.5) 176 | term-ansicolor (1.0.7) 177 | therubyracer (0.9.9) 178 | libv8 (~> 3.3.10) 179 | thin (1.3.1) 180 | daemons (>= 1.0.9) 181 | eventmachine (>= 0.12.6) 182 | rack (>= 1.0.0) 183 | thor (0.14.6) 184 | tilt (1.3.3) 185 | treetop (1.4.10) 186 | polyglot 187 | polyglot (>= 0.3.1) 188 | tzinfo (0.3.31) 189 | uglifier (1.2.3) 190 | execjs (>= 0.3.0) 191 | multi_json (>= 1.0.2) 192 | valid_attribute (1.2.0) 193 | warden (1.1.1) 194 | rack (>= 1.0) 195 | xpath (0.1.4) 196 | nokogiri (~> 1.3) 197 | yard (0.7.5) 198 | 199 | PLATFORMS 200 | ruby 201 | 202 | DEPENDENCIES 203 | albino (~> 1.3) 204 | capybara (~> 1.0) 205 | cucumber-rails (~> 1.0) 206 | database_cleaner (~> 0.6) 207 | devise (~> 2.0) 208 | escape_utils (~> 0.2) 209 | factory_girl_rails (~> 1.1) 210 | inherited_resources (~> 1.2) 211 | jquery-rails (~> 2.0) 212 | launchy (>= 2.0) 213 | mysql2 (~> 0.3) 214 | nokogiri (~> 1.5) 215 | pry 216 | pry-doc 217 | rails (= 3.2.1) 218 | rails3-generators 219 | redcarpet (~> 2.1) 220 | rspec (~> 2.6) 221 | rspec-rails (~> 2.6) 222 | ruby-json (~> 1.1) 223 | simple_form (~> 1.5) 224 | slim (~> 1.0) 225 | spork (~> 0.9.0.rc) 226 | sqlite3-ruby 227 | therubyracer 228 | thin 229 | uglifier 230 | valid_attribute (~> 1.1) 231 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU General Public License 2 | 3 | Copyright (c) 2011 Hugo Henriques Maia Vieira 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: rspec cucumber 2 | 3 | database: 4 | @echo "reset the database" 5 | @rake db:drop:all 6 | @rake db:create:all 7 | @rake db:migrate 8 | @rake db:test:clone 9 | @rake db:seed 10 | 11 | rspec: 12 | @echo "run rspec specs" 13 | @bundle exec rspec spec --drb --format progress 14 | 15 | cucumber: 16 | @echo "run cucumber specs" 17 | @bundle exec cucumber features --drb 18 | 19 | cucumber-nojs: 20 | @echo "run cucumber specs without javascript" 21 | @bundle exec cucumber features --drb --tag ~@javascript 22 | 23 | cucumber-js: 24 | @echo "run cucumber specs with javascript" 25 | @bundle exec cucumber features --drb --tag @javascript 26 | 27 | spork: 28 | @echo "start spork" 29 | @bundle exec spork cucumber & bundle exec spork 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kanban roots [![Build Status](https://secure.travis-ci.org/hugomaiavieira/kanban-roots.png)](http://travis-ci.org/hugomaiavieira/kanban-roots) [![Dependency Status](https://gemnasium.com/hugomaiavieira/kanban-roots.png)](https://gemnasium.com/hugomaiavieira/kanban-roots) 2 | 3 | A kanban board that keep the simplicity as well as the roots of the concept. 4 | 5 | ## Example 6 | 7 | [http://kanban-roots.heroku.com](http://kanban-roots.heroku.com) 8 | 9 | **Obs.:** the database of this example is regularly cleaned up. 10 | 11 | ![kanban-roots board print](http://github.com/downloads/hugomaiavieira/kanban-roots/kanban-roots.png "kanban-roots board print") 12 | 13 | ## System dependencies 14 | 15 | ### pygments 16 | 17 | The [pygments](http://pygments.org/) is a python package used on 18 | [markdown](http://daringfireball.net/projects/markdown/) syntax 19 | highlighting. To install it, just run: 20 | 21 | $ (sudo) easy_install pygments 22 | 23 | 24 | ## Using on Heroku 25 | 26 | If you don't know [heroku](http://heroku.com) yet, just follow the 27 | [Geting Started with Heroku](http://docs.heroku.com/quickstart) guide with one 28 | difference: instead of use `git push heroku master`, you will use the script 29 | _heroku-deploy.sh_. 30 | 31 | I [add a hack](https://github.com/hugomaiavieira/kanban-roots/commit/e008af61bdcce90f5ff0eb0e2edd359ac206f53c) 32 | for pygments work on Heroku, based on [this post](http://matthewboston.com/posts/3) 33 | from [Matthew Boston](https://github.com/bostonaholic) blog. So, don't worry 34 | about that. 35 | 36 | That's it! Simple like that =) 37 | 38 | ## License 39 | 40 | Copyright (c) 2011 Hugo Henriques Maia Vieira 41 | 42 | This program is free software: you can redistribute it and/or modify 43 | it under the terms of the GNU General Public License as published by 44 | the Free Software Foundation, either version 3 of the License, or 45 | (at your option) any later version. 46 | 47 | This program is distributed in the hope that it will be useful, 48 | but WITHOUT ANY WARRANTY; without even the implied warranty of 49 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 50 | GNU General Public License for more details. 51 | 52 | You should have received a copy of the GNU General Public License 53 | along with this program. If not, see . 54 | 55 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | require 'rake' 6 | require 'rake/dsl_definition' # http://migre.me/5nonc 7 | 8 | KanbanRoots::Application.load_tasks 9 | 10 | desc 'run all specs in travis-ci mode' 11 | task :travis => ['travis:database', 'travis:specs'] 12 | 13 | namespace :travis do 14 | desc 'run rspec and cucumber specs' 15 | task :specs => ['rspec', 'cucumber:nojavascript'] 16 | 17 | desc 'run rspec specs' 18 | task :rspec do 19 | sh 'sed -i s/--drb/#--drb/ .rspec' 20 | sh 'rspec spec --format progress' 21 | sh 'sed -i s/#--drb/--drb/ .rspec' 22 | end 23 | 24 | desc 'run cucumber specs' 25 | namespace :cucumber do 26 | desc 'without javascript' 27 | task :nojavascript do 28 | sh 'cucumber features --tag ~@javascript --format progress' 29 | end 30 | 31 | desc 'with javascript' 32 | task :javascript do 33 | sh 'cucumber features --tag @javascript --format progress' 34 | end 35 | 36 | desc 'run all specs, with and without javascript' 37 | task :all do 38 | sh 'cucumber features --format progress' 39 | end 40 | end 41 | 42 | desc 'reset the database' 43 | task :database => ['db:drop', 'db:create', 'db:migrate'] 44 | end 45 | 46 | -------------------------------------------------------------------------------- /app/assets/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/error.png -------------------------------------------------------------------------------- /app/assets/images/gravatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/gravatar.png -------------------------------------------------------------------------------- /app/assets/images/jscolor/arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/jscolor/arrow.gif -------------------------------------------------------------------------------- /app/assets/images/jscolor/cross.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/jscolor/cross.gif -------------------------------------------------------------------------------- /app/assets/images/jscolor/hs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/jscolor/hs.png -------------------------------------------------------------------------------- /app/assets/images/jscolor/hv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/jscolor/hv.png -------------------------------------------------------------------------------- /app/assets/images/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/options.png -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/images/shit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/shit.png -------------------------------------------------------------------------------- /app/assets/images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/success.png -------------------------------------------------------------------------------- /app/assets/images/trophy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hugomaiavieira/kanban-roots/8115084ef5778868cf911fbac154958e4af5cc63/app/assets/images/trophy.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery-ui 3 | //= require jquery_ujs 4 | //= require jscolor/jscolor 5 | //= require_self 6 | //= require_tree . 7 | 8 | $(function() { 9 | $('#project_contributor_tokens').tokenInput('/contributors.json', { 10 | prePopulate: $('project_contributor_tokens').data('pre'), 11 | preventDuplicates: true, 12 | hintText: 'Type in a contributor name or username', 13 | noResultsText: 'No contributors', 14 | theme: 'facebook' 15 | }); 16 | }); 17 | 18 | -------------------------------------------------------------------------------- /app/assets/javascripts/board.js: -------------------------------------------------------------------------------- 1 | function sort_score_list() { 2 | var ordered_list = $('#score_list').children().sort(function(a,b){ 3 | var first_value = parseInt(a.children[0].innerText), 4 | second_value = parseInt(b.children[0].innerText); 5 | if (first_value != second_value) { 6 | return first_value > second_value ? 1 : -1; 7 | } else { 8 | return a.innerText > b.innerText ? 1 : -1; 9 | } 10 | }); 11 | $('#score_list').html(ordered_list); 12 | } 13 | 14 | function update_score_points(contributors, score) { 15 | $.each(contributors, function(index, id) { 16 | contributor = $('#contributor_'.concat(id)); 17 | contributor_points = parseFloat(contributor.text()); 18 | contributor.text((contributor_points + score).toFixed(1)); 19 | // sort of the scores list (first by value asc, then alphabetically asc) 20 | sort_score_list(); 21 | }); 22 | } 23 | 24 | $(function() { 25 | var $todo = $('#todo'), 26 | $doing = $('#doing'), 27 | $done = $('#done'), 28 | $backlog = $('#backlog'), 29 | // the divisions should accept post-its from all divisions, except from itself 30 | $accepted_by = { 31 | todo: '#doing > li, #done > li, #backlog > li', 32 | doing: '#todo > li, #done > li, #backlog > li', 33 | done: '#todo > li, #doing > li, #backlog > li', 34 | backlog: '#todo > li, #doing > li, #done > li' 35 | } 36 | 37 | // let the post-its be draggable 38 | $('.postit').draggable({ 39 | cursor: 'move', 40 | helper: 'clone', 41 | revert: 'invalid' 42 | }); 43 | 44 | // let the divisions be droppable, accepting the post-its from others divisions 45 | $('.droppable').each(function(key, value){ 46 | $(value).droppable({ 47 | accept: $accepted_by[value.id], 48 | hoverClass: 'ui-state-hover', 49 | drop: function(event, ui) { 50 | movePostit(ui.draggable, $(value)); 51 | defineHeight(); 52 | } 53 | }); 54 | }); 55 | }); 56 | 57 | // slide points select 58 | $(function() { 59 | $(".show_points").click(function () { 60 | var task = $(this).parents('li'), 61 | select = task.find('.points_select'); 62 | select.fadeToggle("fast"); 63 | }); 64 | }); 65 | 66 | // change task points and slide back the select 67 | $(function() { 68 | $('.points_select').change(function () { 69 | var show_points = $(this).siblings('.show_points'), 70 | division_id = show_points.closest('ul').attr('id'), 71 | task = $(this).parents('li'), 72 | task_id = task.attr('id'), 73 | points = $(this).children(':selected').attr('value'); 74 | if (points != show_points.text()) { 75 | $.ajax({ 76 | type: "PUT", 77 | url: "/board/update_points", 78 | data: ({ task_id: task_id, points: points, division_id: division_id }), 79 | dataType: 'json', 80 | success: function(data) { 81 | var division_points = data.division_points; 82 | // update task points 83 | show_points.text(points); 84 | // update board division points 85 | show_points.closest('.division').find('span[id*=_points]').text(division_points); 86 | // update score points 87 | update_score_points(data.contributors, data.score); 88 | } 89 | }); 90 | } 91 | $(this).fadeToggle("fast"); 92 | }); 93 | }); 94 | 95 | // slide assignees form 96 | $(function() { 97 | $(".show_assignees").click(function () { 98 | var task = $(this).parents('li'), 99 | form = task.find('.assignees_form'); 100 | form.fadeToggle("fast"); 101 | }); 102 | }); 103 | 104 | // slide postit options 105 | $(function() { 106 | $(".postit_options").click(function () { 107 | var task = $(this).parents('li'), 108 | form = task.find('.postit_options_list'); 109 | form.fadeToggle("fast"); 110 | }); 111 | }); 112 | 113 | // TODO: Update the points in the board divisions and score 114 | // change task assignees and slide back the assignees form 115 | $(function() { 116 | $(".assignees_form > input").click(function () { 117 | var form = $(this).parents('.assignees_form'), 118 | show_assignees = form.siblings('.show_assignees'); 119 | task = form.parents('li'), 120 | task_id = task.attr('id'), 121 | assignees = []; 122 | form.find('option:selected').each(function() { 123 | assignees.push($(this).attr('value')) 124 | }); 125 | $.ajax({ 126 | type: "PUT", 127 | url: "/board/update_assignees", 128 | data: ({ task_id: task_id, assignees: assignees }), 129 | dataType: 'json', 130 | success: function(data) { 131 | if (data.long_sentence == true) { 132 | show_assignees.attr('title', data.assignees_long_sentence); 133 | } 134 | else { 135 | show_assignees.removeClass('help_cursor'); 136 | show_assignees.removeAttr('title'); 137 | } 138 | show_assignees.text(data.assignees_sentence); 139 | } 140 | }); 141 | form.fadeToggle("fast"); 142 | }); 143 | }); 144 | 145 | // move the post-its between the board divisions 146 | function movePostit (postit, ul) { 147 | var task_id = postit.attr('id'), 148 | new_position = ul.attr('id') 149 | 150 | postit.appendTo(ul); 151 | 152 | $.ajax({ 153 | type: "PUT", 154 | url: "/board/update_position", 155 | data: ({ new_position: new_position, task_id: task_id }), 156 | dataType: 'json', 157 | success: function updateBoard(data) { 158 | // update divisions points 159 | old_division = $('#'.concat(data.old_position, '_points')); 160 | new_division = $('#'.concat(new_position, '_points')); 161 | old_division_points = parseInt(old_division.text()); 162 | new_division_points = parseInt(new_division.text()); 163 | new_division.text(new_division_points + data.task_points); 164 | old_division.text(old_division_points - data.task_points); 165 | // update scores 166 | update_score_points(data.contributors, data.score); 167 | } 168 | }); 169 | } 170 | 171 | function defineHeight() { 172 | var max_line_number = 0, 173 | division_postit_per_line = 2, 174 | backlog_postit_per_line = 6, 175 | postit_height = $('.postit').get(0)? $('.postit').get(0).clientHeight : null, 176 | postit_margin = 14, 177 | // TODO: Make this work 178 | // margin_top + margin_bottom == margin * 2 179 | // postit_margin = $('.postit').css('margin') * 2, 180 | divisions = [$('#todo'), $('#doing'), $('#done')] 181 | 182 | // get the maximum divisions height 183 | $.each(divisions, function(index, division) { 184 | line_number = Math.ceil(division.children().length / division_postit_per_line) 185 | if ( line_number > max_line_number ) { 186 | max_line_number = line_number; 187 | } 188 | }); 189 | 190 | // set the divisions height as the maximum height 191 | $.each(divisions, function(index, division) { 192 | division.css('height', function(index, value) { 193 | return max_line_number * ( postit_height + postit_margin ); 194 | }); 195 | }); 196 | 197 | // set the backlog height 198 | backlog = $('#backlog'); 199 | line_number = Math.ceil(backlog.children().length / backlog_postit_per_line); 200 | backlog.css('height', function(index, value) { 201 | return line_number * ( postit_height + postit_margin ); 202 | }); 203 | } 204 | 205 | // define the divisions and board height on page load 206 | $(function() { 207 | defineHeight(); 208 | }); 209 | 210 | // sort score list on page load 211 | $(function() { 212 | sort_score_list(); 213 | }); 214 | 215 | -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap-alerts.js: -------------------------------------------------------------------------------- 1 | /* ========================================================== 2 | * bootstrap-alerts.js v1.4.0 3 | * http://twitter.github.com/bootstrap/javascript.html#alerts 4 | * ========================================================== 5 | * Copyright 2011 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) 26 | * ======================================================= */ 27 | 28 | var transitionEnd 29 | 30 | $(document).ready(function () { 31 | 32 | $.support.transition = (function () { 33 | var thisBody = document.body || document.documentElement 34 | , thisStyle = thisBody.style 35 | , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined 36 | return support 37 | })() 38 | 39 | // set CSS transition event type 40 | if ( $.support.transition ) { 41 | transitionEnd = "TransitionEnd" 42 | if ( $.browser.webkit ) { 43 | transitionEnd = "webkitTransitionEnd" 44 | } else if ( $.browser.mozilla ) { 45 | transitionEnd = "transitionend" 46 | } else if ( $.browser.opera ) { 47 | transitionEnd = "oTransitionEnd" 48 | } 49 | } 50 | 51 | }) 52 | 53 | /* ALERT CLASS DEFINITION 54 | * ====================== */ 55 | 56 | var Alert = function ( content, options ) { 57 | if (options == 'close') return this.close.call(content) 58 | this.settings = $.extend({}, $.fn.alert.defaults, options) 59 | this.$element = $(content) 60 | .delegate(this.settings.selector, 'click', this.close) 61 | } 62 | 63 | Alert.prototype = { 64 | 65 | close: function (e) { 66 | var $element = $(this) 67 | , className = 'alert-message' 68 | 69 | $element = $element.hasClass(className) ? $element : $element.parent() 70 | 71 | e && e.preventDefault() 72 | $element.removeClass('in') 73 | 74 | function removeElement () { 75 | $element.remove() 76 | } 77 | 78 | $.support.transition && $element.hasClass('fade') ? 79 | $element.bind(transitionEnd, removeElement) : 80 | removeElement() 81 | } 82 | 83 | } 84 | 85 | 86 | /* ALERT PLUGIN DEFINITION 87 | * ======================= */ 88 | 89 | $.fn.alert = function ( options ) { 90 | 91 | if ( options === true ) { 92 | return this.data('alert') 93 | } 94 | 95 | return this.each(function () { 96 | var $this = $(this) 97 | , data 98 | 99 | if ( typeof options == 'string' ) { 100 | 101 | data = $this.data('alert') 102 | 103 | if (typeof data == 'object') { 104 | return data[options].call( $this ) 105 | } 106 | 107 | } 108 | 109 | $(this).data('alert', new Alert( this, options )) 110 | 111 | }) 112 | } 113 | 114 | $.fn.alert.defaults = { 115 | selector: '.close' 116 | } 117 | 118 | $(document).ready(function () { 119 | new Alert($('body'), { 120 | selector: '.alert-message[data-alert] .close' 121 | }) 122 | }) 123 | 124 | }( window.jQuery || window.ender ); -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap-dropdown.js: -------------------------------------------------------------------------------- 1 | /* ============================================================ 2 | * bootstrap-dropdown.js v1.4.0 3 | * http://twitter.github.com/bootstrap/javascript.html#dropdown 4 | * ============================================================ 5 | * Copyright 2011 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* DROPDOWN PLUGIN DEFINITION 26 | * ========================== */ 27 | 28 | $.fn.dropdown = function ( selector ) { 29 | return this.each(function () { 30 | $(this).delegate(selector || d, 'click', function (e) { 31 | var li = $(this).parent('li') 32 | , isActive = li.hasClass('open') 33 | 34 | clearMenus() 35 | !isActive && li.toggleClass('open') 36 | return false 37 | }) 38 | }) 39 | } 40 | 41 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 42 | * =================================== */ 43 | 44 | var d = 'a.menu, .dropdown-toggle' 45 | 46 | function clearMenus() { 47 | $(d).parent('li').removeClass('open') 48 | } 49 | 50 | $(function () { 51 | $('html').bind("click", clearMenus) 52 | $('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' ) 53 | }) 54 | 55 | }( window.jQuery || window.ender ); 56 | -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap-modal.js: -------------------------------------------------------------------------------- 1 | /* ========================================================= 2 | * bootstrap-modal.js v1.4.0 3 | * http://twitter.github.com/bootstrap/javascript.html#modal 4 | * ========================================================= 5 | * Copyright 2011 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================= */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) 26 | * ======================================================= */ 27 | 28 | var transitionEnd 29 | 30 | $(document).ready(function () { 31 | 32 | $.support.transition = (function () { 33 | var thisBody = document.body || document.documentElement 34 | , thisStyle = thisBody.style 35 | , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined 36 | return support 37 | })() 38 | 39 | // set CSS transition event type 40 | if ( $.support.transition ) { 41 | transitionEnd = "TransitionEnd" 42 | if ( $.browser.webkit ) { 43 | transitionEnd = "webkitTransitionEnd" 44 | } else if ( $.browser.mozilla ) { 45 | transitionEnd = "transitionend" 46 | } else if ( $.browser.opera ) { 47 | transitionEnd = "oTransitionEnd" 48 | } 49 | } 50 | 51 | }) 52 | 53 | 54 | /* MODAL PUBLIC CLASS DEFINITION 55 | * ============================= */ 56 | 57 | var Modal = function ( content, options ) { 58 | this.settings = $.extend({}, $.fn.modal.defaults, options) 59 | this.$element = $(content) 60 | .delegate('.close', 'click.modal', $.proxy(this.hide, this)) 61 | 62 | if ( this.settings.show ) { 63 | this.show() 64 | } 65 | 66 | return this 67 | } 68 | 69 | Modal.prototype = { 70 | 71 | toggle: function () { 72 | return this[!this.isShown ? 'show' : 'hide']() 73 | } 74 | 75 | , show: function () { 76 | var that = this 77 | this.isShown = true 78 | this.$element.trigger('show') 79 | 80 | escape.call(this) 81 | backdrop.call(this, function () { 82 | var transition = $.support.transition && that.$element.hasClass('fade') 83 | 84 | that.$element 85 | .appendTo(document.body) 86 | .show() 87 | 88 | if (transition) { 89 | that.$element[0].offsetWidth // force reflow 90 | } 91 | 92 | that.$element.addClass('in') 93 | 94 | transition ? 95 | that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) : 96 | that.$element.trigger('shown') 97 | 98 | }) 99 | 100 | return this 101 | } 102 | 103 | , hide: function (e) { 104 | e && e.preventDefault() 105 | 106 | if ( !this.isShown ) { 107 | return this 108 | } 109 | 110 | var that = this 111 | this.isShown = false 112 | 113 | escape.call(this) 114 | 115 | this.$element 116 | .trigger('hide') 117 | .removeClass('in') 118 | 119 | $.support.transition && this.$element.hasClass('fade') ? 120 | hideWithTransition.call(this) : 121 | hideModal.call(this) 122 | 123 | return this 124 | } 125 | 126 | } 127 | 128 | 129 | /* MODAL PRIVATE METHODS 130 | * ===================== */ 131 | 132 | function hideWithTransition() { 133 | // firefox drops transitionEnd events :{o 134 | var that = this 135 | , timeout = setTimeout(function () { 136 | that.$element.unbind(transitionEnd) 137 | hideModal.call(that) 138 | }, 500) 139 | 140 | this.$element.one(transitionEnd, function () { 141 | clearTimeout(timeout) 142 | hideModal.call(that) 143 | }) 144 | } 145 | 146 | function hideModal (that) { 147 | this.$element 148 | .hide() 149 | .trigger('hidden') 150 | 151 | backdrop.call(this) 152 | } 153 | 154 | function backdrop ( callback ) { 155 | var that = this 156 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 157 | if ( this.isShown && this.settings.backdrop ) { 158 | var doAnimate = $.support.transition && animate 159 | 160 | this.$backdrop = $('