commontator 4.10.5 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -2
  3. data/Rakefile +8 -9
  4. data/app/assets/javascripts/commontator/application.js +3 -0
  5. data/app/assets/javascripts/commontator/application.js~ +3 -0
  6. data/app/assets/javascripts/commontator/mentions.js +32 -0
  7. data/app/assets/javascripts/commontator/mentions.js~ +31 -0
  8. data/app/assets/stylesheets/commontator/application.css +1 -9
  9. data/app/assets/stylesheets/commontator/application.css~ +14 -0
  10. data/app/assets/stylesheets/commontator/threads.css +5 -0
  11. data/app/assets/stylesheets/commontator/threads.css~ +71 -0
  12. data/app/controllers/commontator/comments_controller.rb +8 -0
  13. data/app/controllers/commontator/comments_controller.rb~ +160 -0
  14. data/app/controllers/commontator/threads_controller.rb +21 -0
  15. data/app/controllers/commontator/threads_controller.rb~ +75 -0
  16. data/app/mailers/commontator/subscriptions_mailer.rb +31 -13
  17. data/app/mailers/commontator/subscriptions_mailer.rb~ +65 -0
  18. data/app/models/commontator/comment.rb~ +124 -0
  19. data/app/models/commontator/subscription.rb~ +23 -0
  20. data/app/views/commontator/comments/_form.html.erb +1 -0
  21. data/app/views/commontator/comments/_list.html.erb +1 -1
  22. data/app/views/commontator/shared/_thread.html.erb +2 -4
  23. data/app/views/commontator/shared/_thread.html.erb~ +21 -0
  24. data/app/views/commontator/subscriptions_mailer/comment_created.html.erb +1 -1
  25. data/app/views/commontator/subscriptions_mailer/comment_created.html.erb~ +10 -0
  26. data/app/views/commontator/threads/_hide_show.js.erb~ +21 -0
  27. data/app/views/commontator/threads/_hide_show_links.js.erb +17 -0
  28. data/app/views/commontator/threads/_hide_show_links.js.erb~ +17 -0
  29. data/app/views/commontator/threads/_show.html.erb +96 -72
  30. data/app/views/commontator/threads/_show.html.erb~ +118 -0
  31. data/app/views/commontator/threads/_show.js.erb~ +18 -0
  32. data/config/initializers/commontator.rb +39 -8
  33. data/config/initializers/commontator.rb~ +290 -0
  34. data/config/locales/en.yml +3 -2
  35. data/config/locales/en.yml~ +101 -0
  36. data/config/locales/ru.yml +3 -2
  37. data/config/locales/ru.yml~ +79 -0
  38. data/config/locales/zh.yml +79 -0
  39. data/config/locales/zh.yml~ +79 -0
  40. data/config/routes.rb +2 -0
  41. data/config/routes.rb~ +25 -0
  42. data/db/migrate/0_install_commontator.rb~ +52 -0
  43. data/db/migrate/1_add_parent_comment_id_to_commontator_comments.rb~ +9 -0
  44. data/lib/commontator.rb +16 -9
  45. data/lib/commontator.rb~ +145 -0
  46. data/lib/commontator/{controller_includes.rb → controllers.rb} +2 -2
  47. data/lib/commontator/shared_helper.rb~ +26 -0
  48. data/lib/commontator/version.rb +1 -1
  49. data/lib/commontator/version.rb~ +3 -0
  50. data/spec/controllers/commontator/comments_controller_spec.rb +46 -0
  51. data/spec/controllers/commontator/comments_controller_spec.rb~ +612 -0
  52. data/spec/controllers/commontator/subscriptions_controller_spec.rb~ +101 -0
  53. data/spec/controllers/commontator/threads_controller_spec.rb +88 -0
  54. data/spec/controllers/commontator/threads_controller_spec.rb~ +218 -0
  55. data/spec/dummy/README.md~ +3 -0
  56. data/spec/dummy/Rakefile~ +6 -0
  57. data/spec/dummy/app/assets/javascripts/application.js +1 -0
  58. data/spec/dummy/app/assets/javascripts/application.js~ +16 -0
  59. data/spec/dummy/app/assets/stylesheets/application.css +1 -0
  60. data/spec/dummy/app/assets/stylesheets/application.css~ +14 -0
  61. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  62. data/spec/dummy/app/controllers/application_controller.rb~ +4 -0
  63. data/spec/dummy/app/controllers/dummy_models_controller.rb +3 -15
  64. data/spec/dummy/app/controllers/dummy_models_controller.rb~ +23 -0
  65. data/spec/dummy/app/helpers/application_helper.rb~ +15 -0
  66. data/spec/dummy/app/models/dummy_model.rb~ +3 -0
  67. data/spec/dummy/app/models/dummy_user.rb~ +13 -0
  68. data/spec/dummy/app/views/dummy_models/index.html.erb~ +6 -0
  69. data/spec/dummy/app/views/{dummy_model → dummy_models}/show.html.erb +0 -0
  70. data/spec/dummy/app/views/dummy_models/show.html.erb~ +2 -0
  71. data/spec/dummy/app/views/layouts/application.html.erb~ +14 -0
  72. data/spec/dummy/config.ru~ +4 -0
  73. data/spec/dummy/config/application.rb~ +26 -0
  74. data/spec/dummy/config/boot.rb~ +5 -0
  75. data/spec/dummy/config/database.yml~ +25 -0
  76. data/spec/dummy/config/environment.rb +2 -0
  77. data/spec/dummy/config/environment.rb~ +8 -0
  78. data/spec/dummy/config/environments/development.rb~ +31 -0
  79. data/spec/dummy/config/environments/production.rb~ +82 -0
  80. data/spec/dummy/config/environments/test.rb~ +40 -0
  81. data/spec/dummy/config/initializers/backtrace_silencers.rb~ +7 -0
  82. data/spec/dummy/config/initializers/commontator.rb +5 -0
  83. data/spec/dummy/config/initializers/commontator.rb~ +21 -0
  84. data/spec/dummy/config/initializers/filter_parameter_logging.rb~ +4 -0
  85. data/spec/dummy/config/initializers/inflections.rb~ +16 -0
  86. data/spec/dummy/config/initializers/mime_types.rb~ +5 -0
  87. data/spec/dummy/config/initializers/secret_token.rb~ +12 -0
  88. data/spec/dummy/config/initializers/session_store.rb~ +3 -0
  89. data/spec/dummy/config/initializers/wrap_parameters.rb~ +14 -0
  90. data/spec/dummy/config/routes.rb +4 -2
  91. data/spec/dummy/config/routes.rb~ +10 -0
  92. data/spec/dummy/db/development.sqlite3 +0 -0
  93. data/spec/dummy/db/migrate/1_create_dummy_models.rb~ +7 -0
  94. data/spec/dummy/db/migrate/2_create_dummy_users.rb~ +7 -0
  95. data/spec/dummy/db/migrate/3_acts_as_votable_migration.rb~ +27 -0
  96. data/spec/dummy/db/schema.rb +6 -6
  97. data/spec/dummy/db/test.sqlite3 +0 -0
  98. data/spec/dummy/lib/controllers.rb~ +10 -0
  99. data/spec/dummy/lib/dummy_controllers.rb +10 -0
  100. data/spec/dummy/log/development.log +5825 -29
  101. data/spec/dummy/log/test.log +111962 -32939
  102. data/spec/dummy/public/404.html~ +26 -0
  103. data/spec/dummy/public/422.html~ +26 -0
  104. data/spec/dummy/public/500.html~ +25 -0
  105. data/spec/dummy/script/rails~ +6 -0
  106. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/-RolHYhJdGiLoPkoWZXQdI9AIWUjMMCa2yFJezCE_Bo.cache +2 -0
  107. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/-STzK7UuGeY3gSvnmTELWLvtRMKpmSAQCEw4ao3b1r8.cache +1 -0
  108. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/3NH8nN7uktAXgA3NqaqXTXDVic3BxBvqCxoLpGGbib4.cache +0 -0
  109. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/4_iT7KM6P2IT75Rssrk9p4crTBwM8DQWR41gmsxczL0.cache +0 -0
  110. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/58TLCXvf5bFFYY-mIUXrQNOVWlGsq7qPAoSX2OIIB8Y.cache +0 -0
  111. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/6OQdyrATvNatvWu8Mp1qbuvRx-HLmzCZ5XBGYca-rZU.cache +0 -0
  112. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/6UKCUV-ZLaWCoPMfMB6a2W0RCFPQzPJ6Mz-y67sH7zk.cache +2 -0
  113. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/6wKNjFdNd4OHjIpLC0nq1kBWcbYg1aEYrp7ZhWoJlvY.cache +1 -0
  114. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/7Xxb5iYP5elo40JRlhNQB1gLbv3ueELK2rTinYt5xdc.cache +1 -0
  115. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/7twIKlS6VYCyLlwhsQg2vu4wLSUJsT2REHR4DjZf1oE.cache +2 -0
  116. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/87m-4EcbQnkbo2HYkQp4V9I2U3AYQO1mPeReieduolA.cache +1 -0
  117. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/8B331vt8qC4iXTcVzkx3j-ET8i1oaQskj5LyqGq8mPQ.cache +0 -0
  118. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/8KWvIOgvo7BVJYtdTpFuiSQQFFwZhLWYtwacZv52y48.cache +0 -0
  119. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/9yQa5M2ObK2-qDu231zMoarjVbhKUUg-ND3r2iXqB_Q.cache +0 -0
  120. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/A-ffuUI2juZT6qFpTUwUR1P8OPWcyFFN26WSUZe60Ko.cache +1 -0
  121. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/BbO4diS6uacx69Hn_bCabYlXEbWWdjHShRlfzlWSOMI.cache +0 -0
  122. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/CXhqxaQQAQ8b0Y8y0jTQyiqsZ6Oe4fZn0YiacpJ9IoI.cache +1 -0
  123. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/E1zaNOh68xzPxdtdOwRtOaMCoKivN2dxVwCP65WEi5I.cache +2 -0
  124. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/EmPkV3H8p2Snv9WyPjWran_kOMQ0MqQ1a9CVdGDd8l4.cache +1 -0
  125. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Hc12Nxe7cw2e0u2pzNsAe8D3ncQpcqLuI2NVL7aAXgw.cache +1 -0
  126. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/HdWuQr9W2mZvggsAxVjDgLYUNfg3rbI-T8KhaDIsvQk.cache +0 -0
  127. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/I7lsrHTKpbfLWqIqdDIx2RN_12yFL2PyLRyYsMxg1IU.cache +1 -0
  128. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/JOCzfBjMjX3D5BUUGh5lJ7fjzMuJrHLxAginRA2_hZQ.cache +0 -0
  129. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/JusxTSXt06IqBm9jeCMM2nTmM3Wvbl3i3L1IwEvW5YA.cache +2 -0
  130. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/KAY1_IaTONtGr0KK8ihOdoA-RDXybqBMNSZLIDRHx68.cache +1 -0
  131. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/KBHIDNfa4ryw9LAkYqK8GgPWne7HkX6mNYgrJajGm94.cache +1 -0
  132. data/spec/dummy/tmp/cache/assets/{test/sprockets/v3.0/E6KZN1luOC7jAKXFS_xo-XOd5H41vK-eeCsj8MITJHA.cache → development/sprockets/v3.0/L_lv02y00MmIFiFhg5c9zhl7CDHLSahehzLyi_mRZeY.cache} +0 -0
  133. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/MOT2X4iikR8v89A4N1bxDTeS1-xV8c9036TNFXmwXCM.cache +1 -0
  134. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/MiX2Z4Vbha1riozZWw1U3_PGttRiZ1iQ_o4wSZJnKCs.cache +3 -0
  135. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/MntKfwol0ud4LuvrX3MVPthTlfNlJZRYbQXpQBxhRrs.cache +1 -0
  136. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/MrqmgPGNYJV1capJKIKJOVEQ4NiO-Z_2YhpjNteJ8B8.cache +2 -0
  137. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/NVMnAwylzGp5bjl_o9dwMAQxVAPDzc4ygddNQSD1fiw.cache +0 -0
  138. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/O2sKqGxNuCYhjzuEZVC9hX_FeemOfRn_1-CCuHBQYyg.cache +1 -0
  139. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Qy3TykLFmAt5jhSluMTaZaefcA5c_vfBRhQ7tin-gsk.cache +0 -0
  140. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/R3DpUgZ_hja1dQTIzumiP9AD_r8mlOaqv0U9QqnGQqo.cache +0 -0
  141. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/RF07mgb06A30OcDWtCaDlM5tEc1yp0uAsk986Gqs5w8.cache +1 -0
  142. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/S-6Iq5YOEpVnd_vQ0RSSfrmyIwB1dk0op35alFgJ9xA.cache +2 -0
  143. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/TKV8dUTo88gdFY-z2I7Xa5vDC1Z3LY6Paa18385MJsI.cache +1 -0
  144. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/UI4zPmWfZA2d_5ZZIXqK9KmkjOKSDg6JoM7qcOIxm0Q.cache +1 -0
  145. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/UP29vrIQbCkfghZGSCFxpW5gjlsgCxlVrncjjopvRqM.cache +2 -0
  146. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/UoU16f4V7haEXM5GY5j4QFuNMP7PJZaAMEvVNNtNLBA.cache +1 -0
  147. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/VqPqYNG07yqcjbd7FA05Mu-jr5hzsZPaHFf8X0FFbXk.cache +2 -0
  148. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/WkN1QFvcuzXSsyNmfaK02ojXPk-8zmdEegzNPfdAEL4.cache +0 -0
  149. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/WkQX7Wiz41OKx2aGF7uffOmS04hIVZeGCondBAvwum8.cache +2 -0
  150. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/XMeYF1vwAg53eVjXVkw_IKQH2W3-9tWvtuCdqUCbPBM.cache +2 -0
  151. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/XX0Z7OM0xZKfQaAvHARpyeQNZCstNyu9MlsnwThSkg8.cache +1 -0
  152. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Y-pGNFTA6bAKxSvqZvmMVs3b4Els1aByxZVFxtJR71c.cache +1 -0
  153. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Y3p3m5V5NOm7yq56apKmF5KZUUsTfnhT_SG3fqbEJgo.cache +1 -0
  154. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/YLZuRWklL6q-csC-7A7CiOTTTYEQcA9PCdWEOm9MpNU.cache +1 -0
  155. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Yo7V5YXukEBm6z37l-TIRCJx3HZExEUBu3MUMhAzkMU.cache +1 -0
  156. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/bK6QttR8pGmMAMJO0avCBLwH0za8_bAC-yWqkU3Yj24.cache +1 -0
  157. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/cLncjrqpQXzsVBp7K0W7iG1STLrnzfGpbJXxNE7aIUk.cache +2 -0
  158. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/dBcAd64EZFdhHZNXKGXPIR7EtPGf03bzqkci2W12T8g.cache +2 -0
  159. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/d_bbPiareJHKkzFZFCl3pcwfQOFzsB1KHn4A2xxhR20.cache +1 -0
  160. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/eaHZBuJRcawVlkGZVyyRr5_4xYKVOXbCqnTcmaNXzL0.cache +0 -0
  161. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/gWnmfJty3jBn53qsJfOXKrWv4e8i3Dp80wVel-f1L1E.cache +1 -0
  162. data/spec/dummy/tmp/cache/assets/{test/sprockets/v3.0/SN7TWtuyq1ZblzWxqqcr26s_vanAr5PyZ8q_w8IxIPE.cache → development/sprockets/v3.0/gumo32Bd3W_q7MYEt9JIZEiQdHF93tLSsGfmXIm2MqU.cache} +0 -0
  163. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/jKTlG9KP0iaCGHwg8kQ1amz9SHJ1OAWeCRRn9wc5w7c.cache +1 -0
  164. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/kPJfTiWbmX-q6i2rjM9MAMdEf2silSihU0_lxlTGVA8.cache +1 -0
  165. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/lrt1SWPj4qWUZUMH9xg3n9KLYUqJZxRn-XI-NTU6oTI.cache +1 -0
  166. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/mcCP5u08nlCL6TgWdzzrem9uE2rbsbG3KyIXxvWvlJE.cache +3 -0
  167. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/pC4exGjkQLXXPE0O9hjX_2AJ4DASTFeB6RGjXagxEac.cache +0 -0
  168. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/pIRh_Lq-ZhYC_XdRcqIsCtUkTnwVET0Wrrpw1EltHd8.cache +2 -0
  169. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/qfXc71sDbi1cE9f327D6ABPURPU6lLguGiJqH2fqM0w.cache +1 -0
  170. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/rBcrkzXcMaiCjwvWl8tO0eARzKZS69I3i-lfsTAFzcc.cache +1 -0
  171. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/sfl8l1_1AGn-4llkmb91Q0wHJ-A-x5gAGkIUWe1zLqo.cache +1 -0
  172. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/tFQc0MOeWpJ7t7cNP2GOzo7o9Z6YBgLEpdS0tGLvUSw.cache +0 -0
  173. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/tb9v5OemP-ADEwYnETLLi1r088kZm_TMb9ZVeTV5JxI.cache +1 -0
  174. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/uKmWfbgaNZ8FTsVK1VNuUv15rmtTHzSdJ7TQRGr0Rck.cache +2 -0
  175. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/ul0QEoovfr_12YOpyWx8BJs8fvz5Ay3AZG8-lsLr-a4.cache +1 -0
  176. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/vY6eUgBIXKHqfU2ZroS-GugKPg5_fo2QBs-vS5gBN2o.cache +0 -0
  177. data/spec/dummy/tmp/cache/assets/{test/sprockets/v3.0/Kg9VuIGtHRNvM4_TXG3EmqpEWzfEY1kQUI1Mx8AHklY.cache → development/sprockets/v3.0/vrRc4DPAbHIJHJqsXfBYdyKUPFv8f8YYKJUrk-1zdVw.cache} +0 -0
  178. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/wTET4PQq7wlxzrgvNivPJad-CACkoQS4BNxAP0FQaR4.cache +0 -0
  179. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/wcvE87iLx7cDjMDs_Yu1jKYvep-VyLEyj1eXL79KLp4.cache +0 -0
  180. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/xQeZ92qbm2t9FaRck5xUakvNP-MJ2cs0RroN-fm0Tf8.cache +1 -0
  181. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/xQz9WPf67Mu5uV4rNuOfU-y6_KWSlWcnTWrTvQPonKM.cache +0 -0
  182. data/spec/dummy/tmp/cache/assets/{test/sprockets/v3.0/CT_fvD-uYyN5f1Kis6kQ7DNUnwtnSVT1sdDKxW1e4hw.cache → development/sprockets/v3.0/xhYTRUOS8cIvyRp2Jn6FKnXlGOSsIM2z3HAGOJoJs7w.cache} +0 -0
  183. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/yLxMFI0ARh2OKSOQLF2xEfM7sbst2vUbOBXoOuI6iTE.cache +1 -0
  184. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/ynnYZxuxqerlFUytw54dl_CwP94g0U4HmGjyILWnhfQ.cache +1 -0
  185. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/zCivVPbSRpKF_X-P5OJeld32YhymG-bkjQwzqe2o6zg.cache +2 -0
  186. data/spec/dummy/tmp/cache/assets/test/sprockets/{72b63dddbc5c995f79af8e3c94904fd9 → 02d4b791eb831cf2057bf4703a1218d1} +0 -0
  187. data/spec/dummy/tmp/cache/assets/test/sprockets/{a77b1a9223d168112e1705c29220116f → 0f196a1a50363b0a076ec6e1ee5417f6} +0 -0
  188. data/spec/dummy/tmp/cache/assets/test/sprockets/{afa63eb365bdf4f42584b17ac9176b9d → a3fb9025f90ff05a6fd4afc7ded2692c} +0 -0
  189. data/spec/dummy/tmp/cache/assets/test/sprockets/a41c8be5379abec3c0d0d98e2f0d5609 +0 -0
  190. data/spec/dummy/tmp/cache/assets/test/sprockets/{a473b3873e554893372a53d71f5e9879 → c69ee3cc5796188d873574179290a6ef} +0 -0
  191. data/spec/dummy/tmp/cache/assets/test/sprockets/{f721383d531f067d82b071e14aed7a92 → e1f674c11941d62aac1764ef3a7134e4} +0 -0
  192. data/spec/dummy/tmp/cache/assets/test/sprockets/{d2244ccef8e05bb993f75715af0344cc → e85565206c3e5fdf9dfeb367c85557b1} +0 -0
  193. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/-gXoYfEJ-e9QQUbNRpNa-pwMCnTc7Eqvkq6Bosde6W8.cache +0 -0
  194. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/6iNAIrMKxHltOChiHQQf9VNsLQuj2rVKz6oqWnK7aSM.cache +1 -0
  195. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/E1zaNOh68xzPxdtdOwRtOaMCoKivN2dxVwCP65WEi5I.cache +2 -0
  196. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/HsNbq1o4RbrEWNL4zXVqFfUVnXXLK_y0F0BvddDre6g.cache +0 -0
  197. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/JusxTSXt06IqBm9jeCMM2nTmM3Wvbl3i3L1IwEvW5YA.cache +2 -0
  198. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/L5DjABL_iOtoxSOLn3X7_YlxECU5EhnrVIKxJFAysgc.cache +1 -0
  199. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/PNc9TJUmRdGTSwgZvGlxKaIiJIkyoWtTPiGGWBqpHAE.cache +0 -0
  200. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/QkgTHa6nNs7XP6RPoV3yBbWWV-uo1u2-qxLuvLCFe_0.cache +0 -0
  201. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/S-6Iq5YOEpVnd_vQ0RSSfrmyIwB1dk0op35alFgJ9xA.cache +2 -0
  202. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Vuc93A9yywiFxc9CAdxrzdsAQw4jxiCa6JRzRjNxOYs.cache +1 -0
  203. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/YAPBll4U0cgs6cz-WyMRKoakK_gVOOcl9n0CvGyxPjY.cache +1 -0
  204. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/bDNeZfPBQaef5z0YajZc4jFE54nNy9gc06mPNKvvPFk.cache +1 -0
  205. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/c5Wa2loowFYFRBaMoTn1IWYXo4BGMbEy7NIi0vbvfRU.cache +1 -0
  206. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/dkn8MYu2ve_AJW6u0jjTlKrj1KBRqorOHQR0Obx2elU.cache +0 -0
  207. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/fZuAzt_-48u9C7ZXmsPgTraGDYtNC9B9zN-9-EnxJG4.cache +1 -0
  208. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/gumo32Bd3W_q7MYEt9JIZEiQdHF93tLSsGfmXIm2MqU.cache +1 -0
  209. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/ige85jXyj8X7XYr7HpA0gSTThqfPUm71HjhSJXtTbUY.cache +1 -0
  210. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/kuYeE5bV6FdXmfB_o-xhflhSDWoQhYYaaupAXODZ9dQ.cache +1 -0
  211. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/qhZbbNIRUaAOtGano94zLHjeBKUhKr4qbh2tTCi0Bnk.cache +2 -0
  212. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/wJJbzdHJHP6tchng3HhfTwmjc5LursgX8yZkAjpO5UA.cache +0 -0
  213. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/xNL1WW-qU3EvV2iTSW6F4hAFRBsCYmFKJhLjgCZkOV8.cache +2 -0
  214. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/ytHkF2DwUE6oaiLyrK6tL-0INpeNhjN6ctD7J0LNY6I.cache +2 -0
  215. data/spec/helpers/commontator/application_helper_spec.rb~ +9 -0
  216. data/spec/lib/commontator/acts_as_commontable_spec.rb~ +25 -0
  217. data/spec/lib/commontator/acts_as_commontator_spec.rb~ +52 -0
  218. data/spec/lib/commontator/commontable_config_spec.rb~ +29 -0
  219. data/spec/lib/commontator/commontator_config_spec.rb~ +29 -0
  220. data/spec/lib/commontator/controller_includes_spec.rb~ +18 -0
  221. data/spec/lib/commontator/controllers_spec.rb +18 -0
  222. data/spec/lib/commontator/{controller_includes_spec.rb → controllers_spec.rb~} +0 -0
  223. data/spec/lib/commontator/shared_helper_spec.rb~ +22 -0
  224. data/spec/lib/commontator_spec.rb~ +26 -0
  225. data/spec/mailers/commontator/subscriptions_mailer_spec.rb +21 -1
  226. data/spec/mailers/commontator/subscriptions_mailer_spec.rb~ +30 -0
  227. data/spec/models/commontator/comment_spec.rb~ +82 -0
  228. data/spec/models/commontator/subscription_spec.rb~ +38 -0
  229. data/spec/models/commontator/thread_spec.rb~ +122 -0
  230. data/spec/rails_helper.rb~ +74 -0
  231. data/spec/spec_helper.rb +1 -0
  232. data/spec/spec_helper.rb~ +93 -0
  233. data/vendor/assets/javascripts/mentionsInput/index.js~ +3 -0
  234. data/vendor/assets/javascripts/mentionsInput/jquery.mentionsInput.js +538 -0
  235. data/vendor/assets/javascripts/underscore/underscore.js +1590 -0
  236. data/vendor/assets/stylesheets/mentionsInput/jquery.mentionsInput.css +114 -0
  237. metadata +445 -100
  238. data/spec/dummy/tmp/cache/assets/test/sprockets/decb63cac838a5314aa0c22a979f5ac9 +0 -0
  239. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/2MuTpyqaQLj1O4wgROKGqNe4lXIGrVZDYXCWWWMRmrA.cache +0 -0
  240. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/4CjNCL1K4fowKckGvL9F3HkCEtCH42rfsn2geU5A1xs.cache +0 -0
  241. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/CjR916jO_S7Mo8eTI1vKieKJoKQ0t-bk4sxhcYYQ5Bw.cache +0 -1
  242. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/DtzP3rNdkPulzFug4nVQunOws8OXjvPJwB2nNhp9Scs.cache +0 -0
  243. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/FmvRMZstlcKHCKy5g4mmAu4vjz-YPScTigFnnvs1v-E.cache +0 -1
  244. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/HXtFVXhiLFEohXrf9PBX2u9xkPew5yU2IOyxmFCa7fo.cache +0 -2
  245. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Kqg37VotFbWELQyr3-R20M2yWWoiloqBWDWRG-i3m5E.cache +0 -2
  246. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/PeZjQ1KGvso4tt6qvVQZniMzlTlVTWeH-tjln1fERkw.cache +0 -1
  247. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/VH5BWA_SC2XnIxStJ5vtjX3pNqdbo7uMo9Tg9GVFUGU.cache +0 -1
  248. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/lzmR_-kjjgHYgaJd_fvBlAimt7_xADtnhEPo_CIBiPM.cache +0 -1
  249. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/q3giWdNvlLQ39xIHQWPY8vzbfjW9zXkSqwibRQBKcvM.cache +0 -2
  250. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/zpCVMbdGU9JtJWkk95WWomNsxP3Q7jqZmWKJXnsGH0g.cache +0 -2
