blocky 0.0.11 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (416) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -41
  3. data/app/helpers/blocky_helper.rb +31 -13
  4. data/app/models/blocky/content_block.rb +15 -19
  5. data/db/migrate/20140326210255_create_blocky_content_blocks.rb +2 -3
  6. data/lib/blocky.rb +2 -6
  7. data/lib/blocky/admin/content_block.rb +50 -0
  8. data/lib/blocky/engine.rb +9 -9
  9. data/lib/blocky/version.rb +1 -1
  10. data/lib/generators/blocky/install_generator.rb +5 -29
  11. metadata +6 -977
  12. data/app/assets/javascripts/blocky/application.js +0 -21
  13. data/app/assets/javascripts/blocky/flash_messages.js +0 -20
  14. data/app/assets/stylesheets/blocky/_imports.scss +0 -3
  15. data/app/assets/stylesheets/blocky/_variables.scss +0 -37
  16. data/app/assets/stylesheets/blocky/all.scss +0 -20
  17. data/app/assets/stylesheets/blocky/application.css.scss +0 -3
  18. data/app/assets/stylesheets/blocky/application/content_blocks/edit.scss +0 -13
  19. data/app/assets/stylesheets/blocky/application/content_blocks/index.scss +0 -81
  20. data/app/assets/stylesheets/blocky/application/layout.scss +0 -30
  21. data/app/assets/stylesheets/blocky/shared/buttons.scss +0 -119
  22. data/app/assets/stylesheets/blocky/shared/flash_messages.scss +0 -28
  23. data/app/assets/stylesheets/blocky/shared/typography/body.scss +0 -91
  24. data/app/assets/stylesheets/blocky/shared/typography/forms.scss +0 -81
  25. data/app/assets/stylesheets/blocky/shared/typography/headings.scss +0 -38
  26. data/app/assets/stylesheets/blocky/shared/typography/lists.scss +0 -22
  27. data/app/controllers/blocky/application_controller.rb +0 -7
  28. data/app/controllers/blocky/content_blocks_controller.rb +0 -64
  29. data/app/controllers/blocky/images_controller.rb +0 -43
  30. data/app/controllers/concerns/blocky/auth.rb +0 -53
  31. data/app/helpers/blocky/application_helper.rb +0 -26
  32. data/app/models/blocky/ability.rb +0 -11
  33. data/app/views/blocky/content_blocks/_content_block.html.erb +0 -1
  34. data/app/views/blocky/content_blocks/edit.html.erb +0 -62
  35. data/app/views/blocky/content_blocks/index.html.erb +0 -81
  36. data/app/views/blocky/content_blocks/index.json.jbuilder +0 -10
  37. data/app/views/blocky/content_blocks/show.json.jbuilder +0 -10
  38. data/app/views/layouts/blocky/_flash_messages.html.erb +0 -13
  39. data/app/views/layouts/blocky/application.html.erb +0 -20
  40. data/config/jshint.json +0 -28
  41. data/config/routes.rb +0 -5
  42. data/db/migrate/20140520212037_add_page_path_to_content_blocks.rb +0 -7
  43. data/spec/dummy/Procfile +0 -1
  44. data/spec/dummy/README.rdoc +0 -28
  45. data/spec/dummy/Rakefile +0 -6
  46. data/spec/dummy/app/assets/javascripts/application.js +0 -13
  47. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  48. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  49. data/spec/dummy/app/controllers/static_pages_controller.rb +0 -7
  50. data/spec/dummy/app/helpers/application_helper.rb +0 -3
  51. data/spec/dummy/app/models/blocky/ability.rb +0 -9
  52. data/spec/dummy/app/views/layouts/application.html.erb +0 -25
  53. data/spec/dummy/app/views/static_pages/contact.html.erb +0 -8
  54. data/spec/dummy/app/views/static_pages/home.html.erb +0 -7
  55. data/spec/dummy/bin/bundle +0 -3
  56. data/spec/dummy/bin/rails +0 -4
  57. data/spec/dummy/bin/rake +0 -4
  58. data/spec/dummy/config.ru +0 -4
  59. data/spec/dummy/config/application.rb +0 -23
  60. data/spec/dummy/config/boot.rb +0 -5
  61. data/spec/dummy/config/database.yml +0 -25
  62. data/spec/dummy/config/environment.rb +0 -5
  63. data/spec/dummy/config/environments/development.rb +0 -29
  64. data/spec/dummy/config/environments/production.rb +0 -80
  65. data/spec/dummy/config/environments/test.rb +0 -36
  66. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  67. data/spec/dummy/config/initializers/blocky.rb +0 -4
  68. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  69. data/spec/dummy/config/initializers/inflections.rb +0 -16
  70. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  71. data/spec/dummy/config/initializers/secret_token.rb +0 -12
  72. data/spec/dummy/config/initializers/session_store.rb +0 -3
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  74. data/spec/dummy/config/locales/en.yml +0 -23
  75. data/spec/dummy/config/routes.rb +0 -5
  76. data/spec/dummy/db/development.sqlite3 +0 -0
  77. data/spec/dummy/db/migrate/20140326211453_create_blocky_content_blocks.blocky.rb +0 -13
  78. data/spec/dummy/db/migrate/20140521143840_add_page_path_to_content_blocks.blocky.rb +0 -8
  79. data/spec/dummy/db/schema.rb +0 -24
  80. data/spec/dummy/db/test.sqlite3 +0 -0
  81. data/spec/dummy/log/development.log +0 -16366
  82. data/spec/dummy/log/test.log +0 -151
  83. data/spec/dummy/public/404.html +0 -58
  84. data/spec/dummy/public/422.html +0 -58
  85. data/spec/dummy/public/500.html +0 -57
  86. data/spec/dummy/public/favicon.ico +0 -0
  87. data/spec/dummy/tmp/cache/AE1/4D0/blocky%2Fcontent_blocks%2Fnew +0 -0
  88. data/spec/dummy/tmp/cache/E76/DE0/blocky%2Fcontent_blocks%2F1-20140326211612204255000 +0 -1
  89. data/spec/dummy/tmp/cache/E79/1C0/blocky%2Fcontent_blocks%2F4-20140520200831236730000 +0 -6
  90. data/spec/dummy/tmp/cache/E79/630/blocky%2Fcontent_blocks%2F5-20140326220740803013000 +0 -0
  91. data/spec/dummy/tmp/cache/E7D/2C0/blocky%2Fcontent_blocks%2F2-20140326211803501817000 +0 -1
  92. data/spec/dummy/tmp/cache/E7F/480/blocky%2Fcontent_blocks%2F2-20140326211735204743000 +0 -0
  93. data/spec/dummy/tmp/cache/E82/5D0/blocky%2Fcontent_blocks%2F2-20140522172212942644000 +0 -3
  94. data/spec/dummy/tmp/cache/E83/720/blocky%2Fcontent_blocks%2F3-20140326212218805733000 +0 -0
  95. data/spec/dummy/tmp/cache/E85/4F0/blocky%2Fcontent_blocks%2F1-20140326211503578725000 +0 -0
  96. data/spec/dummy/tmp/cache/E86/7B0/blocky%2Fcontent_blocks%2F4-20140522172300720879000 +0 -6
  97. data/spec/dummy/tmp/cache/E88/650/blocky%2Fcontent_blocks%2F1-20140522172212927549000 +0 -3
  98. data/spec/dummy/tmp/cache/E8A/C50/blocky%2Fcontent_blocks%2F6-20140520152442627674000 +0 -0
  99. data/spec/dummy/tmp/cache/E8C/390/blocky%2Fcontent_blocks%2F9-20140521143916645081000 +0 -3
  100. data/spec/dummy/tmp/cache/E8F/4B0/blocky%2Fcontent_blocks%2F8-20140521143847577033000 +0 -3
  101. data/spec/dummy/tmp/cache/E8F/B50/blocky%2Fcontent_blocks%2F3-20140522172212955589000 +0 -3
  102. data/spec/dummy/tmp/cache/E8F/DF0/blocky%2Fcontent_blocks%2F4-20140522172414829485000 +0 -4
  103. data/spec/dummy/tmp/cache/E8F/EE0/blocky%2Fcontent_blocks%2F4-20140326214706659274000 +0 -0
  104. data/spec/dummy/tmp/cache/E95/020/blocky%2Fcontent_blocks%2F4-20140520170832796695000 +0 -2
  105. data/spec/dummy/tmp/cache/E9C/710/blocky%2Fcontent_blocks%2F7-20140521143847555969000 +0 -3
  106. data/spec/dummy/tmp/cache/EB0/BC0/blocky%2Fcontent_blocks%2F10-20140521145206891062000 +0 -6
  107. data/spec/dummy/tmp/cache/EB7/EC0/blocky%2Fcontent_blocks%2F11-20140521145206908717000 +0 -3
  108. data/spec/dummy/tmp/cache/EBC/5C0/blocky%2Fcontent_blocks%2F13-20140521145258981073000 +0 -3
  109. data/spec/dummy/tmp/cache/EC4/780/blocky%2Fcontent_blocks%2F12-20140521145258965683000 +0 -3
  110. data/spec/dummy/tmp/cache/assets/development/sass/1330522281c54fc4f0f88c06856f0cc8052c25e8/buttons.scssc +0 -0
  111. data/spec/dummy/tmp/cache/assets/development/sass/1330522281c54fc4f0f88c06856f0cc8052c25e8/flash_messages.scssc +0 -0
  112. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_compact.scssc +0 -0
  113. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_flex-grid.scssc +0 -0
  114. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_grid-width.scssc +0 -0
  115. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_linear-gradient.scssc +0 -0
  116. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_modular-scale.scssc +0 -0
  117. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_px-to-em.scssc +0 -0
  118. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_radial-gradient.scssc +0 -0
  119. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_tint-shade.scssc +0 -0
  120. data/spec/dummy/tmp/cache/assets/development/sass/16328cd177fa77f37d597cddc166b9d61ed7bdc6/_transition-property-name.scssc +0 -0
  121. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_bordered-pulled.scssc +0 -0
  122. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_core.scssc +0 -0
  123. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_fixed-width.scssc +0 -0
  124. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_icons.scssc +0 -0
  125. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_larger.scssc +0 -0
  126. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_list.scssc +0 -0
  127. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_mixins.scssc +0 -0
  128. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_path.scssc +0 -0
  129. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_rotated-flipped.scssc +0 -0
  130. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_spinning.scssc +0 -0
  131. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_stacked.scssc +0 -0
  132. data/spec/dummy/tmp/cache/assets/development/sass/2ed2f1a12f96a5966a3f2f4a226be3068f8e609b/_variables.scssc +0 -0
  133. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_fill-parent.scssc +0 -0
  134. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_grid.scssc +0 -0
  135. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_media.scssc +0 -0
  136. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_omega.scssc +0 -0
  137. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_outer-container.scssc +0 -0
  138. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_pad.scssc +0 -0
  139. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_private.scssc +0 -0
  140. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_reset.scssc +0 -0
  141. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_row.scssc +0 -0
  142. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_shift.scssc +0 -0
  143. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_span-columns.scssc +0 -0
  144. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_to-deprecate.scssc +0 -0
  145. data/spec/dummy/tmp/cache/assets/development/sass/3fb34f29991e8a63348b29fade50f1de29147c8f/_visual-grid.scssc +0 -0
  146. data/spec/dummy/tmp/cache/assets/development/sass/45a8d9925ba36450f7e3862c914588ae8720003e/_imports.scssc +0 -0
  147. data/spec/dummy/tmp/cache/assets/development/sass/45a8d9925ba36450f7e3862c914588ae8720003e/_variables.scssc +0 -0
  148. data/spec/dummy/tmp/cache/assets/development/sass/45a8d9925ba36450f7e3862c914588ae8720003e/application.css.scssc +0 -0
  149. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_deprecated-webkit-gradient.scssc +0 -0
  150. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_gradient-positions-parser.scssc +0 -0
  151. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_linear-positions-parser.scssc +0 -0
  152. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_radial-arg-parser.scssc +0 -0
  153. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_radial-positions-parser.scssc +0 -0
  154. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_render-gradients.scssc +0 -0
  155. data/spec/dummy/tmp/cache/assets/development/sass/4808b00b5a9150b9a854e6877435916328f1da81/_shape-size-stripper.scssc +0 -0
  156. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_animation.scssc +0 -0
  157. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_appearance.scssc +0 -0
  158. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_backface-visibility.scssc +0 -0
  159. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_background-image.scssc +0 -0
  160. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_background.scssc +0 -0
  161. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_border-image.scssc +0 -0
  162. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_border-radius.scssc +0 -0
  163. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_box-sizing.scssc +0 -0
  164. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_columns.scssc +0 -0
  165. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_flex-box.scssc +0 -0
  166. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_font-face.scssc +0 -0
  167. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_hidpi-media-query.scssc +0 -0
  168. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_image-rendering.scssc +0 -0
  169. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_inline-block.scssc +0 -0
  170. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_keyframes.scssc +0 -0
  171. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_linear-gradient.scssc +0 -0
  172. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_perspective.scssc +0 -0
  173. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_placeholder.scssc +0 -0
  174. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_radial-gradient.scssc +0 -0
  175. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_transform.scssc +0 -0
  176. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_transition.scssc +0 -0
  177. data/spec/dummy/tmp/cache/assets/development/sass/5e68b12f5742e819b59fae21d1dedfbc3da30721/_user-select.scssc +0 -0
  178. data/spec/dummy/tmp/cache/assets/development/sass/7c52080b507114ff73ac654c0177e1dca603143b/body.scssc +0 -0
  179. data/spec/dummy/tmp/cache/assets/development/sass/7c52080b507114ff73ac654c0177e1dca603143b/forms.scssc +0 -0
  180. data/spec/dummy/tmp/cache/assets/development/sass/7c52080b507114ff73ac654c0177e1dca603143b/headings.scssc +0 -0
  181. data/spec/dummy/tmp/cache/assets/development/sass/7c52080b507114ff73ac654c0177e1dca603143b/lists.scssc +0 -0
  182. data/spec/dummy/tmp/cache/assets/development/sass/86088d5ecf0a5701fd22ac3b30255eb2bb94f550/_bourbon-deprecated-upcoming.scssc +0 -0
  183. data/spec/dummy/tmp/cache/assets/development/sass/9de1036a47599e1de75fdb2094e4960ffb18ffcf/_grid.scssc +0 -0
  184. data/spec/dummy/tmp/cache/assets/development/sass/9de1036a47599e1de75fdb2094e4960ffb18ffcf/_visual-grid.scssc +0 -0
  185. data/spec/dummy/tmp/cache/assets/development/sass/9e0f22094073a2727149869ee451bf5155b6b1de/_bourbon.scssc +0 -0
  186. data/spec/dummy/tmp/cache/assets/development/sass/9e0f22094073a2727149869ee451bf5155b6b1de/_neat.scssc +0 -0
  187. data/spec/dummy/tmp/cache/assets/development/sass/9e0f22094073a2727149869ee451bf5155b6b1de/font-awesome.scssc +0 -0
  188. data/spec/dummy/tmp/cache/assets/development/sass/ab9fa2e8e2c4d0592ca80a0885630a538ee36082/_neat-helpers.scssc +0 -0
  189. data/spec/dummy/tmp/cache/assets/development/sass/ccd8e9094d6c3af8a9493bb7fee8eae1bf9b4c52/_new-breakpoint.scssc +0 -0
  190. data/spec/dummy/tmp/cache/assets/development/sass/ccd8e9094d6c3af8a9493bb7fee8eae1bf9b4c52/_private.scssc +0 -0
  191. data/spec/dummy/tmp/cache/assets/development/sass/e32eee285e5a7bcd847a61263245c70a38794724/edit.scssc +0 -0
  192. data/spec/dummy/tmp/cache/assets/development/sass/e32eee285e5a7bcd847a61263245c70a38794724/index.scssc +0 -0
  193. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_button.scssc +0 -0
  194. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_clearfix.scssc +0 -0
  195. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_font-family.scssc +0 -0
  196. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_hide-text.scssc +0 -0
  197. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_html5-input-types.scssc +0 -0
  198. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_position.scssc +0 -0
  199. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_prefixer.scssc +0 -0
  200. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_retina-image.scssc +0 -0
  201. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_size.scssc +0 -0
  202. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_timing-functions.scssc +0 -0
  203. data/spec/dummy/tmp/cache/assets/development/sass/e792c58dcbc932d7b0bbb62be67c59da9796d04b/_triangle.scssc +0 -0
  204. data/spec/dummy/tmp/cache/assets/development/sass/f6aab6f5c59ff0b3c4ff7e11237d10cd45b5353c/layout.scssc +0 -0
  205. data/spec/dummy/tmp/cache/assets/development/sprockets/00b315c99e05fd17eb6ee63c05874610 +0 -0
  206. data/spec/dummy/tmp/cache/assets/development/sprockets/0427945c7b4a3a10bc1b628680c1ac11 +0 -0
  207. data/spec/dummy/tmp/cache/assets/development/sprockets/07a7381ab720b1fcdf48d09e6f4aca3f +0 -0
  208. data/spec/dummy/tmp/cache/assets/development/sprockets/0cba4b819c78286147e22cce1cff06de +0 -0
  209. data/spec/dummy/tmp/cache/assets/development/sprockets/0d045cc286244754010ae01a766487a9 +0 -0
  210. data/spec/dummy/tmp/cache/assets/development/sprockets/0f027312d7555aefd043bc94e678e35d +0 -0
  211. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  212. data/spec/dummy/tmp/cache/assets/development/sprockets/1590fdab706270c5d350582acc774711 +0 -0
  213. data/spec/dummy/tmp/cache/assets/development/sprockets/17d324480cb2a2a47bedc3ef4d022b6d +0 -0
  214. data/spec/dummy/tmp/cache/assets/development/sprockets/21eee9c5050e081a5a1cf91cea7d268f +0 -0
  215. data/spec/dummy/tmp/cache/assets/development/sprockets/2510376ff2d7b20d23bc38a46fcfa055 +0 -0
  216. data/spec/dummy/tmp/cache/assets/development/sprockets/26dfb7b51a72e95c414c783f2ba69222 +0 -0
  217. data/spec/dummy/tmp/cache/assets/development/sprockets/2a12abb42fb17b6520d9d9ad589a20af +0 -0
  218. data/spec/dummy/tmp/cache/assets/development/sprockets/2a87faf509efd55dfdbd16b0fa8239b4 +0 -0
  219. data/spec/dummy/tmp/cache/assets/development/sprockets/2c9e3b499f8c7da0a3d3de2510f78846 +0 -0
  220. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  221. data/spec/dummy/tmp/cache/assets/development/sprockets/2fd51b2bfa391389108d8de69733d84b +0 -0
  222. data/spec/dummy/tmp/cache/assets/development/sprockets/3075115024bd10f7adb951b3baec184c +0 -0
  223. data/spec/dummy/tmp/cache/assets/development/sprockets/309a524a7494382fd3346a82b810c20b +0 -0
  224. data/spec/dummy/tmp/cache/assets/development/sprockets/346918a665641c5e32c0bb368f032b07 +0 -0
  225. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  226. data/spec/dummy/tmp/cache/assets/development/sprockets/359a931a346dd73a40ea88a3e145e4b3 +0 -0
  227. data/spec/dummy/tmp/cache/assets/development/sprockets/3a8c2654e77e18a35f25642e5e3bcb88 +0 -0
  228. data/spec/dummy/tmp/cache/assets/development/sprockets/3a8ecba67750b8ad7df3ba9362857756 +0 -0
  229. data/spec/dummy/tmp/cache/assets/development/sprockets/3aa302111c6bea14859db6fea34cdb94 +0 -0
  230. data/spec/dummy/tmp/cache/assets/development/sprockets/3b05198beb41d8fc2b4a207128140f89 +0 -0
  231. data/spec/dummy/tmp/cache/assets/development/sprockets/3cc020c5e2e8ab2e4acd1b5a9fdc16ab +0 -0
  232. data/spec/dummy/tmp/cache/assets/development/sprockets/3d89aed04c6cdc16f097a2aabfa2b867 +0 -0
  233. data/spec/dummy/tmp/cache/assets/development/sprockets/420c2d9425469c305387fa81d5ef1b30 +0 -0
  234. data/spec/dummy/tmp/cache/assets/development/sprockets/43272d99260411613e550de399f08be8 +0 -0
  235. data/spec/dummy/tmp/cache/assets/development/sprockets/4443d626de6926b2b0e97011a9d3283b +0 -0
  236. data/spec/dummy/tmp/cache/assets/development/sprockets/44ee5490907c6fdf6530eeea203a3908 +0 -0
  237. data/spec/dummy/tmp/cache/assets/development/sprockets/4c016d0efbbfe9fa01bc4d8d800f8548 +0 -0
  238. data/spec/dummy/tmp/cache/assets/development/sprockets/4f41b46926dc79b6d378c60e5e12b1ee +0 -0
  239. data/spec/dummy/tmp/cache/assets/development/sprockets/4ffbbdb75e91e3ef76f0356bd8c9fdb9 +0 -0
  240. data/spec/dummy/tmp/cache/assets/development/sprockets/530a0c5b0d469facb66e00ca952d9069 +0 -0
  241. data/spec/dummy/tmp/cache/assets/development/sprockets/562b764135bc28106a524123de319fac +0 -0
  242. data/spec/dummy/tmp/cache/assets/development/sprockets/59cc9befd7bad256dc0139dc7c32cf34 +0 -0
  243. data/spec/dummy/tmp/cache/assets/development/sprockets/5d455edb538f158d67b710d4c8fb9674 +0 -0
  244. data/spec/dummy/tmp/cache/assets/development/sprockets/5ea0f006a9c4f5744aa307242e43d11a +0 -0
  245. data/spec/dummy/tmp/cache/assets/development/sprockets/5f1b58c3d1b05b422b95fad6ff1236ad +0 -0
  246. data/spec/dummy/tmp/cache/assets/development/sprockets/5f9c0944ded3ac10412c77764c4f83a2 +0 -0
  247. data/spec/dummy/tmp/cache/assets/development/sprockets/613e23bb1e9f2c8dbd8166803b85c57c +0 -0
  248. data/spec/dummy/tmp/cache/assets/development/sprockets/61ac9eefcbf748e59c79b6e84835babd +0 -0
  249. data/spec/dummy/tmp/cache/assets/development/sprockets/64b57c4794688cd1dd9723c89f564ad7 +0 -0
  250. data/spec/dummy/tmp/cache/assets/development/sprockets/65e56fb427fa0e3e148515a9ea998426 +0 -0
  251. data/spec/dummy/tmp/cache/assets/development/sprockets/7344269d882a3e910b3806b007dd9d71 +0 -0
  252. data/spec/dummy/tmp/cache/assets/development/sprockets/74104d7c75a8966708478065693bcca8 +0 -0
  253. data/spec/dummy/tmp/cache/assets/development/sprockets/7415c9f0125deaebddd1c12b2c26367d +0 -0
  254. data/spec/dummy/tmp/cache/assets/development/sprockets/7703867f0dd6cf86b9eb01bce45d1f02 +0 -0
  255. data/spec/dummy/tmp/cache/assets/development/sprockets/7871e5235770cb3607023e3646149255 +0 -0
  256. data/spec/dummy/tmp/cache/assets/development/sprockets/7ce4b6005f5a1535c297ebe897723551 +0 -0
  257. data/spec/dummy/tmp/cache/assets/development/sprockets/8035b3603b1f603513ce0491ef5ee98c +0 -0
  258. data/spec/dummy/tmp/cache/assets/development/sprockets/87b0d0df42a2bb5d08a5417fd0274a6e +0 -0
  259. data/spec/dummy/tmp/cache/assets/development/sprockets/88b8972e085bc284af152cf7b158334c +0 -0
  260. data/spec/dummy/tmp/cache/assets/development/sprockets/8b94d81de8f6f238037cab9a4a1a0c30 +0 -0
  261. data/spec/dummy/tmp/cache/assets/development/sprockets/8bd0f5b2d316327657d6709cf130a550 +0 -0
  262. data/spec/dummy/tmp/cache/assets/development/sprockets/8efc9dce2839c7874c8c1bb8a662acc9 +0 -0
  263. data/spec/dummy/tmp/cache/assets/development/sprockets/8f4e3d9674b96cae9b98843cd6ff18c8 +0 -0
  264. data/spec/dummy/tmp/cache/assets/development/sprockets/92a576a2bd81929a26b143cc02e430aa +0 -0
  265. data/spec/dummy/tmp/cache/assets/development/sprockets/9e58e917e624e0cd3b2154f01fd24962 +0 -0
  266. data/spec/dummy/tmp/cache/assets/development/sprockets/a0c1f9e3d33f8de75d0a594321456c9b +0 -0
  267. data/spec/dummy/tmp/cache/assets/development/sprockets/a147199745f7229dc608d3cefce5df45 +0 -0
  268. data/spec/dummy/tmp/cache/assets/development/sprockets/a72bca95d5c7b54e61fa4e0ebc869d4e +0 -0
  269. data/spec/dummy/tmp/cache/assets/development/sprockets/abe150382a2bf6466264fe8866f34157 +0 -0
  270. data/spec/dummy/tmp/cache/assets/development/sprockets/afa453539adb4bc1f7d844dcb361460d +0 -0
  271. data/spec/dummy/tmp/cache/assets/development/sprockets/b0352a0c3bd6f28326a7fc34fa51fa16 +0 -0
  272. data/spec/dummy/tmp/cache/assets/development/sprockets/b0f77fd26cd7fd672f25ec90ed445fe9 +0 -0
  273. data/spec/dummy/tmp/cache/assets/development/sprockets/b0f88bcdb6579681288ffc314d36281b +0 -0
  274. data/spec/dummy/tmp/cache/assets/development/sprockets/b304f5f5248fd1b0910adaeaf4430da9 +0 -0
  275. data/spec/dummy/tmp/cache/assets/development/sprockets/b5dd7a2c9cdd592440c578b49edff2cb +0 -0
  276. data/spec/dummy/tmp/cache/assets/development/sprockets/b7f85043b18466180fb325cbc7e709c8 +0 -0
  277. data/spec/dummy/tmp/cache/assets/development/sprockets/b8096cbfaf0aa44715d5411926461117 +0 -0
  278. data/spec/dummy/tmp/cache/assets/development/sprockets/b95fb213c4dd9e7f1fdfe6120e88e2e8 +0 -0
  279. data/spec/dummy/tmp/cache/assets/development/sprockets/be95835376c06f09fdd2a3afc3dd195e +0 -0
  280. data/spec/dummy/tmp/cache/assets/development/sprockets/bfacd7859276780db88488d7d7e41b59 +0 -0
  281. data/spec/dummy/tmp/cache/assets/development/sprockets/c954e3a10a9a27d22bbde51534852ce1 +0 -0
  282. data/spec/dummy/tmp/cache/assets/development/sprockets/cee17b1df9168d8c9075ec7c74d54cb5 +0 -0
  283. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  284. data/spec/dummy/tmp/cache/assets/development/sprockets/d101f82ff4e2f7db4eb46cc760aa1d3f +0 -0
  285. data/spec/dummy/tmp/cache/assets/development/sprockets/d1689f5fa7ff2ae20077f9de7fd130e1 +0 -0
  286. data/spec/dummy/tmp/cache/assets/development/sprockets/d31431b0b9739b7fa0843ccfd02d002b +0 -0
  287. data/spec/dummy/tmp/cache/assets/development/sprockets/d410c298186b4110d38ff3d89b29c925 +0 -0
  288. data/spec/dummy/tmp/cache/assets/development/sprockets/d4b45f77d1eed50fcf90f8c5511b99b6 +0 -0
  289. data/spec/dummy/tmp/cache/assets/development/sprockets/d62a46b4d21da7c9091dcbd8fa01da34 +0 -0
  290. data/spec/dummy/tmp/cache/assets/development/sprockets/d6477bff4412a5abb06c8acf405c8a87 +0 -0
  291. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  292. data/spec/dummy/tmp/cache/assets/development/sprockets/d985df74e53b12bfa3af9ea8608eacb2 +0 -0
  293. data/spec/dummy/tmp/cache/assets/development/sprockets/d9db27d114516b1b698ad3520e97d1f9 +0 -0
  294. data/spec/dummy/tmp/cache/assets/development/sprockets/da4c7a7a685a765695e1d781590e6a5a +0 -0
  295. data/spec/dummy/tmp/cache/assets/development/sprockets/dbe056c885afef869a46852b1faa9e60 +0 -0
  296. data/spec/dummy/tmp/cache/assets/development/sprockets/df0a14f77c1e0b39c4284d6d6fce9c97 +0 -0
  297. data/spec/dummy/tmp/cache/assets/development/sprockets/e01e232c8b2f8d1711bcd44d6e017dab +0 -0
  298. data/spec/dummy/tmp/cache/assets/development/sprockets/e333f0976af05d7bc7eca78d1383c2af +0 -0
  299. data/spec/dummy/tmp/cache/assets/development/sprockets/e95f94b756f854b191f179bd558ce3c6 +0 -0
  300. data/spec/dummy/tmp/cache/assets/development/sprockets/eb20aca7df145f553b39afab67d5c0a0 +0 -0
  301. data/spec/dummy/tmp/cache/assets/development/sprockets/edaff551a27cde6faf69cc45ba5de859 +0 -0
  302. data/spec/dummy/tmp/cache/assets/development/sprockets/ee44b9ce0a9a1e5e56418ab84da62277 +0 -0
  303. data/spec/dummy/tmp/cache/assets/development/sprockets/f345273bfd8088c36038c49a5fae3218 +0 -0
  304. data/spec/dummy/tmp/cache/assets/development/sprockets/f3a1691881f9395089d43324197ff863 +0 -0
  305. data/spec/dummy/tmp/cache/assets/development/sprockets/f4e80d0621ebd9be1b2b595ce543037f +0 -0
  306. data/spec/dummy/tmp/cache/assets/development/sprockets/f521da421cda5fe4162aeec62e594eca +0 -0
  307. data/spec/dummy/tmp/cache/assets/development/sprockets/f6fcfc1f4419ff69a85c86234ba475cf +0 -0
  308. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  309. data/spec/dummy/tmp/cache/assets/development/sprockets/f8c2ccce91ab7c89ad8922be93c6f363 +0 -0
  310. data/spec/dummy/tmp/cache/assets/development/sprockets/fa0df232aba62e841f6077c735cec1aa +0 -0
  311. data/spec/dummy/tmp/cache/assets/development/sprockets/fb892eb8050ec923cc8084138b1e6e28 +0 -0
  312. data/spec/factories/content_block_factory.rb +0 -13
  313. data/spec/models/blocky/content_block_spec.rb +0 -37
  314. data/spec/spec_helper.rb +0 -34
  315. data/vendor/assets/fonts/blocky/FontAwesome.otf +0 -0
  316. data/vendor/assets/fonts/blocky/fontawesome-webfont.eot +0 -0
  317. data/vendor/assets/fonts/blocky/fontawesome-webfont.svg +0 -414
  318. data/vendor/assets/fonts/blocky/fontawesome-webfont.ttf +0 -0
  319. data/vendor/assets/fonts/blocky/fontawesome-webfont.woff +0 -0
  320. data/vendor/assets/javascripts/blocky/bootstrap.js +0 -1951
  321. data/vendor/assets/javascripts/blocky/codemirror/closebrackets.js +0 -84
  322. data/vendor/assets/javascripts/blocky/codemirror/codemirror.js +0 -4442
  323. data/vendor/assets/javascripts/blocky/codemirror/formatting.js +0 -1
  324. data/vendor/assets/javascripts/blocky/codemirror/xml.js +0 -1
  325. data/vendor/assets/javascripts/blocky/jquery.js +0 -10338
  326. data/vendor/assets/javascripts/blocky/jquery_ujs.js +0 -398
  327. data/vendor/assets/javascripts/blocky/summernote.js +0 -3922
  328. data/vendor/assets/stylesheets/blocky/_bourbon.scss +0 -59
  329. data/vendor/assets/stylesheets/blocky/_neat.scss +0 -21
  330. data/vendor/assets/stylesheets/blocky/bootstrap.css +0 -5785
  331. data/vendor/assets/stylesheets/blocky/bootstrap.css.map +0 -1
  332. data/vendor/assets/stylesheets/blocky/bourbon/_bourbon-deprecated-upcoming.scss +0 -13
  333. data/vendor/assets/stylesheets/blocky/bourbon/addons/_button.scss +0 -273
  334. data/vendor/assets/stylesheets/blocky/bourbon/addons/_clearfix.scss +0 -29
  335. data/vendor/assets/stylesheets/blocky/bourbon/addons/_font-family.scss +0 -5
  336. data/vendor/assets/stylesheets/blocky/bourbon/addons/_hide-text.scss +0 -5
  337. data/vendor/assets/stylesheets/blocky/bourbon/addons/_html5-input-types.scss +0 -56
  338. data/vendor/assets/stylesheets/blocky/bourbon/addons/_position.scss +0 -42
  339. data/vendor/assets/stylesheets/blocky/bourbon/addons/_prefixer.scss +0 -49
  340. data/vendor/assets/stylesheets/blocky/bourbon/addons/_retina-image.scss +0 -32
  341. data/vendor/assets/stylesheets/blocky/bourbon/addons/_size.scss +0 -44
  342. data/vendor/assets/stylesheets/blocky/bourbon/addons/_timing-functions.scss +0 -32
  343. data/vendor/assets/stylesheets/blocky/bourbon/addons/_triangle.scss +0 -45
  344. data/vendor/assets/stylesheets/blocky/bourbon/css3/_animation.scss +0 -52
  345. data/vendor/assets/stylesheets/blocky/bourbon/css3/_appearance.scss +0 -3
  346. data/vendor/assets/stylesheets/blocky/bourbon/css3/_backface-visibility.scss +0 -6
  347. data/vendor/assets/stylesheets/blocky/bourbon/css3/_background-image.scss +0 -48
  348. data/vendor/assets/stylesheets/blocky/bourbon/css3/_background.scss +0 -103
  349. data/vendor/assets/stylesheets/blocky/bourbon/css3/_border-image.scss +0 -55
  350. data/vendor/assets/stylesheets/blocky/bourbon/css3/_border-radius.scss +0 -22
  351. data/vendor/assets/stylesheets/blocky/bourbon/css3/_box-sizing.scss +0 -4
  352. data/vendor/assets/stylesheets/blocky/bourbon/css3/_columns.scss +0 -47
  353. data/vendor/assets/stylesheets/blocky/bourbon/css3/_flex-box.scss +0 -52
  354. data/vendor/assets/stylesheets/blocky/bourbon/css3/_font-face.scss +0 -23
  355. data/vendor/assets/stylesheets/blocky/bourbon/css3/_hidpi-media-query.scss +0 -10
  356. data/vendor/assets/stylesheets/blocky/bourbon/css3/_image-rendering.scss +0 -13
  357. data/vendor/assets/stylesheets/blocky/bourbon/css3/_inline-block.scss +0 -8
  358. data/vendor/assets/stylesheets/blocky/bourbon/css3/_keyframes.scss +0 -43
  359. data/vendor/assets/stylesheets/blocky/bourbon/css3/_linear-gradient.scss +0 -41
  360. data/vendor/assets/stylesheets/blocky/bourbon/css3/_perspective.scss +0 -8
  361. data/vendor/assets/stylesheets/blocky/bourbon/css3/_placeholder.scss +0 -29
  362. data/vendor/assets/stylesheets/blocky/bourbon/css3/_radial-gradient.scss +0 -44
  363. data/vendor/assets/stylesheets/blocky/bourbon/css3/_transform.scss +0 -15
  364. data/vendor/assets/stylesheets/blocky/bourbon/css3/_transition.scss +0 -34
  365. data/vendor/assets/stylesheets/blocky/bourbon/css3/_user-select.scss +0 -3
  366. data/vendor/assets/stylesheets/blocky/bourbon/functions/_compact.scss +0 -11
  367. data/vendor/assets/stylesheets/blocky/bourbon/functions/_flex-grid.scss +0 -39
  368. data/vendor/assets/stylesheets/blocky/bourbon/functions/_grid-width.scss +0 -13
  369. data/vendor/assets/stylesheets/blocky/bourbon/functions/_linear-gradient.scss +0 -13
  370. data/vendor/assets/stylesheets/blocky/bourbon/functions/_modular-scale.scss +0 -40
  371. data/vendor/assets/stylesheets/blocky/bourbon/functions/_px-to-em.scss +0 -8
  372. data/vendor/assets/stylesheets/blocky/bourbon/functions/_radial-gradient.scss +0 -23
  373. data/vendor/assets/stylesheets/blocky/bourbon/functions/_tint-shade.scss +0 -9
  374. data/vendor/assets/stylesheets/blocky/bourbon/functions/_transition-property-name.scss +0 -22
  375. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_deprecated-webkit-gradient.scss +0 -39
  376. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_gradient-positions-parser.scss +0 -13
  377. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_linear-positions-parser.scss +0 -61
  378. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_radial-arg-parser.scss +0 -69
  379. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_radial-positions-parser.scss +0 -18
  380. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_render-gradients.scss +0 -26
  381. data/vendor/assets/stylesheets/blocky/bourbon/helpers/_shape-size-stripper.scss +0 -10
  382. data/vendor/assets/stylesheets/blocky/codemirror/codemirror.css +0 -1
  383. data/vendor/assets/stylesheets/blocky/codemirror/monokai.css +0 -1
  384. data/vendor/assets/stylesheets/blocky/font-awesome.scss +0 -17
  385. data/vendor/assets/stylesheets/blocky/font-awesome/_bordered-pulled.scss +0 -16
  386. data/vendor/assets/stylesheets/blocky/font-awesome/_core.scss +0 -12
  387. data/vendor/assets/stylesheets/blocky/font-awesome/_fixed-width.scss +0 -6
  388. data/vendor/assets/stylesheets/blocky/font-awesome/_icons.scss +0 -412
  389. data/vendor/assets/stylesheets/blocky/font-awesome/_larger.scss +0 -13
  390. data/vendor/assets/stylesheets/blocky/font-awesome/_list.scss +0 -19
  391. data/vendor/assets/stylesheets/blocky/font-awesome/_mixins.scss +0 -20
  392. data/vendor/assets/stylesheets/blocky/font-awesome/_path.scss +0 -13
  393. data/vendor/assets/stylesheets/blocky/font-awesome/_rotated-flipped.scss +0 -9
  394. data/vendor/assets/stylesheets/blocky/font-awesome/_spinning.scss +0 -30
  395. data/vendor/assets/stylesheets/blocky/font-awesome/_stacked.scss +0 -20
  396. data/vendor/assets/stylesheets/blocky/font-awesome/_variables.scss +0 -381
  397. data/vendor/assets/stylesheets/blocky/neat/_neat-helpers.scss +0 -7
  398. data/vendor/assets/stylesheets/blocky/neat/functions/_new-breakpoint.scss +0 -16
  399. data/vendor/assets/stylesheets/blocky/neat/functions/_private.scss +0 -125
  400. data/vendor/assets/stylesheets/blocky/neat/grid/_fill-parent.scss +0 -7
  401. data/vendor/assets/stylesheets/blocky/neat/grid/_grid.scss +0 -5
  402. data/vendor/assets/stylesheets/blocky/neat/grid/_media.scss +0 -51
  403. data/vendor/assets/stylesheets/blocky/neat/grid/_omega.scss +0 -79
  404. data/vendor/assets/stylesheets/blocky/neat/grid/_outer-container.scss +0 -8
  405. data/vendor/assets/stylesheets/blocky/neat/grid/_pad.scss +0 -8
  406. data/vendor/assets/stylesheets/blocky/neat/grid/_private.scss +0 -50
  407. data/vendor/assets/stylesheets/blocky/neat/grid/_reset.scss +0 -12
  408. data/vendor/assets/stylesheets/blocky/neat/grid/_row.scss +0 -17
  409. data/vendor/assets/stylesheets/blocky/neat/grid/_shift.scss +0 -16
  410. data/vendor/assets/stylesheets/blocky/neat/grid/_span-columns.scss +0 -45
  411. data/vendor/assets/stylesheets/blocky/neat/grid/_to-deprecate.scss +0 -57
  412. data/vendor/assets/stylesheets/blocky/neat/grid/_visual-grid.scss +0 -41
  413. data/vendor/assets/stylesheets/blocky/neat/settings/_grid.scss +0 -7
  414. data/vendor/assets/stylesheets/blocky/neat/settings/_visual-grid.scss +0 -5
  415. data/vendor/assets/stylesheets/blocky/normalize.css +0 -423
  416. data/vendor/assets/stylesheets/blocky/summernote.css +0 -1
