Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Working state.

  • Loading branch information...
commit b19a4186dca2ea9a8a55c3a5a230ae40995387c3 1 parent 7217284
@jpka authored
Showing with 1,018 additions and 39,129 deletions.
  1. +3 −1 Gemfile
  2. +12 −0 Gemfile.lock
  3. +7 −5 checklist
  4. +1 −1  db/mongod.lock
  5. BIN  db/todo.0
  6. BIN  db/todo.1
  7. BIN  db/todo.ns
  8. +43 −27 features/Authentication.feature
  9. +97 −0 features/TaskHandling.feature
  10. +46 −0 features/step_definitions/authentication_steps.rb
  11. +15 −0 features/step_definitions/db_steps.rb
  12. +19 −0 features/step_definitions/generic_steps.rb
  13. +0 −32 features/step_definitions/steps.rb
  14. +67 −0 features/step_definitions/task_steps.rb
  15. +10 −5 features/support/env.rb
  16. +37 −0 features/support/helpers.rb
  17. +0 −204 frontend/Gruntfile.js
  18. +4 −19 frontend/app/index.html
  19. +1 −1  frontend/app/scripts/app.coffee
  20. +1 −3 frontend/app/scripts/config.coffee
  21. +2 −0  frontend/app/scripts/main.coffee
  22. +9 −2 frontend/app/scripts/modules/baseView.coffee
  23. +21 −10 frontend/app/scripts/modules/login.coffee
  24. +117 −0 frontend/app/scripts/modules/tasks.coffee
  25. +0 −15 frontend/app/scripts/modules/user.coffee
  26. +19 −5 frontend/app/scripts/router.coffee
  27. +0 −104 frontend/app/scripts/vendor/bootstrap/bootstrap-affix.js
  28. +0 −90 frontend/app/scripts/vendor/bootstrap/bootstrap-alert.js
  29. +0 −96 frontend/app/scripts/vendor/bootstrap/bootstrap-button.js
  30. +0 −176 frontend/app/scripts/vendor/bootstrap/bootstrap-carousel.js
  31. +0 −158 frontend/app/scripts/vendor/bootstrap/bootstrap-collapse.js
  32. +0 −150 frontend/app/scripts/vendor/bootstrap/bootstrap-dropdown.js
  33. +0 −239 frontend/app/scripts/vendor/bootstrap/bootstrap-modal.js
  34. +0 −103 frontend/app/scripts/vendor/bootstrap/bootstrap-popover.js
  35. +0 −151 frontend/app/scripts/vendor/bootstrap/bootstrap-scrollspy.js
  36. +0 −135 frontend/app/scripts/vendor/bootstrap/bootstrap-tab.js
  37. +0 −275 frontend/app/scripts/vendor/bootstrap/bootstrap-tooltip.js
  38. +0 −60 frontend/app/scripts/vendor/bootstrap/bootstrap-transition.js
  39. +0 −300 frontend/app/scripts/vendor/bootstrap/bootstrap-typeahead.js
  40. +90 −1 frontend/app/styles/main.scss
  41. +5 −10 frontend/app/templates/login.hamlc
  42. +10 −0 frontend/app/templates/task.hamlc
  43. +39 −0 frontend/app/templates/tasks.hamlc
  44. +0 −33 frontend/test/index.html
  45. +0 −3,590 frontend/test/lib/chai.js
  46. +0 −1,202 frontend/test/lib/expect.js
  47. +0 −199 frontend/test/lib/mocha/mocha.css
  48. +0 −4,675 frontend/test/lib/mocha/mocha.js
  49. +0 −41 frontend/test/runner/mocha.js
  50. +0 −3  frontend/testem.json
  51. +0 −1  php.old/.gitignore
  52. +0 −9 php.old/app/scripts/app.js
  53. +0 −31 php.old/app/scripts/config.js
  54. +0 −20 php.old/app/scripts/main.js
  55. +0 −25 php.old/app/scripts/modules/baseView.js
  56. +0 −20 php.old/app/scripts/modules/login.js
  57. +0 −24 php.old/app/scripts/modules/user.js
  58. +0 −18 php.old/app/scripts/router.js
  59. +0 −35 php.old/assets/23679b17/css/ie.css
  60. +0 −528 php.old/assets/23679b17/css/main.css
  61. +0 −29 php.old/assets/23679b17/css/print.css
  62. +0 −235 php.old/assets/23679b17/css/screen.css
  63. BIN  php.old/assets/23679b17/images/logo.png
  64. BIN  php.old/assets/23679b17/js/fancybox/blank.gif
  65. BIN  php.old/assets/23679b17/js/fancybox/fancy_close.png
  66. BIN  php.old/assets/23679b17/js/fancybox/fancy_loading.png
  67. BIN  php.old/assets/23679b17/js/fancybox/fancy_nav_left.png
  68. BIN  php.old/assets/23679b17/js/fancybox/fancy_nav_right.png
  69. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_e.png
  70. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_n.png
  71. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_ne.png
  72. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_nw.png
  73. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_s.png
  74. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_se.png
  75. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_sw.png
  76. BIN  php.old/assets/23679b17/js/fancybox/fancy_shadow_w.png
  77. BIN  php.old/assets/23679b17/js/fancybox/fancy_title_left.png
  78. BIN  php.old/assets/23679b17/js/fancybox/fancy_title_main.png
  79. BIN  php.old/assets/23679b17/js/fancybox/fancy_title_over.png
  80. BIN  php.old/assets/23679b17/js/fancybox/fancy_title_right.png
  81. BIN  php.old/assets/23679b17/js/fancybox/fancybox-x.png
  82. BIN  php.old/assets/23679b17/js/fancybox/fancybox-y.png
  83. BIN  php.old/assets/23679b17/js/fancybox/fancybox.png
  84. +0 −363 php.old/assets/23679b17/js/fancybox/jquery.fancybox-1.3.1.css
  85. +0 −44 php.old/assets/23679b17/js/fancybox/jquery.fancybox-1.3.1.pack.js
  86. +0 −11 php.old/assets/23679b17/js/jquery.tooltip-1.2.6.min.js
  87. +0 −79 php.old/assets/23679b17/js/main.js
  88. BIN  php.old/assets/c2383dc3/autocomplete/indicator.gif
  89. +0 −48 php.old/assets/c2383dc3/autocomplete/jquery.autocomplete.css
  90. +0 −116 php.old/assets/c2383dc3/jquery.ajaxqueue.js
  91. +0 −813 php.old/assets/c2383dc3/jquery.autocomplete.js
  92. +0 −1,137 php.old/assets/c2383dc3/jquery.ba-bbq.js
  93. +0 −39 php.old/assets/c2383dc3/jquery.bgiframe.js
  94. +0 −92 php.old/assets/c2383dc3/jquery.cookie.js
  95. +0 −1  php.old/assets/c2383dc3/jquery.history.js
  96. +0 −9,404 php.old/assets/c2383dc3/jquery.js
  97. +0 −258 php.old/assets/c2383dc3/jquery.maskedinput.js
  98. +0 −7 php.old/assets/c2383dc3/jquery.maskedinput.min.js
  99. +0 −148 php.old/assets/c2383dc3/jquery.metadata.js
  100. +0 −4 php.old/assets/c2383dc3/jquery.min.js
  101. +0 −536 php.old/assets/c2383dc3/jquery.multifile.js
  102. +0 −381 php.old/assets/c2383dc3/jquery.rating.js
  103. +0 −110 php.old/assets/c2383dc3/jquery.treeview.async.js
  104. +0 −37 php.old/assets/c2383dc3/jquery.treeview.edit.js
  105. +0 −256 php.old/assets/c2383dc3/jquery.treeview.js
  106. +0 −53 php.old/assets/c2383dc3/jquery.yii.js
  107. +0 −427 php.old/assets/c2383dc3/jquery.yiiactiveform.js
  108. +0 −50 php.old/assets/c2383dc3/jquery.yiitab.js
  109. +0 −25 php.old/assets/c2383dc3/jui/MIT-LICENSE.txt
  110. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_flat_0_aaaaaa_40x100.png
  111. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_flat_75_ffffff_40x100.png
  112. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_glass_55_fbf9ee_1x400.png
  113. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_glass_65_ffffff_1x400.png
  114. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_glass_75_dadada_1x400.png
  115. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_glass_75_e6e6e6_1x400.png
  116. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_glass_95_fef1ec_1x400.png
  117. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
  118. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-icons_222222_256x240.png
  119. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-icons_2e83ff_256x240.png
  120. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-icons_454545_256x240.png
  121. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-icons_888888_256x240.png
  122. BIN  php.old/assets/c2383dc3/jui/css/base/images/ui-icons_cd0a0a_256x240.png
  123. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery-ui.css
  124. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.accordion.css
  125. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.autocomplete.css
  126. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.button.css
  127. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.core.css
  128. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.datepicker.css
  129. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.dialog.css
  130. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.progressbar.css
  131. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.resizable.css
  132. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.selectable.css
  133. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.slider.css
  134. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.tabs.css
  135. +0 −5 php.old/assets/c2383dc3/jui/css/base/jquery.ui.theme.css
  136. +0 −5 php.old/assets/c2383dc3/jui/js/jquery-ui-i18n.min.js
  137. +0 −5 php.old/assets/c2383dc3/jui/js/jquery-ui.min.js
  138. BIN  php.old/assets/c2383dc3/rating/delete.gif
  139. +0 −12 php.old/assets/c2383dc3/rating/jquery.rating.css
  140. BIN  php.old/assets/c2383dc3/rating/star.gif
  141. BIN  php.old/assets/c2383dc3/treeview/images/ajax-loader.gif
  142. BIN  php.old/assets/c2383dc3/treeview/images/file.gif
  143. BIN  php.old/assets/c2383dc3/treeview/images/folder-closed.gif
  144. BIN  php.old/assets/c2383dc3/treeview/images/folder.gif
  145. BIN  php.old/assets/c2383dc3/treeview/images/minus.gif
  146. BIN  php.old/assets/c2383dc3/treeview/images/plus.gif
  147. BIN  php.old/assets/c2383dc3/treeview/images/treeview-black-line.gif
  148. BIN  php.old/assets/c2383dc3/treeview/images/treeview-black.gif
  149. BIN  php.old/assets/c2383dc3/treeview/images/treeview-default-line.gif
  150. BIN  php.old/assets/c2383dc3/treeview/images/treeview-default.gif
  151. BIN  php.old/assets/c2383dc3/treeview/images/treeview-famfamfam-line.gif
  152. BIN  php.old/assets/c2383dc3/treeview/images/treeview-famfamfam.gif
  153. BIN  php.old/assets/c2383dc3/treeview/images/treeview-gray-line.gif
  154. BIN  php.old/assets/c2383dc3/treeview/images/treeview-gray.gif
  155. BIN  php.old/assets/c2383dc3/treeview/images/treeview-red-line.gif
  156. BIN  php.old/assets/c2383dc3/treeview/images/treeview-red.gif
  157. +0 −74 php.old/assets/c2383dc3/treeview/jquery.treeview.css
  158. +0 −58 php.old/assets/c2383dc3/yiitab/jquery.yiitab.css
  159. +0 −17 php.old/composer.json
  160. +0 −474 php.old/composer.lock
  161. BIN  php.old/composer.phar
  162. BIN  php.old/css/bg.gif
  163. +0 −160 php.old/css/form.css
  164. +0 −36 php.old/css/ie.css
  165. +0 −229 php.old/css/main.css
  166. +0 −29 php.old/css/print.css
  167. +0 −238 php.old/css/screen.css
  168. 0  php.old/images/.gitkeep
  169. +0 −15 php.old/index-test.php
  170. +0 −56 php.old/index.html
  171. +0 −13 php.old/index.php
  172. +0 −1  php.old/protected/.htaccess
  173. 0  php.old/protected/commands/shell/.gitkeep
  174. +0 −23 php.old/protected/components/Controller.php
  175. +0 −33 php.old/protected/components/UserIdentity.php
  176. +0 −37 php.old/protected/config/console.php
  177. +0 −107 php.old/protected/config/main.php
  178. +0 −20 php.old/protected/config/test.php
  179. +0 −109 php.old/protected/controllers/SiteController.php
  180. +0 −28 php.old/protected/data/schema.mysql.sql
  181. +0 −28 php.old/protected/data/schema.sqlite.sql
  182. BIN  php.old/protected/data/testdrive.db
  183. 0  php.old/protected/extensions/.gitkeep
  184. +0 −5 php.old/protected/extensions/YiiMongoDbSuite/.gitignore
  185. +0 −445 php.old/protected/extensions/YiiMongoDbSuite/EMongoCriteria.php
  186. +0 −162 php.old/protected/extensions/YiiMongoDbSuite/EMongoCursor.php
  187. +0 −228 php.old/protected/extensions/YiiMongoDbSuite/EMongoDB.php
  188. +0 −1,342 php.old/protected/extensions/YiiMongoDbSuite/EMongoDocument.php
  189. +0 −36 php.old/protected/extensions/YiiMongoDbSuite/EMongoDocumentBehavior.php
  190. +0 −188 php.old/protected/extensions/YiiMongoDbSuite/EMongoDocumentDataProvider.php
  191. +0 −351 php.old/protected/extensions/YiiMongoDbSuite/EMongoEmbeddedDocument.php
  192. +0 −21 php.old/protected/extensions/YiiMongoDbSuite/EMongoException.php
  193. +0 −314 php.old/protected/extensions/YiiMongoDbSuite/EMongoGridFS.php
  194. +0 −154 php.old/protected/extensions/YiiMongoDbSuite/EMongoModifier.php
  195. +0 −166 php.old/protected/extensions/YiiMongoDbSuite/EMongoSoftDocument.php
  196. +0 −526 php.old/protected/extensions/YiiMongoDbSuite/README.mkd
  197. +0 −27 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.data-provider.txt
  198. +0 −163 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.gridfs.txt
  199. +0 −55 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.indexing.txt
  200. +0 −65 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.named-scopes.txt
  201. +0 −91 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.partial-batch-update.txt
  202. +0 −31 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.partial-update.txt
  203. +0 −50 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.primary-key.txt
  204. +0 −49 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.relations.txt
  205. +0 −63 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.soft-models.txt
  206. +0 −6 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.txt
  207. +0 −53 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/advanced.write-flags.txt
  208. +0 −57 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.arrays.embedded-documents.txt
  209. +0 −33 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.arrays.simple.txt
  210. +0 −6 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.arrays.txt
  211. +0 −57 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.embedded-documents.txt
  212. +0 −93 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.simple-embedded-document.txt
  213. +0 −66 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.simple-model.txt
  214. +0 −10 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/basic.txt
  215. +0 −102 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/changelog.txt
  216. +0 −45 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/gii.txt
  217. +0 −47 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/introduction.txt
  218. +0 −155 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/querying.criteria-object.txt
  219. +0 −25 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/querying.simple-queries.txt
  220. +0 −10 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/querying.txt
  221. +0 −49 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/setup.txt
  222. +0 −113 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/special.multimodel.txt
  223. +0 −47 php.old/protected/extensions/YiiMongoDbSuite/doc/input/en/special.txt
  224. +0 −15 php.old/protected/extensions/YiiMongoDbSuite/doc/settings.ini
  225. +0 −27 php.old/protected/extensions/YiiMongoDbSuite/doc/sort_hints.txt
  226. +0 −62 php.old/protected/extensions/YiiMongoDbSuite/examples/MongoImage.php
  227. +0 −156 php.old/protected/extensions/YiiMongoDbSuite/examples/User.php
  228. +0 −23 php.old/protected/extensions/YiiMongoDbSuite/examples/UserAddress.php
  229. +0 −122 php.old/protected/extensions/YiiMongoDbSuite/extra/EEmbeddedArraysBehavior.php
  230. +0 −172 php.old/protected/extensions/YiiMongoDbSuite/extra/EMongoPartialDocument.php
  231. +0 −41 php.old/protected/extensions/YiiMongoDbSuite/extra/EMongoUniqueValidator.php
  232. +0 −210 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/MongoCRUDCode.php
  233. +0 −27 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/MongoCRUDGenerator.php
  234. +0 −39 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/_form.php
  235. +0 −32 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/_search.php
  236. +0 −26 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/_view.php
  237. +0 −87 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/admin.php
  238. +0 −184 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/controller.php
  239. +0 −24 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/create.php
  240. +0 −26 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/index.php
  241. +0 −28 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/update.php
  242. +0 −36 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/default/view.php
  243. +0 −39 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/_form.php
  244. +0 −32 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/_search.php
  245. +0 −173 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/controller.php
  246. +0 −23 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/create.php
  247. +0 −87 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/index.php
  248. +0 −27 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/update.php
  249. +0 −35 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/templates/withoutAdminView/view.php
  250. +0 −64 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoCRUD/views/index.php
  251. +0 −349 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoModel/MongoModelCode.php
  252. +0 −27 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoModel/MongoModelGenerator.php
  253. +0 −79 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoModel/templates/default/model.php
  254. +0 −101 php.old/protected/extensions/YiiMongoDbSuite/gii/mongoModel/views/index.php
  255. +0 −309 php.old/protected/extensions/YiiMongoDbSuite/test/EMongoDbFixtureManager.php
  256. +0 −32 php.old/protected/extensions/YiiMongoDbSuite/test/EMongoDbTestCase.php
  257. +0 −123 php.old/protected/extensions/YiiMongoDbSuite/test/README.mkd
  258. +0 −11 php.old/protected/extensions/YiiMongoDbSuite/tests/README.mkd
  259. 0  php.old/protected/messages/.gitkeep
  260. 0  php.old/protected/migrations/.gitkeep
  261. +0 −42 php.old/protected/models/ContactForm.php
  262. +0 −77 php.old/protected/models/LoginForm.php
  263. +0 −37 php.old/protected/models/Task.php
  264. +0 −37 php.old/protected/models/User.php
  265. +0 −262 php.old/protected/runtime/application.log
  266. +0 −25 php.old/protected/tests/WebTestCase.php
  267. +0 −10 php.old/protected/tests/bootstrap.php
  268. 0  php.old/protected/tests/fixtures/.gitkeep
  269. +0 −47 php.old/protected/tests/functional/SiteTest.php
  270. +0 −12 php.old/protected/tests/phpunit.xml
  271. 0  php.old/protected/tests/report/.gitkeep
  272. 0  php.old/protected/tests/unit/.gitkeep
  273. +0 −6 php.old/protected/views/layouts/column1.php
  274. +0 −22 php.old/protected/views/layouts/column2.php
  275. +0 −59 php.old/protected/views/layouts/main.php
  276. +0 −85 php.old/protected/views/site/contact.php
  277. +0 −15 php.old/protected/views/site/error.php
  278. +0 −20 php.old/protected/views/site/index.php
  279. +0 −53 php.old/protected/views/site/login.php
  280. +0 −12 php.old/protected/views/site/pages/about.php
  281. +0 −4 php.old/protected/yiic
  282. +0 −16 php.old/protected/yiic.bat
  283. +0 −7 php.old/protected/yiic.php
  284. +0 −1  php.old/themes/classic/views/.htaccess
  285. 0  php.old/themes/classic/views/layouts/.gitkeep
  286. 0  php.old/themes/classic/views/site/.gitkeep
  287. 0  php.old/themes/classic/views/system/.gitkeep
  288. +108 −6 php/api.php
  289. +1 −1  php/app/scripts/app.js
  290. +0 −3  php/app/scripts/config.js
  291. +3 −0  php/app/scripts/main.js
  292. +12 −2 php/app/scripts/modules/baseView.js
  293. +29 −12 php/app/scripts/modules/login.js
  294. +164 −0 php/app/scripts/modules/tasks.js
  295. +0 −24 php/app/scripts/modules/user.js
  296. +26 −5 php/app/scripts/router.js
  297. +0 −104 php/app/scripts/vendor/bootstrap/bootstrap-affix.js
  298. +0 −90 php/app/scripts/vendor/bootstrap/bootstrap-alert.js
  299. +0 −96 php/app/scripts/vendor/bootstrap/bootstrap-button.js
  300. +0 −176 php/app/scripts/vendor/bootstrap/bootstrap-carousel.js