@@ -0,0 +1,74 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require 'spec_helper'
4
+ require File.expand_path("../dummy/config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+ # Add additional requires below this line. Rails is not loaded until this point!
7
+
8
+ # Requires supporting ruby files with custom matchers and macros, etc, in
9
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
10
+ # run as spec files by default. This means that files in spec/support that end
11
+ # in _spec.rb will both be required and run as specs, causing the specs to be
12
+ # run twice. It is recommended that you do not name files matching this glob to
13
+ # end with _spec.rb. You can configure this pattern with the --pattern
14
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
15
+ #
16
+ # The following line is provided for convenience purposes. It has the downside
17
+ # of increasing the boot-up time by auto-requiring all files in the support
18
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
19
+ # require only the support files necessary.
20
+ #
21
+ # Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
22
+
23
+ # Checks for pending migrations before tests are run.
24
+ # If you are not using ActiveRecord, you can remove this line.
25
+ ActiveRecord::Migration.maintain_test_schema!
26
+
27
+ RSpec.configure do |config|
28
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
29
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
30
+
31
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
32
+ # examples within a transaction, remove the following line or assign false
33
+ # instead of true.
34
+ config.use_transactional_fixtures = true
35
+
36
+ # RSpec Rails can automatically mix in different behaviours to your tests
37
+ # based on their file location, for example enabling you to call `get` and
38
+ # `post` in specs under `spec/controllers`.
39
+ #
40
+ # You can disable this behaviour by removing the line below, and instead
41
+ # explicitly tag your specs with their type, e.g.:
42
+ #
43
+ # RSpec.describe UsersController, :type => :controller do
44
+ # # ...
45
+ # end
46
+ #
47
+ # The different available types are documented in the features, such as in
48
+ # https://relishapp.com/rspec/rspec-rails/docs
49
+ config.infer_spec_type_from_file_location!
50
+ end
51
+
52
+ Commontator::ApplicationController.class_eval do
53
+ include ApplicationHelper
54
+ end
55
+
56
+ def setup_model_spec
57
+ @user = DummyUser.create
58
+ @commontable = DummyModel.create
59
+ @thread = @commontable.thread
60
+ end
61
+
62
+ def setup_controller_spec
63
+ class_eval {include ApplicationHelper}
64
+ sign_out
65
+ setup_model_spec
66
+ end
67
+
68
+ def setup_helper_spec
69
+ end
70
+
71
+ def setup_mailer_spec
72
+ setup_model_spec
73
+ end
74
+
@@ -6,6 +6,7 @@ else
6
6
  SimpleCov.start 'rails'
7
7
  end
8
8
 
9
+ require 'byebug'
9
10
  require 'rspec/core'
10
11
 
11
12
  # This file was generated by the `rails generate rspec:install` command. Conventionally, all
@@ -0,0 +1,93 @@
1
+ if ENV['CODECLIMATE_REPO_TOKEN']
2
+ require 'codeclimate-test-reporter'
3
+ CodeClimate::TestReporter.start
4
+ else
5
+ require 'simplecov'
6
+ SimpleCov.start 'rails'
7
+ end
8
+
9
+ require 'rspec/core'
10
+
11
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
12
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
13
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
14
+ # file to always be loaded, without a need to explicitly require it in any files.
15
+ #
16
+ # Given that it is always loaded, you are encouraged to keep this file as
17
+ # light-weight as possible. Requiring heavyweight dependencies from this file
18
+ # will add to the boot time of your test suite on EVERY test run, even for an
19
+ # individual file that may not need all of that loaded. Instead, consider making
20
+ # a separate helper file that requires the additional dependencies and performs
21
+ # the additional setup, and require it from the spec files that actually need it.
22
+ #
23
+ # The `.rspec` file also contains a few flags that are not defaults but that
24
+ # users commonly want.
25
+ #
26
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
27
+ RSpec.configure do |config|
28
+ # rspec-expectations config goes here. You can use an alternate
29
+ # assertion/expectation library such as wrong or the stdlib/minitest
30
+ # assertions if you prefer.
31
+ config.expect_with :rspec do |expectations|
32
+ # This option will default to `true` in RSpec 4. It makes the `description`
33
+ # and `failure_message` of custom matchers include text for helper methods
34
+ # defined using `chain`, e.g.:
35
+ # be_bigger_than(2).and_smaller_than(4).description
36
+ # # => "be bigger than 2 and smaller than 4"
37
+ # ...rather than:
38
+ # # => "be bigger than 2"
39
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
40
+ end
41
+
42
+ # rspec-mocks config goes here. You can use an alternate test double
43
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
44
+ config.mock_with :rspec do |mocks|
45
+ # Prevents you from mocking or stubbing a method that does not exist on
46
+ # a real object. This is generally recommended, and will default to
47
+ # `true` in RSpec 4.
48
+ mocks.verify_partial_doubles = true
49
+ end
50
+
51
+ # The settings below are suggested to provide a good initial experience
52
+ # with RSpec, but feel free to customize to your heart's content.
53
+ # These two settings work together to allow you to limit a spec run
54
+ # to individual examples or groups you care about by tagging them with
55
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
56
+ # get run.
57
+ config.filter_run :focus
58
+ config.run_all_when_everything_filtered = true
59
+
60
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
61
+ # For more details, see:
62
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
63
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
64
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
65
+ config.disable_monkey_patching!
66
+
67
+ # Many RSpec users commonly either run the entire suite or an individual
68
+ # file, and it's useful to allow more verbose output when running an
69
+ # individual spec file.
70
+ if config.files_to_run.one?
71
+ # Use the documentation formatter for detailed output,
72
+ # unless a formatter has already been configured
73
+ # (e.g. via a command-line flag).
74
+ config.default_formatter = 'doc'
75
+ end
76
+
77
+ # Print the 10 slowest examples and example groups at the
78
+ # end of the spec run, to help surface which specs are running
79
+ # particularly slow.
80
+ #config.profile_examples = 10
81
+
82
+ # Run specs in random order to surface order dependencies. If you find an
83
+ # order dependency and want to debug it, you can fix the order by providing
84
+ # the seed, which is printed after each run.
85
+ # --seed 1234
86
+ config.order = :random
87
+
88
+ # Seed global randomization in this process using the `--seed` CLI option.
89
+ # Setting this allows you to use `--seed` to deterministically reproduce
90
+ # test failures related to randomization by passing the same `--seed` value
91
+ # as the one that triggered the failure.
92
+ Kernel.srand config.seed
93
+ end
@@ -0,0 +1,3 @@
1
+ //= require underscore
2
+ //= require jquery.mentionsInput
3
+ //= require commontator/mentions
@@ -0,0 +1,538 @@
1
+ /*
2
+ * Mentions Input
3
+ * Version 1.0.2
4
+ * Written by: Kenneth Auchenberg (Podio)
5
+ *
6
+ * Using underscore.js
7
+ *
8
+ * License: MIT License - http://www.opensource.org/licenses/mit-license.php
9
+ */
10
+
11
+ (function ($, _, undefined) {
12
+
13
+ // Settings
14
+ var KEY = { BACKSPACE : 8, TAB : 9, RETURN : 13, ESC : 27, LEFT : 37, UP : 38, RIGHT : 39, DOWN : 40, COMMA : 188, SPACE : 32, HOME : 36, END : 35 }; // Keys "enum"
15
+
16
+ //Default settings
17
+ var defaultSettings = {
18
+ triggerChar : '@', //Char that respond to event
19
+ onDataRequest : $.noop, //Function where we can search the data
20
+ minChars : 2, //Minimum chars to fire the event
21
+ allowRepeat : false, //Allow repeat mentions
22
+ showAvatars : true, //Show the avatars
23
+ elastic : true, //Grow the textarea automatically
24
+ defaultValue : '',
25
+ onCaret : false,
26
+ classes : {
27
+ autoCompleteItemActive : "active" //Classes to apply in each item
28
+ },
29
+ templates : {
30
+ wrapper : _.template('<div class="mentions-input-box"></div>'),
31
+ autocompleteList : _.template('<div class="mentions-autocomplete-list"></div>'),
32
+ autocompleteListItem : _.template('<li data-ref-id="<%= id %>" data-ref-type="<%= type %>" data-display="<%= display %>"><%= content %></li>'),
33
+ autocompleteListItemAvatar : _.template('<img src="<%= avatar %>" />'),
34
+ autocompleteListItemIcon : _.template('<div class="icon <%= icon %>"></div>'),
35
+ mentionsOverlay : _.template('<div class="mentions"><div></div></div>'),
36
+ mentionItemSyntax : _.template('@[<%= value %>](<%= type %>:<%= id %>)'),
37
+ mentionItemHighlight : _.template('<strong><span><%= value %></span></strong>')
38
+ }
39
+ };
40
+
41
+ //Class util
42
+ var utils = {
43
+ //Encodes the character with _.escape function (undersocre)
44
+ htmlEncode : function (str) {
45
+ return _.escape(str);
46
+ },
47
+ //Encodes the character to be used with RegExp
48
+ regexpEncode : function (str) {
49
+ return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
50
+ },
51
+ highlightTerm : function (value, term) {
52
+ if (!term && !term.length) {
53
+ return value;
54
+ }
55
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
56
+ },
57
+ //Sets the caret in a valid position
58
+ setCaratPosition : function (domNode, caretPos) {
59
+ if (domNode.createTextRange) {
60
+ var range = domNode.createTextRange();
61
+ range.move('character', caretPos);
62
+ range.select();
63
+ } else {
64
+ if (domNode.selectionStart) {
65
+ domNode.focus();
66
+ domNode.setSelectionRange(caretPos, caretPos);
67
+ } else {
68
+ domNode.focus();
69
+ }
70
+ }
71
+ },
72
+ //Deletes the white spaces
73
+ rtrim: function(string) {
74
+ return string.replace(/\s+$/,"");
75
+ }
76
+ };
77
+
78
+ //Main class of MentionsInput plugin
79
+ var MentionsInput = function (settings) {
80
+
81
+ var domInput,
82
+ elmInputBox,
83
+ elmInputWrapper,
84
+ elmAutocompleteList,
85
+ elmWrapperBox,
86
+ elmMentionsOverlay,
87
+ elmActiveAutoCompleteItem,
88
+ mentionsCollection = [],
89
+ autocompleteItemCollection = {},
90
+ inputBuffer = [],
91
+ currentDataQuery = '';
92
+
93
+ //Mix the default setting with the users settings
94
+ settings = $.extend(true, {}, defaultSettings, settings );
95
+
96
+ //Initializes the text area target
97
+ function initTextarea() {
98
+ elmInputBox = $(domInput); //Get the text area target
99
+
100
+ //If the text area is already configured, return
101
+ if (elmInputBox.attr('data-mentions-input') === 'true') {
102
+ return;
103
+ }
104
+
105
+ elmInputWrapper = elmInputBox.parent(); //Get the DOM element parent
106
+ elmWrapperBox = $(settings.templates.wrapper());
107
+ elmInputBox.wrapAll(elmWrapperBox); //Wrap all the text area into the div elmWrapperBox
108
+ elmWrapperBox = elmInputWrapper.find('> div.mentions-input-box'); //Obtains the div elmWrapperBox that now contains the text area
109
+
110
+ elmInputBox.attr('data-mentions-input', 'true'); //Sets the attribute data-mentions-input to true -> Defines if the text area is already configured
111
+ elmInputBox.bind('keydown', onInputBoxKeyDown); //Bind the keydown event to the text area
112
+ elmInputBox.bind('keypress', onInputBoxKeyPress); //Bind the keypress event to the text area
113
+ elmInputBox.bind('click', onInputBoxClick); //Bind the click event to the text area
114
+ elmInputBox.bind('blur', onInputBoxBlur); //Bind the blur event to the text area
115
+
116
+ if (navigator.userAgent.indexOf("MSIE 8") > -1) {
117
+ elmInputBox.bind('propertychange', onInputBoxInput); //IE8 won't fire the input event, so let's bind to the propertychange
118
+ } else {
119
+ elmInputBox.bind('input', onInputBoxInput); //Bind the input event to the text area
120
+ }
121
+
122
+ // Elastic textareas, grow automatically
123
+ if( settings.elastic ) {
124
+ elmInputBox.elastic();
125
+ }
126
+ }
127
+
128
+ //Initializes the autocomplete list, append to elmWrapperBox and delegate the mousedown event to li elements
129
+ function initAutocomplete() {
130
+ elmAutocompleteList = $(settings.templates.autocompleteList()); //Get the HTML code for the list
131
+ elmAutocompleteList.appendTo(elmWrapperBox); //Append to elmWrapperBox element
132
+ elmAutocompleteList.delegate('li', 'mousedown', onAutoCompleteItemClick); //Delegate the event
133
+ }
134
+
135
+ //Initializes the mentions' overlay
136
+ function initMentionsOverlay() {
137
+ elmMentionsOverlay = $(settings.templates.mentionsOverlay()); //Get the HTML code of the mentions' overlay
138
+ elmMentionsOverlay.prependTo(elmWrapperBox); //Insert into elmWrapperBox the mentions overlay
139
+ }
140
+
141
+ //Updates the values of the main variables
142
+ function updateValues() {
143
+ var syntaxMessage = getInputBoxValue(); //Get the actual value of the text area
144
+
145
+ _.each(mentionsCollection, function (mention) {
146
+ var textSyntax = settings.templates.mentionItemSyntax(mention);
147
+ syntaxMessage = syntaxMessage.replace(new RegExp(utils.regexpEncode(mention.value), 'g'), textSyntax);
148
+ });
149
+
150
+ var mentionText = utils.htmlEncode(syntaxMessage); //Encode the syntaxMessage
151
+
152
+ _.each(mentionsCollection, function (mention) {
153
+ var formattedMention = _.extend({}, mention, {value: utils.htmlEncode(mention.value)});
154
+ var textSyntax = settings.templates.mentionItemSyntax(formattedMention);
155
+ var textHighlight = settings.templates.mentionItemHighlight(formattedMention);
156
+
157
+ mentionText = mentionText.replace(new RegExp(utils.regexpEncode(textSyntax), 'g'), textHighlight);
158
+ });
159
+
160
+ mentionText = mentionText.replace(/\n/g, '<br />'); //Replace the escape character for <br />
161
+ mentionText = mentionText.replace(/ {2}/g, '&nbsp; '); //Replace the 2 preceding token to &nbsp;
162
+
163
+ elmInputBox.data('messageText', syntaxMessage); //Save the messageText to elmInputBox
164
+ elmInputBox.trigger('updated');
165
+ elmMentionsOverlay.find('div').html(mentionText); //Insert into a div of the elmMentionsOverlay the mention text
166
+ }
167
+
168
+ //Cleans the buffer
169
+ function resetBuffer() {
170
+ inputBuffer = [];
171
+ }
172
+
173
+ //Updates the mentions collection
174
+ function updateMentionsCollection() {
175
+ var inputText = getInputBoxValue(); //Get the actual value of text area
176
+
177
+ //Returns the values that doesn't match the condition
178
+ mentionsCollection = _.reject(mentionsCollection, function (mention, index) {
179
+ return !mention.value || inputText.indexOf(mention.value) == -1;
180
+ });
181
+ mentionsCollection = _.compact(mentionsCollection); //Delete all the falsy values of the array and return the new array
182
+ }
183
+
184
+ //Adds mention to mentions collections
185
+ function addMention(mention) {
186
+
187
+ var currentMessage = getInputBoxValue(); //Get the actual value of the text area
188
+
189
+ // Using a regex to figure out positions
190
+ var regex = new RegExp("\\" + settings.triggerChar + currentDataQuery, "gi");
191
+ regex.exec(currentMessage); //Executes a search for a match in a specified string. Returns a result array, or null
192
+
193
+ var startCaretPosition = regex.lastIndex - currentDataQuery.length - 1; //Set the star caret position
194
+ var currentCaretPosition = regex.lastIndex; //Set the current caret position
195
+
196
+ var start = currentMessage.substr(0, startCaretPosition);
197
+ var end = currentMessage.substr(currentCaretPosition, currentMessage.length);
198
+ var startEndIndex = (start + mention.value).length + 1;
199
+
200
+ // See if there's the same mention in the list
201
+ if( !_.find(mentionsCollection, function (object) { return object.id == mention.id; }) ) {
202
+ mentionsCollection.push(mention);//Add the mention to mentionsColletions
203
+ }
204
+
205
+ // Cleaning before inserting the value, otherwise auto-complete would be triggered with "old" inputbuffer
206
+ resetBuffer();
207
+ currentDataQuery = '';
208
+ hideAutoComplete();
209
+
210
+ // Mentions and syntax message
211
+ var updatedMessageText = start + mention.value + ' ' + end;
212
+ elmInputBox.val(updatedMessageText); //Set the value to the txt area
213
+ elmInputBox.trigger('mention');
214
+ updateValues();
215
+
216
+ // Set correct focus and selection
217
+ elmInputBox.focus();
218
+ utils.setCaratPosition(elmInputBox[0], startEndIndex);
219
+ }
220
+
221
+ //Gets the actual value of the text area without white spaces from the beginning and end of the value
222
+ function getInputBoxValue() {
223
+ return $.trim(elmInputBox.val());
224
+ }
225
+
226
+ // This is taken straight from live (as of Sep 2012) GitHub code. The
227
+ // technique is known around the web. Just google it. Github's is quite
228
+ // succint though. NOTE: relies on selectionEnd, which as far as IE is concerned,
229
+ // it'll only work on 9+. Good news is nothing will happen if the browser
230
+ // doesn't support it.
231
+ function textareaSelectionPosition($el) {
232
+ var a, b, c, d, e, f, g, h, i, j, k;
233
+ if (!(i = $el[0])) return;
234
+ if (!$(i).is("textarea")) return;
235
+ if (i.selectionEnd == null) return;
236
+ g = {
237
+ position: "absolute",
238
+ overflow: "auto",
239
+ whiteSpace: "pre-wrap",
240
+ wordWrap: "break-word",
241
+ boxSizing: "content-box",
242
+ top: 0,
243
+ left: -9999
244
+ }, h = ["boxSizing", "fontFamily", "fontSize", "fontStyle", "fontVariant", "fontWeight", "height", "letterSpacing", "lineHeight", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textDecoration", "textIndent", "textTransform", "width", "word-spacing"];
245
+ for (j = 0, k = h.length; j < k; j++) e = h[j], g[e] = $(i).css(e);
246
+ return c = document.createElement("div"), $(c).css(g), $(i).after(c), b = document.createTextNode(i.value.substring(0, i.selectionEnd)), a = document.createTextNode(i.value.substring(i.selectionEnd)), d = document.createElement("span"), d.innerHTML = "&nbsp;", c.appendChild(b), c.appendChild(d), c.appendChild(a), c.scrollTop = i.scrollTop, f = $(d).position(), $(c).remove(), f
247
+ }
248
+
249
+ //Scrolls back to the input after autocomplete if the window has scrolled past the input
250
+ function scrollToInput() {
251
+ var elmDistanceFromTop = $(elmInputBox).offset().top; //input offset
252
+ var bodyDistanceFromTop = $('body').offset().top; //body offset
253
+ var distanceScrolled = $(window).scrollTop(); //distance scrolled
254
+
255
+ if (distanceScrolled > elmDistanceFromTop) {
256
+ //subtracts body distance to handle fixed headers
257
+ $(window).scrollTop(elmDistanceFromTop - bodyDistanceFromTop);
258
+ }
259
+ }
260
+
261
+ //Takes the click event when the user select a item of the dropdown
262
+ function onAutoCompleteItemClick(e) {
263
+ var elmTarget = $(this); //Get the item selected
264
+ var mention = autocompleteItemCollection[elmTarget.attr('data-uid')]; //Obtains the mention
265
+
266
+ addMention(mention);
267
+ scrollToInput();
268
+ return false;
269
+ }
270
+
271
+ //Takes the click event on text area
272
+ function onInputBoxClick(e) {
273
+ resetBuffer();
274
+ }
275
+
276
+ //Takes the blur event on text area
277
+ function onInputBoxBlur(e) {
278
+ hideAutoComplete();
279
+ }
280
+
281
+ //Takes the input event when users write or delete something
282
+ function onInputBoxInput(e) {
283
+ updateValues();
284
+ updateMentionsCollection();
285
+
286
+ var triggerCharIndex = _.lastIndexOf(inputBuffer, settings.triggerChar); //Returns the last match of the triggerChar in the inputBuffer
287
+ if (triggerCharIndex > -1) { //If the triggerChar is present in the inputBuffer array
288
+ currentDataQuery = inputBuffer.slice(triggerCharIndex + 1).join(''); //Gets the currentDataQuery
289
+ currentDataQuery = utils.rtrim(currentDataQuery); //Deletes the whitespaces
290
+ _.defer(_.bind(doSearch, this, currentDataQuery)); //Invoking the function doSearch ( Bind the function to this)
291
+ }
292
+ }
293
+
294
+ //Takes the keypress event
295
+ function onInputBoxKeyPress(e) {
296
+ if(e.keyCode !== KEY.BACKSPACE) { //If the key pressed is not the backspace
297
+ var typedValue = String.fromCharCode(e.which || e.keyCode); //Takes the string that represent this CharCode
298
+ inputBuffer.push(typedValue); //Push the value pressed into inputBuffer
299
+ }
300
+ }
301
+
302
+ //Takes the keydown event
303
+ function onInputBoxKeyDown(e) {
304
+
305
+ // This also matches HOME/END on OSX which is CMD+LEFT, CMD+RIGHT
306
+ if (e.keyCode === KEY.LEFT || e.keyCode === KEY.RIGHT || e.keyCode === KEY.HOME || e.keyCode === KEY.END) {
307
+ // Defer execution to ensure carat pos has changed after HOME/END keys then call the resetBuffer function
308
+ _.defer(resetBuffer);
309
+
310
+ // IE9 doesn't fire the oninput event when backspace or delete is pressed. This causes the highlighting
311
+ // to stay on the screen whenever backspace is pressed after a highlighed word. This is simply a hack
312
+ // to force updateValues() to fire when backspace/delete is pressed in IE9.
313
+ if (navigator.userAgent.indexOf("MSIE 9") > -1) {
314
+ _.defer(updateValues); //Call the updateValues function
315
+ }
316
+
317
+ return;
318
+ }
319
+
320
+ //If the key pressed was the backspace
321
+ if (e.keyCode === KEY.BACKSPACE) {
322
+ inputBuffer = inputBuffer.slice(0, -1 + inputBuffer.length); // Can't use splice, not available in IE
323
+ return;
324
+ }
325
+
326
+ //If the elmAutocompleteList is hidden
327
+ if (!elmAutocompleteList.is(':visible')) {
328
+ return true;
329
+ }
330
+
331
+ switch (e.keyCode) {
332
+ case KEY.UP: //If the key pressed was UP or DOWN
333
+ case KEY.DOWN:
334
+ var elmCurrentAutoCompleteItem = null;
335
+ if (e.keyCode === KEY.DOWN) { //If the key pressed was DOWN
336
+ if (elmActiveAutoCompleteItem && elmActiveAutoCompleteItem.length) { //If elmActiveAutoCompleteItem exits
337
+ elmCurrentAutoCompleteItem = elmActiveAutoCompleteItem.next(); //Gets the next li element in the list
338
+ } else {
339
+ elmCurrentAutoCompleteItem = elmAutocompleteList.find('li').first(); //Gets the first li element found
340
+ }
341
+ } else {
342
+ elmCurrentAutoCompleteItem = $(elmActiveAutoCompleteItem).prev(); //The key pressed was UP and gets the previous li element
343
+ }
344
+ if (elmCurrentAutoCompleteItem.length) {
345
+ selectAutoCompleteItem(elmCurrentAutoCompleteItem);
346
+ }
347
+ return false;
348
+ case KEY.RETURN: //If the key pressed was RETURN or TAB
349
+ case KEY.TAB:
350
+ if (elmActiveAutoCompleteItem && elmActiveAutoCompleteItem.length) { //If the elmActiveAutoCompleteItem exists
351
+ elmActiveAutoCompleteItem.trigger('mousedown'); //Calls the mousedown event
352
+ return false;
353
+ }
354
+ break;
355
+ }
356
+
357
+ return true;
358
+ }
359
+
360
+ //Hides the autoomplete
361
+ function hideAutoComplete() {
362
+ elmActiveAutoCompleteItem = null;
363
+ elmAutocompleteList.empty().hide();
364
+ }
365
+
366
+ //Selects the item in the autocomplete list
367
+ function selectAutoCompleteItem(elmItem) {
368
+ elmItem.addClass(settings.classes.autoCompleteItemActive); //Add the class active to item
369
+ elmItem.siblings().removeClass(settings.classes.autoCompleteItemActive); //Gets all li elements in autocomplete list and remove the class active
370
+
371
+ elmActiveAutoCompleteItem = elmItem; //Sets the item to elmActiveAutoCompleteItem
372
+ }
373
+
374
+ //Populates dropdown
375
+ function populateDropdown(query, results) {
376
+ elmAutocompleteList.show(); //Shows the autocomplete list
377
+
378
+ if(!settings.allowRepeat) {
379
+ // Filter items that has already been mentioned
380
+ var mentionValues = _.pluck(mentionsCollection, 'value');
381
+ results = _.reject(results, function (item) {
382
+ return _.include(mentionValues, item.name);
383
+ });
384
+ }
385
+
386
+ if (!results.length) { //If there are not elements hide the autocomplete list
387
+ hideAutoComplete();
388
+ return;
389
+ }
390
+
391
+ elmAutocompleteList.empty(); //Remove all li elements in autocomplete list
392
+ var elmDropDownList = $("<ul>").appendTo(elmAutocompleteList).hide(); //Inserts a ul element to autocomplete div and hide it
393
+
394
+ _.each(results, function (item, index) {
395
+ var itemUid = _.uniqueId('mention_'); //Gets the item with unique id
396
+
397
+ autocompleteItemCollection[itemUid] = _.extend({}, item, {value: item.name}); //Inserts the new item to autocompleteItemCollection
398
+
399
+ var elmListItem = $(settings.templates.autocompleteListItem({
400
+ 'id' : utils.htmlEncode(item.id),
401
+ 'display' : utils.htmlEncode(item.name),
402
+ 'type' : utils.htmlEncode(item.type),
403
+ 'content' : utils.highlightTerm(utils.htmlEncode((item.display ? item.display : item.name)), query)
404
+ })).attr('data-uid', itemUid); //Inserts the new item to list
405
+
406
+ //If the index is 0
407
+ if (index === 0) {
408
+ selectAutoCompleteItem(elmListItem);
409
+ }
410
+
411
+ //If show avatars is true
412
+ if (settings.showAvatars) {
413
+ var elmIcon;
414
+
415
+ //If the item has an avatar
416
+ if (item.avatar) {
417
+ elmIcon = $(settings.templates.autocompleteListItemAvatar({ avatar : item.avatar }));
418
+ } else { //If not then we set an default icon
419
+ elmIcon = $(settings.templates.autocompleteListItemIcon({ icon : item.icon }));
420
+ }
421
+ elmIcon.prependTo(elmListItem); //Inserts the elmIcon to elmListItem
422
+ }
423
+ elmListItem = elmListItem.appendTo(elmDropDownList); //Insets the elmListItem to elmDropDownList
424
+ });
425
+
426
+ elmAutocompleteList.show(); //Shows the elmAutocompleteList div
427
+ if (settings.onCaret) {
428
+ positionAutocomplete(elmAutocompleteList, elmInputBox);
429
+ }
430
+ elmDropDownList.show(); //Shows the elmDropDownList
431
+ }
432
+
433
+ //Search into data list passed as parameter
434
+ function doSearch(query) {
435
+ //If the query is not null, undefined, empty and has the minimum chars
436
+ if (query && query.length && query.length >= settings.minChars) {
437
+ //Call the onDataRequest function and then call the populateDropDrown
438
+ settings.onDataRequest.call(this, 'search', query, function (responseData) {
439
+ populateDropdown(query, responseData);
440
+ });
441
+ } else { //If the query is null, undefined, empty or has not the minimun chars
442
+ hideAutoComplete(); //Hide the autocompletelist
443
+ }
444
+ }
445
+
446
+ function positionAutocomplete(elmAutocompleteList, elmInputBox) {
447
+ var position = textareaSelectionPosition(elmInputBox),
448
+ lineHeight = parseInt(elmInputBox.css('line-height'), 10) || 18;
449
+ elmAutocompleteList.css('width', '15em'); // Sort of a guess
450
+ elmAutocompleteList.css('left', position.left);
451
+ elmAutocompleteList.css('top', lineHeight + position.top);
452
+
453
+ //check if the right position of auto complete is larger than the right position of the input
454
+ //if yes, reset the left of auto complete list to make it fit the input
455
+ var elmInputBoxRight = elmInputBox.offset().left + elmInputBox.width(),
456
+ elmAutocompleteListRight = elmAutocompleteList.offset().left + elmAutocompleteList.width();
457
+ if (elmInputBoxRight <= elmAutocompleteListRight) {
458
+ elmAutocompleteList.css('left', Math.abs(elmAutocompleteList.position().left - (elmAutocompleteListRight - elmInputBoxRight)));
459
+ }
460
+ }
461
+
462
+ //Resets the text area
463
+ function resetInput(currentVal) {
464
+ mentionsCollection = [];
465
+ var mentionText = utils.htmlEncode(currentVal);
466
+ var regex = new RegExp("(" + settings.triggerChar + ")\\[(.*?)\\]\\((.*?):(.*?)\\)", "gi");
467
+ var match, newMentionText = mentionText;
468
+ while ((match = regex.exec(mentionText)) != null) {
469
+ newMentionText = newMentionText.replace(match[0], match[1] + match[2]);
470
+ mentionsCollection.push({ 'id': match[4], 'type': match[3], 'value': match[2], 'trigger': match[1] });
471
+ }
472
+ elmInputBox.val(newMentionText);
473
+ updateValues();
474
+ }
475
+ // Public methods
476
+ return {
477
+ //Initializes the mentionsInput component on a specific element.
478
+ init : function (domTarget) {
479
+
480
+ domInput = domTarget;
481
+
482
+ initTextarea();
483
+ initAutocomplete();
484
+ initMentionsOverlay();
485
+ resetInput(settings.defaultValue);
486
+
487
+ //If the autocomplete list has prefill mentions
488
+ if( settings.prefillMention ) {
489
+ addMention( settings.prefillMention );
490
+ }
491
+ },
492
+
493
+ //An async method which accepts a callback function and returns a value of the input field (including markup) as a first parameter of this function. This is the value you want to send to your server.
494
+ val : function (callback) {
495
+ if (!_.isFunction(callback)) {
496
+ return;
497
+ }
498
+ callback.call(this, mentionsCollection.length ? elmInputBox.data('messageText') : getInputBoxValue());
499
+ },
500
+
501
+ //Resets the text area value and clears all mentions
502
+ reset : function () {
503
+ resetInput();
504
+ },
505
+
506
+ //An async method which accepts a callback function and returns a collection of mentions as hash objects as a first parameter.
507
+ getMentions : function (callback) {
508
+ if (!_.isFunction(callback)) {
509
+ return;
510
+ }
511
+ callback.call(this, mentionsCollection);
512
+ }
513
+ };
514
+ };
515
+
516
+ //Main function to include into jQuery and initialize the plugin
517
+ $.fn.mentionsInput = function (method, settings) {
518
+
519
+ var outerArguments = arguments; //Gets the arguments
520
+ //If method is not a function
521
+ if (typeof method === 'object' || !method) {
522
+ settings = method;
523
+ }
524
+
525
+ return this.each(function () {
526
+ var instance = $.data(this, 'mentionsInput') || $.data(this, 'mentionsInput', new MentionsInput(settings));
527
+
528
+ if (_.isFunction(instance[method])) {
529
+ return instance[method].apply(this, Array.prototype.slice.call(outerArguments, 1));
530
+ } else if (typeof method === 'object' || !method) {
531
+ return instance.init.call(this, this);
532
+ } else {
533
+ $.error('Method ' + method + ' does not exist');
534
+ }
535
+ });
536
+ };
537
+
538
+ })(jQuery, _);