@@ -1,398 +0,0 @@
1
- (function($, undefined) {
2
-
3
- /**
4
- * Unobtrusive scripting adapter for jQuery
5
- * https://github.com/rails/jquery-ujs
6
- *
7
- * Requires jQuery 1.7.0 or later.
8
- *
9
- * Released under the MIT license
10
- *
11
- */
12
-
13
- // Cut down on the number of issues from people inadvertently including jquery_ujs twice
14
- // by detecting and raising an error when it happens.
15
- if ( $.rails !== undefined ) {
16
- $.error('jquery-ujs has already been loaded!');
17
- }
18
-
19
- // Shorthand to make it a little easier to call public rails functions from within rails.js
20
- var rails;
21
- var $document = $(document);
22
-
23
- $.rails = rails = {
24
- // Link elements bound by jquery-ujs
25
- linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',
26
-
27
- // Button elements bound by jquery-ujs
28
- buttonClickSelector: 'button[data-remote]',
29
-
30
- // Select elements bound by jquery-ujs
31
- inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
32
-
33
- // Form elements bound by jquery-ujs
34
- formSubmitSelector: 'form',
35
-
36
- // Form input elements bound by jquery-ujs
37
- formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',
38
-
39
- // Form input elements disabled during form submission
40
- disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',
41
-
42
- // Form input elements re-enabled after form submission
43
- enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',
44
-
45
- // Form required input elements
46
- requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
47
-
48
- // Form file input elements
49
- fileInputSelector: 'input[type=file]',
50
-
51
- // Link onClick disable selector with possible reenable after remote submission
52
- linkDisableSelector: 'a[data-disable-with]',
53
-
54
- // Make sure that every Ajax request sends the CSRF token
55
- CSRFProtection: function(xhr) {
56
- var token = $('meta[name="csrf-token"]').attr('content');
57
- if (token) xhr.setRequestHeader('X-CSRF-Token', token);
58
- },
59
-
60
- // making sure that all forms have actual up-to-date token(cached forms contain old one)
61
- refreshCSRFTokens: function(){
62
- var csrfToken = $('meta[name=csrf-token]').attr('content');
63
- var csrfParam = $('meta[name=csrf-param]').attr('content');
64
- $('form input[name="' + csrfParam + '"]').val(csrfToken);
65
- },
66
-
67
- // Triggers an event on an element and returns false if the event result is false
68
- fire: function(obj, name, data) {
69
- var event = $.Event(name);
70
- obj.trigger(event, data);
71
- return event.result !== false;
72
- },
73
-
74
- // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
75
- confirm: function(message) {
76
- return confirm(message);
77
- },
78
-
79
- // Default ajax function, may be overridden with custom function in $.rails.ajax
80
- ajax: function(options) {
81
- return $.ajax(options);
82
- },
83
-
84
- // Default way to get an element's href. May be overridden at $.rails.href.
85
- href: function(element) {
86
- return element.attr('href');
87
- },
88
-
89
- // Submits "remote" forms and links with ajax
90
- handleRemote: function(element) {
91
- var method, url, data, elCrossDomain, crossDomain, withCredentials, dataType, options;
92
-
93
- if (rails.fire(element, 'ajax:before')) {
94
- elCrossDomain = element.data('cross-domain');
95
- crossDomain = elCrossDomain === undefined ? null : elCrossDomain;
96
- withCredentials = element.data('with-credentials') || null;
97
- dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
98
-
99
- if (element.is('form')) {
100
- method = element.attr('method');
101
- url = element.attr('action');
102
- data = element.serializeArray();
103
- // memoized value from clicked submit button
104
- var button = element.data('ujs:submit-button');
105
- if (button) {
106
- data.push(button);
107
- element.data('ujs:submit-button', null);
108
- }
109
- } else if (element.is(rails.inputChangeSelector)) {
110
- method = element.data('method');
111
- url = element.data('url');
112
- data = element.serialize();
113
- if (element.data('params')) data = data + "&" + element.data('params');
114
- } else if (element.is(rails.buttonClickSelector)) {
115
- method = element.data('method') || 'get';
116
- url = element.data('url');
117
- data = element.serialize();
118
- if (element.data('params')) data = data + "&" + element.data('params');
119
- } else {
120
- method = element.data('method');
121
- url = rails.href(element);
122
- data = element.data('params') || null;
123
- }
124
-
125
- options = {
126
- type: method || 'GET', data: data, dataType: dataType,
127
- // stopping the "ajax:beforeSend" event will cancel the ajax request
128
- beforeSend: function(xhr, settings) {
129
- if (settings.dataType === undefined) {
130
- xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
131
- }
132
- return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
133
- },
134
- success: function(data, status, xhr) {
135
- element.trigger('ajax:success', [data, status, xhr]);
136
- },
137
- complete: function(xhr, status) {
138
- element.trigger('ajax:complete', [xhr, status]);
139
- },
140
- error: function(xhr, status, error) {
141
- element.trigger('ajax:error', [xhr, status, error]);
142
- },
143
- crossDomain: crossDomain
144
- };
145
-
146
- // There is no withCredentials for IE6-8 when
147
- // "Enable native XMLHTTP support" is disabled
148
- if (withCredentials) {
149
- options.xhrFields = {
150
- withCredentials: withCredentials
151
- };
152
- }
153
-
154
- // Only pass url to `ajax` options if not blank
155
- if (url) { options.url = url; }
156
-
157
- var jqxhr = rails.ajax(options);
158
- element.trigger('ajax:send', jqxhr);
159
- return jqxhr;
160
- } else {
161
- return false;
162
- }
163
- },
164
-
165
- // Handles "data-method" on links such as:
166
- // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
167
- handleMethod: function(link) {
168
- var href = rails.href(link),
169
- method = link.data('method'),
170
- target = link.attr('target'),
171
- csrfToken = $('meta[name=csrf-token]').attr('content'),
172
- csrfParam = $('meta[name=csrf-param]').attr('content'),
173
- form = $('<form method="post" action="' + href + '"></form>'),
174
- metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
175
-
176
- if (csrfParam !== undefined && csrfToken !== undefined) {
177
- metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
178
- }
179
-
180
- if (target) { form.attr('target', target); }
181
-
182
- form.hide().append(metadataInput).appendTo('body');
183
- form.submit();
184
- },
185
-
186
- /* Disables form elements:
187
- - Caches element value in 'ujs:enable-with' data store
188
- - Replaces element text with value of 'data-disable-with' attribute
189
- - Sets disabled property to true
190
- */
191
- disableFormElements: function(form) {
192
- form.find(rails.disableSelector).each(function() {
193
- var element = $(this), method = element.is('button') ? 'html' : 'val';
194
- element.data('ujs:enable-with', element[method]());
195
- element[method](element.data('disable-with'));
196
- element.prop('disabled', true);
197
- });
198
- },
199
-
200
- /* Re-enables disabled form elements:
201
- - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
202
- - Sets disabled property to false
203
- */
204
- enableFormElements: function(form) {
205
- form.find(rails.enableSelector).each(function() {
206
- var element = $(this), method = element.is('button') ? 'html' : 'val';
207
- if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
208
- element.prop('disabled', false);
209
- });
210
- },
211
-
212
- /* For 'data-confirm' attribute:
213
- - Fires `confirm` event
214
- - Shows the confirmation dialog
215
- - Fires the `confirm:complete` event
216
-
217
- Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
218
- Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
219
- Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
220
- return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
221
- */
222
- allowAction: function(element) {
223
- var message = element.data('confirm'),
224
- answer = false, callback;
225
- if (!message) { return true; }
226
-
227
- if (rails.fire(element, 'confirm')) {
228
- answer = rails.confirm(message);
229
- callback = rails.fire(element, 'confirm:complete', [answer]);
230
- }
231
- return answer && callback;
232
- },
233
-
234
- // Helper function which checks for blank inputs in a form that match the specified CSS selector
235
- blankInputs: function(form, specifiedSelector, nonBlank) {
236
- var inputs = $(), input, valueToCheck,
237
- selector = specifiedSelector || 'input,textarea',
238
- allInputs = form.find(selector);
239
-
240
- allInputs.each(function() {
241
- input = $(this);
242
- valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : input.val();
243
- // If nonBlank and valueToCheck are both truthy, or nonBlank and valueToCheck are both falsey
244
- if (!valueToCheck === !nonBlank) {
245
-
246
- // Don't count unchecked required radio if other radio with same name is checked
247
- if (input.is('input[type=radio]') && allInputs.filter('input[type=radio]:checked[name="' + input.attr('name') + '"]').length) {
248
- return true; // Skip to next input
249
- }
250
-
251
- inputs = inputs.add(input);
252
- }
253
- });
254
- return inputs.length ? inputs : false;
255
- },
256
-
257
- // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
258
- nonBlankInputs: function(form, specifiedSelector) {
259
- return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
260
- },
261
-
262
- // Helper function, needed to provide consistent behavior in IE
263
- stopEverything: function(e) {
264
- $(e.target).trigger('ujs:everythingStopped');
265
- e.stopImmediatePropagation();
266
- return false;
267
- },
268
-
269
- // replace element's html with the 'data-disable-with' after storing original html
270
- // and prevent clicking on it
271
- disableElement: function(element) {
272
- element.data('ujs:enable-with', element.html()); // store enabled state
273
- element.html(element.data('disable-with')); // set to disabled state
274
- element.bind('click.railsDisable', function(e) { // prevent further clicking
275
- return rails.stopEverything(e);
276
- });
277
- },
278
-
279
- // restore element to its original state which was disabled by 'disableElement' above
280
- enableElement: function(element) {
281
- if (element.data('ujs:enable-with') !== undefined) {
282
- element.html(element.data('ujs:enable-with')); // set to old enabled state
283
- element.removeData('ujs:enable-with'); // clean up cache
284
- }
285
- element.unbind('click.railsDisable'); // enable element
286
- }
287
-
288
- };
289
-
290
- if (rails.fire($document, 'rails:attachBindings')) {
291
-
292
- $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
293
-
294
- $document.delegate(rails.linkDisableSelector, 'ajax:complete', function() {
295
- rails.enableElement($(this));
296
- });
297
-
298
- $document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
299
- var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
300
- if (!rails.allowAction(link)) return rails.stopEverything(e);
301
-
302
- if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
303
-
304
- if (link.data('remote') !== undefined) {
305
- if (metaClick && (!method || method === 'GET') && !data) { return true; }
306
-
307
- var handleRemote = rails.handleRemote(link);
308
- // response from rails.handleRemote() will either be false or a deferred object promise.
309
- if (handleRemote === false) {
310
- rails.enableElement(link);
311
- } else {
312
- handleRemote.error( function() { rails.enableElement(link); } );
313
- }
314
- return false;
315
-
316
- } else if (link.data('method')) {
317
- rails.handleMethod(link);
318
- return false;
319
- }
320
- });
321
-
322
- $document.delegate(rails.buttonClickSelector, 'click.rails', function(e) {
323
- var button = $(this);
324
- if (!rails.allowAction(button)) return rails.stopEverything(e);
325
-
326
- rails.handleRemote(button);
327
- return false;
328
- });
329
-
330
- $document.delegate(rails.inputChangeSelector, 'change.rails', function(e) {
331
- var link = $(this);
332
- if (!rails.allowAction(link)) return rails.stopEverything(e);
333
-
334
- rails.handleRemote(link);
335
- return false;
336
- });
337
-
338
- $document.delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
339
- var form = $(this),
340
- remote = form.data('remote') !== undefined,
341
- blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
342
- nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
343
-
344
- if (!rails.allowAction(form)) return rails.stopEverything(e);
345
-
346
- // skip other logic when required values are missing or file upload is present
347
- if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
348
- return rails.stopEverything(e);
349
- }
350
-
351
- if (remote) {
352
- if (nonBlankFileInputs) {
353
- // slight timeout so that the submit button gets properly serialized
354
- // (make it easy for event handler to serialize form without disabled values)
355
- setTimeout(function(){ rails.disableFormElements(form); }, 13);
356
- var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
357
-
358
- // re-enable form elements if event bindings return false (canceling normal form submission)
359
- if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
360
-
361
- return aborted;
362
- }
363
-
364
- rails.handleRemote(form);
365
- return false;
366
-
367
- } else {
368
- // slight timeout so that the submit button gets properly serialized
369
- setTimeout(function(){ rails.disableFormElements(form); }, 13);
370
- }
371
- });
372
-
373
- $document.delegate(rails.formInputClickSelector, 'click.rails', function(event) {
374
- var button = $(this);
375
-
376
- if (!rails.allowAction(button)) return rails.stopEverything(event);
377
-
378
- // register the pressed submit button
379
- var name = button.attr('name'),
380
- data = name ? {name:name, value:button.val()} : null;
381
-
382
- button.closest('form').data('ujs:submit-button', data);
383
- });
384
-
385
- $document.delegate(rails.formSubmitSelector, 'ajax:beforeSend.rails', function(event) {
386
- if (this == event.target) rails.disableFormElements($(this));
387
- });
388
-
389
- $document.delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
390
- if (this == event.target) rails.enableFormElements($(this));
391
- });
392
-
393
- $(function(){
394
- rails.refreshCSRFTokens();
395
- });
396
- }
397
-
398
- })( jQuery );
@@ -1,3922 +0,0 @@
1
- /**
2
- * Super simple wysiwyg editor on Bootstrap v0.5.2
3
- * http://hackerwins.github.io/summernote/
4
- *
5
- * summernote.js
6
- * Copyright 2013 Alan Hong. and outher contributors
7
- * summernote may be freely distributed under the MIT license./
8
- *
9
- * Date: 2014-05-16T11:28Z
10
- */
11
- (function (factory) {
12
- /* global define */
13
- if (typeof define === 'function' && define.amd) {
14
- // AMD. Register as an anonymous module.
15
- define(['jquery', 'codemirror'], factory);
16
- } else {
17
- // Browser globals: jQuery, CodeMirror
18
- factory(window.jQuery, window.CodeMirror);
19
- }
20
- }(function ($, CodeMirror) {
21
-
22
-
23
-
24
- if ('function' !== typeof Array.prototype.reduce) {
25
- /**
26
- * Array.prototype.reduce fallback
27
- *
28
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
29
- */
30
- Array.prototype.reduce = function (callback, optInitialValue) {
31
- var idx, value, length = this.length >>> 0, isValueSet = false;
32
- if (1 < arguments.length) {
33
- value = optInitialValue;
34
- isValueSet = true;
35
- }
36
- for (idx = 0; length > idx; ++idx) {
37
- if (this.hasOwnProperty(idx)) {
38
- if (isValueSet) {
39
- value = callback(value, this[idx], idx, this);
40
- } else {
41
- value = this[idx];
42
- isValueSet = true;
43
- }
44
- }
45
- }
46
- if (!isValueSet) {
47
- throw new TypeError('Reduce of empty array with no initial value');
48
- }
49
- return value;
50
- };
51
- }
52
-
53
- /**
54
- * Object which check platform and agent
55
- */
56
- var agent = {
57
- bMac: navigator.appVersion.indexOf('Mac') > -1,
58
- bMSIE: navigator.userAgent.indexOf('MSIE') > -1 || navigator.userAgent.indexOf('Trident') > -1,
59
- bFF: navigator.userAgent.indexOf('Firefox') > -1,
60
- jqueryVersion: parseFloat($.fn.jquery),
61
- bCodeMirror: !!CodeMirror
62
- };
63
-
64
- /**
65
- * func utils (for high-order func's arg)
66
- */
67
- var func = (function () {
68
- var eq = function (elA) {
69
- return function (elB) {
70
- return elA === elB;
71
- };
72
- };
73
-
74
- var eq2 = function (elA, elB) {
75
- return elA === elB;
76
- };
77
-
78
- var ok = function () {
79
- return true;
80
- };
81
-
82
- var fail = function () {
83
- return false;
84
- };
85
-
86
- var not = function (f) {
87
- return function () {
88
- return !f.apply(f, arguments);
89
- };
90
- };
91
-
92
- var self = function (a) {
93
- return a;
94
- };
95
-
96
- var idCounter = 0;
97
-
98
- /**
99
- * generate a globally-unique id
100
- *
101
- * @param {String} [prefix]
102
- */
103
- var uniqueId = function (prefix) {
104
- var id = ++idCounter + '';
105
- return prefix ? prefix + id : id;
106
- };
107
-
108
- /**
109
- * returns bnd (bounds) from rect
110
- *
111
- * - IE Compatability Issue: http://goo.gl/sRLOAo
112
- * - Scroll Issue: http://goo.gl/sNjUc
113
- *
114
- * @param {Rect} rect
115
- * @return {Object} bounds
116
- * @return {Number} bounds.top
117
- * @return {Number} bounds.left
118
- * @return {Number} bounds.width
119
- * @return {Number} bounds.height
120
- */
121
- var rect2bnd = function (rect) {
122
- var $document = $(document);
123
- return {
124
- top: rect.top + $document.scrollTop(),
125
- left: rect.left + $document.scrollLeft(),
126
- width: rect.right - rect.left,
127
- height: rect.bottom - rect.top
128
- };
129
- };
130
-
131
- /**
132
- * returns a copy of the object where the keys have become the values and the values the keys.
133
- * @param {Object} obj
134
- * @return {Object}
135
- */
136
- var invertObject = function (obj) {
137
- var inverted = {};
138
- for (var key in obj) {
139
- if (obj.hasOwnProperty(key)) {
140
- inverted[obj[key]] = key;
141
- }
142
- }
143
- return inverted;
144
- };
145
-
146
- return {
147
- eq: eq,
148
- eq2: eq2,
149
- ok: ok,
150
- fail: fail,
151
- not: not,
152
- self: self,
153
- uniqueId: uniqueId,
154
- rect2bnd: rect2bnd,
155
- invertObject: invertObject
156
- };
157
- })();
158
-
159
- /**
160
- * list utils
161
- */
162
- var list = (function () {
163
- /**
164
- * returns the first element of an array.
165
- * @param {Array} array
166
- */
167
- var head = function (array) {
168
- return array[0];
169
- };
170
-
171
- /**
172
- * returns the last element of an array.
173
- * @param {Array} array
174
- */
175
- var last = function (array) {
176
- return array[array.length - 1];
177
- };
178
-
179
- /**
180
- * returns everything but the last entry of the array.
181
- * @param {Array} array
182
- */
183
- var initial = function (array) {
184
- return array.slice(0, array.length - 1);
185
- };
186
-
187
- /**
188
- * returns the rest of the elements in an array.
189
- * @param {Array} array
190
- */
191
- var tail = function (array) {
192
- return array.slice(1);
193
- };
194
-
195
- /**
196
- * returns next item.
197
- * @param {Array} array
198
- */
199
- var next = function (array, item) {
200
- var idx = array.indexOf(item);
201
- if (idx === -1) { return null; }
202
-
203
- return array[idx + 1];
204
- };
205
-
206
- /**
207
- * returns prev item.
208
- * @param {Array} array
209
- */
210
- var prev = function (array, item) {
211
- var idx = array.indexOf(item);
212
- if (idx === -1) { return null; }
213
-
214
- return array[idx - 1];
215
- };
216
-
217
- /**
218
- * get sum from a list
219
- * @param {Array} array - array
220
- * @param {Function} fn - iterator
221
- */
222
- var sum = function (array, fn) {
223
- fn = fn || func.self;
224
- return array.reduce(function (memo, v) {
225
- return memo + fn(v);
226
- }, 0);
227
- };
228
-
229
- /**
230
- * returns a copy of the collection with array type.
231
- * @param {Collection} collection - collection eg) node.childNodes, ...
232
- */
233
- var from = function (collection) {
234
- var result = [], idx = -1, length = collection.length;
235
- while (++idx < length) {
236
- result[idx] = collection[idx];
237
- }
238
- return result;
239
- };
240
-
241
- /**
242
- * cluster elements by predicate function.
243
- * @param {Array} array - array
244
- * @param {Function} fn - predicate function for cluster rule
245
- * @param {Array[]}
246
- */
247
- var clusterBy = function (array, fn) {
248
- if (array.length === 0) { return []; }
249
- var aTail = tail(array);
250
- return aTail.reduce(function (memo, v) {
251
- var aLast = last(memo);
252
- if (fn(last(aLast), v)) {
253
- aLast[aLast.length] = v;
254
- } else {
255
- memo[memo.length] = [v];
256
- }
257
- return memo;
258
- }, [[head(array)]]);
259
- };
260
-
261
- /**
262
- * returns a copy of the array with all falsy values removed
263
- * @param {Array} array - array
264
- * @param {Function} fn - predicate function for cluster rule
265
- */
266
- var compact = function (array) {
267
- var aResult = [];
268
- for (var idx = 0, sz = array.length; idx < sz; idx ++) {
269
- if (array[idx]) { aResult.push(array[idx]); }
270
- }
271
- return aResult;
272
- };
273
-
274
- return { head: head, last: last, initial: initial, tail: tail,
275
- prev: prev, next: next, sum: sum, from: from,
276
- compact: compact, clusterBy: clusterBy };
277
- })();
278
-
279
- /**
280
- * Dom functions
281
- */
282
- var dom = (function () {
283
- /**
284
- * returns whether node is `note-editable` or not.
285
- *
286
- * @param {Element} node
287
- * @return {Boolean}
288
- */
289
- var isEditable = function (node) {
290
- return node && $(node).hasClass('note-editable');
291
- };
292
-
293
- var isControlSizing = function (node) {
294
- return node && $(node).hasClass('note-control-sizing');
295
- };
296
-
297
- /**
298
- * build layoutInfo from $editor(.note-editor)
299
- *
300
- * @param {jQuery} $editor
301
- * @return {Object}
302
- */
303
- var buildLayoutInfo = function ($editor) {
304
- var makeFinder;
305
-
306
- // air mode
307
- if ($editor.hasClass('note-air-editor')) {
308
- var id = list.last($editor.attr('id').split('-'));
309
- makeFinder = function (sIdPrefix) {
310
- return function () { return $(sIdPrefix + id); };
311
- };
312
-
313
- return {
314
- editor: function () { return $editor; },
315
- editable: function () { return $editor; },
316
- popover: makeFinder('#note-popover-'),
317
- handle: makeFinder('#note-handle-'),
318
- dialog: makeFinder('#note-dialog-')
319
- };
320
-
321
- // frame mode
322
- } else {
323
- makeFinder = function (sClassName) {
324
- return function () { return $editor.find(sClassName); };
325
- };
326
- return {
327
- editor: function () { return $editor; },
328
- dropzone: makeFinder('.note-dropzone'),
329
- toolbar: makeFinder('.note-toolbar'),
330
- editable: makeFinder('.note-editable'),
331
- codable: makeFinder('.note-codable'),
332
- statusbar: makeFinder('.note-statusbar'),
333
- popover: makeFinder('.note-popover'),
334
- handle: makeFinder('.note-handle'),
335
- dialog: makeFinder('.note-dialog')
336
- };
337
- }
338
- };
339
-
340
- /**
341
- * returns predicate which judge whether nodeName is same
342
- * @param {String} sNodeName
343
- */
344
- var makePredByNodeName = function (sNodeName) {
345
- // nodeName is always uppercase.
346
- return function (node) {
347
- return node && node.nodeName === sNodeName;
348
- };
349
- };
350
-
351
- var isPara = function (node) {
352
- // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
353
- return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName);
354
- };
355
-
356
- var isList = function (node) {
357
- return node && /^UL|^OL/.test(node.nodeName);
358
- };
359
-
360
- var isCell = function (node) {
361
- return node && /^TD|^TH/.test(node.nodeName);
362
- };
363
-
364
- /**
365
- * find nearest ancestor predicate hit
366
- *
367
- * @param {Element} node
368
- * @param {Function} pred - predicate function
369
- */
370
- var ancestor = function (node, pred) {
371
- while (node) {
372
- if (pred(node)) { return node; }
373
- if (isEditable(node)) { break; }
374
-
375
- node = node.parentNode;
376
- }
377
- return null;
378
- };
379
-
380
- /**
381
- * returns new array of ancestor nodes (until predicate hit).
382
- *
383
- * @param {Element} node
384
- * @param {Function} [optional] pred - predicate function
385
- */
386
- var listAncestor = function (node, pred) {
387
- pred = pred || func.fail;
388
-
389
- var aAncestor = [];
390
- ancestor(node, function (el) {
391
- aAncestor.push(el);
392
- return pred(el);
393
- });
394
- return aAncestor;
395
- };
396
-
397
- /**
398
- * returns common ancestor node between two nodes.
399
- *
400
- * @param {Element} nodeA
401
- * @param {Element} nodeB
402
- */
403
- var commonAncestor = function (nodeA, nodeB) {
404
- var aAncestor = listAncestor(nodeA);
405
- for (var n = nodeB; n; n = n.parentNode) {
406
- if ($.inArray(n, aAncestor) > -1) { return n; }
407
- }
408
- return null; // difference document area
409
- };
410
-
411
- /**
412
- * listing all Nodes between two nodes.
413
- * FIXME: nodeA and nodeB must be sorted, use comparePoints later.
414
- *
415
- * @param {Element} nodeA
416
- * @param {Element} nodeB
417
- */
418
- var listBetween = function (nodeA, nodeB) {
419
- var aNode = [];
420
-
421
- var bStart = false, bEnd = false;
422
-
423
- // DFS(depth first search) with commonAcestor.
424
- (function fnWalk(node) {
425
- if (!node) { return; } // traverse fisnish
426
- if (node === nodeA) { bStart = true; } // start point
427
- if (bStart && !bEnd) { aNode.push(node); } // between
428
- if (node === nodeB) { bEnd = true; return; } // end point
429
-
430
- for (var idx = 0, sz = node.childNodes.length; idx < sz; idx++) {
431
- fnWalk(node.childNodes[idx]);
432
- }
433
- })(commonAncestor(nodeA, nodeB));
434
-
435
- return aNode;
436
- };
437
-
438
- /**
439
- * listing all previous siblings (until predicate hit).
440
- * @param {Element} node
441
- * @param {Function} [optional] pred - predicate function
442
- */
443
- var listPrev = function (node, pred) {
444
- pred = pred || func.fail;
445
-
446
- var aNext = [];
447
- while (node) {
448
- aNext.push(node);
449
- if (pred(node)) { break; }
450
- node = node.previousSibling;
451
- }
452
- return aNext;
453
- };
454
-
455
- /**
456
- * listing next siblings (until predicate hit).
457
- *
458
- * @param {Element} node
459
- * @param {Function} [pred] - predicate function
460
- */
461
- var listNext = function (node, pred) {
462
- pred = pred || func.fail;
463
-
464
- var aNext = [];
465
- while (node) {
466
- aNext.push(node);
467
- if (pred(node)) { break; }
468
- node = node.nextSibling;
469
- }
470
- return aNext;
471
- };
472
-
473
- /**
474
- * listing descendant nodes
475
- *
476
- * @param {Element} node
477
- * @param {Function} [pred] - predicate function
478
- */
479
- var listDescendant = function (node, pred) {
480
- var aDescendant = [];
481
- pred = pred || func.ok;
482
-
483
- // start DFS(depth first search) with node
484
- (function fnWalk(current) {
485
- if (node !== current && pred(current)) {
486
- aDescendant.push(current);
487
- }
488
- for (var idx = 0, sz = current.childNodes.length; idx < sz; idx++) {
489
- fnWalk(current.childNodes[idx]);
490
- }
491
- })(node);
492
-
493
- return aDescendant;
494
- };
495
-
496
- /**
497
- * insert node after preceding
498
- *
499
- * @param {Element} node
500
- * @param {Element} preceding - predicate function
501
- */
502
- var insertAfter = function (node, preceding) {
503
- var next = preceding.nextSibling, parent = preceding.parentNode;
504
- if (next) {
505
- parent.insertBefore(node, next);
506
- } else {
507
- parent.appendChild(node);
508
- }
509
- return node;
510
- };
511
-
512
- /**
513
- * append elements.
514
- *
515
- * @param {Element} node
516
- * @param {Collection} aChild
517
- */
518
- var appends = function (node, aChild) {
519
- $.each(aChild, function (idx, child) {
520
- node.appendChild(child);
521
- });
522
- return node;
523
- };
524
-
525
- var isText = makePredByNodeName('#text');
526
-
527
- /**
528
- * returns #text's text size or element's childNodes size
529
- *
530
- * @param {Element} node
531
- */
532
- var length = function (node) {
533
- if (isText(node)) { return node.nodeValue.length; }
534
- return node.childNodes.length;
535
- };
536
-
537
- /**
538
- * returns offset from parent.
539
- *
540
- * @param {Element} node
541
- */
542
- var position = function (node) {
543
- var offset = 0;
544
- while ((node = node.previousSibling)) { offset += 1; }
545
- return offset;
546
- };
547
-
548
- /**
549
- * return offsetPath(array of offset) from ancestor
550
- *
551
- * @param {Element} ancestor - ancestor node
552
- * @param {Element} node
553
- */
554
- var makeOffsetPath = function (ancestor, node) {
555
- var aAncestor = list.initial(listAncestor(node, func.eq(ancestor)));
556
- return $.map(aAncestor, position).reverse();
557
- };
558
-
559
- /**
560
- * return element from offsetPath(array of offset)
561
- *
562
- * @param {Element} ancestor - ancestor node
563
- * @param {array} aOffset - offsetPath
564
- */
565
- var fromOffsetPath = function (ancestor, aOffset) {
566
- var current = ancestor;
567
- for (var i = 0, sz = aOffset.length; i < sz; i++) {
568
- current = current.childNodes[aOffset[i]];
569
- }
570
- return current;
571
- };
572
-
573
- /**
574
- * split element or #text
575
- *
576
- * @param {Element} node
577
- * @param {Number} offset
578
- */
579
- var splitData = function (node, offset) {
580
- if (offset === 0) { return node; }
581
- if (offset >= length(node)) { return node.nextSibling; }
582
-
583
- // splitText
584
- if (isText(node)) { return node.splitText(offset); }
585
-
586
- // splitElement
587
- var child = node.childNodes[offset];
588
- node = insertAfter(node.cloneNode(false), node);
589
- return appends(node, listNext(child));
590
- };
591
-
592
- /**
593
- * split dom tree by boundaryPoint(pivot and offset)
594
- *
595
- * @param {Element} root
596
- * @param {Element} pivot - this will be boundaryPoint's node
597
- * @param {Number} offset - this will be boundaryPoint's offset
598
- */
599
- var split = function (root, pivot, offset) {
600
- var aAncestor = listAncestor(pivot, func.eq(root));
601
- if (aAncestor.length === 1) { return splitData(pivot, offset); }
602
- return aAncestor.reduce(function (node, parent) {
603
- var clone = parent.cloneNode(false);
604
- insertAfter(clone, parent);
605
- if (node === pivot) {
606
- node = splitData(node, offset);
607
- }
608
- appends(clone, listNext(node));
609
- return clone;
610
- });
611
- };
612
-
613
- /**
614
- * remove node, (bRemoveChild: remove child or not)
615
- * @param {Element} node
616
- * @param {Boolean} bRemoveChild
617
- */
618
- var remove = function (node, bRemoveChild) {
619
- if (!node || !node.parentNode) { return; }
620
- if (node.removeNode) { return node.removeNode(bRemoveChild); }
621
-
622
- var elParent = node.parentNode;
623
- if (!bRemoveChild) {
624
- var aNode = [];
625
- var i, sz;
626
- for (i = 0, sz = node.childNodes.length; i < sz; i++) {
627
- aNode.push(node.childNodes[i]);
628
- }
629
-
630
- for (i = 0, sz = aNode.length; i < sz; i++) {
631
- elParent.insertBefore(aNode[i], node);
632
- }
633
- }
634
-
635
- elParent.removeChild(node);
636
- };
637
-
638
- var html = function ($node) {
639
- return dom.isTextarea($node[0]) ? $node.val() : $node.html();
640
- };
641
-
642
- return {
643
- blank: agent.bMSIE ? '&nbsp;' : '<br/>',
644
- emptyPara: '<p><br/></p>',
645
- isEditable: isEditable,
646
- isControlSizing: isControlSizing,
647
- buildLayoutInfo: buildLayoutInfo,
648
- isText: isText,
649
- isPara: isPara,
650
- isList: isList,
651
- isTable: makePredByNodeName('TABLE'),
652
- isCell: isCell,
653
- isAnchor: makePredByNodeName('A'),
654
- isDiv: makePredByNodeName('DIV'),
655
- isLi: makePredByNodeName('LI'),
656
- isSpan: makePredByNodeName('SPAN'),
657
- isB: makePredByNodeName('B'),
658
- isU: makePredByNodeName('U'),
659
- isS: makePredByNodeName('S'),
660
- isI: makePredByNodeName('I'),
661
- isImg: makePredByNodeName('IMG'),
662
- isTextarea: makePredByNodeName('TEXTAREA'),
663
- ancestor: ancestor,
664
- listAncestor: listAncestor,
665
- listNext: listNext,
666
- listPrev: listPrev,
667
- listDescendant: listDescendant,
668
- commonAncestor: commonAncestor,
669
- listBetween: listBetween,
670
- insertAfter: insertAfter,
671
- position: position,
672
- makeOffsetPath: makeOffsetPath,
673
- fromOffsetPath: fromOffsetPath,
674
- split: split,
675
- remove: remove,
676
- html: html
677
- };
678
- })();
679
-
680
- var settings = {
681
- // version
682
- version: '0.5.2',
683
-
684
- /**
685
- * options
686
- */
687
- options: {
688
- width: null, // set editor width
689
- height: null, // set editable height, ex) 300
690
-
691
- focus: false, // set focus after initilize summernote
692
-
693
- tabsize: 4, // size of tab ex) 2 or 4
694
- styleWithSpan: true, // style with span (Chrome and FF only)
695
-
696
- disableLinkTarget: false, // hide link Target Checkbox
697
- disableDragAndDrop: false, // disable drag and drop event
698
-
699
- codemirror: { // codemirror options
700
- mode: 'text/html',
701
- lineNumbers: true
702
- },
703
-
704
- // language
705
- lang: 'en-US', // language 'en-US', 'ko-KR', ...
706
- direction: null, // text direction, ex) 'rtl'
707
-
708
- // toolbar
709
- toolbar: [
710
- ['style', ['style']],
711
- ['font', ['bold', 'italic', 'underline', 'superscript', 'subscript', 'strikethrough', 'clear']],
712
- ['fontname', ['fontname']],
713
- // ['fontsize', ['fontsize']], // Still buggy
714
- ['color', ['color']],
715
- ['para', ['ul', 'ol', 'paragraph']],
716
- ['height', ['height']],
717
- ['table', ['table']],
718
- ['insert', ['link', 'picture', 'video']],
719
- ['view', ['fullscreen', 'codeview']],
720
- ['help', ['help']]
721
- ],
722
-
723
- // air mode: inline editor
724
- airMode: false,
725
- // airPopover: [
726
- // ['style', ['style']],
727
- // ['font', ['bold', 'italic', 'underline', 'clear']],
728
- // ['fontname', ['fontname']],
729
- // ['fontsize', ['fontsize']], // Still buggy
730
- // ['color', ['color']],
731
- // ['para', ['ul', 'ol', 'paragraph']],
732
- // ['height', ['height']],
733
- // ['table', ['table']],
734
- // ['insert', ['link', 'picture', 'video']],
735
- // ['help', ['help']]
736
- // ],
737
- airPopover: [
738
- ['color', ['color']],
739
- ['font', ['bold', 'underline', 'clear']],
740
- ['para', ['ul', 'paragraph']],
741
- ['table', ['table']],
742
- ['insert', ['link', 'picture']]
743
- ],
744
-
745
- // style tag
746
- styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
747
-
748
- // default fontName
749
- defaultFontName: 'Arial',
750
-
751
- // fontName
752
- fontNames: [
753
- 'Serif', 'Sans', 'Arial', 'Arial Black', 'Courier',
754
- 'Courier New', 'Comic Sans MS', 'Helvetica', 'Impact', 'Lucida Grande',
755
- 'Lucida Sans', 'Tahoma', 'Times', 'Times New Roman', 'Verdana'
756
- ],
757
-
758
- // pallete colors(n x n)
759
- colors: [
760
- ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],
761
- ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
762
- ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
763
- ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
764
- ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
765
- ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
766
- ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
767
- ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']
768
- ],
769
-
770
- // fontSize
771
- fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],
772
-
773
- // lineHeight
774
- lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],
775
-
776
- // callbacks
777
- oninit: null, // initialize
778
- onfocus: null, // editable has focus
779
- onblur: null, // editable out of focus
780
- onenter: null, // enter key pressed
781
- onkeyup: null, // keyup
782
- onkeydown: null, // keydown
783
- onImageUpload: null, // imageUploadHandler
784
- onImageUploadError: null, // imageUploadErrorHandler
785
- onToolbarClick: null,
786
-
787
- keyMap: {
788
- pc: {
789
- 'CTRL+Z': 'undo',
790
- 'CTRL+Y': 'redo',
791
- 'TAB': 'tab',
792
- 'SHIFT+TAB': 'untab',
793
- 'CTRL+B': 'bold',
794
- 'CTRL+I': 'italic',
795
- 'CTRL+U': 'underline',
796
- 'CTRL+SHIFT+S': 'strikethrough',
797
- 'CTRL+BACKSLASH': 'removeFormat',
798
- 'CTRL+SHIFT+L': 'justifyLeft',
799
- 'CTRL+SHIFT+E': 'justifyCenter',
800
- 'CTRL+SHIFT+R': 'justifyRight',
801
- 'CTRL+SHIFT+J': 'justifyFull',
802
- 'CTRL+SHIFT+NUM7': 'insertUnorderedList',
803
- 'CTRL+SHIFT+NUM8': 'insertOrderedList',
804
- 'CTRL+LEFTBRACKET': 'outdent',
805
- 'CTRL+RIGHTBRACKET': 'indent',
806
- 'CTRL+NUM0': 'formatPara',
807
- 'CTRL+NUM1': 'formatH1',
808
- 'CTRL+NUM2': 'formatH2',
809
- 'CTRL+NUM3': 'formatH3',
810
- 'CTRL+NUM4': 'formatH4',
811
- 'CTRL+NUM5': 'formatH5',
812
- 'CTRL+NUM6': 'formatH6',
813
- 'CTRL+ENTER': 'insertHorizontalRule'
814
- },
815
-
816
- mac: {
817
- 'CMD+Z': 'undo',
818
- 'CMD+SHIFT+Z': 'redo',
819
- 'TAB': 'tab',
820
- 'SHIFT+TAB': 'untab',
821
- 'CMD+B': 'bold',
822
- 'CMD+I': 'italic',
823
- 'CMD+U': 'underline',
824
- 'CMD+SHIFT+S': 'strikethrough',
825
- 'CMD+BACKSLASH': 'removeFormat',
826
- 'CMD+SHIFT+L': 'justifyLeft',
827
- 'CMD+SHIFT+E': 'justifyCenter',
828
- 'CMD+SHIFT+R': 'justifyRight',
829
- 'CMD+SHIFT+J': 'justifyFull',
830
- 'CMD+SHIFT+NUM7': 'insertUnorderedList',
831
- 'CMD+SHIFT+NUM8': 'insertOrderedList',
832
- 'CMD+LEFTBRACKET': 'outdent',
833
- 'CMD+RIGHTBRACKET': 'indent',
834
- 'CMD+NUM0': 'formatPara',
835
- 'CMD+NUM1': 'formatH1',
836
- 'CMD+NUM2': 'formatH2',
837
- 'CMD+NUM3': 'formatH3',
838
- 'CMD+NUM4': 'formatH4',
839
- 'CMD+NUM5': 'formatH5',
840
- 'CMD+NUM6': 'formatH6',
841
- 'CMD+ENTER': 'insertHorizontalRule'
842
- }
843
- }
844
- },
845
-
846
- // default language: en-US
847
- lang: {
848
- 'en-US': {
849
- font: {
850
- bold: 'Bold',
851
- italic: 'Italic',
852
- underline: 'Underline',
853
- strikethrough: 'Strikethrough',
854
- clear: 'Remove Font Style',
855
- height: 'Line Height',
856
- name: 'Font Family',
857
- size: 'Font Size'
858
- },
859
- image: {
860
- image: 'Picture',
861
- insert: 'Insert Image',
862
- resizeFull: 'Resize Full',
863
- resizeHalf: 'Resize Half',
864
- resizeQuarter: 'Resize Quarter',
865
- floatLeft: 'Float Left',
866
- floatRight: 'Float Right',
867
- floatNone: 'Float None',
868
- dragImageHere: 'Drag an image here',
869
- selectFromFiles: 'Select from files',
870
- url: 'Image URL',
871
- remove: 'Remove Image'
872
- },
873
- link: {
874
- link: 'Link',
875
- insert: 'Insert Link',
876
- unlink: 'Unlink',
877
- edit: 'Edit',
878
- textToDisplay: 'Text to display',
879
- url: 'To what URL should this link go?',
880
- openInNewWindow: 'Open in new window'
881
- },
882
- video: {
883
- video: 'Video',
884
- videoLink: 'Video Link',
885
- insert: 'Insert Video',
886
- url: 'Video URL?',
887
- providers: '(YouTube, Vimeo, Vine, Instagram, or DailyMotion)'
888
- },
889
- table: {
890
- table: 'Table'
891
- },
892
- hr: {
893
- insert: 'Insert Horizontal Rule'
894
- },
895
- style: {
896
- style: 'Style',
897
- normal: 'Normal',
898
- blockquote: 'Quote',
899
- pre: 'Code',
900
- h1: 'Header 1',
901
- h2: 'Header 2',
902
- h3: 'Header 3',
903
- h4: 'Header 4',
904
- h5: 'Header 5',
905
- h6: 'Header 6'
906
- },
907
- lists: {
908
- unordered: 'Unordered list',
909
- ordered: 'Ordered list'
910
- },
911
- options: {
912
- help: 'Help',
913
- fullscreen: 'Full Screen',
914
- codeview: 'Code View'
915
- },
916
- paragraph: {
917
- paragraph: 'Paragraph',
918
- outdent: 'Outdent',
919
- indent: 'Indent',
920
- left: 'Align left',
921
- center: 'Align center',
922
- right: 'Align right',
923
- justify: 'Justify full'
924
- },
925
- color: {
926
- recent: 'Recent Color',
927
- more: 'More Color',
928
- background: 'BackColor',
929
- foreground: 'FontColor',
930
- transparent: 'Transparent',
931
- setTransparent: 'Set transparent',
932
- reset: 'Reset',
933
- resetToDefault: 'Reset to default'
934
- },
935
- shortcut: {
936
- shortcuts: 'Keyboard shortcuts',
937
- close: 'Close',
938
- textFormatting: 'Text formatting',
939
- action: 'Action',
940
- paragraphFormatting: 'Paragraph formatting',
941
- documentStyle: 'Document Style'
942
- },
943
- history: {
944
- undo: 'Undo',
945
- redo: 'Redo'
946
- }
947
- }
948
- }
949
- };
950
-
951
- /**
952
- * Async functions which returns `Promise`
953
- */
954
- var async = (function () {
955
- /**
956
- * read contents of file as representing URL
957
- *
958
- * @param {File} file
959
- * @return {Promise} - then: sDataUrl
960
- */
961
- var readFileAsDataURL = function (file) {
962
- return $.Deferred(function (deferred) {
963
- $.extend(new FileReader(), {
964
- onload: function (e) {
965
- var sDataURL = e.target.result;
966
- deferred.resolve(sDataURL);
967
- },
968
- onerror: function () {
969
- deferred.reject(this);
970
- }
971
- }).readAsDataURL(file);
972
- }).promise();
973
- };
974
-
975
- /**
976
- * create `<image>` from url string
977
- *
978
- * @param {String} sUrl
979
- * @return {Promise} - then: $image
980
- */
981
- var createImage = function (sUrl) {
982
- return $.Deferred(function (deferred) {
983
- $('<img>').one('load', function () {
984
- deferred.resolve($(this));
985
- }).one('error abort', function () {
986
- deferred.reject($(this));
987
- }).css({
988
- display: 'none'
989
- }).appendTo(document.body).attr('src', sUrl);
990
- }).promise();
991
- };
992
-
993
- return {
994
- readFileAsDataURL: readFileAsDataURL,
995
- createImage: createImage
996
- };
997
- })();
998
-
999
- /**
1000
- * Object for keycodes.
1001
- */
1002
- var key = {
1003
- isEdit: function (keyCode) {
1004
- return [8, 9, 13, 32].indexOf(keyCode) !== -1;
1005
- },
1006
- nameFromCode: {
1007
- '8': 'BACKSPACE',
1008
- '9': 'TAB',
1009
- '13': 'ENTER',
1010
- '32': 'SPACE',
1011
-
1012
- // Number: 0-9
1013
- '48': 'NUM0',
1014
- '49': 'NUM1',
1015
- '50': 'NUM2',
1016
- '51': 'NUM3',
1017
- '52': 'NUM4',
1018
- '53': 'NUM5',
1019
- '54': 'NUM6',
1020
- '55': 'NUM7',
1021
- '56': 'NUM8',
1022
-
1023
- // Alphabet: a-z
1024
- '66': 'B',
1025
- '69': 'E',
1026
- '73': 'I',
1027
- '74': 'J',
1028
- '75': 'K',
1029
- '76': 'L',
1030
- '82': 'R',
1031
- '83': 'S',
1032
- '85': 'U',
1033
- '89': 'Y',
1034
- '90': 'Z',
1035
-
1036
- '191': 'SLASH',
1037
- '219': 'LEFTBRACKET',
1038
- '220': 'BACKSLASH',
1039
- '221': 'RIGHTBRACKET'
1040
- }
1041
- };
1042
-
1043
- /**
1044
- * Style
1045
- * @class
1046
- */
1047
- var Style = function () {
1048
- /**
1049
- * passing an array of style properties to .css()
1050
- * will result in an object of property-value pairs.
1051
- * (compability with version < 1.9)
1052
- *
1053
- * @param {jQuery} $obj
1054
- * @param {Array} propertyNames - An array of one or more CSS properties.
1055
- * @returns {Object}
1056
- */
1057
- var jQueryCSS = function ($obj, propertyNames) {
1058
- if (agent.jqueryVersion < 1.9) {
1059
- var result = {};
1060
- $.each(propertyNames, function (idx, propertyName) {
1061
- result[propertyName] = $obj.css(propertyName);
1062
- });
1063
- return result;
1064
- }
1065
- return $obj.css.call($obj, propertyNames);
1066
- };
1067
-
1068
- /**
1069
- * paragraph level style
1070
- *
1071
- * @param {WrappedRange} rng
1072
- * @param {Object} oStyle
1073
- */
1074
- this.stylePara = function (rng, oStyle) {
1075
- $.each(rng.nodes(dom.isPara), function (idx, elPara) {
1076
- $(elPara).css(oStyle);
1077
- });
1078
- };
1079
-
1080
- /**
1081
- * get current style on cursor
1082
- *
1083
- * @param {WrappedRange} rng
1084
- * @param {Element} elTarget - target element on event
1085
- * @return {Object} - object contains style properties.
1086
- */
1087
- this.current = function (rng, elTarget) {
1088
- var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);
1089
- var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
1090
- var oStyle = jQueryCSS($cont, properties) || {};
1091
-
1092
- oStyle['font-size'] = parseInt(oStyle['font-size'], 10);
1093
-
1094
- // document.queryCommandState for toggle state
1095
- oStyle['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';
1096
- oStyle['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';
1097
- oStyle['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';
1098
- oStyle['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';
1099
- oStyle['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';
1100
- oStyle['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';
1101
-
1102
- // list-style-type to list-style(unordered, ordered)
1103
- if (!rng.isOnList()) {
1104
- oStyle['list-style'] = 'none';
1105
- } else {
1106
- var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];
1107
- var bUnordered = $.inArray(oStyle['list-style-type'], aOrderedType) > -1;
1108
- oStyle['list-style'] = bUnordered ? 'unordered' : 'ordered';
1109
- }
1110
-
1111
- var elPara = dom.ancestor(rng.sc, dom.isPara);
1112
- if (elPara && elPara.style['line-height']) {
1113
- oStyle['line-height'] = elPara.style.lineHeight;
1114
- } else {
1115
- var lineHeight = parseInt(oStyle['line-height'], 10) / parseInt(oStyle['font-size'], 10);
1116
- oStyle['line-height'] = lineHeight.toFixed(1);
1117
- }
1118
-
1119
- oStyle.image = dom.isImg(elTarget) && elTarget;
1120
- oStyle.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
1121
- oStyle.aAncestor = dom.listAncestor(rng.sc, dom.isEditable);
1122
- oStyle.range = rng;
1123
-
1124
- return oStyle;
1125
- };
1126
- };
1127
-
1128
- /**
1129
- * range module
1130
- */
1131
- var range = (function () {
1132
- var bW3CRangeSupport = !!document.createRange;
1133
-
1134
- /**
1135
- * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
1136
- * @param {TextRange} textRange
1137
- * @param {Boolean} bStart
1138
- * @return {BoundaryPoint}
1139
- */
1140
- var textRange2bp = function (textRange, bStart) {
1141
- var elCont = textRange.parentElement(), nOffset;
1142
-
1143
- var tester = document.body.createTextRange(), elPrevCont;
1144
- var aChild = list.from(elCont.childNodes);
1145
- for (nOffset = 0; nOffset < aChild.length; nOffset++) {
1146
- if (dom.isText(aChild[nOffset])) { continue; }
1147
- tester.moveToElementText(aChild[nOffset]);
1148
- if (tester.compareEndPoints('StartToStart', textRange) >= 0) { break; }
1149
- elPrevCont = aChild[nOffset];
1150
- }
1151
-
1152
- if (nOffset !== 0 && dom.isText(aChild[nOffset - 1])) {
1153
- var textRangeStart = document.body.createTextRange(), elCurText = null;
1154
- textRangeStart.moveToElementText(elPrevCont || elCont);
1155
- textRangeStart.collapse(!elPrevCont);
1156
- elCurText = elPrevCont ? elPrevCont.nextSibling : elCont.firstChild;
1157
-
1158
- var pointTester = textRange.duplicate();
1159
- pointTester.setEndPoint('StartToStart', textRangeStart);
1160
- var nTextCount = pointTester.text.replace(/[\r\n]/g, '').length;
1161
-
1162
- while (nTextCount > elCurText.nodeValue.length && elCurText.nextSibling) {
1163
- nTextCount -= elCurText.nodeValue.length;
1164
- elCurText = elCurText.nextSibling;
1165
- }
1166
-
1167
- /* jshint ignore:start */
1168
- var sDummy = elCurText.nodeValue; //enforce IE to re-reference elCurText, hack
1169
- /* jshint ignore:end */
1170
-
1171
- if (bStart && elCurText.nextSibling && dom.isText(elCurText.nextSibling) &&
1172
- nTextCount === elCurText.nodeValue.length) {
1173
- nTextCount -= elCurText.nodeValue.length;
1174
- elCurText = elCurText.nextSibling;
1175
- }
1176
-
1177
- elCont = elCurText;
1178
- nOffset = nTextCount;
1179
- }
1180
-
1181
- return {cont: elCont, offset: nOffset};
1182
- };
1183
-
1184
- /**
1185
- * return TextRange from boundary point (inspired by google closure-library)
1186
- * @param {BoundaryPoint} bp
1187
- * @return {TextRange}
1188
- */
1189
- var bp2textRange = function (bp) {
1190
- var textRangeInfo = function (elCont, nOffset) {
1191
- var elNode, bCollapseToStart;
1192
-
1193
- if (dom.isText(elCont)) {
1194
- var aPrevText = dom.listPrev(elCont, func.not(dom.isText));
1195
- var elPrevCont = list.last(aPrevText).previousSibling;
1196
- elNode = elPrevCont || elCont.parentNode;
1197
- nOffset += list.sum(list.tail(aPrevText), dom.length);
1198
- bCollapseToStart = !elPrevCont;
1199
- } else {
1200
- elNode = elCont.childNodes[nOffset] || elCont;
1201
- if (dom.isText(elNode)) {
1202
- return textRangeInfo(elNode, nOffset);
1203
- }
1204
-
1205
- nOffset = 0;
1206
- bCollapseToStart = false;
1207
- }
1208
-
1209
- return {cont: elNode, collapseToStart: bCollapseToStart, offset: nOffset};
1210
- };
1211
-
1212
- var textRange = document.body.createTextRange();
1213
- var info = textRangeInfo(bp.cont, bp.offset);
1214
-
1215
- textRange.moveToElementText(info.cont);
1216
- textRange.collapse(info.collapseToStart);
1217
- textRange.moveStart('character', info.offset);
1218
- return textRange;
1219
- };
1220
-
1221
- /**
1222
- * Wrapped Range
1223
- *
1224
- * @param {Element} sc - start container
1225
- * @param {Number} so - start offset
1226
- * @param {Element} ec - end container
1227
- * @param {Number} eo - end offset
1228
- */
1229
- var WrappedRange = function (sc, so, ec, eo) {
1230
- this.sc = sc;
1231
- this.so = so;
1232
- this.ec = ec;
1233
- this.eo = eo;
1234
-
1235
- // nativeRange: get nativeRange from sc, so, ec, eo
1236
- var nativeRange = function () {
1237
- if (bW3CRangeSupport) {
1238
- var w3cRange = document.createRange();
1239
- w3cRange.setStart(sc, so);
1240
- w3cRange.setEnd(ec, eo);
1241
- return w3cRange;
1242
- } else {
1243
- var textRange = bp2textRange({cont: sc, offset: so});
1244
- textRange.setEndPoint('EndToEnd', bp2textRange({cont: ec, offset: eo}));
1245
- return textRange;
1246
- }
1247
- };
1248
-
1249
- /**
1250
- * select update visible range
1251
- */
1252
- this.select = function () {
1253
- var nativeRng = nativeRange();
1254
- if (bW3CRangeSupport) {
1255
- var selection = document.getSelection();
1256
- if (selection.rangeCount > 0) { selection.removeAllRanges(); }
1257
- selection.addRange(nativeRng);
1258
- } else {
1259
- nativeRng.select();
1260
- }
1261
- };
1262
-
1263
- /**
1264
- * returns matched nodes on range
1265
- *
1266
- * @param {Function} pred - predicate function
1267
- * @return {Element[]}
1268
- */
1269
- this.nodes = function (pred) {
1270
- var aNode = dom.listBetween(sc, ec);
1271
- var aMatched = list.compact($.map(aNode, function (node) {
1272
- return dom.ancestor(node, pred);
1273
- }));
1274
- return $.map(list.clusterBy(aMatched, func.eq2), list.head);
1275
- };
1276
-
1277
- /**
1278
- * returns commonAncestor of range
1279
- * @return {Element} - commonAncestor
1280
- */
1281
- this.commonAncestor = function () {
1282
- return dom.commonAncestor(sc, ec);
1283
- };
1284
-
1285
- /**
1286
- * makeIsOn: return isOn(pred) function
1287
- */
1288
- var makeIsOn = function (pred) {
1289
- return function () {
1290
- var elAncestor = dom.ancestor(sc, pred);
1291
- return !!elAncestor && (elAncestor === dom.ancestor(ec, pred));
1292
- };
1293
- };
1294
-
1295
- // isOnEditable: judge whether range is on editable or not
1296
- this.isOnEditable = makeIsOn(dom.isEditable);
1297
- // isOnList: judge whether range is on list node or not
1298
- this.isOnList = makeIsOn(dom.isList);
1299
- // isOnAnchor: judge whether range is on anchor node or not
1300
- this.isOnAnchor = makeIsOn(dom.isAnchor);
1301
- // isOnAnchor: judge whether range is on cell node or not
1302
- this.isOnCell = makeIsOn(dom.isCell);
1303
- // isCollapsed: judge whether range was collapsed
1304
- this.isCollapsed = function () { return sc === ec && so === eo; };
1305
-
1306
- /**
1307
- * insert node at current cursor
1308
- * @param {Element} node
1309
- */
1310
- this.insertNode = function (node) {
1311
- var nativeRng = nativeRange();
1312
- if (bW3CRangeSupport) {
1313
- nativeRng.insertNode(node);
1314
- } else {
1315
- nativeRng.pasteHTML(node.outerHTML); // NOTE: missing node reference.
1316
- }
1317
- };
1318
-
1319
- this.toString = function () {
1320
- var nativeRng = nativeRange();
1321
- return bW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
1322
- };
1323
-
1324
- /**
1325
- * create offsetPath bookmark
1326
- * @param {Element} elEditable
1327
- */
1328
- this.bookmark = function (elEditable) {
1329
- return {
1330
- s: { path: dom.makeOffsetPath(elEditable, sc), offset: so },
1331
- e: { path: dom.makeOffsetPath(elEditable, ec), offset: eo }
1332
- };
1333
- };
1334
-
1335
- /**
1336
- * getClientRects
1337
- * @return {Rect[]}
1338
- */
1339
- this.getClientRects = function () {
1340
- var nativeRng = nativeRange();
1341
- return nativeRng.getClientRects();
1342
- };
1343
- };
1344
-
1345
- return {
1346
- /**
1347
- * create Range Object From arguments or Browser Selection
1348
- *
1349
- * @param {Element} sc - start container
1350
- * @param {Number} so - start offset
1351
- * @param {Element} ec - end container
1352
- * @param {Number} eo - end offset
1353
- */
1354
- create : function (sc, so, ec, eo) {
1355
- if (arguments.length === 0) { // from Browser Selection
1356
- if (bW3CRangeSupport) { // webkit, firefox
1357
- var selection = document.getSelection();
1358
- if (selection.rangeCount === 0) { return null; }
1359
-
1360
- var nativeRng = selection.getRangeAt(0);
1361
- sc = nativeRng.startContainer;
1362
- so = nativeRng.startOffset;
1363
- ec = nativeRng.endContainer;
1364
- eo = nativeRng.endOffset;
1365
- } else { // IE8: TextRange
1366
- var textRange = document.selection.createRange();
1367
- var textRangeEnd = textRange.duplicate();
1368
- textRangeEnd.collapse(false);
1369
- var textRangeStart = textRange;
1370
- textRangeStart.collapse(true);
1371
-
1372
- var bpStart = textRange2bp(textRangeStart, true),
1373
- bpEnd = textRange2bp(textRangeEnd, false);
1374
-
1375
- sc = bpStart.cont;
1376
- so = bpStart.offset;
1377
- ec = bpEnd.cont;
1378
- eo = bpEnd.offset;
1379
- }
1380
- } else if (arguments.length === 2) { //collapsed
1381
- ec = sc;
1382
- eo = so;
1383
- }
1384
- return new WrappedRange(sc, so, ec, eo);
1385
- },
1386
-
1387
- /**
1388
- * create WrappedRange from node
1389
- *
1390
- * @param {Element} node
1391
- * @return {WrappedRange}
1392
- */
1393
- createFromNode: function (node) {
1394
- return this.create(node, 0, node, 1);
1395
- },
1396
-
1397
- /**
1398
- * create WrappedRange from Bookmark
1399
- *
1400
- * @param {Element} elEditable
1401
- * @param {Obkect} bookmark
1402
- * @return {WrappedRange}
1403
- */
1404
- createFromBookmark : function (elEditable, bookmark) {
1405
- var sc = dom.fromOffsetPath(elEditable, bookmark.s.path);
1406
- var so = bookmark.s.offset;
1407
- var ec = dom.fromOffsetPath(elEditable, bookmark.e.path);
1408
- var eo = bookmark.e.offset;
1409
- return new WrappedRange(sc, so, ec, eo);
1410
- }
1411
- };
1412
- })();
1413
-
1414
- /**
1415
- * Table
1416
- * @class
1417
- */
1418
- var Table = function () {
1419
- /**
1420
- * handle tab key
1421
- *
1422
- * @param {WrappedRange} rng
1423
- * @param {Boolean} bShift
1424
- */
1425
- this.tab = function (rng, bShift) {
1426
- var elCell = dom.ancestor(rng.commonAncestor(), dom.isCell);
1427
- var elTable = dom.ancestor(elCell, dom.isTable);
1428
- var aCell = dom.listDescendant(elTable, dom.isCell);
1429
-
1430
- var elNext = list[bShift ? 'prev' : 'next'](aCell, elCell);
1431
- if (elNext) {
1432
- range.create(elNext, 0).select();
1433
- }
1434
- };
1435
-
1436
- /**
1437
- * create empty table element
1438
- *
1439
- * @param {Number} nRow
1440
- * @param {Number} nCol
1441
- */
1442
- this.createTable = function (nCol, nRow) {
1443
- var aTD = [], sTD;
1444
- for (var idxCol = 0; idxCol < nCol; idxCol++) {
1445
- aTD.push('<td>' + dom.blank + '</td>');
1446
- }
1447
- sTD = aTD.join('');
1448
-
1449
- var aTR = [], sTR;
1450
- for (var idxRow = 0; idxRow < nRow; idxRow++) {
1451
- aTR.push('<tr>' + sTD + '</tr>');
1452
- }
1453
- sTR = aTR.join('');
1454
- var sTable = '<table class="table table-bordered">' + sTR + '</table>';
1455
-
1456
- return $(sTable)[0];
1457
- };
1458
- };
1459
-
1460
- /**
1461
- * Editor
1462
- * @class
1463
- */
1464
- var Editor = function () {
1465
-
1466
- var style = new Style();
1467
- var table = new Table();
1468
-
1469
- /**
1470
- * save current range
1471
- *
1472
- * @param {jQuery} $editable
1473
- */
1474
- this.saveRange = function ($editable) {
1475
- $editable.data('range', range.create());
1476
- };
1477
-
1478
- /**
1479
- * restore lately range
1480
- *
1481
- * @param {jQuery} $editable
1482
- */
1483
- this.restoreRange = function ($editable) {
1484
- var rng = $editable.data('range');
1485
- if (rng) { rng.select(); }
1486
- };
1487
-
1488
- /**
1489
- * current style
1490
- * @param {Element} elTarget
1491
- */
1492
- this.currentStyle = function (elTarget) {
1493
- var rng = range.create();
1494
- return rng.isOnEditable() && style.current(rng, elTarget);
1495
- };
1496
-
1497
- /**
1498
- * undo
1499
- * @param {jQuery} $editable
1500
- */
1501
- this.undo = function ($editable) {
1502
- $editable.data('NoteHistory').undo($editable);
1503
- };
1504
-
1505
- /**
1506
- * redo
1507
- * @param {jQuery} $editable
1508
- */
1509
- this.redo = function ($editable) {
1510
- $editable.data('NoteHistory').redo($editable);
1511
- };
1512
-
1513
- /**
1514
- * record Undo
1515
- * @param {jQuery} $editable
1516
- */
1517
- var recordUndo = this.recordUndo = function ($editable) {
1518
- $editable.data('NoteHistory').recordUndo($editable);
1519
- };
1520
-
1521
- /* jshint ignore:start */
1522
- // native commands(with execCommand), generate function for execCommand
1523
- var aCmd = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',
1524
- 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',
1525
- 'insertOrderedList', 'insertUnorderedList',
1526
- 'indent', 'outdent', 'formatBlock', 'removeFormat',
1527
- 'backColor', 'foreColor', 'insertHorizontalRule', 'fontName'];
1528
-
1529
- for (var idx = 0, len = aCmd.length; idx < len; idx ++) {
1530
- this[aCmd[idx]] = (function (sCmd) {
1531
- return function ($editable, sValue) {
1532
- recordUndo($editable);
1533
- document.execCommand(sCmd, false, sValue);
1534
- };
1535
- })(aCmd[idx]);
1536
- }
1537
- /* jshint ignore:end */
1538
-
1539
- /**
1540
- * @param {jQuery} $editable
1541
- * @param {WrappedRange} rng
1542
- * @param {Number} nTabsize
1543
- */
1544
- var insertTab = function ($editable, rng, nTabsize) {
1545
- recordUndo($editable);
1546
- var sNbsp = new Array(nTabsize + 1).join('&nbsp;');
1547
- rng.insertNode($('<span id="noteTab">' + sNbsp + '</span>')[0]);
1548
- var $tab = $('#noteTab').removeAttr('id');
1549
- rng = range.create($tab[0], 1);
1550
- rng.select();
1551
- dom.remove($tab[0]);
1552
- };
1553
-
1554
- /**
1555
- * handle tab key
1556
- * @param {jQuery} $editable
1557
- * @param {Number} nTabsize
1558
- * @param {Boolean} bShift
1559
- */
1560
- this.tab = function ($editable, options) {
1561
- var rng = range.create();
1562
- if (rng.isCollapsed() && rng.isOnCell()) {
1563
- table.tab(rng);
1564
- } else {
1565
- insertTab($editable, rng, options.tabsize);
1566
- }
1567
- };
1568
-
1569
- /**
1570
- * handle shift+tab key
1571
- */
1572
- this.untab = function () {
1573
- var rng = range.create();
1574
- if (rng.isCollapsed() && rng.isOnCell()) {
1575
- table.tab(rng, true);
1576
- }
1577
- };
1578
-
1579
- /**
1580
- * insert image
1581
- *
1582
- * @param {jQuery} $editable
1583
- * @param {String} sUrl
1584
- */
1585
- this.insertImage = function ($editable, sUrl) {
1586
- async.createImage(sUrl).then(function ($image) {
1587
- recordUndo($editable);
1588
- $image.css({
1589
- display: '',
1590
- width: Math.min($editable.width(), $image.width())
1591
- });
1592
- range.create().insertNode($image[0]);
1593
- }).fail(function () {
1594
- var callbacks = $editable.data('callbacks');
1595
- if (callbacks.onImageUploadError) {
1596
- callbacks.onImageUploadError();
1597
- }
1598
- });
1599
- };
1600
-
1601
- /**
1602
- * insert video
1603
- * @param {jQuery} $editable
1604
- * @param {String} sUrl
1605
- */
1606
- this.insertVideo = function ($editable, sUrl) {
1607
- recordUndo($editable);
1608
-
1609
- // video url patterns(youtube, instagram, vimeo, dailymotion)
1610
- var ytRegExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
1611
- var ytMatch = sUrl.match(ytRegExp);
1612
-
1613
- var igRegExp = /\/\/instagram.com\/p\/(.[a-zA-Z0-9]*)/;
1614
- var igMatch = sUrl.match(igRegExp);
1615
-
1616
- var vRegExp = /\/\/vine.co\/v\/(.[a-zA-Z0-9]*)/;
1617
- var vMatch = sUrl.match(vRegExp);
1618
-
1619
- var vimRegExp = /\/\/(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/;
1620
- var vimMatch = sUrl.match(vimRegExp);
1621
-
1622
- var dmRegExp = /.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/;
1623
- var dmMatch = sUrl.match(dmRegExp);
1624
-
1625
- var $video;
1626
- if (ytMatch && ytMatch[2].length === 11) {
1627
- var youtubeId = ytMatch[2];
1628
- $video = $('<iframe>')
1629
- .attr('src', '//www.youtube.com/embed/' + youtubeId)
1630
- .attr('width', '640').attr('height', '360');
1631
- } else if (igMatch && igMatch[0].length > 0) {
1632
- $video = $('<iframe>')
1633
- .attr('src', igMatch[0] + '/embed/')
1634
- .attr('width', '612').attr('height', '710')
1635
- .attr('scrolling', 'no')
1636
- .attr('allowtransparency', 'true');
1637
- } else if (vMatch && vMatch[0].length > 0) {
1638
- $video = $('<iframe>')
1639
- .attr('src', vMatch[0] + '/embed/simple')
1640
- .attr('width', '600').attr('height', '600')
1641
- .attr('class', 'vine-embed');
1642
- } else if (vimMatch && vimMatch[3].length > 0) {
1643
- $video = $('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>')
1644
- .attr('src', '//player.vimeo.com/video/' + vimMatch[3])
1645
- .attr('width', '640').attr('height', '360');
1646
- } else if (dmMatch && dmMatch[2].length > 0) {
1647
- $video = $('<iframe>')
1648
- .attr('src', '//www.dailymotion.com/embed/video/' + dmMatch[2])
1649
- .attr('width', '640').attr('height', '360');
1650
- } else {
1651
- // this is not a known video link. Now what, Cat? Now what?
1652
- }
1653
-
1654
- if ($video) {
1655
- $video.attr('frameborder', 0);
1656
- range.create().insertNode($video[0]);
1657
- }
1658
- };
1659
-
1660
- /**
1661
- * formatBlock
1662
- *
1663
- * @param {jQuery} $editable
1664
- * @param {String} sTagName
1665
- */
1666
- this.formatBlock = function ($editable, sTagName) {
1667
- recordUndo($editable);
1668
- sTagName = agent.bMSIE ? '<' + sTagName + '>' : sTagName;
1669
- document.execCommand('FormatBlock', false, sTagName);
1670
- };
1671
-
1672
- this.formatPara = function ($editable) {
1673
- this.formatBlock($editable, 'P');
1674
- };
1675
-
1676
- /* jshint ignore:start */
1677
- for (var idx = 1; idx <= 6; idx ++) {
1678
- this['formatH' + idx] = function (idx) {
1679
- return function ($editable) {
1680
- this.formatBlock($editable, 'H' + idx);
1681
- };
1682
- }(idx);
1683
- };
1684
- /* jshint ignore:end */
1685
-
1686
- /**
1687
- * fontsize
1688
- * FIXME: Still buggy
1689
- *
1690
- * @param {jQuery} $editable
1691
- * @param {String} sValue - px
1692
- */
1693
- this.fontSize = function ($editable, sValue) {
1694
- recordUndo($editable);
1695
- document.execCommand('fontSize', false, 3);
1696
- if (agent.bFF) {
1697
- // firefox: <font size="3"> to <span style='font-size={sValue}px;'>, buggy
1698
- $editable.find('font[size=3]').removeAttr('size').css('font-size', sValue + 'px');
1699
- } else {
1700
- // chrome: <span style="font-size: medium"> to <span style='font-size={sValue}px;'>
1701
- $editable.find('span').filter(function () {
1702
- return this.style.fontSize === 'medium';
1703
- }).css('font-size', sValue + 'px');
1704
- }
1705
- };
1706
-
1707
- /**
1708
- * lineHeight
1709
- * @param {jQuery} $editable
1710
- * @param {String} sValue
1711
- */
1712
- this.lineHeight = function ($editable, sValue) {
1713
- recordUndo($editable);
1714
- style.stylePara(range.create(), {lineHeight: sValue});
1715
- };
1716
-
1717
- /**
1718
- * unlink
1719
- * @param {jQuery} $editable
1720
- */
1721
- this.unlink = function ($editable) {
1722
- var rng = range.create();
1723
- if (rng.isOnAnchor()) {
1724
- recordUndo($editable);
1725
- var elAnchor = dom.ancestor(rng.sc, dom.isAnchor);
1726
- rng = range.createFromNode(elAnchor);
1727
- rng.select();
1728
- document.execCommand('unlink');
1729
- }
1730
- };
1731
-
1732
- /**
1733
- * create link
1734
- *
1735
- * @param {jQuery} $editable
1736
- * @param {String} sLinkUrl
1737
- * @param {Boolean} bNewWindow
1738
- */
1739
- this.createLink = function ($editable, sLinkText, sLinkUrl, bNewWindow) {
1740
- var rng = range.create();
1741
- recordUndo($editable);
1742
-
1743
- // protocol
1744
- var sLinkUrlWithProtocol = sLinkUrl;
1745
- if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {
1746
- sLinkUrlWithProtocol = 'mailto:' + sLinkUrl;
1747
- } else if (sLinkUrl.indexOf('://') === -1) {
1748
- sLinkUrlWithProtocol = 'http://' + sLinkUrl;
1749
- }
1750
-
1751
- // createLink when range collapsed (IE, Firefox).
1752
- if ((agent.bMSIE || agent.bFF) && rng.isCollapsed()) {
1753
- rng.insertNode($('<A id="linkAnchor">' + sLinkText + '</A>')[0]);
1754
- var $anchor = $('#linkAnchor').attr('href', sLinkUrlWithProtocol).removeAttr('id');
1755
- rng = range.createFromNode($anchor[0]);
1756
- rng.select();
1757
- } else {
1758
- document.execCommand('createlink', false, sLinkUrlWithProtocol);
1759
- }
1760
-
1761
- // target
1762
- $.each(rng.nodes(dom.isAnchor), function (idx, elAnchor) {
1763
- // update link text
1764
- $(elAnchor).html(sLinkText);
1765
- if (bNewWindow) {
1766
- $(elAnchor).attr('target', '_blank');
1767
- } else {
1768
- $(elAnchor).removeAttr('target');
1769
- }
1770
- });
1771
- };
1772
-
1773
- /**
1774
- * get link info
1775
- *
1776
- * @return {Promise}
1777
- */
1778
- this.getLinkInfo = function () {
1779
- var rng = range.create();
1780
- var bNewWindow = true;
1781
- var sUrl = '';
1782
-
1783
- // If range on anchor expand range on anchor(for edit link).
1784
- if (rng.isOnAnchor()) {
1785
- var elAnchor = dom.ancestor(rng.sc, dom.isAnchor);
1786
- rng = range.createFromNode(elAnchor);
1787
- bNewWindow = $(elAnchor).attr('target') === '_blank';
1788
- sUrl = elAnchor.href;
1789
- }
1790
-
1791
- return {
1792
- text: rng.toString(),
1793
- url: sUrl,
1794
- newWindow: bNewWindow
1795
- };
1796
- };
1797
-
1798
- /**
1799
- * get video info
1800
- *
1801
- * @return {Object}
1802
- */
1803
- this.getVideoInfo = function () {
1804
- var rng = range.create();
1805
-
1806
- if (rng.isOnAnchor()) {
1807
- var elAnchor = dom.ancestor(rng.sc, dom.isAnchor);
1808
- rng = range.createFromNode(elAnchor);
1809
- }
1810
-
1811
- return {
1812
- text: rng.toString()
1813
- };
1814
- };
1815
-
1816
- this.color = function ($editable, sObjColor) {
1817
- var oColor = JSON.parse(sObjColor);
1818
- var foreColor = oColor.foreColor, backColor = oColor.backColor;
1819
-
1820
- recordUndo($editable);
1821
- if (foreColor) { document.execCommand('foreColor', false, foreColor); }
1822
- if (backColor) { document.execCommand('backColor', false, backColor); }
1823
- };
1824
-
1825
- this.insertTable = function ($editable, sDim) {
1826
- recordUndo($editable);
1827
- var aDim = sDim.split('x');
1828
- range.create().insertNode(table.createTable(aDim[0], aDim[1]));
1829
- };
1830
-
1831
- /**
1832
- * @param {jQuery} $editable
1833
- * @param {String} sValue
1834
- * @param {jQuery} $target
1835
- */
1836
- this.floatMe = function ($editable, sValue, $target) {
1837
- recordUndo($editable);
1838
- $target.css('float', sValue);
1839
- };
1840
-
1841
- /**
1842
- * resize overlay element
1843
- * @param {jQuery} $editable
1844
- * @param {String} sValue
1845
- * @param {jQuery} $target - target element
1846
- */
1847
- this.resize = function ($editable, sValue, $target) {
1848
- recordUndo($editable);
1849
-
1850
- $target.css({
1851
- width: $editable.width() * sValue + 'px',
1852
- height: ''
1853
- });
1854
- };
1855
-
1856
- /**
1857
- * @param {Position} pos
1858
- * @param {jQuery} $target - target element
1859
- * @param {Boolean} [bKeepRatio] - keep ratio
1860
- */
1861
- this.resizeTo = function (pos, $target, bKeepRatio) {
1862
- var szImage;
1863
- if (bKeepRatio) {
1864
- var newRatio = pos.y / pos.x;
1865
- var ratio = $target.data('ratio');
1866
- szImage = {
1867
- width: ratio > newRatio ? pos.x : pos.y / ratio,
1868
- height: ratio > newRatio ? pos.x * ratio : pos.y
1869
- };
1870
- } else {
1871
- szImage = {
1872
- width: pos.x,
1873
- height: pos.y
1874
- };
1875
- }
1876
-
1877
- $target.css(szImage);
1878
- };
1879
-
1880
- /**
1881
- * remove media object
1882
- *
1883
- * @param {jQuery} $editable
1884
- * @param {String} sValue - dummy argument (for keep interface)
1885
- * @param {jQuery} $target - target element
1886
- */
1887
- this.removeMedia = function ($editable, sValue, $target) {
1888
- recordUndo($editable);
1889
- $target.detach();
1890
- };
1891
- };
1892
-
1893
- /**
1894
- * History
1895
- * @class
1896
- */
1897
- var History = function () {
1898
- var aUndo = [], aRedo = [];
1899
-
1900
- var makeSnap = function ($editable) {
1901
- var elEditable = $editable[0], rng = range.create();
1902
- return {
1903
- contents: $editable.html(),
1904
- bookmark: rng.bookmark(elEditable),
1905
- scrollTop: $editable.scrollTop()
1906
- };
1907
- };
1908
-
1909
- var applySnap = function ($editable, oSnap) {
1910
- $editable.html(oSnap.contents).scrollTop(oSnap.scrollTop);
1911
- range.createFromBookmark($editable[0], oSnap.bookmark).select();
1912
- };
1913
-
1914
- this.undo = function ($editable) {
1915
- var oSnap = makeSnap($editable);
1916
- if (aUndo.length === 0) { return; }
1917
- applySnap($editable, aUndo.pop());
1918
- aRedo.push(oSnap);
1919
- };
1920
-
1921
- this.redo = function ($editable) {
1922
- var oSnap = makeSnap($editable);
1923
- if (aRedo.length === 0) { return; }
1924
- applySnap($editable, aRedo.pop());
1925
- aUndo.push(oSnap);
1926
- };
1927
-
1928
- this.recordUndo = function ($editable) {
1929
- aRedo = [];
1930
- aUndo.push(makeSnap($editable));
1931
- };
1932
- };
1933
-
1934
- /**
1935
- * Button
1936
- */
1937
- var Button = function () {
1938
- /**
1939
- * update button status
1940
- *
1941
- * @param {jQuery} $container
1942
- * @param {Object} oStyle
1943
- */
1944
- this.update = function ($container, oStyle) {
1945
- /**
1946
- * handle dropdown's check mark (for fontname, fontsize, lineHeight).
1947
- * @param {jQuery} $btn
1948
- * @param {Number} nValue
1949
- */
1950
- var checkDropdownMenu = function ($btn, nValue) {
1951
- $btn.find('.dropdown-menu li a').each(function () {
1952
- // always compare string to avoid creating another func.
1953
- var bChecked = ($(this).data('value') + '') === (nValue + '');
1954
- this.className = bChecked ? 'checked' : '';
1955
- });
1956
- };
1957
-
1958
- /**
1959
- * update button state(active or not).
1960
- *
1961
- * @param {String} sSelector
1962
- * @param {Function} pred
1963
- */
1964
- var btnState = function (sSelector, pred) {
1965
- var $btn = $container.find(sSelector);
1966
- $btn.toggleClass('active', pred());
1967
- };
1968
-
1969
- // fontname
1970
- var $fontname = $container.find('.note-fontname');
1971
- if ($fontname.length > 0) {
1972
- var selectedFont = oStyle['font-family'];
1973
- if (!!selectedFont) {
1974
- selectedFont = list.head(selectedFont.split(','));
1975
- selectedFont = selectedFont.replace(/\'/g, '');
1976
- $fontname.find('.note-current-fontname').text(selectedFont);
1977
- checkDropdownMenu($fontname, selectedFont);
1978
- }
1979
- }
1980
-
1981
- // fontsize
1982
- var $fontsize = $container.find('.note-fontsize');
1983
- $fontsize.find('.note-current-fontsize').text(oStyle['font-size']);
1984
- checkDropdownMenu($fontsize, parseFloat(oStyle['font-size']));
1985
-
1986
- // lineheight
1987
- var $lineHeight = $container.find('.note-height');
1988
- checkDropdownMenu($lineHeight, parseFloat(oStyle['line-height']));
1989
-
1990
- btnState('button[data-event="bold"]', function () {
1991
- return oStyle['font-bold'] === 'bold';
1992
- });
1993
- btnState('button[data-event="italic"]', function () {
1994
- return oStyle['font-italic'] === 'italic';
1995
- });
1996
- btnState('button[data-event="underline"]', function () {
1997
- return oStyle['font-underline'] === 'underline';
1998
- });
1999
- btnState('button[data-event="strikethrough"]', function () {
2000
- return oStyle['font-strikethrough'] === 'strikethrough';
2001
- });
2002
- btnState('button[data-event="superscript"]', function () {
2003
- return oStyle['font-superscript'] === 'superscript';
2004
- });
2005
- btnState('button[data-event="subscript"]', function () {
2006
- return oStyle['font-subscript'] === 'subscript';
2007
- });
2008
- btnState('button[data-event="justifyLeft"]', function () {
2009
- return oStyle['text-align'] === 'left' || oStyle['text-align'] === 'start';
2010
- });
2011
- btnState('button[data-event="justifyCenter"]', function () {
2012
- return oStyle['text-align'] === 'center';
2013
- });
2014
- btnState('button[data-event="justifyRight"]', function () {
2015
- return oStyle['text-align'] === 'right';
2016
- });
2017
- btnState('button[data-event="justifyFull"]', function () {
2018
- return oStyle['text-align'] === 'justify';
2019
- });
2020
- btnState('button[data-event="insertUnorderedList"]', function () {
2021
- return oStyle['list-style'] === 'unordered';
2022
- });
2023
- btnState('button[data-event="insertOrderedList"]', function () {
2024
- return oStyle['list-style'] === 'ordered';
2025
- });
2026
- };
2027
-
2028
- /**
2029
- * update recent color
2030
- *
2031
- * @param {Element} elBtn
2032
- * @param {String} sEvent
2033
- * @param {sValue} sValue
2034
- */
2035
- this.updateRecentColor = function (elBtn, sEvent, sValue) {
2036
- var $color = $(elBtn).closest('.note-color');
2037
- var $recentColor = $color.find('.note-recent-color');
2038
- var oColor = JSON.parse($recentColor.attr('data-value'));
2039
- oColor[sEvent] = sValue;
2040
- $recentColor.attr('data-value', JSON.stringify(oColor));
2041
- var sKey = sEvent === 'backColor' ? 'background-color' : 'color';
2042
- $recentColor.find('i').css(sKey, sValue);
2043
- };
2044
- };
2045
-
2046
- /**
2047
- * Toolbar
2048
- */
2049
- var Toolbar = function () {
2050
- var button = new Button();
2051
-
2052
- this.update = function ($toolbar, oStyle) {
2053
- button.update($toolbar, oStyle);
2054
- };
2055
-
2056
- this.updateRecentColor = function (elBtn, sEvent, sValue) {
2057
- button.updateRecentColor(elBtn, sEvent, sValue);
2058
- };
2059
-
2060
- /**
2061
- * activate buttons exclude codeview
2062
- * @param {jQuery} $toolbar
2063
- */
2064
- this.activate = function ($toolbar) {
2065
- $toolbar.find('button').not('button[data-event="codeview"]').removeClass('disabled');
2066
- };
2067
-
2068
- /**
2069
- * deactivate buttons exclude codeview
2070
- * @param {jQuery} $toolbar
2071
- */
2072
- this.deactivate = function ($toolbar) {
2073
- $toolbar.find('button').not('button[data-event="codeview"]').addClass('disabled');
2074
- };
2075
-
2076
- this.updateFullscreen = function ($container, bFullscreen) {
2077
- var $btn = $container.find('button[data-event="fullscreen"]');
2078
- $btn.toggleClass('active', bFullscreen);
2079
- };
2080
-
2081
- this.updateCodeview = function ($container, bCodeview) {
2082
- var $btn = $container.find('button[data-event="codeview"]');
2083
- $btn.toggleClass('active', bCodeview);
2084
- };
2085
- };
2086
-
2087
- /**
2088
- * Popover (http://getbootstrap.com/javascript/#popovers)
2089
- */
2090
- var Popover = function () {
2091
- var button = new Button();
2092
-
2093
- /**
2094
- * show popover
2095
- * @param {jQuery} popover
2096
- * @param {Element} elPlaceholder - placeholder for popover
2097
- */
2098
- var showPopover = function ($popover, elPlaceholder) {
2099
- var $placeholder = $(elPlaceholder);
2100
- var pos = $placeholder.position();
2101
-
2102
- // include margin
2103
- var height = $placeholder.outerHeight(true);
2104
-
2105
- // display popover below placeholder.
2106
- $popover.css({
2107
- display: 'block',
2108
- left: pos.left,
2109
- top: pos.top + height
2110
- });
2111
- };
2112
-
2113
- var PX_POPOVER_ARROW_OFFSET_X = 20;
2114
-
2115
- /**
2116
- * update current state
2117
- * @param {jQuery} $popover - popover container
2118
- * @param {Object} oStyle - style object
2119
- * @param {Boolean} isAirMode
2120
- */
2121
- this.update = function ($popover, oStyle, isAirMode) {
2122
- button.update($popover, oStyle);
2123
-
2124
- var $linkPopover = $popover.find('.note-link-popover');
2125
-
2126
- if (oStyle.anchor) {
2127
- var $anchor = $linkPopover.find('a');
2128
- $anchor.attr('href', oStyle.anchor.href).html(oStyle.anchor.href);
2129
- showPopover($linkPopover, oStyle.anchor);
2130
- } else {
2131
- $linkPopover.hide();
2132
- }
2133
-
2134
- var $imagePopover = $popover.find('.note-image-popover');
2135
- if (oStyle.image) {
2136
- showPopover($imagePopover, oStyle.image);
2137
- } else {
2138
- $imagePopover.hide();
2139
- }
2140
-
2141
- if (isAirMode) {
2142
- var $airPopover = $popover.find('.note-air-popover');
2143
- if (!oStyle.range.isCollapsed()) {
2144
- var bnd = func.rect2bnd(list.last(oStyle.range.getClientRects()));
2145
- $airPopover.css({
2146
- display: 'block',
2147
- left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),
2148
- top: bnd.top + bnd.height
2149
- });
2150
- } else {
2151
- $airPopover.hide();
2152
- }
2153
- }
2154
- };
2155
-
2156
- this.updateRecentColor = function (elBtn, sEvent, sValue) {
2157
- button.updateRecentColor(elBtn, sEvent, sValue);
2158
- };
2159
-
2160
- /**
2161
- * hide all popovers
2162
- * @param {jQuery} $popover - popover contaienr
2163
- */
2164
- this.hide = function ($popover) {
2165
- $popover.children().hide();
2166
- };
2167
- };
2168
-
2169
- /**
2170
- * Handle
2171
- */
2172
- var Handle = function () {
2173
- /**
2174
- * update handle
2175
- * @param {jQuery} $handle
2176
- * @param {Object} oStyle
2177
- */
2178
- this.update = function ($handle, oStyle) {
2179
- var $selection = $handle.find('.note-control-selection');
2180
- if (oStyle.image) {
2181
- var $image = $(oStyle.image);
2182
- var pos = $image.position();
2183
-
2184
- // include margin
2185
- var szImage = {
2186
- w: $image.outerWidth(true),
2187
- h: $image.outerHeight(true)
2188
- };
2189
-
2190
- $selection.css({
2191
- display: 'block',
2192
- left: pos.left,
2193
- top: pos.top,
2194
- width: szImage.w,
2195
- height: szImage.h
2196
- }).data('target', oStyle.image); // save current image element.
2197
- var sSizing = szImage.w + 'x' + szImage.h;
2198
- $selection.find('.note-control-selection-info').text(sSizing);
2199
- } else {
2200
- $selection.hide();
2201
- }
2202
- };
2203
-
2204
- this.hide = function ($handle) {
2205
- $handle.children().hide();
2206
- };
2207
- };
2208
-
2209
- /**
2210
- * Dialog
2211
- *
2212
- * @class
2213
- */
2214
- var Dialog = function () {
2215
-
2216
- /**
2217
- * toggle button status
2218
- *
2219
- * @param {jQuery} $btn
2220
- * @param {Boolean} bEnable
2221
- */
2222
- var toggleBtn = function ($btn, bEnable) {
2223
- $btn.toggleClass('disabled', !bEnable);
2224
- $btn.attr('disabled', !bEnable);
2225
- };
2226
-
2227
- /**
2228
- * show image dialog
2229
- *
2230
- * @param {jQuery} $editable
2231
- * @param {jQuery} $dialog
2232
- * @return {Promise}
2233
- */
2234
- this.showImageDialog = function ($editable, $dialog) {
2235
- return $.Deferred(function (deferred) {
2236
- var $imageDialog = $dialog.find('.note-image-dialog');
2237
-
2238
- var $imageInput = $dialog.find('.note-image-input'),
2239
- $imageUrl = $dialog.find('.note-image-url'),
2240
- $imageBtn = $dialog.find('.note-image-btn');
2241
-
2242
- $imageDialog.one('shown.bs.modal', function () {
2243
- // Cloning imageInput to clear element.
2244
- $imageInput.replaceWith($imageInput.clone()
2245
- .on('change', function () {
2246
- $imageDialog.modal('hide');
2247
- deferred.resolve(this.files);
2248
- })
2249
- );
2250
-
2251
- $imageBtn.click(function (event) {
2252
- event.preventDefault();
2253
-
2254
- $imageDialog.modal('hide');
2255
- deferred.resolve($imageUrl.val());
2256
- });
2257
-
2258
- $imageUrl.keyup(function () {
2259
- toggleBtn($imageBtn, $imageUrl.val());
2260
- }).val('').focus();
2261
- }).one('hidden.bs.modal', function () {
2262
- $editable.focus();
2263
- $imageInput.off('change');
2264
- $imageUrl.off('keyup');
2265
- $imageBtn.off('click');
2266
- }).modal('show');
2267
- });
2268
- };
2269
-
2270
- /**
2271
- * Show video dialog and set event handlers on dialog controls.
2272
- *
2273
- * @param {jQuery} $dialog
2274
- * @param {Object} videoInfo
2275
- * @return {Promise}
2276
- */
2277
- this.showVideoDialog = function ($editable, $dialog, videoInfo) {
2278
- return $.Deferred(function (deferred) {
2279
- var $videoDialog = $dialog.find('.note-video-dialog');
2280
- var $videoUrl = $videoDialog.find('.note-video-url'),
2281
- $videoBtn = $videoDialog.find('.note-video-btn');
2282
-
2283
- $videoDialog.one('shown.bs.modal', function () {
2284
- $videoUrl.val(videoInfo.text).keyup(function () {
2285
- toggleBtn($videoBtn, $videoUrl.val());
2286
- }).trigger('keyup').trigger('focus');
2287
-
2288
- $videoBtn.click(function (event) {
2289
- event.preventDefault();
2290
-
2291
- $videoDialog.modal('hide');
2292
- deferred.resolve($videoUrl.val());
2293
- });
2294
- }).one('hidden.bs.modal', function () {
2295
- $editable.focus();
2296
- $videoUrl.off('keyup');
2297
- $videoBtn.off('click');
2298
- }).modal('show');
2299
- });
2300
- };
2301
-
2302
- /**
2303
- * Show link dialog and set event handlers on dialog controls.
2304
- *
2305
- * @param {jQuery} $dialog
2306
- * @param {Object} linkInfo
2307
- * @return {Promise}
2308
- */
2309
- this.showLinkDialog = function ($editable, $dialog, linkInfo) {
2310
- return $.Deferred(function (deferred) {
2311
- var $linkDialog = $dialog.find('.note-link-dialog');
2312
-
2313
- var $linkText = $linkDialog.find('.note-link-text'),
2314
- $linkUrl = $linkDialog.find('.note-link-url'),
2315
- $linkBtn = $linkDialog.find('.note-link-btn'),
2316
- $openInNewWindow = $linkDialog.find('input[type=checkbox]');
2317
-
2318
- $linkDialog.one('shown.bs.modal', function () {
2319
- $linkText.val(linkInfo.text);
2320
-
2321
- $linkText.keyup(function () {
2322
- // if linktext was modified by keyup,
2323
- // stop cloning text from linkUrl
2324
- linkInfo.text = $linkText.val();
2325
- });
2326
-
2327
- // if no url was given, copy text to url
2328
- if (!linkInfo.url) {
2329
- linkInfo.url = linkInfo.text;
2330
- toggleBtn($linkBtn, linkInfo.text);
2331
- }
2332
-
2333
- $linkUrl.keyup(function () {
2334
- toggleBtn($linkBtn, $linkUrl.val());
2335
- // display same link on `Text to display` input
2336
- // when create a new link
2337
- if (!linkInfo.text) {
2338
- $linkText.val($linkUrl.val());
2339
- }
2340
- }).val(linkInfo.url).trigger('focus').trigger('select');
2341
-
2342
- $openInNewWindow.prop('checked', linkInfo.newWindow);
2343
-
2344
- $linkBtn.one('click', function (event) {
2345
- event.preventDefault();
2346
-
2347
- $linkDialog.modal('hide');
2348
- deferred.resolve($linkText.val(), $linkUrl.val(), $openInNewWindow.is(':checked'));
2349
- });
2350
- }).one('hidden.bs.modal', function () {
2351
- $editable.focus();
2352
- $linkUrl.off('keyup');
2353
- }).modal('show');
2354
- }).promise();
2355
- };
2356
-
2357
- /**
2358
- * show help dialog
2359
- *
2360
- * @param {jQuery} $dialog
2361
- */
2362
- this.showHelpDialog = function ($editable, $dialog) {
2363
- var $helpDialog = $dialog.find('.note-help-dialog');
2364
-
2365
- $helpDialog.one('hidden.bs.modal', function () {
2366
- $editable.focus();
2367
- }).modal('show');
2368
- };
2369
- };
2370
-
2371
- /**
2372
- * EventHandler
2373
- */
2374
- var EventHandler = function () {
2375
- var $document = $(document);
2376
-
2377
- var editor = new Editor();
2378
- var toolbar = new Toolbar(), popover = new Popover();
2379
- var handle = new Handle(), dialog = new Dialog();
2380
-
2381
- /**
2382
- * returns makeLayoutInfo from editor's descendant node.
2383
- *
2384
- * @param {Element} descendant
2385
- * @returns {Object}
2386
- */
2387
- var makeLayoutInfo = function (descendant) {
2388
- var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');
2389
-
2390
- if ($target.length === 0) { return null; }
2391
-
2392
- var $editor;
2393
- if ($target.is('.note-editor, .note-air-editor')) {
2394
- $editor = $target;
2395
- } else {
2396
- $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));
2397
- }
2398
-
2399
- return dom.buildLayoutInfo($editor);
2400
- };
2401
-
2402
- /**
2403
- * insert Images from file array.
2404
- *
2405
- * @param {jQuery} $editable
2406
- * @param {File[]} files
2407
- */
2408
- var insertImages = function ($editable, files) {
2409
- editor.restoreRange($editable);
2410
- var callbacks = $editable.data('callbacks');
2411
-
2412
- // If onImageUpload options setted
2413
- if (callbacks.onImageUpload) {
2414
- callbacks.onImageUpload(files, editor, $editable);
2415
- // else insert Image as dataURL
2416
- } else {
2417
- $.each(files, function (idx, file) {
2418
- async.readFileAsDataURL(file).then(function (sDataURL) {
2419
- editor.insertImage($editable, sDataURL);
2420
- }).fail(function () {
2421
- if (callbacks.onImageUploadError) {
2422
- callbacks.onImageUploadError();
2423
- }
2424
- });
2425
- });
2426
- }
2427
- };
2428
-
2429
- var hMousedown = function (event) {
2430
- //preventDefault Selection for FF, IE8+
2431
- if (dom.isImg(event.target)) {
2432
- event.preventDefault();
2433
- }
2434
- };
2435
-
2436
- var hToolbarAndPopoverUpdate = function (event) {
2437
- // delay for range after mouseup
2438
- setTimeout(function () {
2439
- var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
2440
- var oStyle = editor.currentStyle(event.target);
2441
- if (!oStyle) { return; }
2442
-
2443
- var isAirMode = oLayoutInfo.editor().data('options').airMode;
2444
- if (!isAirMode) {
2445
- toolbar.update(oLayoutInfo.toolbar(), oStyle);
2446
- }
2447
-
2448
- popover.update(oLayoutInfo.popover(), oStyle, isAirMode);
2449
- handle.update(oLayoutInfo.handle(), oStyle);
2450
- }, 0);
2451
- };
2452
-
2453
- var hScroll = function (event) {
2454
- var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
2455
- //hide popover and handle when scrolled
2456
- popover.hide(oLayoutInfo.popover());
2457
- handle.hide(oLayoutInfo.handle());
2458
- };
2459
-
2460
- /**
2461
- * paste clipboard image
2462
- *
2463
- * @param {Event} event
2464
- */
2465
- var hPasteClipboardImage = function (event) {
2466
- var originalEvent = event.originalEvent;
2467
- if (!originalEvent.clipboardData ||
2468
- !originalEvent.clipboardData.items ||
2469
- !originalEvent.clipboardData.items.length) {
2470
- return;
2471
- }
2472
-
2473
- var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
2474
- var item = list.head(originalEvent.clipboardData.items);
2475
- var bClipboardImage = item.kind === 'file' && item.type.indexOf('image/') !== -1;
2476
-
2477
- if (bClipboardImage) {
2478
- insertImages(oLayoutInfo.editable(), [item.getAsFile()]);
2479
- }
2480
- };
2481
-
2482
- /**
2483
- * `mousedown` event handler on $handle
2484
- * - controlSizing: resize image
2485
- *
2486
- * @param {MouseEvent} event
2487
- */
2488
- var hHandleMousedown = function (event) {
2489
- if (dom.isControlSizing(event.target)) {
2490
- event.preventDefault();
2491
- event.stopPropagation();
2492
-
2493
- var oLayoutInfo = makeLayoutInfo(event.target),
2494
- $handle = oLayoutInfo.handle(), $popover = oLayoutInfo.popover(),
2495
- $editable = oLayoutInfo.editable();
2496
-
2497
- var elTarget = $handle.find('.note-control-selection').data('target'),
2498
- $target = $(elTarget), posStart = $target.offset(),
2499
- scrollTop = $document.scrollTop();
2500
-
2501
- $document.on('mousemove', function (event) {
2502
- editor.resizeTo({
2503
- x: event.clientX - posStart.left,
2504
- y: event.clientY - (posStart.top - scrollTop)
2505
- }, $target, !event.shiftKey);
2506
-
2507
- handle.update($handle, {image: elTarget});
2508
- popover.update($popover, {image: elTarget});
2509
- }).one('mouseup', function () {
2510
- $document.off('mousemove');
2511
- });
2512
-
2513
- if (!$target.data('ratio')) { // original ratio.
2514
- $target.data('ratio', $target.height() / $target.width());
2515
- }
2516
-
2517
- editor.recordUndo($editable);
2518
- }
2519
- };
2520
-
2521
- var hToolbarAndPopoverMousedown = function (event) {
2522
- // prevent default event when insertTable (FF, Webkit)
2523
- var $btn = $(event.target).closest('[data-event]');
2524
- if ($btn.length > 0) {
2525
- event.preventDefault();
2526
- }
2527
- };
2528
-
2529
- var toggleFullscreen = function (oLayoutInfo) {
2530
- var $editor = oLayoutInfo.editor(),
2531
- $toolbar = oLayoutInfo.toolbar(),
2532
- $editable = oLayoutInfo.editable(),
2533
- $codable = oLayoutInfo.codable();
2534
-
2535
- var options = $editor.data('options');
2536
-
2537
- var $scrollbar = $('html, body');
2538
-
2539
- var resize = function (size) {
2540
- $editor.css('width', size.w);
2541
- $editable.css('height', size.h);
2542
- $codable.css('height', size.h);
2543
- if ($codable.data('cmEditor')) {
2544
- $codable.data('cmEditor').setSize(null, size.h);
2545
- }
2546
- };
2547
-
2548
- $editor.toggleClass('fullscreen');
2549
- var isFullscreen = $editor.hasClass('fullscreen');
2550
- if (isFullscreen) {
2551
- $editable.data('orgHeight', $editable.css('height'));
2552
-
2553
- $(window).on('resize', function () {
2554
- resize({
2555
- w: $(window).width(),
2556
- h: $(window).height() - $toolbar.outerHeight()
2557
- });
2558
- }).trigger('resize');
2559
-
2560
- $scrollbar.css('overflow', 'hidden');
2561
- } else {
2562
- $(window).off('resize');
2563
- resize({
2564
- w: options.width || '',
2565
- h: $editable.data('orgHeight')
2566
- });
2567
- $scrollbar.css('overflow', 'visible');
2568
- }
2569
-
2570
- toolbar.updateFullscreen($toolbar, isFullscreen);
2571
- };
2572
-
2573
- var toggleCodeView = function (oLayoutInfo) {
2574
- var $editor = oLayoutInfo.editor(),
2575
- $toolbar = oLayoutInfo.toolbar(),
2576
- $editable = oLayoutInfo.editable(),
2577
- $codable = oLayoutInfo.codable(),
2578
- $popover = oLayoutInfo.popover();
2579
-
2580
- var options = $editor.data('options');
2581
-
2582
- var cmEditor, server;
2583
-
2584
- $editor.toggleClass('codeview');
2585
-
2586
- var bCodeview = $editor.hasClass('codeview');
2587
- if (bCodeview) {
2588
- $codable.val($editable.html());
2589
- $codable.height($editable.height());
2590
- toolbar.deactivate($toolbar);
2591
- popover.hide($popover);
2592
- $codable.focus();
2593
-
2594
- // activate CodeMirror as codable
2595
- if (agent.bCodeMirror) {
2596
- cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);
2597
-
2598
- // CodeMirror TernServer
2599
- if (options.codemirror.tern) {
2600
- server = new CodeMirror.TernServer(options.codemirror.tern);
2601
- cmEditor.ternServer = server;
2602
- cmEditor.on('cursorActivity', function (cm) {
2603
- server.updateArgHints(cm);
2604
- });
2605
- }
2606
-
2607
- // CodeMirror hasn't Padding.
2608
- cmEditor.setSize(null, $editable.outerHeight());
2609
- // autoFormatRange If formatting included
2610
- if (cmEditor.autoFormatRange) {
2611
- cmEditor.autoFormatRange({line: 0, ch: 0}, {
2612
- line: cmEditor.lineCount(),
2613
- ch: cmEditor.getTextArea().value.length
2614
- });
2615
- }
2616
- $codable.data('cmEditor', cmEditor);
2617
- }
2618
- } else {
2619
- // deactivate CodeMirror as codable
2620
- if (agent.bCodeMirror) {
2621
- cmEditor = $codable.data('cmEditor');
2622
- $codable.val(cmEditor.getValue());
2623
- cmEditor.toTextArea();
2624
- }
2625
-
2626
- $editable.html($codable.val() || dom.emptyPara);
2627
- $editable.height(options.height ? $codable.height() : 'auto');
2628
-
2629
- toolbar.activate($toolbar);
2630
- $editable.focus();
2631
- }
2632
-
2633
- toolbar.updateCodeview(oLayoutInfo.toolbar(), bCodeview);
2634
- };
2635
-
2636
- var hToolbarAndPopoverClick = function (event) {
2637
- var $btn = $(event.target).closest('[data-event]');
2638
-
2639
- if ($btn.length > 0) {
2640
- var sEvent = $btn.attr('data-event'), sValue = $btn.attr('data-value');
2641
-
2642
- var oLayoutInfo = makeLayoutInfo(event.target);
2643
- var $dialog = oLayoutInfo.dialog(),
2644
- $editable = oLayoutInfo.editable();
2645
-
2646
- // before command: detect control selection element($target)
2647
- var $target;
2648
- if ($.inArray(sEvent, ['resize', 'floatMe', 'removeMedia']) !== -1) {
2649
- var $selection = oLayoutInfo.handle().find('.note-control-selection');
2650
- $target = $($selection.data('target'));
2651
- }
2652
-
2653
- if (editor[sEvent]) { // on command
2654
- $editable.trigger('focus');
2655
- editor[sEvent]($editable, sValue, $target);
2656
- }
2657
-
2658
- // after command
2659
- if ($.inArray(sEvent, ['backColor', 'foreColor']) !== -1) {
2660
- var options = oLayoutInfo.editor().data('options', options);
2661
- var module = options.airMode ? popover : toolbar;
2662
- module.updateRecentColor(list.head($btn), sEvent, sValue);
2663
- } else if (sEvent === 'showLinkDialog') { // popover to dialog
2664
- $editable.focus();
2665
- var linkInfo = editor.getLinkInfo();
2666
-
2667
- editor.saveRange($editable);
2668
- dialog.showLinkDialog($editable, $dialog, linkInfo).then(function (sLinkText, sLinkUrl, bNewWindow) {
2669
- editor.restoreRange($editable);
2670
- editor.createLink($editable, sLinkText, sLinkUrl, bNewWindow);
2671
- // hide popover after creating link
2672
- popover.hide(oLayoutInfo.popover());
2673
- });
2674
- } else if (sEvent === 'showImageDialog') {
2675
- $editable.focus();
2676
-
2677
- dialog.showImageDialog($editable, $dialog).then(function (data) {
2678
- if (typeof data === 'string') {
2679
- editor.restoreRange($editable);
2680
- editor.insertImage($editable, data);
2681
- } else {
2682
- insertImages($editable, data);
2683
- }
2684
- });
2685
- } else if (sEvent === 'showVideoDialog') {
2686
- $editable.focus();
2687
- var videoInfo = editor.getVideoInfo();
2688
-
2689
- editor.saveRange($editable);
2690
- dialog.showVideoDialog($editable, $dialog, videoInfo).then(function (sUrl) {
2691
- editor.restoreRange($editable);
2692
- editor.insertVideo($editable, sUrl);
2693
- });
2694
- } else if (sEvent === 'showHelpDialog') {
2695
- dialog.showHelpDialog($editable, $dialog);
2696
- } else if (sEvent === 'fullscreen') {
2697
- toggleFullscreen(oLayoutInfo);
2698
- } else if (sEvent === 'codeview') {
2699
- toggleCodeView(oLayoutInfo);
2700
- }
2701
-
2702
- hToolbarAndPopoverUpdate(event);
2703
- }
2704
- };
2705
-
2706
- var EDITABLE_PADDING = 24;
2707
- /**
2708
- * `mousedown` event handler on statusbar
2709
- *
2710
- * @param {MouseEvent} event
2711
- */
2712
- var hStatusbarMousedown = function (event) {
2713
- event.preventDefault();
2714
- event.stopPropagation();
2715
-
2716
- var $editable = makeLayoutInfo(event.target).editable();
2717
- var nEditableTop = $editable.offset().top - $document.scrollTop();
2718
-
2719
- $document.on('mousemove', function (event) {
2720
- var nHeight = event.clientY - (nEditableTop + EDITABLE_PADDING);
2721
- $editable.height(nHeight);
2722
- }).one('mouseup', function () {
2723
- $document.off('mousemove');
2724
- });
2725
- };
2726
-
2727
- var PX_PER_EM = 18;
2728
- var hDimensionPickerMove = function (event) {
2729
- var $picker = $(event.target.parentNode); // target is mousecatcher
2730
- var $dimensionDisplay = $picker.next();
2731
- var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
2732
- var $highlighted = $picker.find('.note-dimension-picker-highlighted');
2733
- var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
2734
-
2735
- var posOffset;
2736
- // HTML5 with jQuery - e.offsetX is undefined in Firefox
2737
- if (event.offsetX === undefined) {
2738
- var posCatcher = $(event.target).offset();
2739
- posOffset = {
2740
- x: event.pageX - posCatcher.left,
2741
- y: event.pageY - posCatcher.top
2742
- };
2743
- } else {
2744
- posOffset = {
2745
- x: event.offsetX,
2746
- y: event.offsetY
2747
- };
2748
- }
2749
-
2750
- var dim = {
2751
- c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
2752
- r: Math.ceil(posOffset.y / PX_PER_EM) || 1
2753
- };
2754
-
2755
- $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });
2756
- $catcher.attr('data-value', dim.c + 'x' + dim.r);
2757
-
2758
- if (3 < dim.c && dim.c < 10) { // 5~10
2759
- $unhighlighted.css({ width: dim.c + 1 + 'em'});
2760
- }
2761
-
2762
- if (3 < dim.r && dim.r < 10) { // 5~10
2763
- $unhighlighted.css({ height: dim.r + 1 + 'em'});
2764
- }
2765
-
2766
- $dimensionDisplay.html(dim.c + ' x ' + dim.r);
2767
- };
2768
-
2769
- /**
2770
- * attach Drag and Drop Events
2771
- *
2772
- * @param {Object} oLayoutInfo - layout Informations
2773
- */
2774
- var attachDragAndDropEvent = function (oLayoutInfo) {
2775
- var collection = $(), $dropzone = oLayoutInfo.dropzone,
2776
- $dropzoneMessage = oLayoutInfo.dropzone.find('.note-dropzone-message');
2777
-
2778
- // show dropzone on dragenter when dragging a object to document.
2779
- $document.on('dragenter', function (e) {
2780
- var bCodeview = oLayoutInfo.editor.hasClass('codeview');
2781
- if (!bCodeview && collection.length === 0) {
2782
- oLayoutInfo.editor.addClass('dragover');
2783
- $dropzone.width(oLayoutInfo.editor.width());
2784
- $dropzone.height(oLayoutInfo.editor.height());
2785
- $dropzoneMessage.text('Drag Image Here');
2786
- }
2787
- collection = collection.add(e.target);
2788
- }).on('dragleave', function (e) {
2789
- collection = collection.not(e.target);
2790
- if (collection.length === 0) {
2791
- oLayoutInfo.editor.removeClass('dragover');
2792
- }
2793
- }).on('drop', function () {
2794
- collection = $();
2795
- oLayoutInfo.editor.removeClass('dragover');
2796
- });
2797
-
2798
- // change dropzone's message on hover.
2799
- $dropzone.on('dragenter', function () {
2800
- $dropzone.addClass('hover');
2801
- $dropzoneMessage.text('Drop Image');
2802
- }).on('dragleave', function () {
2803
- $dropzone.removeClass('hover');
2804
- $dropzoneMessage.text('Drag Image Here');
2805
- });
2806
-
2807
- // attach dropImage
2808
- $dropzone.on('drop', function (event) {
2809
- event.preventDefault();
2810
-
2811
- var dataTransfer = event.originalEvent.dataTransfer;
2812
- if (dataTransfer && dataTransfer.files) {
2813
- var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
2814
- oLayoutInfo.editable().focus();
2815
- insertImages(oLayoutInfo.editable(), dataTransfer.files);
2816
- }
2817
- }).on('dragover', false); // prevent default dragover event
2818
- };
2819
-
2820
-
2821
- /**
2822
- * bind KeyMap on keydown
2823
- *
2824
- * @param {Object} oLayoutInfo
2825
- * @param {Object} keyMap
2826
- */
2827
- this.bindKeyMap = function (oLayoutInfo, keyMap) {
2828
- var $editor = oLayoutInfo.editor;
2829
- var $editable = oLayoutInfo.editable;
2830
-
2831
- $editable.on('keydown', function (event) {
2832
- var aKey = [];
2833
-
2834
- // modifier
2835
- if (event.metaKey) { aKey.push('CMD'); }
2836
- if (event.ctrlKey) { aKey.push('CTRL'); }
2837
- if (event.shiftKey) { aKey.push('SHIFT'); }
2838
-
2839
- // keycode
2840
- var keyName = key.nameFromCode[event.keyCode];
2841
- if (keyName) { aKey.push(keyName); }
2842
-
2843
- var handler = keyMap[aKey.join('+')];
2844
- if (handler) {
2845
- event.preventDefault();
2846
-
2847
- editor[handler]($editable, $editor.data('options'));
2848
- } else if (key.isEdit(event.keyCode)) {
2849
- editor.recordUndo($editable);
2850
- }
2851
- });
2852
- };
2853
-
2854
- /**
2855
- * attach eventhandler
2856
- *
2857
- * @param {Object} oLayoutInfo - layout Informations
2858
- * @param {Object} options - user options include custom event handlers
2859
- * @param {Function} options.enter - enter key handler
2860
- */
2861
- this.attach = function (oLayoutInfo, options) {
2862
- // handlers for editable
2863
- this.bindKeyMap(oLayoutInfo, options.keyMap[agent.bMac ? 'mac' : 'pc']);
2864
- oLayoutInfo.editable.on('mousedown', hMousedown);
2865
- oLayoutInfo.editable.on('keyup mouseup', hToolbarAndPopoverUpdate);
2866
- oLayoutInfo.editable.on('scroll', hScroll);
2867
- oLayoutInfo.editable.on('paste', hPasteClipboardImage);
2868
-
2869
- // handler for handle and popover
2870
- oLayoutInfo.handle.on('mousedown', hHandleMousedown);
2871
- oLayoutInfo.popover.on('click', hToolbarAndPopoverClick);
2872
- oLayoutInfo.popover.on('mousedown', hToolbarAndPopoverMousedown);
2873
-
2874
- // handlers for frame mode (toolbar, statusbar)
2875
- if (!options.airMode) {
2876
- // handler for drag and drop
2877
- if (!options.disableDragAndDrop) {
2878
- attachDragAndDropEvent(oLayoutInfo);
2879
- }
2880
-
2881
- // handler for toolbar
2882
- oLayoutInfo.toolbar.on('click', hToolbarAndPopoverClick);
2883
- oLayoutInfo.toolbar.on('mousedown', hToolbarAndPopoverMousedown);
2884
-
2885
- // handler for statusbar
2886
- oLayoutInfo.statusbar.on('mousedown', hStatusbarMousedown);
2887
- }
2888
-
2889
- // handler for table dimension
2890
- var $catcherContainer = options.airMode ? oLayoutInfo.popover :
2891
- oLayoutInfo.toolbar;
2892
- var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');
2893
- $catcher.on('mousemove', hDimensionPickerMove);
2894
-
2895
- // save selection when focusout
2896
- oLayoutInfo.editable.on('blur', function () {
2897
- editor.saveRange(oLayoutInfo.editable);
2898
- });
2899
-
2900
- // save options on editor
2901
- oLayoutInfo.editor.data('options', options);
2902
-
2903
- // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.
2904
- if (options.styleWithSpan && !agent.bMSIE) {
2905
- // protect FF Error: NS_ERROR_FAILURE: Failure
2906
- setTimeout(function () {
2907
- document.execCommand('styleWithCSS', 0, true);
2908
- }, 0);
2909
- }
2910
-
2911
- // History
2912
- oLayoutInfo.editable.data('NoteHistory', new History());
2913
-
2914
- // basic event callbacks (lowercase)
2915
- // enter, focus, blur, keyup, keydown
2916
- if (options.onenter) {
2917
- oLayoutInfo.editable.keypress(function (event) {
2918
- if (event.keyCode === key.ENTER) { options.onenter(event); }
2919
- });
2920
- }
2921
-
2922
- if (options.onfocus) { oLayoutInfo.editable.focus(options.onfocus); }
2923
- if (options.onblur) { oLayoutInfo.editable.blur(options.onblur); }
2924
- if (options.onkeyup) { oLayoutInfo.editable.keyup(options.onkeyup); }
2925
- if (options.onkeydown) { oLayoutInfo.editable.keydown(options.onkeydown); }
2926
- if (options.onpaste) { oLayoutInfo.editable.on('paste', options.onpaste); }
2927
-
2928
- // callbacks for advanced features (camel)
2929
- if (options.onToolbarClick) { oLayoutInfo.toolbar.click(options.onToolbarClick); }
2930
- if (options.onChange) {
2931
- var hChange = function () {
2932
- options.onChange(oLayoutInfo.editable, oLayoutInfo.editable.html());
2933
- };
2934
-
2935
- if (agent.bMSIE) {
2936
- var sDomEvents = 'DOMCharacterDataModified, DOMSubtreeModified, DOMNodeInserted';
2937
- oLayoutInfo.editable.on(sDomEvents, hChange);
2938
- } else {
2939
- oLayoutInfo.editable.on('input', hChange);
2940
- }
2941
- }
2942
-
2943
- // All editor status will be saved on editable with jquery's data
2944
- // for support multiple editor with singleton object.
2945
- oLayoutInfo.editable.data('callbacks', {
2946
- onAutoSave: options.onAutoSave,
2947
- onImageUpload: options.onImageUpload,
2948
- onImageUploadError: options.onImageUploadError,
2949
- onFileUpload: options.onFileUpload,
2950
- onFileUploadError: options.onFileUpload
2951
- });
2952
- };
2953
-
2954
- this.dettach = function (oLayoutInfo) {
2955
- oLayoutInfo.editable.off();
2956
-
2957
- oLayoutInfo.popover.off();
2958
- oLayoutInfo.handle.off();
2959
- oLayoutInfo.dialog.off();
2960
-
2961
- if (oLayoutInfo.editor.data('options').airMode) {
2962
- oLayoutInfo.dropzone.off();
2963
- oLayoutInfo.toolbar.off();
2964
- oLayoutInfo.statusbar.off();
2965
- }
2966
- };
2967
- };
2968
-
2969
- /**
2970
- * renderer
2971
- *
2972
- * rendering toolbar and editable
2973
- */
2974
- var Renderer = function () {
2975
-
2976
- /**
2977
- * bootstrap button template
2978
- *
2979
- * @param {String} sLabel
2980
- * @param {Object} [options]
2981
- * @param {String} [options.event]
2982
- * @param {String} [options.value]
2983
- * @param {String} [options.title]
2984
- * @param {String} [options.dropdown]
2985
- */
2986
- var tplButton = function (sLabel, options) {
2987
- var event = options.event;
2988
- var value = options.value;
2989
- var title = options.title;
2990
- var className = options.className;
2991
- var dropdown = options.dropdown;
2992
-
2993
- return '<button type="button"' +
2994
- ' class="btn btn-default btn-sm btn-small' +
2995
- (className ? ' ' + className : '') +
2996
- (dropdown ? ' dropdown-toggle' : '') +
2997
- '"' +
2998
- (dropdown ? ' data-toggle="dropdown"' : '') +
2999
- (title ? ' title="' + title + '"' : '') +
3000
- (event ? ' data-event="' + event + '"' : '') +
3001
- (value ? ' data-value=\'' + value + '\'' : '') +
3002
- ' tabindex="-1">' +
3003
- sLabel +
3004
- (dropdown ? ' <span class="caret"></span>' : '') +
3005
- '</button>' +
3006
- (dropdown || '');
3007
- };
3008
-
3009
- /**
3010
- * bootstrap icon button template
3011
- *
3012
- * @param {String} sIconClass
3013
- * @param {Object} [options]
3014
- * @param {String} [options.event]
3015
- * @param {String} [options.value]
3016
- * @param {String} [options.title]
3017
- * @param {String} [options.dropdown]
3018
- */
3019
- var tplIconButton = function (sIconClass, options) {
3020
- var sLabel = '<i class="' + sIconClass + '"></i>';
3021
- return tplButton(sLabel, options);
3022
- };
3023
-
3024
- /**
3025
- * bootstrap popover template
3026
- *
3027
- * @param {String} className
3028
- * @param {String} content
3029
- */
3030
- var tplPopover = function (className, content) {
3031
- return '<div class="' + className + ' popover bottom in" style="display: none;">' +
3032
- '<div class="arrow"></div>' +
3033
- '<div class="popover-content">' +
3034
- content +
3035
- '</div>' +
3036
- '</div>';
3037
- };
3038
-
3039
- /**
3040
- * bootstrap dialog template
3041
- *
3042
- * @param {String} className
3043
- * @param {String} [title]
3044
- * @param {String} body
3045
- * @param {String} [footer]
3046
- */
3047
- var tplDialog = function (className, title, body, footer) {
3048
- return '<div class="' + className + ' modal" aria-hidden="false">' +
3049
- '<div class="modal-dialog">' +
3050
- '<div class="modal-content">' +
3051
- (title ?
3052
- '<div class="modal-header">' +
3053
- '<button type="button" class="close" aria-hidden="true" tabindex="-1">&times;</button>' +
3054
- '<h4>' + title + '</h4>' +
3055
- '</div>' : ''
3056
- ) +
3057
- '<form class="note-modal-form">' +
3058
- '<div class="modal-body">' +
3059
- '<div class="row-fluid">' + body + '</div>' +
3060
- '</div>' +
3061
- (footer ?
3062
- '<div class="modal-footer">' + footer + '</div>' : ''
3063
- ) +
3064
- '</form>' +
3065
- '</div>' +
3066
- '</div>' +
3067
- '</div>';
3068
- };
3069
-
3070
- var tplButtonInfo = {
3071
- picture: function (lang) {
3072
- return tplIconButton('fa fa-picture-o icon-picture', {
3073
- event: 'showImageDialog',
3074
- title: lang.image.image
3075
- });
3076
- },
3077
- link: function (lang) {
3078
- return tplIconButton('fa fa-link icon-link', {
3079
- event: 'showLinkDialog',
3080
- title: lang.link.link
3081
- });
3082
- },
3083
- video: function (lang) {
3084
- return tplIconButton('fa fa-youtube-play icon-play', {
3085
- event: 'showVideoDialog',
3086
- title: lang.video.video
3087
- });
3088
- },
3089
- table: function (lang) {
3090
- var dropdown = '<ul class="dropdown-menu">' +
3091
- '<div class="note-dimension-picker">' +
3092
- '<div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div>' +
3093
- '<div class="note-dimension-picker-highlighted"></div>' +
3094
- '<div class="note-dimension-picker-unhighlighted"></div>' +
3095
- '</div>' +
3096
- '<div class="note-dimension-display"> 1 x 1 </div>' +
3097
- '</ul>';
3098
- return tplIconButton('fa fa-table icon-table', {
3099
- title: lang.table.table,
3100
- dropdown: dropdown
3101
- });
3102
- },
3103
- style: function (lang, options) {
3104
- var items = options.styleTags.reduce(function (memo, v) {
3105
- var label = lang.style[v === 'p' ? 'normal' : v];
3106
- return memo + '<li><a data-event="formatBlock" data-value="' + v + '">' +
3107
- (
3108
- (v === 'p' || v === 'pre') ? label :
3109
- '<' + v + '>' + label + '</' + v + '>'
3110
- ) +
3111
- '</a></li>';
3112
- }, '');
3113
-
3114
- return tplIconButton('fa fa-magic icon-magic', {
3115
- title: lang.style.style,
3116
- dropdown: '<ul class="dropdown-menu">' + items + '</ul>'
3117
- });
3118
- },
3119
- fontname: function (lang, options) {
3120
- var items = options.fontNames.reduce(function (memo, v) {
3121
- return memo + '<li><a data-event="fontName" data-value="' + v + '">' +
3122
- '<i class="fa fa-check icon-ok"></i> ' + v +
3123
- '</a></li>';
3124
- }, '');
3125
- var sLabel = '<span class="note-current-fontname">' +
3126
- options.defaultFontName +
3127
- '</span>';
3128
- return tplButton(sLabel, {
3129
- title: lang.font.name,
3130
- dropdown: '<ul class="dropdown-menu">' + items + '</ul>'
3131
- });
3132
- },
3133
- fontsize: function (lang, options) {
3134
- var items = options.fontSizes.reduce(function (memo, v) {
3135
- return memo + '<li><a data-event="fontSize" data-value="' + v + '">' +
3136
- '<i class="fa fa-check icon-ok"></i> ' + v +
3137
- '</a></li>';
3138
- }, '');
3139
-
3140
- var sLabel = '<span class="note-current-fontsize">11</span>';
3141
- return tplButton(sLabel, {
3142
- title: lang.font.size,
3143
- dropdown: '<ul class="dropdown-menu">' + items + '</ul>'
3144
- });
3145
- },
3146
-
3147
- color: function (lang) {
3148
- var colorButtonLabel = '<i class="fa fa-font icon-font" style="color:black;background-color:yellow;"></i>';
3149
- var colorButton = tplButton(colorButtonLabel, {
3150
- className: 'note-recent-color',
3151
- title: lang.color.recent,
3152
- event: 'color',
3153
- value: '{"backColor":"yellow"}'
3154
- });
3155
-
3156
- var dropdown = '<ul class="dropdown-menu">' +
3157
- '<li>' +
3158
- '<div class="btn-group">' +
3159
- '<div class="note-palette-title">' + lang.color.background + '</div>' +
3160
- '<div class="note-color-reset" data-event="backColor"' +
3161
- ' data-value="inherit" title="' + lang.color.transparent + '">' +
3162
- lang.color.setTransparent +
3163
- '</div>' +
3164
- '<div class="note-color-palette" data-target-event="backColor"></div>' +
3165
- '</div>' +
3166
- '<div class="btn-group">' +
3167
- '<div class="note-palette-title">' + lang.color.foreground + '</div>' +
3168
- '<div class="note-color-reset" data-event="foreColor" data-value="inherit" title="' + lang.color.reset + '">' +
3169
- lang.color.resetToDefault +
3170
- '</div>' +
3171
- '<div class="note-color-palette" data-target-event="foreColor"></div>' +
3172
- '</div>' +
3173
- '</li>' +
3174
- '</ul>';
3175
-
3176
- var moreButton = tplButton('', {
3177
- title: lang.color.more,
3178
- dropdown: dropdown
3179
- });
3180
-
3181
- return colorButton + moreButton;
3182
- },
3183
- bold: function (lang) {
3184
- return tplIconButton('fa fa-bold icon-bold', {
3185
- event: 'bold',
3186
- title: lang.font.bold
3187
- });
3188
- },
3189
- italic: function (lang) {
3190
- return tplIconButton('fa fa-italic icon-italic', {
3191
- event: 'italic',
3192
- title: lang.font.italic
3193
- });
3194
- },
3195
- underline: function (lang) {
3196
- return tplIconButton('fa fa-underline icon-underline', {
3197
- event: 'underline',
3198
- title: lang.font.underline
3199
- });
3200
- },
3201
- strikethrough: function (lang) {
3202
- return tplIconButton('fa fa-strikethrough icon-strikethrough', {
3203
- event: 'strikethrough',
3204
- title: lang.font.strikethrough
3205
- });
3206
- },
3207
- superscript: function (lang) {
3208
- return tplIconButton('fa fa-superscript icon-superscript', {
3209
- event: 'superscript',
3210
- title: lang.font.superscript
3211
- });
3212
- },
3213
- subscript: function (lang) {
3214
- return tplIconButton('fa fa-subscript icon-subscript', {
3215
- event: 'subscript',
3216
- title: lang.font.subscript
3217
- });
3218
- },
3219
- clear: function (lang) {
3220
- return tplIconButton('fa fa-eraser icon-eraser', {
3221
- event: 'removeFormat',
3222
- title: lang.font.clear
3223
- });
3224
- },
3225
- ul: function (lang) {
3226
- return tplIconButton('fa fa-list-ul icon-list-ul', {
3227
- event: 'insertUnorderedList',
3228
- title: lang.lists.unordered
3229
- });
3230
- },
3231
- ol: function (lang) {
3232
- return tplIconButton('fa fa-list-ol icon-list-ol', {
3233
- event: 'insertOrderedList',
3234
- title: lang.lists.ordered
3235
- });
3236
- },
3237
- paragraph: function (lang) {
3238
- var leftButton = tplIconButton('fa fa-align-left icon-align-left', {
3239
- title: lang.paragraph.left,
3240
- event: 'justifyLeft'
3241
- });
3242
- var centerButton = tplIconButton('fa fa-align-center icon-align-center', {
3243
- title: lang.paragraph.center,
3244
- event: 'justifyCenter'
3245
- });
3246
- var rightButton = tplIconButton('fa fa-align-right icon-align-right', {
3247
- title: lang.paragraph.right,
3248
- event: 'justifyRight'
3249
- });
3250
- var justifyButton = tplIconButton('fa fa-align-justify icon-align-justify', {
3251
- title: lang.paragraph.justify,
3252
- event: 'justifyFull'
3253
- });
3254
-
3255
- var outdentButton = tplIconButton('fa fa-outdent icon-indent-left', {
3256
- title: lang.paragraph.outdent,
3257
- event: 'outdent'
3258
- });
3259
- var indentButton = tplIconButton('fa fa-indent icon-indent-right', {
3260
- title: lang.paragraph.indent,
3261
- event: 'indent'
3262
- });
3263
-
3264
- var dropdown = '<div class="dropdown-menu">' +
3265
- '<div class="note-align btn-group">' +
3266
- leftButton + centerButton + rightButton + justifyButton +
3267
- '</div>' +
3268
- '<div class="note-list btn-group">' +
3269
- indentButton + outdentButton +
3270
- '</div>' +
3271
- '</div>';
3272
-
3273
- return tplIconButton('fa fa-align-left icon-align-left', {
3274
- title: lang.paragraph.paragraph,
3275
- dropdown: dropdown
3276
- });
3277
- },
3278
- height: function (lang, options) {
3279
- var items = options.lineHeights.reduce(function (memo, v) {
3280
- return memo + '<li><a data-event="lineHeight" data-value="' + parseFloat(v) + '">' +
3281
- '<i class="fa fa-check icon-ok"></i> ' + v +
3282
- '</a></li>';
3283
- }, '');
3284
-
3285
- return tplIconButton('fa fa-text-height icon-text-height', {
3286
- title: lang.font.height,
3287
- dropdown: '<ul class="dropdown-menu">' + items + '</ul>'
3288
- });
3289
-
3290
- },
3291
- help: function (lang) {
3292
- return tplIconButton('fa fa-question icon-question', {
3293
- event: 'showHelpDialog',
3294
- title: lang.options.help
3295
- });
3296
- },
3297
- fullscreen: function (lang) {
3298
- return tplIconButton('fa fa-arrows-alt icon-fullscreen', {
3299
- event: 'fullscreen',
3300
- title: lang.options.fullscreen
3301
- });
3302
- },
3303
- codeview: function (lang) {
3304
- return tplIconButton('fa fa-code icon-code', {
3305
- event: 'codeview',
3306
- title: lang.options.codeview
3307
- });
3308
- },
3309
- undo: function (lang) {
3310
- return tplIconButton('fa fa-undo icon-undo', {
3311
- event: 'undo',
3312
- title: lang.history.undo
3313
- });
3314
- },
3315
- redo: function (lang) {
3316
- return tplIconButton('fa fa-repeat icon-repeat', {
3317
- event: 'redo',
3318
- title: lang.history.redo
3319
- });
3320
- }
3321
- };
3322
-
3323
- var tplPopovers = function (lang, options) {
3324
- var tplLinkPopover = function () {
3325
- var linkButton = tplIconButton('fa fa-edit icon-edit', {
3326
- title: lang.link.edit,
3327
- event: 'showLinkDialog'
3328
- });
3329
- var unlinkButton = tplIconButton('fa fa-unlink icon-unlink', {
3330
- title: lang.link.unlink,
3331
- event: 'unlink'
3332
- });
3333
- var content = '<a href="http://www.google.com" target="_blank">www.google.com</a>&nbsp;&nbsp;' +
3334
- '<div class="note-insert btn-group">' +
3335
- linkButton + unlinkButton +
3336
- '</div>';
3337
- return tplPopover('note-link-popover', content);
3338
- };
3339
-
3340
- var tplImagePopover = function () {
3341
- var fullButton = tplButton('<span class="note-fontsize-10">100%</span>', {
3342
- title: lang.image.resizeFull,
3343
- event: 'resize',
3344
- value: '1'
3345
- });
3346
- var halfButton = tplButton('<span class="note-fontsize-10">50%</span>', {
3347
- title: lang.image.resizeHalf,
3348
- event: 'resize',
3349
- value: '0.5'
3350
- });
3351
- var quarterButton = tplButton('<span class="note-fontsize-10">25%</span>', {
3352
- title: lang.image.resizeQuarter,
3353
- event: 'resize',
3354
- value: '0.25'
3355
- });
3356
-
3357
- var leftButton = tplIconButton('fa fa-align-left icon-align-left', {
3358
- title: lang.image.floatLeft,
3359
- event: 'floatMe',
3360
- value: 'left'
3361
- });
3362
- var rightButton = tplIconButton('fa fa-align-right icon-align-right', {
3363
- title: lang.image.floatRight,
3364
- event: 'floatMe',
3365
- value: 'right'
3366
- });
3367
- var justifyButton = tplIconButton('fa fa-align-justify icon-align-justify', {
3368
- title: lang.image.floatNone,
3369
- event: 'floatMe',
3370
- value: 'none'
3371
- });
3372
-
3373
- var removeButton = tplIconButton('fa fa-trash-o icon-trash', {
3374
- title: lang.image.remove,
3375
- event: 'removeMedia',
3376
- value: 'none'
3377
- });
3378
-
3379
- var content = '<div class="btn-group">' + fullButton + halfButton + quarterButton + '</div>' +
3380
- '<div class="btn-group">' + leftButton + rightButton + justifyButton + '</div>' +
3381
- '<div class="btn-group">' + removeButton + '</div>';
3382
- return tplPopover('note-image-popover', content);
3383
- };
3384
-
3385
- var tplAirPopover = function () {
3386
- var content = '';
3387
- for (var idx = 0, sz = options.airPopover.length; idx < sz; idx ++) {
3388
- var group = options.airPopover[idx];
3389
- content += '<div class="note-' + group[0] + ' btn-group">';
3390
- for (var i = 0, szGroup = group[1].length; i < szGroup; i++) {
3391
- content += tplButtonInfo[group[1][i]](lang, options);
3392
- }
3393
- content += '</div>';
3394
- }
3395
-
3396
- return tplPopover('note-air-popover', content);
3397
- };
3398
-
3399
- return '<div class="note-popover">' +
3400
- tplLinkPopover() +
3401
- tplImagePopover() +
3402
- (options.airMode ? tplAirPopover() : '') +
3403
- '</div>';
3404
- };
3405
-
3406
- var tplHandles = function () {
3407
- return '<div class="note-handle">' +
3408
- '<div class="note-control-selection">' +
3409
- '<div class="note-control-selection-bg"></div>' +
3410
- '<div class="note-control-holder note-control-nw"></div>' +
3411
- '<div class="note-control-holder note-control-ne"></div>' +
3412
- '<div class="note-control-holder note-control-sw"></div>' +
3413
- '<div class="note-control-sizing note-control-se"></div>' +
3414
- '<div class="note-control-selection-info"></div>' +
3415
- '</div>' +
3416
- '</div>';
3417
- };
3418
-
3419
- /**
3420
- * shortcut table template
3421
- * @param {String} title
3422
- * @param {String} body
3423
- */
3424
- var tplShortcut = function (title, body) {
3425
- return '<table class="note-shortcut">' +
3426
- '<thead>' +
3427
- '<tr><th></th><th>' + title + '</th></tr>' +
3428
- '</thead>' +
3429
- '<tbody>' + body + '</tbody>' +
3430
- '</table>';
3431
- };
3432
-
3433
- var tplShortcutText = function (lang) {
3434
- var body = '<tr><td>⌘ + B</td><td>' + lang.font.bold + '</td></tr>' +
3435
- '<tr><td>⌘ + I</td><td>' + lang.font.italic + '</td></tr>' +
3436
- '<tr><td>⌘ + U</td><td>' + lang.font.underline + '</td></tr>' +
3437
- '<tr><td>⌘ + ⇧ + S</td><td>' + lang.font.strikethrough + '</td></tr>' +
3438
- '<tr><td>⌘ + \\</td><td>' + lang.font.clear + '</td></tr>';
3439
-
3440
- return tplShortcut(lang.shortcut.textFormatting, body);
3441
- };
3442
-
3443
- var tplShortcutAction = function (lang) {
3444
- var body = '<tr><td>⌘ + Z</td><td>' + lang.history.undo + '</td></tr>' +
3445
- '<tr><td>⌘ + ⇧ + Z</td><td>' + lang.history.redo + '</td></tr>' +
3446
- '<tr><td>⌘ + ]</td><td>' + lang.paragraph.indent + '</td></tr>' +
3447
- '<tr><td>⌘ + [</td><td>' + lang.paragraph.outdent + '</td></tr>' +
3448
- '<tr><td>⌘ + ENTER</td><td>' + lang.hr.insert + '</td></tr>';
3449
-
3450
- return tplShortcut(lang.shortcut.action, body);
3451
- };
3452
-
3453
- var tplShortcutPara = function (lang) {
3454
- var body = '<tr><td>⌘ + ⇧ + L</td><td>' + lang.paragraph.left + '</td></tr>' +
3455
- '<tr><td>⌘ + ⇧ + E</td><td>' + lang.paragraph.center + '</td></tr>' +
3456
- '<tr><td>⌘ + ⇧ + R</td><td>' + lang.paragraph.right + '</td></tr>' +
3457
- '<tr><td>⌘ + ⇧ + J</td><td>' + lang.paragraph.justify + '</td></tr>' +
3458
- '<tr><td>⌘ + ⇧ + NUM7</td><td>' + lang.lists.ordered + '</td></tr>' +
3459
- '<tr><td>⌘ + ⇧ + NUM8</td><td>' + lang.lists.unordered + '</td></tr>';
3460
-
3461
- return tplShortcut(lang.shortcut.paragraphFormatting, body);
3462
- };
3463
-
3464
- var tplShortcutStyle = function (lang) {
3465
- var body = '<tr><td>⌘ + NUM0</td><td>' + lang.style.normal + '</td></tr>' +
3466
- '<tr><td>⌘ + NUM1</td><td>' + lang.style.h1 + '</td></tr>' +
3467
- '<tr><td>⌘ + NUM2</td><td>' + lang.style.h2 + '</td></tr>' +
3468
- '<tr><td>⌘ + NUM3</td><td>' + lang.style.h3 + '</td></tr>' +
3469
- '<tr><td>⌘ + NUM4</td><td>' + lang.style.h4 + '</td></tr>' +
3470
- '<tr><td>⌘ + NUM5</td><td>' + lang.style.h5 + '</td></tr>' +
3471
- '<tr><td>⌘ + NUM6</td><td>' + lang.style.h6 + '</td></tr>';
3472
-
3473
- return tplShortcut(lang.shortcut.documentStyle, body);
3474
- };
3475
-
3476
- var tplExtraShortcuts = function (lang, options) {
3477
- var extraKeys = options.extraKeys;
3478
- var body = '';
3479
- for (var key in extraKeys) {
3480
- if (extraKeys.hasOwnProperty(key)) {
3481
- body += '<tr><td>' + key + '</td><td>' + extraKeys[key] + '</td></tr>';
3482
- }
3483
- }
3484
-
3485
- return tplShortcut(lang.shortcut.extraKeys, body);
3486
- };
3487
-
3488
- var tplShortcutTable = function (lang, options) {
3489
- var template = '<table class="note-shortcut-layout">' +
3490
- '<tbody>' +
3491
- '<tr><td>' + tplShortcutAction(lang, options) + '</td><td>' + tplShortcutText(lang, options) + '</td></tr>' +
3492
- '<tr><td>' + tplShortcutStyle(lang, options) + '</td><td>' + tplShortcutPara(lang, options) + '</td></tr>';
3493
- if (options.extraKeys) {
3494
- template += '<tr><td colspan="2">' + tplExtraShortcuts(lang, options) + '</td></tr>';
3495
- }
3496
- template += '</tbody</table>';
3497
- return template;
3498
- };
3499
-
3500
- var replaceMacKeys = function (sHtml) {
3501
- return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');
3502
- };
3503
-
3504
- var tplDialogs = function (lang, options) {
3505
- var tplImageDialog = function () {
3506
- var body = '<h5>' + lang.image.selectFromFiles + '</h5>' +
3507
- '<input class="note-image-input" type="file" name="files" accept="image/*" />' +
3508
- '<h5>' + lang.image.url + '</h5>' +
3509
- '<input class="note-image-url form-control span12" type="text" />';
3510
- var footer = '<button href="#" class="btn btn-primary note-image-btn disabled" disabled>' + lang.image.insert + '</button>';
3511
- return tplDialog('note-image-dialog', lang.image.insert, body, footer);
3512
- };
3513
-
3514
- var tplLinkDialog = function () {
3515
- var body = '<div class="form-group">' +
3516
- '<label>' + lang.link.textToDisplay + '</label>' +
3517
- '<input class="note-link-text form-control span12" type="text" />' +
3518
- '</div>' +
3519
- '<div class="form-group">' +
3520
- '<label>' + lang.link.url + '</label>' +
3521
- '<input class="note-link-url form-control span12" type="text" />' +
3522
- '</div>' +
3523
- (!options.disableLinkTarget ?
3524
- '<div class="checkbox">' +
3525
- '<label>' + '<input type="checkbox" checked> ' +
3526
- lang.link.openInNewWindow +
3527
- '</label>' +
3528
- '</div>' : ''
3529
- );
3530
- var footer = '<button href="#" class="btn btn-primary note-link-btn disabled" disabled>' + lang.link.insert + '</button>';
3531
- return tplDialog('note-link-dialog', lang.link.insert, body, footer);
3532
- };
3533
-
3534
- var tplVideoDialog = function () {
3535
- var body = '<div class="form-group">' +
3536
- '<label>' + lang.video.url + '</label>&nbsp;<small class="text-muted">' + lang.video.providers + '</small>' +
3537
- '<input class="note-video-url form-control span12" type="text" />' +
3538
- '</div>';
3539
- var footer = '<button href="#" class="btn btn-primary note-video-btn disabled" disabled>' + lang.video.insert + '</button>';
3540
- return tplDialog('note-video-dialog', lang.video.insert, body, footer);
3541
- };
3542
-
3543
- var tplHelpDialog = function () {
3544
- var body = '<a class="modal-close pull-right" aria-hidden="true" tabindex="-1">' + lang.shortcut.close + '</a>' +
3545
- '<div class="title">' + lang.shortcut.shortcuts + '</div>' +
3546
- (agent.bMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options))) +
3547
- '<p class="text-center">' +
3548
- '<a href="//hackerwins.github.io/summernote/" target="_blank">Summernote 0.5.2</a> · ' +
3549
- '<a href="//github.com/HackerWins/summernote" target="_blank">Project</a> · ' +
3550
- '<a href="//github.com/HackerWins/summernote/issues" target="_blank">Issues</a>' +
3551
- '</p>';
3552
- return tplDialog('note-help-dialog', '', body, '');
3553
- };
3554
-
3555
- return '<div class="note-dialog">' +
3556
- tplImageDialog() +
3557
- tplLinkDialog() +
3558
- tplVideoDialog() +
3559
- tplHelpDialog() +
3560
- '</div>';
3561
- };
3562
-
3563
- var tplStatusbar = function () {
3564
- return '<div class="note-resizebar">' +
3565
- '<div class="note-icon-bar"></div>' +
3566
- '<div class="note-icon-bar"></div>' +
3567
- '<div class="note-icon-bar"></div>' +
3568
- '</div>';
3569
- };
3570
-
3571
- var representShortcut = function (str) {
3572
- if (agent.bMac) {
3573
- str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');
3574
- }
3575
-
3576
- return str.replace('BACKSLASH', '\\')
3577
- .replace('SLASH', '/')
3578
- .replace('LEFTBRACKET', '[')
3579
- .replace('RIGHTBRACKET', ']');
3580
- };
3581
-
3582
- /**
3583
- * createTooltip
3584
- *
3585
- * @param {jQuery} $container
3586
- * @param {Object} keyMap
3587
- * @param {String} [sPlacement]
3588
- */
3589
- var createTooltip = function ($container, keyMap, sPlacement) {
3590
- var invertedKeyMap = func.invertObject(keyMap);
3591
- var $buttons = $container.find('button');
3592
-
3593
- $buttons.each(function (i, elBtn) {
3594
- var $btn = $(elBtn);
3595
- var sShortcut = invertedKeyMap[$btn.data('event')];
3596
- if (sShortcut) {
3597
- $btn.attr('title', function (i, v) {
3598
- return v + ' (' + representShortcut(sShortcut) + ')';
3599
- });
3600
- }
3601
- // bootstrap tooltip on btn-group bug
3602
- // https://github.com/twitter/bootstrap/issues/5687
3603
- }).tooltip({
3604
- container: 'body',
3605
- trigger: 'hover',
3606
- placement: sPlacement || 'top'
3607
- }).on('click', function () {
3608
- $(this).tooltip('hide');
3609
- });
3610
- };
3611
-
3612
- // createPalette
3613
- var createPalette = function ($container, options) {
3614
- var aaColor = options.colors;
3615
- $container.find('.note-color-palette').each(function () {
3616
- var $palette = $(this), sEvent = $palette.attr('data-target-event');
3617
- var aPaletteContents = [];
3618
- for (var row = 0, szRow = aaColor.length; row < szRow; row++) {
3619
- var aColor = aaColor[row];
3620
- var aButton = [];
3621
- for (var col = 0, szCol = aColor.length; col < szCol; col++) {
3622
- var sColor = aColor[col];
3623
- aButton.push(['<button type="button" class="note-color-btn" style="background-color:', sColor,
3624
- ';" data-event="', sEvent,
3625
- '" data-value="', sColor,
3626
- '" title="', sColor,
3627
- '" data-toggle="button" tabindex="-1"></button>'].join(''));
3628
- }
3629
- aPaletteContents.push('<div>' + aButton.join('') + '</div>');
3630
- }
3631
- $palette.html(aPaletteContents.join(''));
3632
- });
3633
- };
3634
-
3635
- /**
3636
- * create summernote layout (air mode)
3637
- *
3638
- * @param {jQuery} $holder
3639
- * @param {Object} options
3640
- */
3641
- this.createLayoutByAirMode = function ($holder, options) {
3642
- var keyMap = options.keyMap[agent.bMac ? 'mac' : 'pc'];
3643
- var langInfo = $.summernote.lang[options.lang];
3644
-
3645
- var id = func.uniqueId();
3646
-
3647
- $holder.addClass('note-air-editor note-editable');
3648
- $holder.attr({
3649
- 'id': 'note-editor-' + id,
3650
- 'contentEditable': true
3651
- });
3652
-
3653
- var body = document.body;
3654
-
3655
- // create Popover
3656
- var $popover = $(tplPopovers(langInfo, options));
3657
- $popover.addClass('note-air-layout');
3658
- $popover.attr('id', 'note-popover-' + id);
3659
- $popover.appendTo(body);
3660
- createTooltip($popover, keyMap);
3661
- createPalette($popover, options);
3662
-
3663
- // create Handle
3664
- var $handle = $(tplHandles());
3665
- $handle.addClass('note-air-layout');
3666
- $handle.attr('id', 'note-handle-' + id);
3667
- $handle.appendTo(body);
3668
-
3669
- // create Dialog
3670
- var $dialog = $(tplDialogs(langInfo, options));
3671
- $dialog.addClass('note-air-layout');
3672
- $dialog.attr('id', 'note-dialog-' + id);
3673
- $dialog.find('button.close, a.modal-close').click(function () {
3674
- $(this).closest('.modal').modal('hide');
3675
- });
3676
- $dialog.appendTo(body);
3677
- };
3678
-
3679
- /**
3680
- * create summernote layout (normal mode)
3681
- *
3682
- * @param {jQuery} $holder
3683
- * @param {Object} options
3684
- */
3685
- this.createLayoutByFrame = function ($holder, options) {
3686
- //01. create Editor
3687
- var $editor = $('<div class="note-editor"></div>');
3688
- if (options.width) {
3689
- $editor.width(options.width);
3690
- }
3691
-
3692
- //02. statusbar (resizebar)
3693
- if (options.height > 0) {
3694
- $('<div class="note-statusbar">' + tplStatusbar() + '</div>').prependTo($editor);
3695
- }
3696
-
3697
- //03. create Editable
3698
- var isContentEditable = !$holder.is(':disabled');
3699
- var $editable = $('<div class="note-editable" contentEditable="' + isContentEditable + '"></div>')
3700
- .prependTo($editor);
3701
- if (options.height) {
3702
- $editable.height(options.height);
3703
- }
3704
- if (options.direction) {
3705
- $editable.attr('dir', options.direction);
3706
- }
3707
-
3708
- $editable.html(dom.html($holder) || dom.emptyPara);
3709
-
3710
- //031. create codable
3711
- $('<textarea class="note-codable"></textarea>').prependTo($editor);
3712
-
3713
- var langInfo = $.summernote.lang[options.lang];
3714
-
3715
- //04. create Toolbar
3716
- var sToolbar = '';
3717
- for (var idx = 0, sz = options.toolbar.length; idx < sz; idx ++) {
3718
- var group = options.toolbar[idx];
3719
- sToolbar += '<div class="note-' + group[0] + ' btn-group">';
3720
- for (var i = 0, szGroup = group[1].length; i < szGroup; i++) {
3721
- sToolbar += tplButtonInfo[group[1][i]](langInfo, options);
3722
- }
3723
- sToolbar += '</div>';
3724
- }
3725
-
3726
- sToolbar = '<div class="note-toolbar btn-toolbar">' + sToolbar + '</div>';
3727
-
3728
- var $toolbar = $(sToolbar).prependTo($editor);
3729
- var keyMap = options.keyMap[agent.bMac ? 'mac' : 'pc'];
3730
- createPalette($toolbar, options);
3731
- createTooltip($toolbar, keyMap, 'bottom');
3732
-
3733
- //05. create Popover
3734
- var $popover = $(tplPopovers(langInfo, options)).prependTo($editor);
3735
- createPalette($popover, options);
3736
- createTooltip($popover, keyMap);
3737
-
3738
- //06. handle(control selection, ...)
3739
- $(tplHandles()).prependTo($editor);
3740
-
3741
- //07. create Dialog
3742
- var $dialog = $(tplDialogs(langInfo, options)).prependTo($editor);
3743
- $dialog.find('button.close, a.modal-close').click(function () {
3744
- $(this).closest('.modal').modal('hide');
3745
- });
3746
-
3747
- //08. create Dropzone
3748
- $('<div class="note-dropzone"><div class="note-dropzone-message"></div></div>').prependTo($editor);
3749
-
3750
- //09. Editor/Holder switch
3751
- $editor.insertAfter($holder);
3752
- $holder.hide();
3753
- };
3754
-
3755
- this.noteEditorFromHolder = function ($holder) {
3756
- if ($holder.hasClass('note-air-editor')) {
3757
- return $holder;
3758
- } else if ($holder.next().hasClass('note-editor')) {
3759
- return $holder.next();
3760
- } else {
3761
- return $();
3762
- }
3763
- };
3764
-
3765
- /**
3766
- * create summernote layout
3767
- *
3768
- * @param {jQuery} $holder
3769
- * @param {Object} options
3770
- */
3771
- this.createLayout = function ($holder, options) {
3772
- if (this.noteEditorFromHolder($holder).length > 0) {
3773
- return;
3774
- }
3775
-
3776
- if (options.airMode) {
3777
- this.createLayoutByAirMode($holder, options);
3778
- } else {
3779
- this.createLayoutByFrame($holder, options);
3780
- }
3781
- };
3782
-
3783
- /**
3784
- * returns layoutInfo from holder
3785
- *
3786
- * @param {jQuery} $holder - placeholder
3787
- * @returns {Object}
3788
- */
3789
- this.layoutInfoFromHolder = function ($holder) {
3790
- var $editor = this.noteEditorFromHolder($holder);
3791
- if (!$editor.length) { return; }
3792
-
3793
- var layoutInfo = dom.buildLayoutInfo($editor);
3794
- // cache all properties.
3795
- for (var key in layoutInfo) {
3796
- if (layoutInfo.hasOwnProperty(key)) {
3797
- layoutInfo[key] = layoutInfo[key].call();
3798
- }
3799
- }
3800
- return layoutInfo;
3801
- };
3802
-
3803
- /**
3804
- * removeLayout
3805
- *
3806
- * @param {jQuery} $holder - placeholder
3807
- */
3808
- this.removeLayout = function ($holder) {
3809
- var info = this.layoutInfoFromHolder($holder);
3810
- if (!info) { return; }
3811
- $holder.html(info.editable.html());
3812
-
3813
- info.editor.remove();
3814
- $holder.show();
3815
- };
3816
- };
3817
-
3818
- // jQuery namespace for summernote
3819
- $.summernote = $.summernote || {};
3820
-
3821
- // extends default `settings`
3822
- $.extend($.summernote, settings);
3823
-
3824
- var renderer = new Renderer();
3825
- var eventHandler = new EventHandler();
3826
-
3827
- /**
3828
- * extend jquery fn
3829
- */
3830
- $.fn.extend({
3831
- /**
3832
- * initialize summernote
3833
- * - create editor layout and attach Mouse and keyboard events.
3834
- *
3835
- * @param {Object} options
3836
- * @returns {this}
3837
- */
3838
- summernote: function (options) {
3839
- // extend default options
3840
- options = $.extend({}, $.summernote.options, options);
3841
-
3842
- this.each(function (idx, elHolder) {
3843
- var $holder = $(elHolder);
3844
-
3845
- // createLayout with options
3846
- renderer.createLayout($holder, options);
3847
-
3848
- var info = renderer.layoutInfoFromHolder($holder);
3849
- eventHandler.attach(info, options);
3850
-
3851
- // Textarea: auto filling the code before form submit.
3852
- if (dom.isTextarea($holder[0])) {
3853
- $holder.closest('form').submit(function () {
3854
- $holder.html($holder.code());
3855
- });
3856
- }
3857
- });
3858
-
3859
- // focus on first editable element
3860
- if (this.first().length && options.focus) {
3861
- var info = renderer.layoutInfoFromHolder(this.first());
3862
- info.editable.focus();
3863
- }
3864
-
3865
- // callback on init
3866
- if (this.length > 0 && options.oninit) {
3867
- options.oninit();
3868
- }
3869
-
3870
- return this;
3871
- },
3872
- //
3873
-
3874
- /**
3875
- * get the HTML contents of note or set the HTML contents of note.
3876
- *
3877
- * @param {String} [sHTML] - HTML contents(optional, set)
3878
- * @returns {this|String} - context(set) or HTML contents of note(get).
3879
- */
3880
- code: function (sHTML) {
3881
- // get the HTML contents of note
3882
- if (sHTML === undefined) {
3883
- var $holder = this.first();
3884
- if ($holder.length === 0) { return; }
3885
- var info = renderer.layoutInfoFromHolder($holder);
3886
- if (!!(info && info.editable)) {
3887
- var bCodeview = info.editor.hasClass('codeview');
3888
- if (bCodeview && agent.bCodeMirror) {
3889
- info.codable.data('cmEditor').save();
3890
- }
3891
- return bCodeview ? info.codable.val() : info.editable.html();
3892
- }
3893
- return $holder.html();
3894
- }
3895
-
3896
- // set the HTML contents of note
3897
- this.each(function (i, elHolder) {
3898
- var info = renderer.layoutInfoFromHolder($(elHolder));
3899
- if (info && info.editable) { info.editable.html(sHTML); }
3900
- });
3901
-
3902
- return this;
3903
- },
3904
-
3905
- /**
3906
- * destroy Editor Layout and dettach Key and Mouse Event
3907
- * @returns {this}
3908
- */
3909
- destroy: function () {
3910
- this.each(function (idx, elHolder) {
3911
- var $holder = $(elHolder);
3912
-
3913
- var info = renderer.layoutInfoFromHolder($holder);
3914
- if (!info || !info.editable) { return; }
3915
- eventHandler.dettach(info);
3916
- renderer.removeLayout($holder);
3917
- });
3918
-
3919
- return this;
3920
- }
3921
- });
3922
- }));