Sorry, we could not display the entire diff because too many files (317) changed.
View
4 Gemfile
@@ -3,4 +3,6 @@ source "https://rubygems.org"
gem "cucumber"
gem "rspec"
gem "poltergeist"
-gem "compass"
+gem "compass"
+gem "mongo"
+gem "bson_ext"
View
12 Gemfile.lock
@@ -1,7 +1,14 @@
GEM
remote: https://rubygems.org/
specs:
+ activesupport (3.2.9)
+ i18n (~> 0.6)
+ multi_json (~> 1.0)
addressable (2.3.2)
+ bson (1.8.0)
+ activesupport
+ bson_ext (1.8.0)
+ bson (~> 1.8.0)
builder (3.1.4)
capybara (1.1.4)
mime-types (>= 1.16)
@@ -31,11 +38,14 @@ GEM
gherkin (2.11.5)
json (>= 1.4.6)
http_parser.rb (0.5.3)
+ i18n (0.6.1)
json (1.7.5)
libwebsocket (0.1.7.1)
addressable
websocket
mime-types (1.19)
+ mongo (1.8.0)
+ bson (~> 1.8.0)
multi_json (1.4.0)
nokogiri (1.5.5)
poltergeist (1.0.2)
@@ -70,7 +80,9 @@ PLATFORMS
ruby
DEPENDENCIES
+ bson_ext
compass
cucumber
+ mongo
poltergeist
rspec
View
12 checklist
@@ -1,9 +1,11 @@
+- I need every client operation done using JavaScript, reloading the page is
+not an option.
- I can have my todo list displayed.
-- I can manipulate my list (add/remove/modify entries).
+- I can mark an entry as completed.
- Assign priorities and due dates to the entries.
+- I can manipulate my list (add/remove/modify entries).
- I can sort my entry lists using due date and priority.
-- I can mark an entry as completed.
-- Minimal UI/UX design is needed.
-- I need every client operation done using JavaScript, reloading the page is
-not an option.
- Write a RESTful API which will allow a third-party application to trigger actions on your app (same actions available on the webpage).
+
+- Minimal UI/UX design is needed.
+
View
2  db/mongod.lock
@@ -1 +1 @@
-19186
+17602
View
BIN  db/todo.0
Binary file not shown
View
BIN  db/todo.1
Binary file not shown
View
BIN  db/todo.ns
Binary file not shown
View
70 features/Authentication.feature
@@ -5,37 +5,53 @@ Feature: Authentication
Background:
Given I am not logged in
+ And I have a user "test" with password "secret"
Scenario: Visiting the page
When I visit the page
Then I should see the login form
- Scenario Outline: Filling the form
- Given I am on the login form
- When I try to login with <username> and <password>
- Then I see <message>
+ Scenario Outline: Unsuccesful authentication
+ When I log in with <username> and <password>
+ Then I should see <message>
Examples:
- | username | password | message |
- | "random" | "" | "Password cannot be empty" |
- | "" | "random" | "Username cannot be empty" |
- | "random" | "random" | "Invalid username/password" |
-
- # Scenario: Reading when online
- # When I search for "Ulysses"
- # And I select the first book
- # And I wait
- # Then I should get to read it
-
- # Background: Offline
- # Given I am offline
- # Scenario Outline: Reading while offline
- # Given I am offline
- # When I search for <book>
- # And I select the first book
- # Then I <should> get to read it
-
- # Examples:
- # | book | should |
- # | 'Leaves of grass' | shouldn't |
- # | 'Ulysses' | should |
+ | username | password | message |
+ | "random" | "" | "Password is required" |
+ | "" | "random" | "Username is required" |
+ | "random" | "random" | "Invalid username" |
+ | "test" | "random" | "Invalid password" |
+
+ Scenario: Succesfull authentication
+ When I log in with "test" and "secret"
+ Then I should see the tasks page for user "test"
+
+ Scenario: Authentication persistance
+ Given I am logged in with "test" and "secret"
+ When I visit the page
+ Then I should see the tasks page for user "test"
+
+ Scenario Outline: Unsuccesful registering
+ When I register with <username> and <password>
+ Then I should see <message>
+ And I cannot log in with <username> and <password>
+
+ Examples:
+ | username | password | message |
+ | "random" | "" | "Password is required" |
+ | "" | "random" | "Username is required" |
+ | "test" | "random" | "Username is taken" |
+
+ Scenario: Succesful registering
+ When I register with "username" and "password"
+ Then I should see the tasks page for user "username"
+
+ # Scenario: Succesful registration comeback
+ # When I register with "username" and "password"
+ # And I visit the page
+ # Then I should see the tasks page for user "username"
+
+ Scenario: Succesful registration logout and comeback
+ When I register with "username" and "password"
+ And I log in with "username" and "password"
+ Then I should see the tasks page for user "username"
View
97 features/TaskHandling.feature
@@ -0,0 +1,97 @@
+Feature: Task Handling
+ In order to get things done
+ As a busy fellow
+ I want to manage my tasks
+
+ Background:
+ Given I have a user "test" with password "secret"
+ And user "test" has a task with description "laundry"
+ And user "test" has a task with description "eat"
+
+ Scenario: Task listing
+ When I log in with "test" and "secret"
+ Then I should see "laundry"
+ And I should see "eat"
+
+ Scenario: Task listing when reloading
+ Given I am logged in with "test" and "secret"
+ When I reload the page
+ Then I should see "laundry"
+
+ Scenario Outline: Task creation
+ Given I log in with "test" and "secret"
+ When I create task <description> with due date <due date> and priority <priority>
+ Then I should see <something>
+
+ Examples:
+ | description | due date | priority | something |
+ | "" | "" | "" | "Description is required" |
+ | "wash car" | "" | "" | task "wash car" |
+ | "wash car" | "10/10/10" | "" | task "wash car" with due date "2010-10-10" |
+ | "wash car" | "10/10/10" | "10" | task "wash car" with due date "2010-10-10" and priority "10"|
+
+ Scenario: Task creation persistance
+ Given I log in with "test" and "secret"
+ When I create task "task" with due date "10/10/10" and priority "3"
+ And I reload the page
+ Then I should see task "task" with due date "2010-10-10" and priority "3"
+
+ Scenario: Task crossing
+ Given I log in with "test" and "secret"
+ When I cross "laundry"
+ And I reload the page
+ Then "laundry" should be crossed
+
+ Scenario: Task removal
+ Given I log in with "test" and "secret"
+ When I remove task "laundry"
+ Then I should not see "laundry"
+
+ When I reload the page
+ Then I should not see "laundry"
+
+ Scenario: Task editing
+ Given I log in with "test" and "secret"
+ When I edit task "laundry" with description "Do laundry", due date "10/10/10" and priority "3"
+ Then I should see task "Do laundry" with due date "2010-10-10" and priority "3"
+
+ When I reload the page
+ Then I should see task "Do laundry" with due date "2010-10-10" and priority "3"
+
+ When I edit task "Do laundry" with description "", due date "10/10/10" and priority "3"
+ #Then I should see "Do laundry"
+
+ When I reload the page
+ Then I should see "Do laundry"
+
+ Scenario: Sorting
+ Given there are no tasks stored
+ And I log in with "test" and "secret"
+ And I create task "task" with due date "10/12/10" and priority "3"
+ And I create task "task2" with due date "10/10/10" and priority "1"
+ And I create task "task3" with due date "10/11/11" and priority "2"
+
+ When I sort by priority
+ Then my tasks should be sorted in this order:
+ | task |
+ | task3 |
+ | task2 |
+
+ When I sort by priority
+ Then my tasks should be sorted in this order:
+ | task2 |
+ | task3 |
+ | task |
+
+ When I sort by due date
+ Then my tasks should be sorted in this order:
+ | task2 |
+ | task |
+ | task3 |
+
+ When I sort by due date
+ Then my tasks should be sorted in this order:
+ | task3 |
+ | task |
+ | task2 |
+
View
46 features/step_definitions/authentication_steps.rb
@@ -0,0 +1,46 @@
+Then /^I should see the login form$/ do
+ page.should have_selector "#login-form"
+end
+
+Given /^I am on the login form$/ do
+ logout
+ visit "/"
+end
+
+When /^I log in with "(.*?)" and "(.*?)"$/ do |username, password|
+ logout
+ visit "/"
+ fill_in "username", :with => username
+ fill_in "password", :with => password
+ click_button "login-button"
+end
+
+When /^I register with "(.*?)" and "(.*?)"$/ do |username, password|
+ logout
+ visit "/"
+ fill_in "username", :with => username
+ fill_in "password", :with => password
+ click_button "register-button"
+end
+
+Then /^I cannot log in with "(.*?)" and "(.*?)"$/ do |username, password|
+ logout
+ visit "/"
+ fill_in "username", :with => username
+ fill_in "password", :with => password
+ click_button "login-button"
+ page.should_not have_content "#{username}'s tasks"
+end
+
+Then /^I should see the tasks page for user "(.*?)"$/ do |user|
+ page.should have_content "#{user}'s tasks"
+end
+
+Given /^I am logged in with "(.*?)" and "(.*?)"$/ do |username, password|
+ page.driver.set_cookie("username", "test")
+ page.driver.set_cookie("password", "secret")
+end
+
+Given /^I am not logged in$/ do
+ logout
+end
View
15 features/step_definitions/db_steps.rb
@@ -0,0 +1,15 @@
+Given /^I have a user "(.*?)" with password "(.*?)"$/ do |username, password|
+ add_user username, password
+end
+
+Given /^the database is empty$/ do
+ reset_db
+end
+
+Given /^user "(.*?)" has a task with description "(.*?)"$/ do |username, desc|
+ add_task username, desc, 0
+end
+
+Given /^there are no tasks stored$/ do
+ tasks_coll.remove
+end
View
19 features/step_definitions/generic_steps.rb
@@ -0,0 +1,19 @@
+When /^I do nothing$/ do
+end
+
+When /^I visit the page$/ do
+ visit "/"
+end
+
+When /^I reload the page$/ do
+ visit "/"
+end
+
+Then /^I should see "(.*?)"$/ do |message|
+ page.should have_content message
+end
+
+Then /^I should not see "(.*?)"$/ do |message|
+ page.should_not have_content message
+end
+
View
32 features/step_definitions/steps.rb
@@ -1,32 +0,0 @@
-def logout
-end
-
-When /^I do nothing$/ do
-end
-
-Given /^I am not logged in$/ do
- logout
-end
-
-When /^I visit the page$/ do
- visit "/"
-end
-
-Then /^I should see the login form$/ do
- page.should have_selector "#login-form"
-end
-
-Given /^I am on the login form$/ do
- logout
- visit "/"
-end
-
-When /^I try to login with "(.*?)" and "(.*?)"$/ do |username, password|
- fill_in "username", :with => username
- fill_in "password", :with => password
- click_button "login-button"
-end
-
-Then /^I see "(.*?)"$/ do |message|
- page.should have_content message
-end
View
67 features/step_definitions/task_steps.rb
@@ -0,0 +1,67 @@
+When /^I cross "(.*?)"$/ do |task|
+ page.find(:xpath, "//span[text()='#{task}']").find(:xpath, "..").find(".task-done").set(true)
+end
+
+Then /^"(.*?)" should be crossed$/ do |task|
+ page.find(:xpath, "//span[text()='#{task}']").find(:xpath, "..").find(".task-done").should be_checked
+end
+
+When /^I create task "(.*?)" with due date "(.*?)" and priority "(.*?)"$/ do |description, due_date, priority|
+ fill_in "description", :with => description
+ fill_in "due-date", :with => due_date
+ fill_in "priority", :with => priority
+ click_button "create-task"
+end
+
+Then /^I should see task "(.*?)"$/ do |description|
+ page.should have_xpath "//span[text()='#{description}']"
+end
+
+Then /^I should see task "(.*?)" with due date "(.*?)"$/ do |desc, due_date|
+ page.should have_xpath "//span[text()='#{desc}']"
+ page.find(:xpath, "//span[text()='#{desc}']").find(:xpath, "..").should have_content due_date
+end
+
+Then /^I should see task "(.*?)" with due date "(.*?)" and priority "(.*?)"$/ do |desc, due_date, priority|
+ #page.should have_xpath "//span[text()='#{desc}']"
+ taskEl = page.find(:xpath, "//span[text()='#{desc}']").find(:xpath, "..")
+ taskEl.should have_content due_date
+ taskEl.should have_content priority
+end
+
+When /^I remove task "(.*?)"$/ do |task|
+ page.find(:xpath, "//span[text()='#{task}']").find(:xpath, "..").find(".remove").click
+end
+
+When /^I edit task "(.*?)" with description "(.*?)", due date "(.*?)" and priority "(.*?)"$/ do |task, desc, due_date, priority|
+ taskEl = page.find(:xpath, "//span[text()='#{task}']").find(:xpath, "..")
+ taskEl.find(".desc").trigger("click")
+ taskEl.find("input.desc").set(desc)
+ taskEl.find(".due-date").trigger("click")
+ taskEl.find("input.due-date").set(due_date)
+ taskEl.find(".priority").trigger("click")
+ taskEl.find("input.priority").set(priority)
+end
+
+# When /^I edit task "(.*?)" with description "(.*?)", due date "(.*?)" and priority "(.*?)"$/ do |task, desc, due_date, priority|
+# taskEl = page.find(:xpath, "//span[text()='#{task}']").find(:xpath, "..")
+# taskEl.find(".desc").trigger("click")
+# taskEl.find("input.desc").set(desc)
+# taskEl.find(".due-date").trigger("click")
+# taskEl.find("input.due-date").set(due_date)
+# taskEl.find(".priority").trigger("click")
+# taskEl.find("input.priority").set(priority)
+# end
+
+When /^I sort by priority$/ do
+ find("#sort-by-priority").click
+end
+
+When /^I sort by due date$/ do
+ find("#sort-by-due-date").click
+end
+
+Then /^my tasks should be sorted in this order:$/ do |table|
+ page.all(".desc").collect(&:text).should === table.raw
+end
+
View
15 features/support/env.rb
@@ -3,17 +3,22 @@
require 'capybara/dsl'
require 'capybara/cucumber'
require 'capybara/poltergeist'
+require 'rubygems'
+require 'mongo'
+
+include Mongo
# Capybara.register_driver :poltergeist do |app|
# Capybara::Poltergeist::Driver.new(app, {:timeout => 10})
# end
-# Capybara.javascript_driver = :poltergeist
-# Capybara.default_driver = :poltergeist
-Capybara.default_driver = :selenium
-Capybara.app_host = 'http://localhost/dev/todos/php/'
+Capybara.javascript_driver = :poltergeist
+Capybara.default_driver = :poltergeist
+Capybara.app_host = 'http://localhost/dev/todos/php'
Capybara.default_wait_time = 5
-class Fixtures
+require_relative 'helpers'
+Before do
+ reset_db
end
World(Capybara)
View
37 features/support/helpers.rb
@@ -0,0 +1,37 @@
+def logout
+ page.driver.remove_cookie("username")
+ page.driver.remove_cookie("password")
+end
+
+def db
+ MongoClient.new("localhost", 27017).db("todo")
+end
+
+def users_coll
+ db.collection('users')
+end
+
+def tasks_coll
+ db.collection('tasks')
+end
+
+def reset_db
+ users_coll.remove
+ tasks_coll.remove
+end
+
+def add_user(username, password)
+ users_coll.insert({"username" => username, "password" => password})
+end
+
+def add_task(username, desc, priority)
+ @hash ||= {}
+
+ if @hash.has_key?(username)
+ @hash[username] = @hash[username] + 1
+ else
+ @hash[username] = 1
+ end
+
+ tasks_coll.insert({"user" => username, "description" => desc, "done" => false, "id" => @hash[username], "priority" => priority})
+end
View
204 frontend/Gruntfile.js
@@ -1,204 +0,0 @@
-module.exports = function( grunt ) {
- 'use strict';
- //
- // Grunt configuration:
- //
- // https://github.com/cowboy/grunt/blob/master/docs/getting_started.md
- //
- grunt.initConfig({
-
- // Project configuration
- // ---------------------
-
- // specify an alternate install location for Bower
- bower: {
- dir: 'app/components'
- },
-
- // Coffee to JS compilation
- coffee: {
- compile: {
- files: {
- 'php/app/scripts/*.js': 'app/scripts/**/*.coffee'
- },
- options: {
- basePath: 'app/scripts'
- }
- },
- test: {
- files: {
- 'test/specs.js': 'test/spec/**/*.coffee',
- 'test/config.js': 'app/scripts/config.coffee'
- }
- }
- },
-
- // compile .scss/.sass to .css using Compass
- compass: {
- dist: {
- // http://compass-style.org/help/tutorials/configuration-reference/#configuration-properties
- options: {
- css_dir: 'php/app/styles',
- sass_dir: 'app/styles',
- images_dir: 'app/images',
- javascripts_dir: 'php/app/scripts',
- force: true
- }
- }
- },
-
- // generate application cache manifest
- manifest:{
- dest: ''
- },
-
- // headless testing through PhantomJS
- mocha: {
- all: ['test/**/*.html']
- },
-
- // default watch configuration
- watch: {
- coffee: {
- files: 'app/scripts/**/*.coffee',
- tasks: 'coffee reload'
- },
- compass: {
- files: [
- 'app/styles/**/*.{scss,sass}'
- ],
- tasks: 'compass reload'
- },
- reload: {
- files: [
- 'app/*.html',
- 'app/styles/**/*.css',
- 'app/scripts/**/*.js',
- 'app/images/**/*'
- ],
- tasks: 'reload'
- },
- test: {
- files: [
- 'test/specs/**/*.coffee',
- 'app/scripts/**/*.coffee',
- 'app/templates/**/*',
- ],
- tasks: 'build:test'
- }
- },
-
- // default lint configuration, change this to match your setup:
- // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md#lint-built-in-task
- lint: {
- files: [
- 'Gruntfile.js',
- 'app/scripts/**/*.js',
- 'spec/**/*.js'
- ]
- },
-
- // specifying JSHint options and globals
- // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md#specifying-jshint-options-and-globals
- jshint: {
- options: {
- curly: true,
- eqeqeq: true,
- immed: true,
- latedef: true,
- newcap: true,
- noarg: true,
- sub: true,
- undef: true,
- boss: true,
- eqnull: true,
- browser: true
- },
- globals: {
- jQuery: true
- }
- },
-
- // Build configuration
- // -------------------
-
- // the staging directory used during the process
- staging: 'temp',
- // final build output
- output: 'dist',
-
- mkdirs: {
- staging: 'app/'
- },
-
- // Below, all paths are relative to the staging directory, which is a copy
- // of the app/ directory. Any .gitignore, .ignore and .buildignore file
- // that might appear in the app/ tree are used to ignore these values
- // during the copy process.
-
- // concat css/**/*.css files, inline @import, output a single minified css
- css: {
- 'styles/main.css': ['styles/**/*.css']
- },
-
- // renames JS/CSS to prepend a hash of their contents for easier
- // versioning
- rev: {
- js: 'scripts/**/*.js',
- css: 'styles/**/*.css',
- img: 'images/**'
- },
-
- // usemin handler should point to the file containing
- // the usemin blocks to be parsed
- 'usemin-handler': {
- html: 'index.html'
- },
-
- // update references in HTML/CSS to revved files
- usemin: {
- html: ['**/*.html'],
- css: ['**/*.css']
- },
-
- // HTML minification
- html: {
- files: ['**/*.html']
- },
-
- // Optimizes JPGs and PNGs (with jpegtran & optipng)
- img: {
- dist: '<config:rev.img>'
- },
-
- // rjs configuration. You don't necessarily need to specify the typical
- // `path` configuration, the rjs task will parse these values from your
- // main module, using http://requirejs.org/docs/optimization.html#mainConfigFile
- //
- // name / out / mainConfig file should be used. You can let it blank if
- // you're using usemin-handler to parse rjs config from markup (default
- // setup)
- rjs: {
- // no minification, is done by the min task
- optimize: 'none',
- baseUrl: './scripts',
- wrap: true,
- name: 'main'
- },
-
- // While Yeoman handles concat/min when using
- // usemin blocks, you can still use them manually
- concat: {
- dist: ''
- },
-
- min: {
- dist: ''
- }
- });
-
- // Alias the `test` task to run the `mocha` task instead
- grunt.registerTask('test', 'server:phantom mocha');
-
-
-};
View
23 frontend/app/index.html
@@ -20,6 +20,8 @@
<div class="hero-unit">
<h1>Todo</h1>
</div>
+ <div id="content">
+ </div>
</div>
<!--[if lt IE 7]>
@@ -29,28 +31,11 @@
<!-- Add your site or application content here -->
<!--<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>-->
- <script>window.jQuery || document.write('<script src="app/scripts/vendor/jquery.min.js"><\/script>')</script>
+ <script>window.jQuery || document.write('<script src="app/scripts/vendor/jquery.min.js"><\/script>')</script>
- <!-- build:js scripts/plugins.js -->
- <!--<script src="scripts/vendor/bootstrap/bootstrap-affix.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-alert.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-dropdown.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-tooltip.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-modal.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-transition.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-button.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-popover.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-typeahead.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-carousel.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-scrollspy.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-collapse.js"></script>
- <script src="scripts/vendor/bootstrap/bootstrap-tab.js"></script>-->
- <!-- endbuild -->
- <!-- build:js scripts/amd-app.js -->
- <!--<script type="text/javascript" src="http://localhost:5984/_utils/script/jquery.couch.js"></script>-->
<script data-main="app/scripts/main" src="app/scripts/vendor/require.js"></script>
- <!-- endbuild -->
+
</body>
</html>
View
2  frontend/app/scripts/app.coffee
@@ -1,6 +1,6 @@
define ["jquery", "lodash", "backbone"], ($, _, Backbone) ->
app =
- url: "http://localhost/dev/todos/php/index.php?r="
+ url: "http://localhost/dev/todos/php/api"
app
View
4 frontend/app/scripts/config.coffee
@@ -18,6 +18,4 @@ require.config
window.CoffeeScript = cs
process.browser = true
- require("./hamlc")
- monocle:
- exports: "Monocle"
+ require("./hamlc")
View
2  frontend/app/scripts/main.coffee
@@ -5,6 +5,8 @@ require ["config", "app", "router"], (config, app, Router) ->
Backbone.history.start()
#pushState: true
+ $.ajaxSetup({cache:false})
+
# // All navigation that is relative should be passed through the navigate
# // method, to be processed by the router. If the link has a `data-bypass`
# // attribute, bypass the delegation completely.
View
11 frontend/app/scripts/modules/baseView.coffee
@@ -8,10 +8,17 @@ define ["app", "hamlCoffee"], (app, hamlc)->
@$el.append el
el
- render: ->
+ serialize: ->
+ if @model?
+ @model.attributes
+ else
+ @
+
+ render: (cb) ->
if @template?
$.get "app/templates/#{@template}.hamlc", (template) =>
- @$el.html hamlc.compile(template)(@model)
+ @$el.html hamlc.compile(template)(@serialize())
+ cb() if cb
initialize: ->
@render()
View
31 frontend/app/scripts/modules/login.coffee
@@ -1,17 +1,28 @@
-define ["modules/baseView", "modules/user"], (View, User) ->
+define ["app", "modules/baseView", "modules/tasks"], (app, View, Tasks) ->
View.extend
+ tagName: "form"
+ id: "login-form"
template: "login"
events:
- "click #login-button": "login"
+ "click #login-button": (e) ->
+ e.preventDefault()
+ @login()
+ "click #register-button": (e) ->
+ e.preventDefault()
+ @login(true)
- login: (e) ->
- e.preventDefault()
- user = new User
- username: $el.find("#username").val()
- password: $el.find("#password").val()
+ login: (registerFirst) ->
+ $.ajax
+ type: "POST"
+ url: "#{app.url}/" + if registerFirst then "register" else "login"
+ dataType: "json"
+ data: @$el.serialize()
+ error: (xhr) =>
+ @showError JSON.parse(xhr.responseText).error if xhr.responseText
+ success: (data) =>
+ @$el.replaceWith (new Tasks(data.username, data.tasks)).$el
- auth = user.authenticate()
- if auth.err
- $el.find("#login-error").text(auth.err)
+ showError: (error) ->
+ @$el.find("#login-error").text error
View
117 frontend/app/scripts/modules/tasks.coffee
@@ -0,0 +1,117 @@
+define ["app", "modules/baseView"], (app, View) ->
+
+ TaskModel = Backbone.Model.extend
+ url: ->
+ url = "#{app.url}/#{@get('user')}/tasks"
+ url += "/#{@get('id')}" unless @isNew()
+ url
+
+ Collection = Backbone.Collection.extend
+ model: TaskModel
+
+ url: ->
+ "#{app.url}/#{@user}/tasks"
+
+ TaskView = View.extend
+ tagName: "tr"
+ template: "task"
+
+ events:
+ "click .task-done": "cross"
+ "click .remove": "remove"
+ "dblclick .editable": "edit"
+
+ edit: (e) ->
+ $el = $(e.currentTarget)
+ input = $ "<input>",
+ type: "text"
+ class: $el.attr "class"
+ val: $el.text()
+
+ input.removeClass "editable"
+
+ if $el.hasClass "due-date"
+ input.attr "type", "date"
+ field = "dueDate"
+ else if $el.hasClass "priority"
+ input.attr
+ type: "number"
+ min: 1
+ max: 10
+ field = "priority"
+ else
+ field = "description"
+ $el.replaceWith input
+
+ input.focus()
+ input.on "blur", =>
+ data = {}
+ data[field] = input.val()
+ @model.save data,
+ success: (model) ->
+ input.replaceWith $el.text(model.attributes[field])
+ error: =>
+ @$el.parent().find(".error").text(JSON.parse(xhr.responseText).error) if xhr.responseText
+
+ remove: ->
+ @$el.remove()
+ @model.destroy()
+
+ cross: (e) ->
+ @model.set("done", e.currentTarget.checked).save()
+
+ TasksView = View.extend
+ template: "tasks"
+
+ events:
+ "click button#create-task": "createTask"
+ "click #sort-by-due-date": -> @sortBy "dueDate"
+ "click #sort-by-priority": -> @sortBy "priority"
+ "click #logout": -> app.router.logout()
+
+ serialize: -> @
+
+ initialize: (username, tasks = []) ->
+ @user = username
+ @model = new Collection(tasks)
+ @model.user = username
+ @model.on "add", (model) =>
+ @table.append (new TaskView({model: model})).$el
+
+ @render =>
+ @table = @$el.find("tbody")
+ if tasks.length
+ @populate()
+
+ populate: ->
+ @table.html ""
+ @model.each (model) =>
+ @table.append (new TaskView({model: model})).$el
+
+ createTask: (e) ->
+ e.preventDefault()
+
+ task = new TaskModel
+ description: @$el.find("input.description").val()
+ dueDate: @$el.find("input.due-date").val()
+ priority: @$el.find("input.priority").val()
+ user: @user
+
+ task.save null,
+ success: =>
+ @model.add task
+ error: (model, xhr) =>
+ @$el.find(".error").text(JSON.parse(xhr.responseText).error) if xhr.responseText
+
+ sortBy: (what) ->
+ qs = "sortedBy=#{what}"
+ if what is @sortedBy
+ qs += "&desc=true"
+ @sortedBy = ""
+ else
+ @sortedBy = what
+
+ @model.fetch
+ data: qs
+ .done =>
+ @populate()
View
15 frontend/app/scripts/modules/user.coffee
@@ -1,15 +0,0 @@
-define ["app"], (app) ->
-
- Backbone.Model.extend
- url: "#{app.url}api/user"
-
- authenticate: (cb) ->
- if !@isValid()
- cb {err: "User and/or password missing"}
- else
- $.ajax
- type: "POST"
- url: "#{@url}/authenticate"
- data: @attrs
- dataType: "json"
- success: cb
View
24 frontend/app/scripts/router.coffee
@@ -1,12 +1,26 @@
-define ["app"], ->
+define ["app", "modules/login", "modules/tasks"], (app, Login, Tasks) ->
Router = Backbone.Router.extend
routes:
"": "start"
- start: () ->
- require ["modules/login"], (Login) ->
- $(".container").append (new Login()).$el
+ login: ->
+ $("#content").html (new Login()).$el
- Router
+ logout: ->
+ $.getJSON "#{app.url}/logout", => @login()
+
+ tasks: (user, tasks) ->
+ $("#content").html (new Tasks(user, tasks)).$el
+
+ start: ->
+ $.ajax
+ type: "POST"
+ url: "#{app.url}/login"
+ data: ""
+ dataType: "json"
+ success: (data) =>
+ @tasks(data.username, data.tasks)
+ error: =>
+ @login()
View
104 frontend/app/scripts/vendor/bootstrap/bootstrap-affix.js
@@ -1,104 +0,0 @@
-/* ==========================================================
- * bootstrap-affix.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#affix
- * ==========================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================== */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* AFFIX CLASS DEFINITION
- * ====================== */
-
- var Affix = function (element, options) {
- this.options = $.extend({}, $.fn.affix.defaults, options)
- this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
- this.$element = $(element)
- this.checkPosition()
- }
-
- Affix.prototype.checkPosition = function () {
- if (!this.$element.is(':visible')) return
-
- var scrollHeight = $(document).height()
- , scrollTop = this.$window.scrollTop()
- , position = this.$element.offset()
- , offset = this.options.offset
- , offsetBottom = offset.bottom
- , offsetTop = offset.top
- , reset = 'affix affix-top affix-bottom'
- , affix
-
- if (typeof offset != 'object') offsetBottom = offsetTop = offset
- if (typeof offsetTop == 'function') offsetTop = offset.top()
- if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
-
- affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
- false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
- 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
- 'top' : false
-
- if (this.affixed === affix) return
-
- this.affixed = affix
- this.unpin = affix == 'bottom' ? position.top - scrollTop : null
-
- this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
- }
-
-
- /* AFFIX PLUGIN DEFINITION
- * ======================= */
-
- $.fn.affix = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('affix')
- , options = typeof option == 'object' && option
- if (!data) $this.data('affix', (data = new Affix(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- $.fn.affix.Constructor = Affix
-
- $.fn.affix.defaults = {
- offset: 0
- }
-
-
- /* AFFIX DATA-API
- * ============== */
-
- $(window).on('load', function () {
- $('[data-spy="affix"]').each(function () {
- var $spy = $(this)
- , data = $spy.data()
-
- data.offset = data.offset || {}
-
- data.offsetBottom && (data.offset.bottom = data.offsetBottom)
- data.offsetTop && (data.offset.top = data.offsetTop)
-
- $spy.affix(data)
- })
- })
-
-
-}(window.jQuery);
View
90 frontend/app/scripts/vendor/bootstrap/bootstrap-alert.js
@@ -1,90 +0,0 @@
-/* ==========================================================
- * bootstrap-alert.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#alerts
- * ==========================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================== */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* ALERT CLASS DEFINITION
- * ====================== */
-
- var dismiss = '[data-dismiss="alert"]'
- , Alert = function (el) {
- $(el).on('click', dismiss, this.close)
- }
-
- Alert.prototype.close = function (e) {
- var $this = $(this)
- , selector = $this.attr('data-target')
- , $parent
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
- }
-
- $parent = $(selector)
-
- e && e.preventDefault()
-
- $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
-
- $parent.trigger(e = $.Event('close'))
-
- if (e.isDefaultPrevented()) return
-
- $parent.removeClass('in')
-
- function removeElement() {
- $parent
- .trigger('closed')
- .remove()
- }
-
- $.support.transition && $parent.hasClass('fade') ?
- $parent.on($.support.transition.end, removeElement) :
- removeElement()
- }
-
-
- /* ALERT PLUGIN DEFINITION
- * ======================= */
-
- $.fn.alert = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('alert')
- if (!data) $this.data('alert', (data = new Alert(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
-
- $.fn.alert.Constructor = Alert
-
-
- /* ALERT DATA-API
- * ============== */
-
- $(function () {
- $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
- })
-
-}(window.jQuery);
View
96 frontend/app/scripts/vendor/bootstrap/bootstrap-button.js
@@ -1,96 +0,0 @@
-/* ============================================================
- * bootstrap-button.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#buttons
- * ============================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============================================================ */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* BUTTON PUBLIC CLASS DEFINITION
- * ============================== */
-
- var Button = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, $.fn.button.defaults, options)
- }
-
- Button.prototype.setState = function (state) {
- var d = 'disabled'
- , $el = this.$element
- , data = $el.data()
- , val = $el.is('input') ? 'val' : 'html'
-
- state = state + 'Text'
- data.resetText || $el.data('resetText', $el[val]())
-
- $el[val](data[state] || this.options[state])
-
- // push to event loop to allow forms to submit
- setTimeout(function () {
- state == 'loadingText' ?
- $el.addClass(d).attr(d, d) :
- $el.removeClass(d).removeAttr(d)
- }, 0)
- }
-
- Button.prototype.toggle = function () {
- var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
-
- $parent && $parent
- .find('.active')
- .removeClass('active')
-
- this.$element.toggleClass('active')
- }
-
-
- /* BUTTON PLUGIN DEFINITION
- * ======================== */
-
- $.fn.button = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('button')
- , options = typeof option == 'object' && option
- if (!data) $this.data('button', (data = new Button(this, options)))
- if (option == 'toggle') data.toggle()
- else if (option) data.setState(option)
- })
- }
-
- $.fn.button.defaults = {
- loadingText: 'loading...'
- }
-
- $.fn.button.Constructor = Button
-
-
- /* BUTTON DATA-API
- * =============== */
-
- $(function () {
- $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
- var $btn = $(e.target)
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
- $btn.button('toggle')
- })
- })
-
-}(window.jQuery);
View
176 frontend/app/scripts/vendor/bootstrap/bootstrap-carousel.js
@@ -1,176 +0,0 @@
-/* ==========================================================
- * bootstrap-carousel.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#carousel
- * ==========================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================== */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* CAROUSEL CLASS DEFINITION
- * ========================= */
-
- var Carousel = function (element, options) {
- this.$element = $(element)
- this.options = options
- this.options.slide && this.slide(this.options.slide)
- this.options.pause == 'hover' && this.$element
- .on('mouseenter', $.proxy(this.pause, this))
- .on('mouseleave', $.proxy(this.cycle, this))
- }
-
- Carousel.prototype = {
-
- cycle: function (e) {
- if (!e) this.paused = false
- this.options.interval
- && !this.paused
- && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
- return this
- }
-
- , to: function (pos) {
- var $active = this.$element.find('.item.active')
- , children = $active.parent().children()
- , activePos = children.index($active)
- , that = this
-
- if (pos > (children.length - 1) || pos < 0) return
-
- if (this.sliding) {
- return this.$element.one('slid', function () {
- that.to(pos)
- })
- }
-
- if (activePos == pos) {
- return this.pause().cycle()
- }
-
- return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
- }
-
- , pause: function (e) {
- if (!e) this.paused = true
- if (this.$element.find('.next, .prev').length && $.support.transition.end) {
- this.$element.trigger($.support.transition.end)
- this.cycle()
- }
- clearInterval(this.interval)
- this.interval = null
- return this
- }
-
- , next: function () {
- if (this.sliding) return
- return this.slide('next')
- }
-
- , prev: function () {
- if (this.sliding) return
- return this.slide('prev')
- }
-
- , slide: function (type, next) {
- var $active = this.$element.find('.item.active')
- , $next = next || $active[type]()
- , isCycling = this.interval
- , direction = type == 'next' ? 'left' : 'right'
- , fallback = type == 'next' ? 'first' : 'last'
- , that = this
- , e = $.Event('slide', {
- relatedTarget: $next[0]
- })
-
- this.sliding = true
-
- isCycling && this.pause()
-
- $next = $next.length ? $next : this.$element.find('.item')[fallback]()
-
- if ($next.hasClass('active')) return
-
- if ($.support.transition && this.$element.hasClass('slide')) {
- this.$element.trigger(e)
- if (e.isDefaultPrevented()) return
- $next.addClass(type)
- $next[0].offsetWidth // force reflow
- $active.addClass(direction)
- $next.addClass(direction)
- this.$element.one($.support.transition.end, function () {
- $next.removeClass([type, direction].join(' ')).addClass('active')
- $active.removeClass(['active', direction].join(' '))
- that.sliding = false
- setTimeout(function () { that.$element.trigger('slid') }, 0)
- })
- } else {
- this.$element.trigger(e)
- if (e.isDefaultPrevented()) return
- $active.removeClass('active')
- $next.addClass('active')
- this.sliding = false
- this.$element.trigger('slid')
- }
-
- isCycling && this.cycle()
-
- return this
- }
-
- }
-
-
- /* CAROUSEL PLUGIN DEFINITION
- * ========================== */
-
- $.fn.carousel = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('carousel')
- , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
- , action = typeof option == 'string' ? option : options.slide
- if (!data) $this.data('carousel', (data = new Carousel(this, options)))
- if (typeof option == 'number') data.to(option)
- else if (action) data[action]()
- else if (options.interval) data.cycle()
- })
- }
-
- $.fn.carousel.defaults = {
- interval: 5000
- , pause: 'hover'
- }
-
- $.fn.carousel.Constructor = Carousel
-
-
- /* CAROUSEL DATA-API
- * ================= */
-
- $(function () {
- $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
- var $this = $(this), href
- , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
- , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
- $target.carousel(options)
- e.preventDefault()
- })
- })
-
-}(window.jQuery);
View
158 frontend/app/scripts/vendor/bootstrap/bootstrap-collapse.js
@@ -1,158 +0,0 @@
-/* =============================================================
- * bootstrap-collapse.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#collapse
- * =============================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============================================================ */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* COLLAPSE PUBLIC CLASS DEFINITION
- * ================================ */
-
- var Collapse = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, $.fn.collapse.defaults, options)
-
- if (this.options.parent) {
- this.$parent = $(this.options.parent)
- }
-
- this.options.toggle && this.toggle()
- }
-
- Collapse.prototype = {
-
- constructor: Collapse
-
- , dimension: function () {
- var hasWidth = this.$element.hasClass('width')
- return hasWidth ? 'width' : 'height'
- }
-
- , show: function () {
- var dimension
- , scroll
- , actives
- , hasData
-
- if (this.transitioning) return
-
- dimension = this.dimension()
- scroll = $.camelCase(['scroll', dimension].join('-'))
- actives = this.$parent && this.$parent.find('> .accordion-group > .in')
-
- if (actives && actives.length) {
- hasData = actives.data('collapse')
- if (hasData && hasData.transitioning) return
- actives.collapse('hide')
- hasData || actives.data('collapse', null)
- }
-
- this.$element[dimension](0)
- this.transition('addClass', $.Event('show'), 'shown')
- $.support.transition && this.$element[dimension](this.$element[0][scroll])
- }
-
- , hide: function () {
- var dimension
- if (this.transitioning) return
- dimension = this.dimension()
- this.reset(this.$element[dimension]())
- this.transition('removeClass', $.Event('hide'), 'hidden')
- this.$element[dimension](0)
- }
-
- , reset: function (size) {
- var dimension = this.dimension()
-
- this.$element
- .removeClass('collapse')
- [dimension](size || 'auto')
- [0].offsetWidth
-
- this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
-
- return this
- }
-
- , transition: function (method, startEvent, completeEvent) {
- var that = this
- , complete = function () {
- if (startEvent.type == 'show') that.reset()
- that.transitioning = 0
- that.$element.trigger(completeEvent)
- }
-
- this.$element.trigger(startEvent)
-
- if (startEvent.isDefaultPrevented()) return
-
- this.transitioning = 1
-
- this.$element[method]('in')
-
- $.support.transition && this.$element.hasClass('collapse') ?
- this.$element.one($.support.transition.end, complete) :
- complete()
- }
-
- , toggle: function () {
- this[this.$element.hasClass('in') ? 'hide' : 'show']()
- }
-
- }
-
-
- /* COLLAPSIBLE PLUGIN DEFINITION
- * ============================== */
-
- $.fn.collapse = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('collapse')
- , options = typeof option == 'object' && option
- if (!data) $this.data('collapse', (data = new Collapse(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- $.fn.collapse.defaults = {
- toggle: true
- }
-
- $.fn.collapse.Constructor = Collapse
-
-
- /* COLLAPSIBLE DATA-API
- * ==================== */
-
- $(function () {
- $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
- var $this = $(this), href
- , target = $this.attr('data-target')
- || e.preventDefault()
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
- , option = $(target).data('collapse') ? 'toggle' : $this.data()
- $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
- $(target).collapse(option)
- })
- })
-
-}(window.jQuery);
View
150 frontend/app/scripts/vendor/bootstrap/bootstrap-dropdown.js
@@ -1,150 +0,0 @@
-/* ============================================================
- * bootstrap-dropdown.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#dropdowns
- * ============================================================
- * Copyright 2012 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============================================================ */
-
-
-!function ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* DROPDOWN CLASS DEFINITION
- * ========================= */
-
- var toggle = '[data-toggle=dropdown]'
- , Dropdown = function (element) {
- var $el = $(element).on('click.dropdown.data-api', this.toggle)
- $('html').on('click.dropdown.data-api', function () {
- $el.parent().removeClass('open')
- })
- }
-
- Dropdown.prototype = {
-
- constructor: Dropdown
-
- , toggle: function (e) {
- var $this = $(this)
- , $parent
- , isActive
-
- if ($this.is('.disabled, :disabled')) return
-
- $parent = getParent($this)
-
- isActive = $parent.hasClass('open')
-
- clearMenus()
-
- if (!isActive) {
- $parent.toggleClass('open')
- $this.focus()
- }
-
- return false
- }
-
- , keydown: function (e) {
- var $this
- , $items
- , $active
- , $parent
- , isActive
- , index
-
- if (!/(38|40|27)/.test(e.keyCode)) return
-
- $this = $(this)
-
- e.preventDefault()
- e.stopPropagation()
-
- if ($this.is('.disabled, :disabled')) return
-
- $parent = getParent($this)
-
- isActive = $parent.hasClass('open')
-
- if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
-
- $items = $('[role=menu] li:not(.divider) a', $parent)
-
- if (!$items.length) return
-
- index = $items.index($items.filter(':focus'))
-
- if (e.keyCode == 38 && index > 0) index-- // up
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
-
- $items
- .eq(index)
- .focus()
- }
-
- }
-
- function clearMenus() {
- getParent($(toggle))
- .removeClass('open')
- }
-
- function getParent($this) {
- var selector = $this.attr('data-target')
- , $parent
-
- if (!selector) {
- selector = $this.attr('href')
- selector