lines-engine 0.6.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (572) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +10 -3
  6. data/Gemfile +1 -0
  7. data/Gemfile.lock +10 -6
  8. data/app/assets/images/favicon.ico +0 -0
  9. data/app/assets/images/gplus.svg +17 -0
  10. data/app/assets/javascripts/lines/admin/admin.js +299 -0
  11. data/app/assets/javascripts/lines/{autosize.min.js → admin/autosize.min.js} +0 -0
  12. data/app/assets/javascripts/lines/admin/navbar.js +51 -0
  13. data/app/assets/javascripts/lines/{pictures.js.coffee → admin/pictures.js.coffee} +2 -1
  14. data/app/assets/javascripts/lines/application.js +3 -0
  15. data/app/assets/javascripts/lines/articles.js.coffee +1 -0
  16. data/app/assets/javascripts/lines/viewer.js.coffee +3 -0
  17. data/app/assets/stylesheets/lines/admin/admin.scss +609 -0
  18. data/app/assets/stylesheets/lines/admin/variables_and_mixins.scss +36 -0
  19. data/app/assets/stylesheets/lines/application.scss +2 -13
  20. data/app/assets/stylesheets/lines/article.scss +165 -69
  21. data/app/assets/stylesheets/lines/fonts.scss +2 -2
  22. data/app/assets/stylesheets/lines/footer.scss +10 -56
  23. data/app/assets/stylesheets/lines/general.scss +18 -13
  24. data/app/assets/stylesheets/lines/media_queries.scss +5 -1
  25. data/app/assets/stylesheets/lines/messages.scss +28 -0
  26. data/app/assets/stylesheets/lines/navbar.scss +199 -122
  27. data/app/assets/stylesheets/lines/pagination.scss +8 -31
  28. data/app/assets/stylesheets/lines/pygments.css.erb +1 -2
  29. data/app/assets/stylesheets/lines/variables_and_mixins.scss +4 -0
  30. data/app/controllers/lines/admin/articles_controller.rb +8 -6
  31. data/app/controllers/lines/admin/authors_controller.rb +2 -2
  32. data/app/controllers/lines/admin/pictures_controller.rb +1 -1
  33. data/app/controllers/lines/application_controller.rb +1 -1
  34. data/app/controllers/lines/articles_controller.rb +3 -1
  35. data/app/controllers/lines/password_resets_controller.rb +4 -7
  36. data/app/controllers/lines/sessions_controller.rb +3 -3
  37. data/app/helpers/lines/application_helper.rb +25 -4
  38. data/app/mailers/lines/user_mailer.rb +1 -1
  39. data/app/models/lines/article.rb +13 -3
  40. data/app/models/lines/user.rb +2 -2
  41. data/app/uploaders/picture_uploader.rb +1 -1
  42. data/app/views/layouts/lines/_markdown_cheatsheet.html.erb +72 -0
  43. data/app/views/layouts/lines/admin.html.erb +15 -4
  44. data/app/views/layouts/lines/application.html.erb +16 -4
  45. data/app/views/layouts/lines/preview.html.erb +30 -2
  46. data/app/views/lines/admin/articles/_form.html.erb +50 -148
  47. data/app/views/lines/admin/articles/_picture_box.html.erb +37 -8
  48. data/app/views/lines/admin/articles/edit.html.erb +2 -12
  49. data/app/views/lines/admin/articles/index.html.erb +40 -28
  50. data/app/views/lines/admin/articles/new.html.erb +3 -10
  51. data/app/views/lines/admin/articles/show.html.erb +6 -4
  52. data/app/views/lines/admin/authors/_form.html.erb +12 -41
  53. data/app/views/lines/admin/authors/index.html.erb +18 -13
  54. data/app/views/lines/admin/authors/show.html.erb +19 -48
  55. data/app/views/lines/admin/pictures/_picture.html.erb +5 -4
  56. data/app/views/lines/admin/pictures/create.js.erb +1 -1
  57. data/app/views/lines/admin/pictures/destroy.js.erb +1 -1
  58. data/app/views/lines/articles/_article.html.erb +10 -6
  59. data/app/views/lines/articles/_article_collection.html.erb +1 -1
  60. data/app/views/lines/articles/_article_small.html.erb +9 -7
  61. data/app/views/lines/articles/index.atom.builder +10 -9
  62. data/app/views/lines/articles/index.html.erb +2 -2
  63. data/app/views/lines/articles/show.html.erb +5 -1
  64. data/app/views/lines/password_resets/edit.html.erb +25 -12
  65. data/app/views/lines/password_resets/new.html.erb +14 -8
  66. data/app/views/lines/sessions/new.html.erb +6 -10
  67. data/app/views/lines/shared/_flash.html.erb +1 -1
  68. data/app/views/lines/shared/_footer.html.erb +5 -28
  69. data/app/views/lines/user_mailer/password_reset.html.erb +6 -5
  70. data/app/views/lines/user_mailer/password_reset.text.erb +8 -4
  71. data/config/lines_config.yml +15 -14
  72. data/config/routes.rb +2 -2
  73. data/db/seeds.rb +5 -5
  74. data/lib/lines/engine.rb +1 -1
  75. data/lib/lines/version.rb +1 -1
  76. data/lines.gemspec +1 -1
  77. data/public/codemirror/.gitattributes +8 -0
  78. data/public/codemirror/.gitignore +8 -0
  79. data/public/codemirror/.npmignore +9 -0
  80. data/public/codemirror/.travis.yml +4 -0
  81. data/public/codemirror/AUTHORS +474 -0
  82. data/public/codemirror/CONTRIBUTING.md +88 -0
  83. data/public/codemirror/LICENSE +19 -0
  84. data/public/codemirror/README.md +27 -0
  85. data/public/codemirror/addon/comment/comment.js +183 -0
  86. data/public/codemirror/addon/comment/continuecomment.js +85 -0
  87. data/public/codemirror/addon/dialog/dialog.css +32 -0
  88. data/public/codemirror/addon/dialog/dialog.js +157 -0
  89. data/public/codemirror/addon/display/fullscreen.css +6 -0
  90. data/public/codemirror/addon/display/fullscreen.js +41 -0
  91. data/public/codemirror/addon/display/panel.js +112 -0
  92. data/public/codemirror/addon/display/placeholder.js +58 -0
  93. data/public/codemirror/addon/display/rulers.js +63 -0
  94. data/public/codemirror/addon/edit/closebrackets.js +185 -0
  95. data/public/codemirror/addon/edit/closetag.js +166 -0
  96. data/public/codemirror/addon/edit/continuelist.js +51 -0
  97. data/public/codemirror/addon/edit/matchbrackets.js +120 -0
  98. data/public/codemirror/addon/edit/matchtags.js +66 -0
  99. data/public/codemirror/addon/edit/trailingspace.js +27 -0
  100. data/public/codemirror/addon/fold/brace-fold.js +105 -0
  101. data/public/codemirror/addon/fold/comment-fold.js +57 -0
  102. data/public/codemirror/addon/fold/foldcode.js +149 -0
  103. data/public/codemirror/addon/fold/foldgutter.css +20 -0
  104. data/public/codemirror/addon/fold/foldgutter.js +146 -0
  105. data/public/codemirror/addon/fold/indent-fold.js +44 -0
  106. data/public/codemirror/addon/fold/markdown-fold.js +49 -0
  107. data/public/codemirror/addon/fold/xml-fold.js +182 -0
  108. data/public/codemirror/addon/hint/anyword-hint.js +41 -0
  109. data/public/codemirror/addon/hint/css-hint.js +60 -0
  110. data/public/codemirror/addon/hint/html-hint.js +348 -0
  111. data/public/codemirror/addon/hint/javascript-hint.js +146 -0
  112. data/public/codemirror/addon/hint/show-hint.css +38 -0
  113. data/public/codemirror/addon/hint/show-hint.js +386 -0
  114. data/public/codemirror/addon/hint/sql-hint.js +254 -0
  115. data/public/codemirror/addon/hint/xml-hint.js +110 -0
  116. data/public/codemirror/addon/lint/coffeescript-lint.js +41 -0
  117. data/public/codemirror/addon/lint/css-lint.js +35 -0
  118. data/public/codemirror/addon/lint/javascript-lint.js +136 -0
  119. data/public/codemirror/addon/lint/json-lint.js +31 -0
  120. data/public/codemirror/addon/lint/lint.css +73 -0
  121. data/public/codemirror/addon/lint/lint.js +207 -0
  122. data/public/codemirror/addon/lint/yaml-lint.js +28 -0
  123. data/public/codemirror/addon/merge/merge.css +112 -0
  124. data/public/codemirror/addon/merge/merge.js +775 -0
  125. data/public/codemirror/addon/mode/loadmode.js +64 -0
  126. data/public/codemirror/addon/mode/multiplex.js +123 -0
  127. data/public/codemirror/addon/mode/multiplex_test.js +33 -0
  128. data/public/codemirror/addon/mode/overlay.js +85 -0
  129. data/public/codemirror/addon/mode/simple.js +213 -0
  130. data/public/codemirror/addon/runmode/colorize.js +40 -0
  131. data/public/codemirror/addon/runmode/runmode-standalone.js +157 -0
  132. data/public/codemirror/addon/runmode/runmode.js +72 -0
  133. data/public/codemirror/addon/runmode/runmode.node.js +178 -0
  134. data/public/codemirror/addon/scroll/annotatescrollbar.js +115 -0
  135. data/public/codemirror/addon/scroll/scrollpastend.js +46 -0
  136. data/public/codemirror/addon/scroll/simplescrollbars.css +66 -0
  137. data/public/codemirror/addon/scroll/simplescrollbars.js +147 -0
  138. data/public/codemirror/addon/search/match-highlighter.js +128 -0
  139. data/public/codemirror/addon/search/matchesonscrollbar.css +8 -0
  140. data/public/codemirror/addon/search/matchesonscrollbar.js +97 -0
  141. data/public/codemirror/addon/search/search.js +202 -0
  142. data/public/codemirror/addon/search/searchcursor.js +189 -0
  143. data/public/codemirror/addon/selection/active-line.js +71 -0
  144. data/public/codemirror/addon/selection/mark-selection.js +118 -0
  145. data/public/codemirror/addon/selection/selection-pointer.js +98 -0
  146. data/public/codemirror/addon/tern/tern.css +87 -0
  147. data/public/codemirror/addon/tern/tern.js +699 -0
  148. data/public/codemirror/addon/tern/worker.js +44 -0
  149. data/public/codemirror/addon/wrap/hardwrap.js +139 -0
  150. data/public/codemirror/bin/authors.sh +6 -0
  151. data/public/codemirror/bin/compress +92 -0
  152. data/public/codemirror/bin/lint +3 -0
  153. data/public/codemirror/bin/release +45 -0
  154. data/public/codemirror/bin/source-highlight +51 -0
  155. data/public/codemirror/bower.json +17 -0
  156. data/public/codemirror/demo/activeline.html +78 -0
  157. data/public/codemirror/demo/anywordhint.html +79 -0
  158. data/public/codemirror/demo/bidi.html +74 -0
  159. data/public/codemirror/demo/btree.html +85 -0
  160. data/public/codemirror/demo/buffers.html +109 -0
  161. data/public/codemirror/demo/changemode.html +58 -0
  162. data/public/codemirror/demo/closebrackets.html +52 -0
  163. data/public/codemirror/demo/closetag.html +41 -0
  164. data/public/codemirror/demo/complete.html +79 -0
  165. data/public/codemirror/demo/emacs.html +75 -0
  166. data/public/codemirror/demo/folding.html +95 -0
  167. data/public/codemirror/demo/fullscreen.html +83 -0
  168. data/public/codemirror/demo/hardwrap.html +72 -0
  169. data/public/codemirror/demo/html5complete.html +56 -0
  170. data/public/codemirror/demo/indentwrap.html +59 -0
  171. data/public/codemirror/demo/lint.html +171 -0
  172. data/public/codemirror/demo/loadmode.html +72 -0
  173. data/public/codemirror/demo/marker.html +52 -0
  174. data/public/codemirror/demo/markselection.html +52 -0
  175. data/public/codemirror/demo/matchhighlighter.html +47 -0
  176. data/public/codemirror/demo/matchtags.html +48 -0
  177. data/public/codemirror/demo/merge.html +122 -0
  178. data/public/codemirror/demo/multiplex.html +75 -0
  179. data/public/codemirror/demo/mustache.html +69 -0
  180. data/public/codemirror/demo/panel.html +136 -0
  181. data/public/codemirror/demo/placeholder.html +45 -0
  182. data/public/codemirror/demo/preview.html +87 -0
  183. data/public/codemirror/demo/requirejs.html +70 -0
  184. data/public/codemirror/demo/resize.html +51 -0
  185. data/public/codemirror/demo/rulers.html +49 -0
  186. data/public/codemirror/demo/runmode.html +62 -0
  187. data/public/codemirror/demo/search.html +95 -0
  188. data/public/codemirror/demo/simplemode.html +186 -0
  189. data/public/codemirror/demo/simplescrollbars.html +82 -0
  190. data/public/codemirror/demo/spanaffectswrapping_shim.html +85 -0
  191. data/public/codemirror/demo/sublime.html +76 -0
  192. data/public/codemirror/demo/tern.html +133 -0
  193. data/public/codemirror/demo/theme.html +152 -0
  194. data/public/codemirror/demo/trailingspace.html +48 -0
  195. data/public/codemirror/demo/variableheight.html +67 -0
  196. data/public/codemirror/demo/vim.html +104 -0
  197. data/public/codemirror/demo/visibletabs.html +62 -0
  198. data/public/codemirror/demo/widget.html +85 -0
  199. data/public/codemirror/demo/xmlcomplete.html +119 -0
  200. data/public/codemirror/doc/activebookmark.js +57 -0
  201. data/public/codemirror/doc/compress.html +329 -0
  202. data/public/codemirror/doc/docs.css +271 -0
  203. data/public/codemirror/doc/internals.html +503 -0
  204. data/public/codemirror/doc/logo.png +0 -0
  205. data/public/codemirror/doc/logo.svg +181 -0
  206. data/public/codemirror/doc/manual.html +3327 -0
  207. data/public/codemirror/doc/realworld.html +174 -0
  208. data/public/codemirror/doc/releases.html +1116 -0
  209. data/public/codemirror/doc/reporting.html +61 -0
  210. data/public/codemirror/doc/upgrade_v2.2.html +96 -0
  211. data/public/codemirror/doc/upgrade_v3.html +230 -0
  212. data/public/codemirror/doc/upgrade_v4.html +144 -0
  213. data/public/codemirror/doc/yinyang.png +0 -0
  214. data/public/codemirror/index.html +199 -0
  215. data/public/codemirror/keymap/emacs.js +412 -0
  216. data/public/codemirror/keymap/sublime.js +555 -0
  217. data/public/codemirror/keymap/vim.js +5060 -0
  218. data/public/codemirror/lib/codemirror.css +332 -0
  219. data/public/codemirror/lib/codemirror.js +8788 -0
  220. data/public/codemirror/mode/apl/apl.js +174 -0
  221. data/public/codemirror/mode/apl/index.html +72 -0
  222. data/public/codemirror/mode/asciiarmor/asciiarmor.js +73 -0
  223. data/public/codemirror/mode/asciiarmor/index.html +46 -0
  224. data/public/codemirror/mode/asn.1/asn.1.js +204 -0
  225. data/public/codemirror/mode/asn.1/index.html +78 -0
  226. data/public/codemirror/mode/asterisk/asterisk.js +196 -0
  227. data/public/codemirror/mode/asterisk/index.html +154 -0
  228. data/public/codemirror/mode/brainfuck/brainfuck.js +85 -0
  229. data/public/codemirror/mode/brainfuck/index.html +85 -0
  230. data/public/codemirror/mode/clike/clike.js +604 -0
  231. data/public/codemirror/mode/clike/index.html +252 -0
  232. data/public/codemirror/mode/clike/scala.html +767 -0
  233. data/public/codemirror/mode/clike/test.js +33 -0
  234. data/public/codemirror/mode/clojure/clojure.js +244 -0
  235. data/public/codemirror/mode/clojure/index.html +88 -0
  236. data/public/codemirror/mode/cmake/cmake.js +97 -0
  237. data/public/codemirror/mode/cmake/index.html +129 -0
  238. data/public/codemirror/mode/cobol/cobol.js +255 -0
  239. data/public/codemirror/mode/cobol/index.html +210 -0
  240. data/public/codemirror/mode/coffeescript/coffeescript.js +369 -0
  241. data/public/codemirror/mode/coffeescript/index.html +740 -0
  242. data/public/codemirror/mode/commonlisp/commonlisp.js +123 -0
  243. data/public/codemirror/mode/commonlisp/index.html +177 -0
  244. data/public/codemirror/mode/css/css.js +756 -0
  245. data/public/codemirror/mode/css/index.html +75 -0
  246. data/public/codemirror/mode/css/less.html +152 -0
  247. data/public/codemirror/mode/css/less_test.js +54 -0
  248. data/public/codemirror/mode/css/scss.html +157 -0
  249. data/public/codemirror/mode/css/scss_test.js +110 -0
  250. data/public/codemirror/mode/css/test.js +188 -0
  251. data/public/codemirror/mode/cypher/cypher.js +146 -0
  252. data/public/codemirror/mode/cypher/index.html +63 -0
  253. data/public/codemirror/mode/d/d.js +218 -0
  254. data/public/codemirror/mode/d/index.html +273 -0
  255. data/public/codemirror/mode/dart/dart.js +50 -0
  256. data/public/codemirror/mode/dart/index.html +71 -0
  257. data/public/codemirror/mode/diff/diff.js +47 -0
  258. data/public/codemirror/mode/diff/index.html +117 -0
  259. data/public/codemirror/mode/django/django.js +350 -0
  260. data/public/codemirror/mode/django/index.html +73 -0
  261. data/public/codemirror/mode/dockerfile/dockerfile.js +76 -0
  262. data/public/codemirror/mode/dockerfile/index.html +73 -0
  263. data/public/codemirror/mode/dtd/dtd.js +142 -0
  264. data/public/codemirror/mode/dtd/index.html +89 -0
  265. data/public/codemirror/mode/dylan/dylan.js +291 -0
  266. data/public/codemirror/mode/dylan/index.html +407 -0
  267. data/public/codemirror/mode/ebnf/ebnf.js +195 -0
  268. data/public/codemirror/mode/ebnf/index.html +102 -0
  269. data/public/codemirror/mode/ecl/ecl.js +206 -0
  270. data/public/codemirror/mode/ecl/index.html +52 -0
  271. data/public/codemirror/mode/eiffel/eiffel.js +160 -0
  272. data/public/codemirror/mode/eiffel/index.html +429 -0
  273. data/public/codemirror/mode/elm/elm.js +205 -0
  274. data/public/codemirror/mode/elm/index.html +61 -0
  275. data/public/codemirror/mode/erlang/erlang.js +618 -0
  276. data/public/codemirror/mode/erlang/index.html +76 -0
  277. data/public/codemirror/mode/factor/factor.js +83 -0
  278. data/public/codemirror/mode/factor/index.html +77 -0
  279. data/public/codemirror/mode/forth/forth.js +180 -0
  280. data/public/codemirror/mode/forth/index.html +75 -0
  281. data/public/codemirror/mode/fortran/fortran.js +188 -0
  282. data/public/codemirror/mode/fortran/index.html +81 -0
  283. data/public/codemirror/mode/gas/gas.js +345 -0
  284. data/public/codemirror/mode/gas/index.html +68 -0
  285. data/public/codemirror/mode/gfm/gfm.js +124 -0
  286. data/public/codemirror/mode/gfm/index.html +93 -0
  287. data/public/codemirror/mode/gfm/test.js +213 -0
  288. data/public/codemirror/mode/gherkin/gherkin.js +178 -0
  289. data/public/codemirror/mode/gherkin/index.html +48 -0
  290. data/public/codemirror/mode/go/go.js +185 -0
  291. data/public/codemirror/mode/go/index.html +85 -0
  292. data/public/codemirror/mode/groovy/groovy.js +230 -0
  293. data/public/codemirror/mode/groovy/index.html +84 -0
  294. data/public/codemirror/mode/haml/haml.js +159 -0
  295. data/public/codemirror/mode/haml/index.html +79 -0
  296. data/public/codemirror/mode/haml/test.js +97 -0
  297. data/public/codemirror/mode/handlebars/handlebars.js +53 -0
  298. data/public/codemirror/mode/handlebars/index.html +83 -0
  299. data/public/codemirror/mode/haskell/haskell.js +267 -0
  300. data/public/codemirror/mode/haskell/index.html +73 -0
  301. data/public/codemirror/mode/haxe/haxe.js +518 -0
  302. data/public/codemirror/mode/haxe/index.html +124 -0
  303. data/public/codemirror/mode/htmlembedded/htmlembedded.js +28 -0
  304. data/public/codemirror/mode/htmlembedded/index.html +59 -0
  305. data/public/codemirror/mode/htmlmixed/htmlmixed.js +121 -0
  306. data/public/codemirror/mode/htmlmixed/index.html +89 -0
  307. data/public/codemirror/mode/http/http.js +113 -0
  308. data/public/codemirror/mode/http/index.html +45 -0
  309. data/public/codemirror/mode/idl/idl.js +290 -0
  310. data/public/codemirror/mode/idl/index.html +64 -0
  311. data/public/codemirror/mode/index.html +149 -0
  312. data/public/codemirror/mode/jade/index.html +70 -0
  313. data/public/codemirror/mode/jade/jade.js +590 -0
  314. data/public/codemirror/mode/javascript/index.html +114 -0
  315. data/public/codemirror/mode/javascript/javascript.js +704 -0
  316. data/public/codemirror/mode/javascript/json-ld.html +72 -0
  317. data/public/codemirror/mode/javascript/test.js +205 -0
  318. data/public/codemirror/mode/javascript/typescript.html +61 -0
  319. data/public/codemirror/mode/jinja2/index.html +54 -0
  320. data/public/codemirror/mode/jinja2/jinja2.js +142 -0
  321. data/public/codemirror/mode/julia/index.html +195 -0
  322. data/public/codemirror/mode/julia/julia.js +299 -0
  323. data/public/codemirror/mode/kotlin/index.html +89 -0
  324. data/public/codemirror/mode/kotlin/kotlin.js +284 -0
  325. data/public/codemirror/mode/livescript/index.html +459 -0
  326. data/public/codemirror/mode/livescript/livescript.js +280 -0
  327. data/public/codemirror/mode/lua/index.html +85 -0
  328. data/public/codemirror/mode/lua/lua.js +159 -0
  329. data/public/codemirror/mode/markdown/index.html +359 -0
  330. data/public/codemirror/mode/markdown/markdown.js +781 -0
  331. data/public/codemirror/mode/markdown/test.js +792 -0
  332. data/public/codemirror/mode/mathematica/index.html +72 -0
  333. data/public/codemirror/mode/mathematica/mathematica.js +175 -0
  334. data/public/codemirror/mode/meta.js +190 -0
  335. data/public/codemirror/mode/mirc/index.html +160 -0
  336. data/public/codemirror/mode/mirc/mirc.js +193 -0
  337. data/public/codemirror/mode/mllike/index.html +179 -0
  338. data/public/codemirror/mode/mllike/mllike.js +205 -0
  339. data/public/codemirror/mode/modelica/index.html +67 -0
  340. data/public/codemirror/mode/modelica/modelica.js +245 -0
  341. data/public/codemirror/mode/mumps/index.html +85 -0
  342. data/public/codemirror/mode/mumps/mumps.js +148 -0
  343. data/public/codemirror/mode/nginx/index.html +181 -0
  344. data/public/codemirror/mode/nginx/nginx.js +178 -0
  345. data/public/codemirror/mode/ntriples/index.html +45 -0
  346. data/public/codemirror/mode/ntriples/ntriples.js +186 -0
  347. data/public/codemirror/mode/octave/index.html +83 -0
  348. data/public/codemirror/mode/octave/octave.js +135 -0
  349. data/public/codemirror/mode/pascal/index.html +61 -0
  350. data/public/codemirror/mode/pascal/pascal.js +109 -0
  351. data/public/codemirror/mode/pegjs/index.html +66 -0
  352. data/public/codemirror/mode/pegjs/pegjs.js +114 -0
  353. data/public/codemirror/mode/perl/index.html +75 -0
  354. data/public/codemirror/mode/perl/perl.js +837 -0
  355. data/public/codemirror/mode/php/index.html +64 -0
  356. data/public/codemirror/mode/php/php.js +230 -0
  357. data/public/codemirror/mode/php/test.js +154 -0
  358. data/public/codemirror/mode/pig/index.html +55 -0
  359. data/public/codemirror/mode/pig/pig.js +178 -0
  360. data/public/codemirror/mode/properties/index.html +53 -0
  361. data/public/codemirror/mode/properties/properties.js +78 -0
  362. data/public/codemirror/mode/puppet/index.html +121 -0
  363. data/public/codemirror/mode/puppet/puppet.js +220 -0
  364. data/public/codemirror/mode/python/index.html +198 -0
  365. data/public/codemirror/mode/python/python.js +358 -0
  366. data/public/codemirror/mode/q/index.html +144 -0
  367. data/public/codemirror/mode/q/q.js +139 -0
  368. data/public/codemirror/mode/r/index.html +85 -0
  369. data/public/codemirror/mode/r/r.js +162 -0
  370. data/public/codemirror/mode/rpm/changes/index.html +66 -0
  371. data/public/codemirror/mode/rpm/index.html +149 -0
  372. data/public/codemirror/mode/rpm/rpm.js +101 -0
  373. data/public/codemirror/mode/rst/index.html +535 -0
  374. data/public/codemirror/mode/rst/rst.js +557 -0
  375. data/public/codemirror/mode/ruby/index.html +183 -0
  376. data/public/codemirror/mode/ruby/ruby.js +285 -0
  377. data/public/codemirror/mode/ruby/test.js +14 -0
  378. data/public/codemirror/mode/rust/index.html +60 -0
  379. data/public/codemirror/mode/rust/rust.js +451 -0
  380. data/public/codemirror/mode/sass/index.html +66 -0
  381. data/public/codemirror/mode/sass/sass.js +414 -0
  382. data/public/codemirror/mode/scheme/index.html +77 -0
  383. data/public/codemirror/mode/scheme/scheme.js +249 -0
  384. data/public/codemirror/mode/shell/index.html +66 -0
  385. data/public/codemirror/mode/shell/shell.js +139 -0
  386. data/public/codemirror/mode/shell/test.js +58 -0
  387. data/public/codemirror/mode/sieve/index.html +93 -0
  388. data/public/codemirror/mode/sieve/sieve.js +193 -0
  389. data/public/codemirror/mode/slim/index.html +96 -0
  390. data/public/codemirror/mode/slim/slim.js +575 -0
  391. data/public/codemirror/mode/slim/test.js +96 -0
  392. data/public/codemirror/mode/smalltalk/index.html +68 -0
  393. data/public/codemirror/mode/smalltalk/smalltalk.js +168 -0
  394. data/public/codemirror/mode/smarty/index.html +138 -0
  395. data/public/codemirror/mode/smarty/smarty.js +225 -0
  396. data/public/codemirror/mode/solr/index.html +57 -0
  397. data/public/codemirror/mode/solr/solr.js +104 -0
  398. data/public/codemirror/mode/soy/index.html +68 -0
  399. data/public/codemirror/mode/soy/soy.js +198 -0
  400. data/public/codemirror/mode/sparql/index.html +61 -0
  401. data/public/codemirror/mode/sparql/sparql.js +174 -0
  402. data/public/codemirror/mode/spreadsheet/index.html +42 -0
  403. data/public/codemirror/mode/spreadsheet/spreadsheet.js +109 -0
  404. data/public/codemirror/mode/sql/index.html +84 -0
  405. data/public/codemirror/mode/sql/sql.js +391 -0
  406. data/public/codemirror/mode/stex/index.html +110 -0
  407. data/public/codemirror/mode/stex/stex.js +251 -0
  408. data/public/codemirror/mode/stex/test.js +123 -0
  409. data/public/codemirror/mode/stylus/index.html +106 -0
  410. data/public/codemirror/mode/stylus/stylus.js +768 -0
  411. data/public/codemirror/mode/swift/index.html +88 -0
  412. data/public/codemirror/mode/swift/swift.js +203 -0
  413. data/public/codemirror/mode/tcl/index.html +142 -0
  414. data/public/codemirror/mode/tcl/tcl.js +147 -0
  415. data/public/codemirror/mode/textile/index.html +191 -0
  416. data/public/codemirror/mode/textile/test.js +417 -0
  417. data/public/codemirror/mode/textile/textile.js +469 -0
  418. data/public/codemirror/mode/tiddlywiki/index.html +154 -0
  419. data/public/codemirror/mode/tiddlywiki/tiddlywiki.css +14 -0
  420. data/public/codemirror/mode/tiddlywiki/tiddlywiki.js +358 -0
  421. data/public/codemirror/mode/tiki/index.html +95 -0
  422. data/public/codemirror/mode/tiki/tiki.css +26 -0
  423. data/public/codemirror/mode/tiki/tiki.js +312 -0
  424. data/public/codemirror/mode/toml/index.html +73 -0
  425. data/public/codemirror/mode/toml/toml.js +88 -0
  426. data/public/codemirror/mode/tornado/index.html +63 -0
  427. data/public/codemirror/mode/tornado/tornado.js +68 -0
  428. data/public/codemirror/mode/troff/index.html +146 -0
  429. data/public/codemirror/mode/troff/troff.js +82 -0
  430. data/public/codemirror/mode/ttcn-cfg/index.html +115 -0
  431. data/public/codemirror/mode/ttcn-cfg/ttcn-cfg.js +214 -0
  432. data/public/codemirror/mode/ttcn/index.html +118 -0
  433. data/public/codemirror/mode/ttcn/ttcn.js +283 -0
  434. data/public/codemirror/mode/turtle/index.html +50 -0
  435. data/public/codemirror/mode/turtle/turtle.js +162 -0
  436. data/public/codemirror/mode/twig/index.html +45 -0
  437. data/public/codemirror/mode/twig/twig.js +132 -0
  438. data/public/codemirror/mode/vb/index.html +102 -0
  439. data/public/codemirror/mode/vb/vb.js +276 -0
  440. data/public/codemirror/mode/vbscript/index.html +55 -0
  441. data/public/codemirror/mode/vbscript/vbscript.js +350 -0
  442. data/public/codemirror/mode/velocity/index.html +118 -0
  443. data/public/codemirror/mode/velocity/velocity.js +201 -0
  444. data/public/codemirror/mode/verilog/index.html +120 -0
  445. data/public/codemirror/mode/verilog/test.js +273 -0
  446. data/public/codemirror/mode/verilog/verilog.js +537 -0
  447. data/public/codemirror/mode/vhdl/index.html +95 -0
  448. data/public/codemirror/mode/vhdl/vhdl.js +189 -0
  449. data/public/codemirror/mode/xml/index.html +57 -0
  450. data/public/codemirror/mode/xml/test.js +51 -0
  451. data/public/codemirror/mode/xml/xml.js +385 -0
  452. data/public/codemirror/mode/xquery/index.html +210 -0
  453. data/public/codemirror/mode/xquery/test.js +67 -0
  454. data/public/codemirror/mode/xquery/xquery.js +437 -0
  455. data/public/codemirror/mode/yaml/index.html +80 -0
  456. data/public/codemirror/mode/yaml/yaml.js +117 -0
  457. data/public/codemirror/mode/z80/index.html +53 -0
  458. data/public/codemirror/mode/z80/z80.js +116 -0
  459. data/public/codemirror/package.json +20 -0
  460. data/public/codemirror/test/comment_test.js +100 -0
  461. data/public/codemirror/test/doc_test.js +371 -0
  462. data/public/codemirror/test/driver.js +138 -0
  463. data/public/codemirror/test/emacs_test.js +147 -0
  464. data/public/codemirror/test/index.html +241 -0
  465. data/public/codemirror/test/lint.js +11 -0
  466. data/public/codemirror/test/mode_test.css +23 -0
  467. data/public/codemirror/test/mode_test.js +192 -0
  468. data/public/codemirror/test/multi_test.js +285 -0
  469. data/public/codemirror/test/phantom_driver.js +31 -0
  470. data/public/codemirror/test/run.js +31 -0
  471. data/public/codemirror/test/scroll_test.js +115 -0
  472. data/public/codemirror/test/search_test.js +62 -0
  473. data/public/codemirror/test/sql-hint-test.js +189 -0
  474. data/public/codemirror/test/sublime_test.js +303 -0
  475. data/public/codemirror/test/test.js +2142 -0
  476. data/public/codemirror/test/vim_test.js +3955 -0
  477. data/public/codemirror/theme/3024-day.css +41 -0
  478. data/public/codemirror/theme/3024-night.css +39 -0
  479. data/public/codemirror/theme/ambiance-mobile.css +5 -0
  480. data/public/codemirror/theme/ambiance.css +76 -0
  481. data/public/codemirror/theme/base16-dark.css +38 -0
  482. data/public/codemirror/theme/base16-light.css +38 -0
  483. data/public/codemirror/theme/blackboard.css +32 -0
  484. data/public/codemirror/theme/cobalt.css +25 -0
  485. data/public/codemirror/theme/colorforth.css +33 -0
  486. data/public/codemirror/theme/dracula.css +87 -0
  487. data/public/codemirror/theme/eclipse.css +23 -0
  488. data/public/codemirror/theme/elegant.css +13 -0
  489. data/public/codemirror/theme/erlang-dark.css +34 -0
  490. data/public/codemirror/theme/icecoder.css +42 -0
  491. data/public/codemirror/theme/lesser-dark.css +47 -0
  492. data/public/codemirror/theme/lines.css +109 -0
  493. data/public/codemirror/theme/liquibyte.css +95 -0
  494. data/public/codemirror/theme/material.css +105 -0
  495. data/public/codemirror/theme/mbo.css +37 -0
  496. data/public/codemirror/theme/mdn-like.css +46 -0
  497. data/public/codemirror/theme/midnight.css +47 -0
  498. data/public/codemirror/theme/monokai.css +35 -0
  499. data/public/codemirror/theme/neat.css +12 -0
  500. data/public/codemirror/theme/neo.css +43 -0
  501. data/public/codemirror/theme/night.css +28 -0
  502. data/public/codemirror/theme/paraiso-dark.css +38 -0
  503. data/public/codemirror/theme/paraiso-light.css +38 -0
  504. data/public/codemirror/theme/pastel-on-dark.css +53 -0
  505. data/public/codemirror/theme/rubyblue.css +25 -0
  506. data/public/codemirror/theme/seti.css +88 -0
  507. data/public/codemirror/theme/solarized.css +165 -0
  508. data/public/codemirror/theme/the-matrix.css +30 -0
  509. data/public/codemirror/theme/tomorrow-night-bright.css +35 -0
  510. data/public/codemirror/theme/tomorrow-night-eighties.css +38 -0
  511. data/public/codemirror/theme/ttcn.css +65 -0
  512. data/public/codemirror/theme/twilight.css +32 -0
  513. data/public/codemirror/theme/vibrant-ink.css +34 -0
  514. data/public/codemirror/theme/xq-dark.css +53 -0
  515. data/public/codemirror/theme/xq-light.css +43 -0
  516. data/public/codemirror/theme/yeti.css +86 -0
  517. data/public/codemirror/theme/zenburn.css +37 -0
  518. data/public/fira-mono/FiraMono-Bold.eot +0 -0
  519. data/public/fira-mono/FiraMono-Bold.otf +0 -0
  520. data/public/fira-mono/FiraMono-Bold.ttf +0 -0
  521. data/public/fira-mono/FiraMono-Bold.woff +0 -0
  522. data/public/fira-mono/FiraMono-Medium.eot +0 -0
  523. data/public/fira-mono/FiraMono-Medium.otf +0 -0
  524. data/public/fira-mono/FiraMono-Medium.ttf +0 -0
  525. data/public/fira-mono/FiraMono-Medium.woff +0 -0
  526. data/public/fira-mono/FiraMono-Regular.eot +0 -0
  527. data/public/fira-mono/FiraMono-Regular.otf +0 -0
  528. data/public/fira-mono/FiraMono-Regular.ttf +0 -0
  529. data/public/fira-mono/FiraMono-Regular.woff +0 -0
  530. data/public/fira-mono/fira-mono.css +32 -0
  531. data/public/heroes/lines_default_01.png +0 -0
  532. data/public/heroes/lines_default_02.png +0 -0
  533. data/public/heroes/lines_default_03.png +0 -0
  534. data/public/iconfont/iconfont.css +48 -0
  535. data/public/iconfont/iconfont.eot +0 -0
  536. data/public/iconfont/iconfont.svg +18 -0
  537. data/public/iconfont/iconfont.ttf +0 -0
  538. data/public/iconfont/iconfont.woff +0 -0
  539. data/spec/dummy/config/environments/test.rb +3 -1
  540. data/spec/dummy/db/migrate/20140505122014_base_migration.rb +84 -0
  541. data/spec/dummy/db/migrate/20140702160602_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb +31 -0
  542. data/spec/dummy/db/migrate/20140702160603_add_missing_unique_indices.acts_as_taggable_on_engine.rb +20 -0
  543. data/spec/dummy/db/migrate/20140702160604_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb +15 -0
  544. data/spec/dummy/db/migrate/20141027143656_add_teaser_to_article.rb +5 -0
  545. data/spec/dummy/db/migrate/20150421093311_add_reset_password_fields_to_users.rb +6 -0
  546. data/spec/dummy/db/schema.rb +50 -50
  547. data/spec/dummy/db/seeds.rb +5 -5
  548. data/spec/factories/users.rb +1 -1
  549. data/spec/features/article_spec.rb +4 -4
  550. data/spec/features/password_reset_spec.rb +17 -17
  551. data/spec/features/user_logs_in_spec.rb +6 -8
  552. data/spec/mailers/lines/user_mailer_spec.rb +1 -1
  553. data/spec/models/article_spec.rb +6 -6
  554. data/spec/support/auth_macros.rb +2 -2
  555. metadata +492 -26
  556. metadata.gz.sig +0 -0
  557. data/app/assets/images/ic_gplus.png +0 -0
  558. data/app/assets/images/ic_gplus_hover.png +0 -0
  559. data/app/assets/images/logo.png +0 -0
  560. data/app/assets/images/logo_opoloo.png +0 -0
  561. data/app/assets/images/signet.png +0 -0
  562. data/app/assets/javascripts/lines/admin.js +0 -201
  563. data/app/assets/stylesheets/lines/admin.scss +0 -970
  564. data/app/views/layouts/lines/_messages.html.erb +0 -8
  565. data/app/views/lines/admin/articles/_formatting_guide.html.erb +0 -89
  566. data/public/heroes/001.jpg +0 -0
  567. data/public/heroes/001_dark.jpg +0 -0
  568. data/public/heroes/002.jpg +0 -0
  569. data/public/heroes/002_dark.jpg +0 -0
  570. data/public/heroes/003.jpg +0 -0
  571. data/public/heroes/003_dark.jpg +0 -0
  572. data/spec/dummy/config/lines_config.yml +0 -58
@@ -0,0 +1,2142 @@
1
+ var Pos = CodeMirror.Pos;
2
+
3
+ CodeMirror.defaults.rtlMoveVisually = true;
4
+
5
+ function forEach(arr, f) {
6
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i], i);
7
+ }
8
+
9
+ function addDoc(cm, width, height) {
10
+ var content = [], line = "";
11
+ for (var i = 0; i < width; ++i) line += "x";
12
+ for (var i = 0; i < height; ++i) content.push(line);
13
+ cm.setValue(content.join("\n"));
14
+ }
15
+
16
+ function byClassName(elt, cls) {
17
+ if (elt.getElementsByClassName) return elt.getElementsByClassName(cls);
18
+ var found = [], re = new RegExp("\\b" + cls + "\\b");
19
+ function search(elt) {
20
+ if (elt.nodeType == 3) return;
21
+ if (re.test(elt.className)) found.push(elt);
22
+ for (var i = 0, e = elt.childNodes.length; i < e; ++i)
23
+ search(elt.childNodes[i]);
24
+ }
25
+ search(elt);
26
+ return found;
27
+ }
28
+
29
+ var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
30
+ var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
31
+ var mac = /Mac/.test(navigator.platform);
32
+ var phantom = /PhantomJS/.test(navigator.userAgent);
33
+ var opera = /Opera\/\./.test(navigator.userAgent);
34
+ var opera_version = opera && navigator.userAgent.match(/Version\/(\d+\.\d+)/);
35
+ if (opera_version) opera_version = Number(opera_version);
36
+ var opera_lt10 = opera && (!opera_version || opera_version < 10);
37
+
38
+ namespace = "core_";
39
+
40
+ test("core_fromTextArea", function() {
41
+ var te = document.getElementById("code");
42
+ te.value = "CONTENT";
43
+ var cm = CodeMirror.fromTextArea(te);
44
+ is(!te.offsetHeight);
45
+ eq(cm.getValue(), "CONTENT");
46
+ cm.setValue("foo\nbar");
47
+ eq(cm.getValue(), "foo\nbar");
48
+ cm.save();
49
+ is(/^foo\r?\nbar$/.test(te.value));
50
+ cm.setValue("xxx");
51
+ cm.toTextArea();
52
+ is(te.offsetHeight);
53
+ eq(te.value, "xxx");
54
+ });
55
+
56
+ testCM("getRange", function(cm) {
57
+ eq(cm.getLine(0), "1234");
58
+ eq(cm.getLine(1), "5678");
59
+ eq(cm.getLine(2), null);
60
+ eq(cm.getLine(-1), null);
61
+ eq(cm.getRange(Pos(0, 0), Pos(0, 3)), "123");
62
+ eq(cm.getRange(Pos(0, -1), Pos(0, 200)), "1234");
63
+ eq(cm.getRange(Pos(0, 2), Pos(1, 2)), "34\n56");
64
+ eq(cm.getRange(Pos(1, 2), Pos(100, 0)), "78");
65
+ }, {value: "1234\n5678"});
66
+
67
+ testCM("replaceRange", function(cm) {
68
+ eq(cm.getValue(), "");
69
+ cm.replaceRange("foo\n", Pos(0, 0));
70
+ eq(cm.getValue(), "foo\n");
71
+ cm.replaceRange("a\nb", Pos(0, 1));
72
+ eq(cm.getValue(), "fa\nboo\n");
73
+ eq(cm.lineCount(), 3);
74
+ cm.replaceRange("xyzzy", Pos(0, 0), Pos(1, 1));
75
+ eq(cm.getValue(), "xyzzyoo\n");
76
+ cm.replaceRange("abc", Pos(0, 0), Pos(10, 0));
77
+ eq(cm.getValue(), "abc");
78
+ eq(cm.lineCount(), 1);
79
+ });
80
+
81
+ testCM("selection", function(cm) {
82
+ cm.setSelection(Pos(0, 4), Pos(2, 2));
83
+ is(cm.somethingSelected());
84
+ eq(cm.getSelection(), "11\n222222\n33");
85
+ eqPos(cm.getCursor(false), Pos(2, 2));
86
+ eqPos(cm.getCursor(true), Pos(0, 4));
87
+ cm.setSelection(Pos(1, 0));
88
+ is(!cm.somethingSelected());
89
+ eq(cm.getSelection(), "");
90
+ eqPos(cm.getCursor(true), Pos(1, 0));
91
+ cm.replaceSelection("abc", "around");
92
+ eq(cm.getSelection(), "abc");
93
+ eq(cm.getValue(), "111111\nabc222222\n333333");
94
+ cm.replaceSelection("def", "end");
95
+ eq(cm.getSelection(), "");
96
+ eqPos(cm.getCursor(true), Pos(1, 3));
97
+ cm.setCursor(Pos(2, 1));
98
+ eqPos(cm.getCursor(true), Pos(2, 1));
99
+ cm.setCursor(1, 2);
100
+ eqPos(cm.getCursor(true), Pos(1, 2));
101
+ }, {value: "111111\n222222\n333333"});
102
+
103
+ testCM("extendSelection", function(cm) {
104
+ cm.setExtending(true);
105
+ addDoc(cm, 10, 10);
106
+ cm.setSelection(Pos(3, 5));
107
+ eqPos(cm.getCursor("head"), Pos(3, 5));
108
+ eqPos(cm.getCursor("anchor"), Pos(3, 5));
109
+ cm.setSelection(Pos(2, 5), Pos(5, 5));
110
+ eqPos(cm.getCursor("head"), Pos(5, 5));
111
+ eqPos(cm.getCursor("anchor"), Pos(2, 5));
112
+ eqPos(cm.getCursor("start"), Pos(2, 5));
113
+ eqPos(cm.getCursor("end"), Pos(5, 5));
114
+ cm.setSelection(Pos(5, 5), Pos(2, 5));
115
+ eqPos(cm.getCursor("head"), Pos(2, 5));
116
+ eqPos(cm.getCursor("anchor"), Pos(5, 5));
117
+ eqPos(cm.getCursor("start"), Pos(2, 5));
118
+ eqPos(cm.getCursor("end"), Pos(5, 5));
119
+ cm.extendSelection(Pos(3, 2));
120
+ eqPos(cm.getCursor("head"), Pos(3, 2));
121
+ eqPos(cm.getCursor("anchor"), Pos(5, 5));
122
+ cm.extendSelection(Pos(6, 2));
123
+ eqPos(cm.getCursor("head"), Pos(6, 2));
124
+ eqPos(cm.getCursor("anchor"), Pos(5, 5));
125
+ cm.extendSelection(Pos(6, 3), Pos(6, 4));
126
+ eqPos(cm.getCursor("head"), Pos(6, 4));
127
+ eqPos(cm.getCursor("anchor"), Pos(5, 5));
128
+ cm.extendSelection(Pos(0, 3), Pos(0, 4));
129
+ eqPos(cm.getCursor("head"), Pos(0, 3));
130
+ eqPos(cm.getCursor("anchor"), Pos(5, 5));
131
+ cm.extendSelection(Pos(4, 5), Pos(6, 5));
132
+ eqPos(cm.getCursor("head"), Pos(6, 5));
133
+ eqPos(cm.getCursor("anchor"), Pos(4, 5));
134
+ cm.setExtending(false);
135
+ cm.extendSelection(Pos(0, 3), Pos(0, 4));
136
+ eqPos(cm.getCursor("head"), Pos(0, 3));
137
+ eqPos(cm.getCursor("anchor"), Pos(0, 4));
138
+ });
139
+
140
+ testCM("lines", function(cm) {
141
+ eq(cm.getLine(0), "111111");
142
+ eq(cm.getLine(1), "222222");
143
+ eq(cm.getLine(-1), null);
144
+ cm.replaceRange("", Pos(1, 0), Pos(2, 0))
145
+ cm.replaceRange("abc", Pos(1, 0), Pos(1));
146
+ eq(cm.getValue(), "111111\nabc");
147
+ }, {value: "111111\n222222\n333333"});
148
+
149
+ testCM("indent", function(cm) {
150
+ cm.indentLine(1);
151
+ eq(cm.getLine(1), " blah();");
152
+ cm.setOption("indentUnit", 8);
153
+ cm.indentLine(1);
154
+ eq(cm.getLine(1), "\tblah();");
155
+ cm.setOption("indentUnit", 10);
156
+ cm.setOption("tabSize", 4);
157
+ cm.indentLine(1);
158
+ eq(cm.getLine(1), "\t\t blah();");
159
+ }, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true, tabSize: 8});
160
+
161
+ testCM("indentByNumber", function(cm) {
162
+ cm.indentLine(0, 2);
163
+ eq(cm.getLine(0), " foo");
164
+ cm.indentLine(0, -200);
165
+ eq(cm.getLine(0), "foo");
166
+ cm.setSelection(Pos(0, 0), Pos(1, 2));
167
+ cm.indentSelection(3);
168
+ eq(cm.getValue(), " foo\n bar\nbaz");
169
+ }, {value: "foo\nbar\nbaz"});
170
+
171
+ test("core_defaults", function() {
172
+ var defsCopy = {}, defs = CodeMirror.defaults;
173
+ for (var opt in defs) defsCopy[opt] = defs[opt];
174
+ defs.indentUnit = 5;
175
+ defs.value = "uu";
176
+ defs.indentWithTabs = true;
177
+ defs.tabindex = 55;
178
+ var place = document.getElementById("testground"), cm = CodeMirror(place);
179
+ try {
180
+ eq(cm.getOption("indentUnit"), 5);
181
+ cm.setOption("indentUnit", 10);
182
+ eq(defs.indentUnit, 5);
183
+ eq(cm.getValue(), "uu");
184
+ eq(cm.getOption("indentWithTabs"), true);
185
+ eq(cm.getInputField().tabIndex, 55);
186
+ }
187
+ finally {
188
+ for (var opt in defsCopy) defs[opt] = defsCopy[opt];
189
+ place.removeChild(cm.getWrapperElement());
190
+ }
191
+ });
192
+
193
+ testCM("lineInfo", function(cm) {
194
+ eq(cm.lineInfo(-1), null);
195
+ var mark = document.createElement("span");
196
+ var lh = cm.setGutterMarker(1, "FOO", mark);
197
+ var info = cm.lineInfo(1);
198
+ eq(info.text, "222222");
199
+ eq(info.gutterMarkers.FOO, mark);
200
+ eq(info.line, 1);
201
+ eq(cm.lineInfo(2).gutterMarkers, null);
202
+ cm.setGutterMarker(lh, "FOO", null);
203
+ eq(cm.lineInfo(1).gutterMarkers, null);
204
+ cm.setGutterMarker(1, "FOO", mark);
205
+ cm.setGutterMarker(0, "FOO", mark);
206
+ cm.clearGutter("FOO");
207
+ eq(cm.lineInfo(0).gutterMarkers, null);
208
+ eq(cm.lineInfo(1).gutterMarkers, null);
209
+ }, {value: "111111\n222222\n333333"});
210
+
211
+ testCM("coords", function(cm) {
212
+ cm.setSize(null, 100);
213
+ addDoc(cm, 32, 200);
214
+ var top = cm.charCoords(Pos(0, 0));
215
+ var bot = cm.charCoords(Pos(200, 30));
216
+ is(top.left < bot.left);
217
+ is(top.top < bot.top);
218
+ is(top.top < top.bottom);
219
+ cm.scrollTo(null, 100);
220
+ var top2 = cm.charCoords(Pos(0, 0));
221
+ is(top.top > top2.top);
222
+ eq(top.left, top2.left);
223
+ });
224
+
225
+ testCM("coordsChar", function(cm) {
226
+ addDoc(cm, 35, 70);
227
+ for (var i = 0; i < 2; ++i) {
228
+ var sys = i ? "local" : "page";
229
+ for (var ch = 0; ch <= 35; ch += 5) {
230
+ for (var line = 0; line < 70; line += 5) {
231
+ cm.setCursor(line, ch);
232
+ var coords = cm.charCoords(Pos(line, ch), sys);
233
+ var pos = cm.coordsChar({left: coords.left + 1, top: coords.top + 1}, sys);
234
+ eqPos(pos, Pos(line, ch));
235
+ }
236
+ }
237
+ }
238
+ }, {lineNumbers: true});
239
+
240
+ testCM("posFromIndex", function(cm) {
241
+ cm.setValue(
242
+ "This function should\n" +
243
+ "convert a zero based index\n" +
244
+ "to line and ch."
245
+ );
246
+
247
+ var examples = [
248
+ { index: -1, line: 0, ch: 0 }, // <- Tests clipping
249
+ { index: 0, line: 0, ch: 0 },
250
+ { index: 10, line: 0, ch: 10 },
251
+ { index: 39, line: 1, ch: 18 },
252
+ { index: 55, line: 2, ch: 7 },
253
+ { index: 63, line: 2, ch: 15 },
254
+ { index: 64, line: 2, ch: 15 } // <- Tests clipping
255
+ ];
256
+
257
+ for (var i = 0; i < examples.length; i++) {
258
+ var example = examples[i];
259
+ var pos = cm.posFromIndex(example.index);
260
+ eq(pos.line, example.line);
261
+ eq(pos.ch, example.ch);
262
+ if (example.index >= 0 && example.index < 64)
263
+ eq(cm.indexFromPos(pos), example.index);
264
+ }
265
+ });
266
+
267
+ testCM("undo", function(cm) {
268
+ cm.replaceRange("def", Pos(0, 0), Pos(0));
269
+ eq(cm.historySize().undo, 1);
270
+ cm.undo();
271
+ eq(cm.getValue(), "abc");
272
+ eq(cm.historySize().undo, 0);
273
+ eq(cm.historySize().redo, 1);
274
+ cm.redo();
275
+ eq(cm.getValue(), "def");
276
+ eq(cm.historySize().undo, 1);
277
+ eq(cm.historySize().redo, 0);
278
+ cm.setValue("1\n\n\n2");
279
+ cm.clearHistory();
280
+ eq(cm.historySize().undo, 0);
281
+ for (var i = 0; i < 20; ++i) {
282
+ cm.replaceRange("a", Pos(0, 0));
283
+ cm.replaceRange("b", Pos(3, 0));
284
+ }
285
+ eq(cm.historySize().undo, 40);
286
+ for (var i = 0; i < 40; ++i)
287
+ cm.undo();
288
+ eq(cm.historySize().redo, 40);
289
+ eq(cm.getValue(), "1\n\n\n2");
290
+ }, {value: "abc"});
291
+
292
+ testCM("undoDepth", function(cm) {
293
+ cm.replaceRange("d", Pos(0));
294
+ cm.replaceRange("e", Pos(0));
295
+ cm.replaceRange("f", Pos(0));
296
+ cm.undo(); cm.undo(); cm.undo();
297
+ eq(cm.getValue(), "abcd");
298
+ }, {value: "abc", undoDepth: 4});
299
+
300
+ testCM("undoDoesntClearValue", function(cm) {
301
+ cm.undo();
302
+ eq(cm.getValue(), "x");
303
+ }, {value: "x"});
304
+
305
+ testCM("undoMultiLine", function(cm) {
306
+ cm.operation(function() {
307
+ cm.replaceRange("x", Pos(0, 0));
308
+ cm.replaceRange("y", Pos(1, 0));
309
+ });
310
+ cm.undo();
311
+ eq(cm.getValue(), "abc\ndef\nghi");
312
+ cm.operation(function() {
313
+ cm.replaceRange("y", Pos(1, 0));
314
+ cm.replaceRange("x", Pos(0, 0));
315
+ });
316
+ cm.undo();
317
+ eq(cm.getValue(), "abc\ndef\nghi");
318
+ cm.operation(function() {
319
+ cm.replaceRange("y", Pos(2, 0));
320
+ cm.replaceRange("x", Pos(1, 0));
321
+ cm.replaceRange("z", Pos(2, 0));
322
+ });
323
+ cm.undo();
324
+ eq(cm.getValue(), "abc\ndef\nghi", 3);
325
+ }, {value: "abc\ndef\nghi"});
326
+
327
+ testCM("undoComposite", function(cm) {
328
+ cm.replaceRange("y", Pos(1));
329
+ cm.operation(function() {
330
+ cm.replaceRange("x", Pos(0));
331
+ cm.replaceRange("z", Pos(2));
332
+ });
333
+ eq(cm.getValue(), "ax\nby\ncz\n");
334
+ cm.undo();
335
+ eq(cm.getValue(), "a\nby\nc\n");
336
+ cm.undo();
337
+ eq(cm.getValue(), "a\nb\nc\n");
338
+ cm.redo(); cm.redo();
339
+ eq(cm.getValue(), "ax\nby\ncz\n");
340
+ }, {value: "a\nb\nc\n"});
341
+
342
+ testCM("undoSelection", function(cm) {
343
+ cm.setSelection(Pos(0, 2), Pos(0, 4));
344
+ cm.replaceSelection("");
345
+ cm.setCursor(Pos(1, 0));
346
+ cm.undo();
347
+ eqPos(cm.getCursor(true), Pos(0, 2));
348
+ eqPos(cm.getCursor(false), Pos(0, 4));
349
+ cm.setCursor(Pos(1, 0));
350
+ cm.redo();
351
+ eqPos(cm.getCursor(true), Pos(0, 2));
352
+ eqPos(cm.getCursor(false), Pos(0, 2));
353
+ }, {value: "abcdefgh\n"});
354
+
355
+ testCM("undoSelectionAsBefore", function(cm) {
356
+ cm.replaceSelection("abc", "around");
357
+ cm.undo();
358
+ cm.redo();
359
+ eq(cm.getSelection(), "abc");
360
+ });
361
+
362
+ testCM("selectionChangeConfusesHistory", function(cm) {
363
+ cm.replaceSelection("abc", null, "dontmerge");
364
+ cm.operation(function() {
365
+ cm.setCursor(Pos(0, 0));
366
+ cm.replaceSelection("abc", null, "dontmerge");
367
+ });
368
+ eq(cm.historySize().undo, 2);
369
+ });
370
+
371
+ testCM("markTextSingleLine", function(cm) {
372
+ forEach([{a: 0, b: 1, c: "", f: 2, t: 5},
373
+ {a: 0, b: 4, c: "", f: 0, t: 2},
374
+ {a: 1, b: 2, c: "x", f: 3, t: 6},
375
+ {a: 4, b: 5, c: "", f: 3, t: 5},
376
+ {a: 4, b: 5, c: "xx", f: 3, t: 7},
377
+ {a: 2, b: 5, c: "", f: 2, t: 3},
378
+ {a: 2, b: 5, c: "abcd", f: 6, t: 7},
379
+ {a: 2, b: 6, c: "x", f: null, t: null},
380
+ {a: 3, b: 6, c: "", f: null, t: null},
381
+ {a: 0, b: 9, c: "hallo", f: null, t: null},
382
+ {a: 4, b: 6, c: "x", f: 3, t: 4},
383
+ {a: 4, b: 8, c: "", f: 3, t: 4},
384
+ {a: 6, b: 6, c: "a", f: 3, t: 6},
385
+ {a: 8, b: 9, c: "", f: 3, t: 6}], function(test) {
386
+ cm.setValue("1234567890");
387
+ var r = cm.markText(Pos(0, 3), Pos(0, 6), {className: "foo"});
388
+ cm.replaceRange(test.c, Pos(0, test.a), Pos(0, test.b));
389
+ var f = r.find();
390
+ eq(f && f.from.ch, test.f); eq(f && f.to.ch, test.t);
391
+ });
392
+ });
393
+
394
+ testCM("markTextMultiLine", function(cm) {
395
+ function p(v) { return v && Pos(v[0], v[1]); }
396
+ forEach([{a: [0, 0], b: [0, 5], c: "", f: [0, 0], t: [2, 5]},
397
+ {a: [0, 0], b: [0, 5], c: "foo\n", f: [1, 0], t: [3, 5]},
398
+ {a: [0, 1], b: [0, 10], c: "", f: [0, 1], t: [2, 5]},
399
+ {a: [0, 5], b: [0, 6], c: "x", f: [0, 6], t: [2, 5]},
400
+ {a: [0, 0], b: [1, 0], c: "", f: [0, 0], t: [1, 5]},
401
+ {a: [0, 6], b: [2, 4], c: "", f: [0, 5], t: [0, 7]},
402
+ {a: [0, 6], b: [2, 4], c: "aa", f: [0, 5], t: [0, 9]},
403
+ {a: [1, 2], b: [1, 8], c: "", f: [0, 5], t: [2, 5]},
404
+ {a: [0, 5], b: [2, 5], c: "xx", f: null, t: null},
405
+ {a: [0, 0], b: [2, 10], c: "x", f: null, t: null},
406
+ {a: [1, 5], b: [2, 5], c: "", f: [0, 5], t: [1, 5]},
407
+ {a: [2, 0], b: [2, 3], c: "", f: [0, 5], t: [2, 2]},
408
+ {a: [2, 5], b: [3, 0], c: "a\nb", f: [0, 5], t: [2, 5]},
409
+ {a: [2, 3], b: [3, 0], c: "x", f: [0, 5], t: [2, 3]},
410
+ {a: [1, 1], b: [1, 9], c: "1\n2\n3", f: [0, 5], t: [4, 5]}], function(test) {
411
+ cm.setValue("aaaaaaaaaa\nbbbbbbbbbb\ncccccccccc\ndddddddd\n");
412
+ var r = cm.markText(Pos(0, 5), Pos(2, 5),
413
+ {className: "CodeMirror-matchingbracket"});
414
+ cm.replaceRange(test.c, p(test.a), p(test.b));
415
+ var f = r.find();
416
+ eqPos(f && f.from, p(test.f)); eqPos(f && f.to, p(test.t));
417
+ });
418
+ });
419
+
420
+ testCM("markTextUndo", function(cm) {
421
+ var marker1, marker2, bookmark;
422
+ marker1 = cm.markText(Pos(0, 1), Pos(0, 3),
423
+ {className: "CodeMirror-matchingbracket"});
424
+ marker2 = cm.markText(Pos(0, 0), Pos(2, 1),
425
+ {className: "CodeMirror-matchingbracket"});
426
+ bookmark = cm.setBookmark(Pos(1, 5));
427
+ cm.operation(function(){
428
+ cm.replaceRange("foo", Pos(0, 2));
429
+ cm.replaceRange("bar\nbaz\nbug\n", Pos(2, 0), Pos(3, 0));
430
+ });
431
+ var v1 = cm.getValue();
432
+ cm.setValue("");
433
+ eq(marker1.find(), null); eq(marker2.find(), null); eq(bookmark.find(), null);
434
+ cm.undo();
435
+ eqPos(bookmark.find(), Pos(1, 5), "still there");
436
+ cm.undo();
437
+ var m1Pos = marker1.find(), m2Pos = marker2.find();
438
+ eqPos(m1Pos.from, Pos(0, 1)); eqPos(m1Pos.to, Pos(0, 3));
439
+ eqPos(m2Pos.from, Pos(0, 0)); eqPos(m2Pos.to, Pos(2, 1));
440
+ eqPos(bookmark.find(), Pos(1, 5));
441
+ cm.redo(); cm.redo();
442
+ eq(bookmark.find(), null);
443
+ cm.undo();
444
+ eqPos(bookmark.find(), Pos(1, 5));
445
+ eq(cm.getValue(), v1);
446
+ }, {value: "1234\n56789\n00\n"});
447
+
448
+ testCM("markTextStayGone", function(cm) {
449
+ var m1 = cm.markText(Pos(0, 0), Pos(0, 1));
450
+ cm.replaceRange("hi", Pos(0, 2));
451
+ m1.clear();
452
+ cm.undo();
453
+ eq(m1.find(), null);
454
+ }, {value: "hello"});
455
+
456
+ testCM("markTextAllowEmpty", function(cm) {
457
+ var m1 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false});
458
+ is(m1.find());
459
+ cm.replaceRange("x", Pos(0, 0));
460
+ is(m1.find());
461
+ cm.replaceRange("y", Pos(0, 2));
462
+ is(m1.find());
463
+ cm.replaceRange("z", Pos(0, 3), Pos(0, 4));
464
+ is(!m1.find());
465
+ var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false,
466
+ inclusiveLeft: true,
467
+ inclusiveRight: true});
468
+ cm.replaceRange("q", Pos(0, 1), Pos(0, 2));
469
+ is(m2.find());
470
+ cm.replaceRange("", Pos(0, 0), Pos(0, 3));
471
+ is(!m2.find());
472
+ var m3 = cm.markText(Pos(0, 1), Pos(0, 1), {clearWhenEmpty: false});
473
+ cm.replaceRange("a", Pos(0, 3));
474
+ is(m3.find());
475
+ cm.replaceRange("b", Pos(0, 1));
476
+ is(!m3.find());
477
+ }, {value: "abcde"});
478
+
479
+ testCM("markTextStacked", function(cm) {
480
+ var m1 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false});
481
+ var m2 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false});
482
+ cm.replaceRange("B", Pos(0, 1));
483
+ is(m1.find() && m2.find());
484
+ }, {value: "A"});
485
+
486
+ testCM("undoPreservesNewMarks", function(cm) {
487
+ cm.markText(Pos(0, 3), Pos(0, 4));
488
+ cm.markText(Pos(1, 1), Pos(1, 3));
489
+ cm.replaceRange("", Pos(0, 3), Pos(3, 1));
490
+ var mBefore = cm.markText(Pos(0, 0), Pos(0, 1));
491
+ var mAfter = cm.markText(Pos(0, 5), Pos(0, 6));
492
+ var mAround = cm.markText(Pos(0, 2), Pos(0, 4));
493
+ cm.undo();
494
+ eqPos(mBefore.find().from, Pos(0, 0));
495
+ eqPos(mBefore.find().to, Pos(0, 1));
496
+ eqPos(mAfter.find().from, Pos(3, 3));
497
+ eqPos(mAfter.find().to, Pos(3, 4));
498
+ eqPos(mAround.find().from, Pos(0, 2));
499
+ eqPos(mAround.find().to, Pos(3, 2));
500
+ var found = cm.findMarksAt(Pos(2, 2));
501
+ eq(found.length, 1);
502
+ eq(found[0], mAround);
503
+ }, {value: "aaaa\nbbbb\ncccc\ndddd"});
504
+
505
+ testCM("markClearBetween", function(cm) {
506
+ cm.setValue("aaa\nbbb\nccc\nddd\n");
507
+ cm.markText(Pos(0, 0), Pos(2));
508
+ cm.replaceRange("aaa\nbbb\nccc", Pos(0, 0), Pos(2));
509
+ eq(cm.findMarksAt(Pos(1, 1)).length, 0);
510
+ });
511
+
512
+ testCM("deleteSpanCollapsedInclusiveLeft", function(cm) {
513
+ var from = Pos(1, 0), to = Pos(1, 1);
514
+ var m = cm.markText(from, to, {collapsed: true, inclusiveLeft: true});
515
+ // Delete collapsed span.
516
+ cm.replaceRange("", from, to);
517
+ }, {value: "abc\nX\ndef"});
518
+
519
+ testCM("markTextCSS", function(cm) {
520
+ function present() {
521
+ var spans = cm.display.lineDiv.getElementsByTagName("span");
522
+ for (var i = 0; i < spans.length; i++)
523
+ if (spans[i].style.color == "cyan" && span[i].textContent == "cdefg") return true;
524
+ }
525
+ var m = cm.markText(Pos(0, 2), Pos(0, 6), {css: "color: cyan"});
526
+ m.clear();
527
+ is(!present());
528
+ }, {value: "abcdefgh"});
529
+
530
+ testCM("bookmark", function(cm) {
531
+ function p(v) { return v && Pos(v[0], v[1]); }
532
+ forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]},
533
+ {a: [1, 1], b: [1, 1], c: "xx", d: [1, 7]},
534
+ {a: [1, 4], b: [1, 5], c: "ab", d: [1, 6]},
535
+ {a: [1, 4], b: [1, 6], c: "", d: null},
536
+ {a: [1, 5], b: [1, 6], c: "abc", d: [1, 5]},
537
+ {a: [1, 6], b: [1, 8], c: "", d: [1, 5]},
538
+ {a: [1, 4], b: [1, 4], c: "\n\n", d: [3, 1]},
539
+ {bm: [1, 9], a: [1, 1], b: [1, 1], c: "\n", d: [2, 8]}], function(test) {
540
+ cm.setValue("1234567890\n1234567890\n1234567890");
541
+ var b = cm.setBookmark(p(test.bm) || Pos(1, 5));
542
+ cm.replaceRange(test.c, p(test.a), p(test.b));
543
+ eqPos(b.find(), p(test.d));
544
+ });
545
+ });
546
+
547
+ testCM("bookmarkInsertLeft", function(cm) {
548
+ var br = cm.setBookmark(Pos(0, 2), {insertLeft: false});
549
+ var bl = cm.setBookmark(Pos(0, 2), {insertLeft: true});
550
+ cm.setCursor(Pos(0, 2));
551
+ cm.replaceSelection("hi");
552
+ eqPos(br.find(), Pos(0, 2));
553
+ eqPos(bl.find(), Pos(0, 4));
554
+ cm.replaceRange("", Pos(0, 4), Pos(0, 5));
555
+ cm.replaceRange("", Pos(0, 2), Pos(0, 4));
556
+ cm.replaceRange("", Pos(0, 1), Pos(0, 2));
557
+ // Verify that deleting next to bookmarks doesn't kill them
558
+ eqPos(br.find(), Pos(0, 1));
559
+ eqPos(bl.find(), Pos(0, 1));
560
+ }, {value: "abcdef"});
561
+
562
+ testCM("bookmarkCursor", function(cm) {
563
+ var pos01 = cm.cursorCoords(Pos(0, 1)), pos11 = cm.cursorCoords(Pos(1, 1)),
564
+ pos20 = cm.cursorCoords(Pos(2, 0)), pos30 = cm.cursorCoords(Pos(3, 0)),
565
+ pos41 = cm.cursorCoords(Pos(4, 1));
566
+ cm.setBookmark(Pos(0, 1), {widget: document.createTextNode("←"), insertLeft: true});
567
+ cm.setBookmark(Pos(2, 0), {widget: document.createTextNode("←"), insertLeft: true});
568
+ cm.setBookmark(Pos(1, 1), {widget: document.createTextNode("→")});
569
+ cm.setBookmark(Pos(3, 0), {widget: document.createTextNode("→")});
570
+ var new01 = cm.cursorCoords(Pos(0, 1)), new11 = cm.cursorCoords(Pos(1, 1)),
571
+ new20 = cm.cursorCoords(Pos(2, 0)), new30 = cm.cursorCoords(Pos(3, 0));
572
+ near(new01.left, pos01.left, 1);
573
+ near(new01.top, pos01.top, 1);
574
+ is(new11.left > pos11.left, "at right, middle of line");
575
+ near(new11.top == pos11.top, 1);
576
+ near(new20.left, pos20.left, 1);
577
+ near(new20.top, pos20.top, 1);
578
+ is(new30.left > pos30.left, "at right, empty line");
579
+ near(new30.top, pos30, 1);
580
+ cm.setBookmark(Pos(4, 0), {widget: document.createTextNode("→")});
581
+ is(cm.cursorCoords(Pos(4, 1)).left > pos41.left, "single-char bug");
582
+ }, {value: "foo\nbar\n\n\nx\ny"});
583
+
584
+ testCM("multiBookmarkCursor", function(cm) {
585
+ if (phantom) return;
586
+ var ms = [], m;
587
+ function add(insertLeft) {
588
+ for (var i = 0; i < 3; ++i) {
589
+ var node = document.createElement("span");
590
+ node.innerHTML = "X";
591
+ ms.push(cm.setBookmark(Pos(0, 1), {widget: node, insertLeft: insertLeft}));
592
+ }
593
+ }
594
+ var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left;
595
+ add(true);
596
+ near(base1, cm.cursorCoords(Pos(0, 1)).left, 1);
597
+ while (m = ms.pop()) m.clear();
598
+ add(false);
599
+ near(base4, cm.cursorCoords(Pos(0, 1)).left, 1);
600
+ }, {value: "abcdefg"});
601
+
602
+ testCM("getAllMarks", function(cm) {
603
+ addDoc(cm, 10, 10);
604
+ var m1 = cm.setBookmark(Pos(0, 2));
605
+ var m2 = cm.markText(Pos(0, 2), Pos(3, 2));
606
+ var m3 = cm.markText(Pos(1, 2), Pos(1, 8));
607
+ var m4 = cm.markText(Pos(8, 0), Pos(9, 0));
608
+ eq(cm.getAllMarks().length, 4);
609
+ m1.clear();
610
+ m3.clear();
611
+ eq(cm.getAllMarks().length, 2);
612
+ });
613
+
614
+ testCM("setValueClears", function(cm) {
615
+ cm.addLineClass(0, "wrap", "foo");
616
+ var mark = cm.markText(Pos(0, 0), Pos(1, 1), {inclusiveLeft: true, inclusiveRight: true});
617
+ cm.setValue("foo");
618
+ is(!cm.lineInfo(0).wrapClass);
619
+ is(!mark.find());
620
+ }, {value: "a\nb"});
621
+
622
+ testCM("bug577", function(cm) {
623
+ cm.setValue("a\nb");
624
+ cm.clearHistory();
625
+ cm.setValue("fooooo");
626
+ cm.undo();
627
+ });
628
+
629
+ testCM("scrollSnap", function(cm) {
630
+ cm.setSize(100, 100);
631
+ addDoc(cm, 200, 200);
632
+ cm.setCursor(Pos(100, 180));
633
+ var info = cm.getScrollInfo();
634
+ is(info.left > 0 && info.top > 0);
635
+ cm.setCursor(Pos(0, 0));
636
+ info = cm.getScrollInfo();
637
+ is(info.left == 0 && info.top == 0, "scrolled clean to top");
638
+ cm.setCursor(Pos(100, 180));
639
+ cm.setCursor(Pos(199, 0));
640
+ info = cm.getScrollInfo();
641
+ is(info.left == 0 && info.top + 2 > info.height - cm.getScrollerElement().clientHeight, "scrolled clean to bottom");
642
+ });
643
+
644
+ testCM("scrollIntoView", function(cm) {
645
+ if (phantom) return;
646
+ var outer = cm.getWrapperElement().getBoundingClientRect();
647
+ function test(line, ch, msg) {
648
+ var pos = Pos(line, ch);
649
+ cm.scrollIntoView(pos);
650
+ var box = cm.charCoords(pos, "window");
651
+ is(box.left >= outer.left, msg + " (left)");
652
+ is(box.right <= outer.right, msg + " (right)");
653
+ is(box.top >= outer.top, msg + " (top)");
654
+ is(box.bottom <= outer.bottom, msg + " (bottom)");
655
+ }
656
+ addDoc(cm, 200, 200);
657
+ test(199, 199, "bottom right");
658
+ test(0, 0, "top left");
659
+ test(100, 100, "center");
660
+ test(199, 0, "bottom left");
661
+ test(0, 199, "top right");
662
+ test(100, 100, "center again");
663
+ });
664
+
665
+ testCM("scrollBackAndForth", function(cm) {
666
+ addDoc(cm, 1, 200);
667
+ cm.operation(function() {
668
+ cm.scrollIntoView(Pos(199, 0));
669
+ cm.scrollIntoView(Pos(4, 0));
670
+ });
671
+ is(cm.getScrollInfo().top > 0);
672
+ });
673
+
674
+ testCM("selectAllNoScroll", function(cm) {
675
+ addDoc(cm, 1, 200);
676
+ cm.execCommand("selectAll");
677
+ eq(cm.getScrollInfo().top, 0);
678
+ cm.setCursor(199);
679
+ cm.execCommand("selectAll");
680
+ is(cm.getScrollInfo().top > 0);
681
+ });
682
+
683
+ testCM("selectionPos", function(cm) {
684
+ if (phantom || cm.getOption("inputStyle") != "textarea") return;
685
+ cm.setSize(100, 100);
686
+ addDoc(cm, 200, 100);
687
+ cm.setSelection(Pos(1, 100), Pos(98, 100));
688
+ var lineWidth = cm.charCoords(Pos(0, 200), "local").left;
689
+ var lineHeight = (cm.charCoords(Pos(99)).top - cm.charCoords(Pos(0)).top) / 100;
690
+ cm.scrollTo(0, 0);
691
+ var selElt = byClassName(cm.getWrapperElement(), "CodeMirror-selected");
692
+ var outer = cm.getWrapperElement().getBoundingClientRect();
693
+ var sawMiddle, sawTop, sawBottom;
694
+ for (var i = 0, e = selElt.length; i < e; ++i) {
695
+ var box = selElt[i].getBoundingClientRect();
696
+ var atLeft = box.left - outer.left < 30;
697
+ var width = box.right - box.left;
698
+ var atRight = box.right - outer.left > .8 * lineWidth;
699
+ if (atLeft && atRight) {
700
+ sawMiddle = true;
701
+ is(box.bottom - box.top > 90 * lineHeight, "middle high");
702
+ is(width > .9 * lineWidth, "middle wide");
703
+ } else {
704
+ is(width > .4 * lineWidth, "top/bot wide enough");
705
+ is(width < .6 * lineWidth, "top/bot slim enough");
706
+ if (atLeft) {
707
+ sawBottom = true;
708
+ is(box.top - outer.top > 96 * lineHeight, "bot below");
709
+ } else if (atRight) {
710
+ sawTop = true;
711
+ is(box.top - outer.top < 2.1 * lineHeight, "top above");
712
+ }
713
+ }
714
+ }
715
+ is(sawTop && sawBottom && sawMiddle, "all parts");
716
+ }, null);
717
+
718
+ testCM("restoreHistory", function(cm) {
719
+ cm.setValue("abc\ndef");
720
+ cm.replaceRange("hello", Pos(1, 0), Pos(1));
721
+ cm.replaceRange("goop", Pos(0, 0), Pos(0));
722
+ cm.undo();
723
+ var storedVal = cm.getValue(), storedHist = cm.getHistory();
724
+ if (window.JSON) storedHist = JSON.parse(JSON.stringify(storedHist));
725
+ eq(storedVal, "abc\nhello");
726
+ cm.setValue("");
727
+ cm.clearHistory();
728
+ eq(cm.historySize().undo, 0);
729
+ cm.setValue(storedVal);
730
+ cm.setHistory(storedHist);
731
+ cm.redo();
732
+ eq(cm.getValue(), "goop\nhello");
733
+ cm.undo(); cm.undo();
734
+ eq(cm.getValue(), "abc\ndef");
735
+ });
736
+
737
+ testCM("doubleScrollbar", function(cm) {
738
+ var dummy = document.body.appendChild(document.createElement("p"));
739
+ dummy.style.cssText = "height: 50px; overflow: scroll; width: 50px";
740
+ var scrollbarWidth = dummy.offsetWidth + 1 - dummy.clientWidth;
741
+ document.body.removeChild(dummy);
742
+ if (scrollbarWidth < 2) return;
743
+ cm.setSize(null, 100);
744
+ addDoc(cm, 1, 300);
745
+ var wrap = cm.getWrapperElement();
746
+ is(wrap.offsetWidth - byClassName(wrap, "CodeMirror-lines")[0].offsetWidth <= scrollbarWidth * 1.5);
747
+ });
748
+
749
+ testCM("weirdLinebreaks", function(cm) {
750
+ cm.setValue("foo\nbar\rbaz\r\nquux\n\rplop");
751
+ is(cm.getValue(), "foo\nbar\nbaz\nquux\n\nplop");
752
+ is(cm.lineCount(), 6);
753
+ cm.setValue("\n\n");
754
+ is(cm.lineCount(), 3);
755
+ });
756
+
757
+ testCM("setSize", function(cm) {
758
+ cm.setSize(100, 100);
759
+ var wrap = cm.getWrapperElement();
760
+ is(wrap.offsetWidth, 100);
761
+ is(wrap.offsetHeight, 100);
762
+ cm.setSize("100%", "3em");
763
+ is(wrap.style.width, "100%");
764
+ is(wrap.style.height, "3em");
765
+ cm.setSize(null, 40);
766
+ is(wrap.style.width, "100%");
767
+ is(wrap.style.height, "40px");
768
+ });
769
+
770
+ function foldLines(cm, start, end, autoClear) {
771
+ return cm.markText(Pos(start, 0), Pos(end - 1), {
772
+ inclusiveLeft: true,
773
+ inclusiveRight: true,
774
+ collapsed: true,
775
+ clearOnEnter: autoClear
776
+ });
777
+ }
778
+
779
+ testCM("collapsedLines", function(cm) {
780
+ addDoc(cm, 4, 10);
781
+ var range = foldLines(cm, 4, 5), cleared = 0;
782
+ CodeMirror.on(range, "clear", function() {cleared++;});
783
+ cm.setCursor(Pos(3, 0));
784
+ CodeMirror.commands.goLineDown(cm);
785
+ eqPos(cm.getCursor(), Pos(5, 0));
786
+ cm.replaceRange("abcdefg", Pos(3, 0), Pos(3));
787
+ cm.setCursor(Pos(3, 6));
788
+ CodeMirror.commands.goLineDown(cm);
789
+ eqPos(cm.getCursor(), Pos(5, 4));
790
+ cm.replaceRange("ab", Pos(3, 0), Pos(3));
791
+ cm.setCursor(Pos(3, 2));
792
+ CodeMirror.commands.goLineDown(cm);
793
+ eqPos(cm.getCursor(), Pos(5, 2));
794
+ cm.operation(function() {range.clear(); range.clear();});
795
+ eq(cleared, 1);
796
+ });
797
+
798
+ testCM("collapsedRangeCoordsChar", function(cm) {
799
+ var pos_1_3 = cm.charCoords(Pos(1, 3));
800
+ pos_1_3.left += 2; pos_1_3.top += 2;
801
+ var opts = {collapsed: true, inclusiveLeft: true, inclusiveRight: true};
802
+ var m1 = cm.markText(Pos(0, 0), Pos(2, 0), opts);
803
+ eqPos(cm.coordsChar(pos_1_3), Pos(3, 3));
804
+ m1.clear();
805
+ var m1 = cm.markText(Pos(0, 0), Pos(1, 1), {collapsed: true, inclusiveLeft: true});
806
+ var m2 = cm.markText(Pos(1, 1), Pos(2, 0), {collapsed: true, inclusiveRight: true});
807
+ eqPos(cm.coordsChar(pos_1_3), Pos(3, 3));
808
+ m1.clear(); m2.clear();
809
+ var m1 = cm.markText(Pos(0, 0), Pos(1, 6), opts);
810
+ eqPos(cm.coordsChar(pos_1_3), Pos(3, 3));
811
+ }, {value: "123456\nabcdef\nghijkl\nmnopqr\n"});
812
+
813
+ testCM("collapsedRangeBetweenLinesSelected", function(cm) {
814
+ if (cm.getOption("inputStyle") != "textarea") return;
815
+ var widget = document.createElement("span");
816
+ widget.textContent = "\u2194";
817
+ cm.markText(Pos(0, 3), Pos(1, 0), {replacedWith: widget});
818
+ cm.setSelection(Pos(0, 3), Pos(1, 0));
819
+ var selElts = byClassName(cm.getWrapperElement(), "CodeMirror-selected");
820
+ for (var i = 0, w = 0; i < selElts.length; i++)
821
+ w += selElts[i].offsetWidth;
822
+ is(w > 0);
823
+ }, {value: "one\ntwo"});
824
+
825
+ testCM("randomCollapsedRanges", function(cm) {
826
+ addDoc(cm, 20, 500);
827
+ cm.operation(function() {
828
+ for (var i = 0; i < 200; i++) {
829
+ var start = Pos(Math.floor(Math.random() * 500), Math.floor(Math.random() * 20));
830
+ if (i % 4)
831
+ try { cm.markText(start, Pos(start.line + 2, 1), {collapsed: true}); }
832
+ catch(e) { if (!/overlapping/.test(String(e))) throw e; }
833
+ else
834
+ cm.markText(start, Pos(start.line, start.ch + 4), {"className": "foo"});
835
+ }
836
+ });
837
+ });
838
+
839
+ testCM("hiddenLinesAutoUnfold", function(cm) {
840
+ var range = foldLines(cm, 1, 3, true), cleared = 0;
841
+ CodeMirror.on(range, "clear", function() {cleared++;});
842
+ cm.setCursor(Pos(3, 0));
843
+ eq(cleared, 0);
844
+ cm.execCommand("goCharLeft");
845
+ eq(cleared, 1);
846
+ range = foldLines(cm, 1, 3, true);
847
+ CodeMirror.on(range, "clear", function() {cleared++;});
848
+ eqPos(cm.getCursor(), Pos(3, 0));
849
+ cm.setCursor(Pos(0, 3));
850
+ cm.execCommand("goCharRight");
851
+ eq(cleared, 2);
852
+ }, {value: "abc\ndef\nghi\njkl"});
853
+
854
+ testCM("hiddenLinesSelectAll", function(cm) { // Issue #484
855
+ addDoc(cm, 4, 20);
856
+ foldLines(cm, 0, 10);
857
+ foldLines(cm, 11, 20);
858
+ CodeMirror.commands.selectAll(cm);
859
+ eqPos(cm.getCursor(true), Pos(10, 0));
860
+ eqPos(cm.getCursor(false), Pos(10, 4));
861
+ });
862
+
863
+
864
+ testCM("everythingFolded", function(cm) {
865
+ addDoc(cm, 2, 2);
866
+ function enterPress() {
867
+ cm.triggerOnKeyDown({type: "keydown", keyCode: 13, preventDefault: function(){}, stopPropagation: function(){}});
868
+ }
869
+ var fold = foldLines(cm, 0, 2);
870
+ enterPress();
871
+ eq(cm.getValue(), "xx\nxx");
872
+ fold.clear();
873
+ fold = foldLines(cm, 0, 2, true);
874
+ eq(fold.find(), null);
875
+ enterPress();
876
+ eq(cm.getValue(), "\nxx\nxx");
877
+ });
878
+
879
+ testCM("structuredFold", function(cm) {
880
+ if (phantom) return;
881
+ addDoc(cm, 4, 8);
882
+ var range = cm.markText(Pos(1, 2), Pos(6, 2), {
883
+ replacedWith: document.createTextNode("Q")
884
+ });
885
+ cm.setCursor(0, 3);
886
+ CodeMirror.commands.goLineDown(cm);
887
+ eqPos(cm.getCursor(), Pos(6, 2));
888
+ CodeMirror.commands.goCharLeft(cm);
889
+ eqPos(cm.getCursor(), Pos(1, 2));
890
+ CodeMirror.commands.delCharAfter(cm);
891
+ eq(cm.getValue(), "xxxx\nxxxx\nxxxx");
892
+ addDoc(cm, 4, 8);
893
+ range = cm.markText(Pos(1, 2), Pos(6, 2), {
894
+ replacedWith: document.createTextNode("M"),
895
+ clearOnEnter: true
896
+ });
897
+ var cleared = 0;
898
+ CodeMirror.on(range, "clear", function(){++cleared;});
899
+ cm.setCursor(0, 3);
900
+ CodeMirror.commands.goLineDown(cm);
901
+ eqPos(cm.getCursor(), Pos(6, 2));
902
+ CodeMirror.commands.goCharLeft(cm);
903
+ eqPos(cm.getCursor(), Pos(6, 1));
904
+ eq(cleared, 1);
905
+ range.clear();
906
+ eq(cleared, 1);
907
+ range = cm.markText(Pos(1, 2), Pos(6, 2), {
908
+ replacedWith: document.createTextNode("Q"),
909
+ clearOnEnter: true
910
+ });
911
+ range.clear();
912
+ cm.setCursor(1, 2);
913
+ CodeMirror.commands.goCharRight(cm);
914
+ eqPos(cm.getCursor(), Pos(1, 3));
915
+ range = cm.markText(Pos(2, 0), Pos(4, 4), {
916
+ replacedWith: document.createTextNode("M")
917
+ });
918
+ cm.setCursor(1, 0);
919
+ CodeMirror.commands.goLineDown(cm);
920
+ eqPos(cm.getCursor(), Pos(2, 0));
921
+ }, null);
922
+
923
+ testCM("nestedFold", function(cm) {
924
+ addDoc(cm, 10, 3);
925
+ function fold(ll, cl, lr, cr) {
926
+ return cm.markText(Pos(ll, cl), Pos(lr, cr), {collapsed: true});
927
+ }
928
+ var inner1 = fold(0, 6, 1, 3), inner2 = fold(0, 2, 1, 8), outer = fold(0, 1, 2, 3), inner0 = fold(0, 5, 0, 6);
929
+ cm.setCursor(0, 1);
930
+ CodeMirror.commands.goCharRight(cm);
931
+ eqPos(cm.getCursor(), Pos(2, 3));
932
+ inner0.clear();
933
+ CodeMirror.commands.goCharLeft(cm);
934
+ eqPos(cm.getCursor(), Pos(0, 1));
935
+ outer.clear();
936
+ CodeMirror.commands.goCharRight(cm);
937
+ eqPos(cm.getCursor(), Pos(0, 2));
938
+ CodeMirror.commands.goCharRight(cm);
939
+ eqPos(cm.getCursor(), Pos(1, 8));
940
+ inner2.clear();
941
+ CodeMirror.commands.goCharLeft(cm);
942
+ eqPos(cm.getCursor(), Pos(1, 7));
943
+ cm.setCursor(0, 5);
944
+ CodeMirror.commands.goCharRight(cm);
945
+ eqPos(cm.getCursor(), Pos(0, 6));
946
+ CodeMirror.commands.goCharRight(cm);
947
+ eqPos(cm.getCursor(), Pos(1, 3));
948
+ });
949
+
950
+ testCM("badNestedFold", function(cm) {
951
+ addDoc(cm, 4, 4);
952
+ cm.markText(Pos(0, 2), Pos(3, 2), {collapsed: true});
953
+ var caught;
954
+ try {cm.markText(Pos(0, 1), Pos(0, 3), {collapsed: true});}
955
+ catch(e) {caught = e;}
956
+ is(caught instanceof Error, "no error");
957
+ is(/overlap/i.test(caught.message), "wrong error");
958
+ });
959
+
960
+ testCM("nestedFoldOnSide", function(cm) {
961
+ var m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true, inclusiveRight: true});
962
+ var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true});
963
+ cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true}).clear();
964
+ try { cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true, inclusiveLeft: true}); }
965
+ catch(e) { var caught = e; }
966
+ is(caught && /overlap/i.test(caught.message));
967
+ var m3 = cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true});
968
+ var m4 = cm.markText(Pos(2, 0), Pos(2, 1), {collapse: true, inclusiveRight: true});
969
+ m1.clear(); m4.clear();
970
+ m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true});
971
+ cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true}).clear();
972
+ try { cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true, inclusiveRight: true}); }
973
+ catch(e) { var caught = e; }
974
+ is(caught && /overlap/i.test(caught.message));
975
+ }, {value: "ab\ncd\ef"});
976
+
977
+ testCM("editInFold", function(cm) {
978
+ addDoc(cm, 4, 6);
979
+ var m = cm.markText(Pos(1, 2), Pos(3, 2), {collapsed: true});
980
+ cm.replaceRange("", Pos(0, 0), Pos(1, 3));
981
+ cm.replaceRange("", Pos(2, 1), Pos(3, 3));
982
+ cm.replaceRange("a\nb\nc\nd", Pos(0, 1), Pos(1, 0));
983
+ cm.cursorCoords(Pos(0, 0));
984
+ });
985
+
986
+ testCM("wrappingInlineWidget", function(cm) {
987
+ cm.setSize("11em");
988
+ var w = document.createElement("span");
989
+ w.style.color = "red";
990
+ w.innerHTML = "one two three four";
991
+ cm.markText(Pos(0, 6), Pos(0, 9), {replacedWith: w});
992
+ var cur0 = cm.cursorCoords(Pos(0, 0)), cur1 = cm.cursorCoords(Pos(0, 10));
993
+ is(cur0.top < cur1.top);
994
+ is(cur0.bottom < cur1.bottom);
995
+ var curL = cm.cursorCoords(Pos(0, 6)), curR = cm.cursorCoords(Pos(0, 9));
996
+ eq(curL.top, cur0.top);
997
+ eq(curL.bottom, cur0.bottom);
998
+ eq(curR.top, cur1.top);
999
+ eq(curR.bottom, cur1.bottom);
1000
+ cm.replaceRange("", Pos(0, 9), Pos(0));
1001
+ curR = cm.cursorCoords(Pos(0, 9));
1002
+ if (phantom) return;
1003
+ eq(curR.top, cur1.top);
1004
+ eq(curR.bottom, cur1.bottom);
1005
+ }, {value: "1 2 3 xxx 4", lineWrapping: true});
1006
+
1007
+ testCM("showEmptyWidgetSpan", function(cm) {
1008
+ var marker = cm.markText(Pos(0, 2), Pos(0, 2), {
1009
+ clearWhenEmpty: false,
1010
+ replacedWith: document.createTextNode("X")
1011
+ });
1012
+ eq(cm.display.view[0].text.textContent, "abXc");
1013
+ }, {value: "abc"});
1014
+
1015
+ testCM("changedInlineWidget", function(cm) {
1016
+ cm.setSize("10em");
1017
+ var w = document.createElement("span");
1018
+ w.innerHTML = "x";
1019
+ var m = cm.markText(Pos(0, 4), Pos(0, 5), {replacedWith: w});
1020
+ w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed";
1021
+ m.changed();
1022
+ var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0];
1023
+ is(hScroll.scrollWidth > hScroll.clientWidth);
1024
+ }, {value: "hello there"});
1025
+
1026
+ testCM("changedBookmark", function(cm) {
1027
+ cm.setSize("10em");
1028
+ var w = document.createElement("span");
1029
+ w.innerHTML = "x";
1030
+ var m = cm.setBookmark(Pos(0, 4), {widget: w});
1031
+ w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed";
1032
+ m.changed();
1033
+ var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0];
1034
+ is(hScroll.scrollWidth > hScroll.clientWidth);
1035
+ }, {value: "abcdefg"});
1036
+
1037
+ testCM("inlineWidget", function(cm) {
1038
+ var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")});
1039
+ cm.setCursor(0, 2);
1040
+ CodeMirror.commands.goLineDown(cm);
1041
+ eqPos(cm.getCursor(), Pos(1, 4));
1042
+ cm.setCursor(0, 2);
1043
+ cm.replaceSelection("hi");
1044
+ eqPos(w.find(), Pos(0, 2));
1045
+ cm.setCursor(0, 1);
1046
+ cm.replaceSelection("ay");
1047
+ eqPos(w.find(), Pos(0, 4));
1048
+ eq(cm.getLine(0), "uayuhiuu");
1049
+ }, {value: "uuuu\nuuuuuu"});
1050
+
1051
+ testCM("wrappingAndResizing", function(cm) {
1052
+ cm.setSize(null, "auto");
1053
+ cm.setOption("lineWrapping", true);
1054
+ var wrap = cm.getWrapperElement(), h0 = wrap.offsetHeight;
1055
+ var doc = "xxx xxx xxx xxx xxx";
1056
+ cm.setValue(doc);
1057
+ for (var step = 10, w = cm.charCoords(Pos(0, 18), "div").right;; w += step) {
1058
+ cm.setSize(w);
1059
+ if (wrap.offsetHeight <= h0 * (opera_lt10 ? 1.2 : 1.5)) {
1060
+ if (step == 10) { w -= 10; step = 1; }
1061
+ else break;
1062
+ }
1063
+ }
1064
+ // Ensure that putting the cursor at the end of the maximally long
1065
+ // line doesn't cause wrapping to happen.
1066
+ cm.setCursor(Pos(0, doc.length));
1067
+ eq(wrap.offsetHeight, h0);
1068
+ cm.replaceSelection("x");
1069
+ is(wrap.offsetHeight > h0, "wrapping happens");
1070
+ // Now add a max-height and, in a document consisting of
1071
+ // almost-wrapped lines, go over it so that a scrollbar appears.
1072
+ cm.setValue(doc + "\n" + doc + "\n");
1073
+ cm.getScrollerElement().style.maxHeight = "100px";
1074
+ cm.replaceRange("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n!\n", Pos(2, 0));
1075
+ forEach([Pos(0, doc.length), Pos(0, doc.length - 1),
1076
+ Pos(0, 0), Pos(1, doc.length), Pos(1, doc.length - 1)],
1077
+ function(pos) {
1078
+ var coords = cm.charCoords(pos);
1079
+ eqPos(pos, cm.coordsChar({left: coords.left + 2, top: coords.top + 5}));
1080
+ });
1081
+ }, null, ie_lt8);
1082
+
1083
+ testCM("measureEndOfLine", function(cm) {
1084
+ cm.setSize(null, "auto");
1085
+ var inner = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild;
1086
+ var lh = inner.offsetHeight;
1087
+ for (var step = 10, w = cm.charCoords(Pos(0, 7), "div").right;; w += step) {
1088
+ cm.setSize(w);
1089
+ if (inner.offsetHeight < 2.5 * lh) {
1090
+ if (step == 10) { w -= 10; step = 1; }
1091
+ else break;
1092
+ }
1093
+ }
1094
+ cm.setValue(cm.getValue() + "\n\n");
1095
+ var endPos = cm.charCoords(Pos(0, 18), "local");
1096
+ is(endPos.top > lh * .8, "not at top");
1097
+ is(endPos.left > w - 20, "not at right");
1098
+ endPos = cm.charCoords(Pos(0, 18));
1099
+ eqPos(cm.coordsChar({left: endPos.left, top: endPos.top + 5}), Pos(0, 18));
1100
+ }, {mode: "text/html", value: "<!-- foo barrr -->", lineWrapping: true}, ie_lt8 || opera_lt10);
1101
+
1102
+ testCM("scrollVerticallyAndHorizontally", function(cm) {
1103
+ if (cm.getOption("inputStyle") != "textarea") return;
1104
+ cm.setSize(100, 100);
1105
+ addDoc(cm, 40, 40);
1106
+ cm.setCursor(39);
1107
+ var wrap = cm.getWrapperElement(), bar = byClassName(wrap, "CodeMirror-vscrollbar")[0];
1108
+ is(bar.offsetHeight < wrap.offsetHeight, "vertical scrollbar limited by horizontal one");
1109
+ var cursorBox = byClassName(wrap, "CodeMirror-cursor")[0].getBoundingClientRect();
1110
+ var editorBox = wrap.getBoundingClientRect();
1111
+ is(cursorBox.bottom < editorBox.top + cm.getScrollerElement().clientHeight,
1112
+ "bottom line visible");
1113
+ }, {lineNumbers: true});
1114
+
1115
+ testCM("moveVstuck", function(cm) {
1116
+ var lines = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild, h0 = lines.offsetHeight;
1117
+ var val = "fooooooooooooooooooooooooo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\n";
1118
+ cm.setValue(val);
1119
+ for (var w = cm.charCoords(Pos(0, 26), "div").right * 2.8;; w += 5) {
1120
+ cm.setSize(w);
1121
+ if (lines.offsetHeight <= 3.5 * h0) break;
1122
+ }
1123
+ cm.setCursor(Pos(0, val.length - 1));
1124
+ cm.moveV(-1, "line");
1125
+ eqPos(cm.getCursor(), Pos(0, 26));
1126
+ }, {lineWrapping: true}, ie_lt8 || opera_lt10);
1127
+
1128
+ testCM("collapseOnMove", function(cm) {
1129
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
1130
+ cm.execCommand("goLineUp");
1131
+ is(!cm.somethingSelected());
1132
+ eqPos(cm.getCursor(), Pos(0, 1));
1133
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
1134
+ cm.execCommand("goPageDown");
1135
+ is(!cm.somethingSelected());
1136
+ eqPos(cm.getCursor(), Pos(2, 4));
1137
+ cm.execCommand("goLineUp");
1138
+ cm.execCommand("goLineUp");
1139
+ eqPos(cm.getCursor(), Pos(0, 4));
1140
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
1141
+ cm.execCommand("goCharLeft");
1142
+ is(!cm.somethingSelected());
1143
+ eqPos(cm.getCursor(), Pos(0, 1));
1144
+ }, {value: "aaaaa\nb\nccccc"});
1145
+
1146
+ testCM("clickTab", function(cm) {
1147
+ var p0 = cm.charCoords(Pos(0, 0));
1148
+ eqPos(cm.coordsChar({left: p0.left + 5, top: p0.top + 5}), Pos(0, 0));
1149
+ eqPos(cm.coordsChar({left: p0.right - 5, top: p0.top + 5}), Pos(0, 1));
1150
+ }, {value: "\t\n\n", lineWrapping: true, tabSize: 8});
1151
+
1152
+ testCM("verticalScroll", function(cm) {
1153
+ cm.setSize(100, 200);
1154
+ cm.setValue("foo\nbar\nbaz\n");
1155
+ var sc = cm.getScrollerElement(), baseWidth = sc.scrollWidth;
1156
+ cm.replaceRange("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah", Pos(0, 0), Pos(0));
1157
+ is(sc.scrollWidth > baseWidth, "scrollbar present");
1158
+ cm.replaceRange("foo", Pos(0, 0), Pos(0));
1159
+ if (!phantom) eq(sc.scrollWidth, baseWidth, "scrollbar gone");
1160
+ cm.replaceRange("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah", Pos(0, 0), Pos(0));
1161
+ cm.replaceRange("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh", Pos(1, 0), Pos(1));
1162
+ is(sc.scrollWidth > baseWidth, "present again");
1163
+ var curWidth = sc.scrollWidth;
1164
+ cm.replaceRange("foo", Pos(0, 0), Pos(0));
1165
+ is(sc.scrollWidth < curWidth, "scrollbar smaller");
1166
+ is(sc.scrollWidth > baseWidth, "but still present");
1167
+ });
1168
+
1169
+ testCM("extraKeys", function(cm) {
1170
+ var outcome;
1171
+ function fakeKey(expected, code, props) {
1172
+ if (typeof code == "string") code = code.charCodeAt(0);
1173
+ var e = {type: "keydown", keyCode: code, preventDefault: function(){}, stopPropagation: function(){}};
1174
+ if (props) for (var n in props) e[n] = props[n];
1175
+ outcome = null;
1176
+ cm.triggerOnKeyDown(e);
1177
+ eq(outcome, expected);
1178
+ }
1179
+ CodeMirror.commands.testCommand = function() {outcome = "tc";};
1180
+ CodeMirror.commands.goTestCommand = function() {outcome = "gtc";};
1181
+ cm.setOption("extraKeys", {"Shift-X": function() {outcome = "sx";},
1182
+ "X": function() {outcome = "x";},
1183
+ "Ctrl-Alt-U": function() {outcome = "cau";},
1184
+ "End": "testCommand",
1185
+ "Home": "goTestCommand",
1186
+ "Tab": false});
1187
+ fakeKey(null, "U");
1188
+ fakeKey("cau", "U", {ctrlKey: true, altKey: true});
1189
+ fakeKey(null, "U", {shiftKey: true, ctrlKey: true, altKey: true});
1190
+ fakeKey("x", "X");
1191
+ fakeKey("sx", "X", {shiftKey: true});
1192
+ fakeKey("tc", 35);
1193
+ fakeKey(null, 35, {shiftKey: true});
1194
+ fakeKey("gtc", 36);
1195
+ fakeKey("gtc", 36, {shiftKey: true});
1196
+ fakeKey(null, 9);
1197
+ }, null, window.opera && mac);
1198
+
1199
+ testCM("wordMovementCommands", function(cm) {
1200
+ cm.execCommand("goWordLeft");
1201
+ eqPos(cm.getCursor(), Pos(0, 0));
1202
+ cm.execCommand("goWordRight"); cm.execCommand("goWordRight");
1203
+ eqPos(cm.getCursor(), Pos(0, 7));
1204
+ cm.execCommand("goWordLeft");
1205
+ eqPos(cm.getCursor(), Pos(0, 5));
1206
+ cm.execCommand("goWordRight"); cm.execCommand("goWordRight");
1207
+ eqPos(cm.getCursor(), Pos(0, 12));
1208
+ cm.execCommand("goWordLeft");
1209
+ eqPos(cm.getCursor(), Pos(0, 9));
1210
+ cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); cm.execCommand("goWordRight");
1211
+ eqPos(cm.getCursor(), Pos(0, 24));
1212
+ cm.execCommand("goWordRight"); cm.execCommand("goWordRight");
1213
+ eqPos(cm.getCursor(), Pos(1, 9));
1214
+ cm.execCommand("goWordRight");
1215
+ eqPos(cm.getCursor(), Pos(1, 13));
1216
+ cm.execCommand("goWordRight"); cm.execCommand("goWordRight");
1217
+ eqPos(cm.getCursor(), Pos(2, 0));
1218
+ }, {value: "this is (the) firstline.\na foo12\u00e9\u00f8\u00d7bar\n"});
1219
+
1220
+ testCM("groupMovementCommands", function(cm) {
1221
+ cm.execCommand("goGroupLeft");
1222
+ eqPos(cm.getCursor(), Pos(0, 0));
1223
+ cm.execCommand("goGroupRight");
1224
+ eqPos(cm.getCursor(), Pos(0, 4));
1225
+ cm.execCommand("goGroupRight");
1226
+ eqPos(cm.getCursor(), Pos(0, 7));
1227
+ cm.execCommand("goGroupRight");
1228
+ eqPos(cm.getCursor(), Pos(0, 10));
1229
+ cm.execCommand("goGroupLeft");
1230
+ eqPos(cm.getCursor(), Pos(0, 7));
1231
+ cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight");
1232
+ eqPos(cm.getCursor(), Pos(0, 15));
1233
+ cm.setCursor(Pos(0, 17));
1234
+ cm.execCommand("goGroupLeft");
1235
+ eqPos(cm.getCursor(), Pos(0, 16));
1236
+ cm.execCommand("goGroupLeft");
1237
+ eqPos(cm.getCursor(), Pos(0, 14));
1238
+ cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight");
1239
+ eqPos(cm.getCursor(), Pos(0, 20));
1240
+ cm.execCommand("goGroupRight");
1241
+ eqPos(cm.getCursor(), Pos(1, 0));
1242
+ cm.execCommand("goGroupRight");
1243
+ eqPos(cm.getCursor(), Pos(1, 2));
1244
+ cm.execCommand("goGroupRight");
1245
+ eqPos(cm.getCursor(), Pos(1, 5));
1246
+ cm.execCommand("goGroupLeft"); cm.execCommand("goGroupLeft");
1247
+ eqPos(cm.getCursor(), Pos(1, 0));
1248
+ cm.execCommand("goGroupLeft");
1249
+ eqPos(cm.getCursor(), Pos(0, 20));
1250
+ cm.execCommand("goGroupLeft");
1251
+ eqPos(cm.getCursor(), Pos(0, 16));
1252
+ }, {value: "booo ba---quux. ffff\n abc d"});
1253
+
1254
+ testCM("groupsAndWhitespace", function(cm) {
1255
+ var positions = [Pos(0, 0), Pos(0, 2), Pos(0, 5), Pos(0, 9), Pos(0, 11),
1256
+ Pos(1, 0), Pos(1, 2), Pos(1, 5)];
1257
+ for (var i = 1; i < positions.length; i++) {
1258
+ cm.execCommand("goGroupRight");
1259
+ eqPos(cm.getCursor(), positions[i]);
1260
+ }
1261
+ for (var i = positions.length - 2; i >= 0; i--) {
1262
+ cm.execCommand("goGroupLeft");
1263
+ eqPos(cm.getCursor(), i == 2 ? Pos(0, 6) : positions[i]);
1264
+ }
1265
+ }, {value: " foo +++ \n bar"});
1266
+
1267
+ testCM("charMovementCommands", function(cm) {
1268
+ cm.execCommand("goCharLeft"); cm.execCommand("goColumnLeft");
1269
+ eqPos(cm.getCursor(), Pos(0, 0));
1270
+ cm.execCommand("goCharRight"); cm.execCommand("goCharRight");
1271
+ eqPos(cm.getCursor(), Pos(0, 2));
1272
+ cm.setCursor(Pos(1, 0));
1273
+ cm.execCommand("goColumnLeft");
1274
+ eqPos(cm.getCursor(), Pos(1, 0));
1275
+ cm.execCommand("goCharLeft");
1276
+ eqPos(cm.getCursor(), Pos(0, 5));
1277
+ cm.execCommand("goColumnRight");
1278
+ eqPos(cm.getCursor(), Pos(0, 5));
1279
+ cm.execCommand("goCharRight");
1280
+ eqPos(cm.getCursor(), Pos(1, 0));
1281
+ cm.execCommand("goLineEnd");
1282
+ eqPos(cm.getCursor(), Pos(1, 5));
1283
+ cm.execCommand("goLineStartSmart");
1284
+ eqPos(cm.getCursor(), Pos(1, 1));
1285
+ cm.execCommand("goLineStartSmart");
1286
+ eqPos(cm.getCursor(), Pos(1, 0));
1287
+ cm.setCursor(Pos(2, 0));
1288
+ cm.execCommand("goCharRight"); cm.execCommand("goColumnRight");
1289
+ eqPos(cm.getCursor(), Pos(2, 0));
1290
+ }, {value: "line1\n ine2\n"});
1291
+
1292
+ testCM("verticalMovementCommands", function(cm) {
1293
+ cm.execCommand("goLineUp");
1294
+ eqPos(cm.getCursor(), Pos(0, 0));
1295
+ cm.execCommand("goLineDown");
1296
+ if (!phantom) // This fails in PhantomJS, though not in a real Webkit
1297
+ eqPos(cm.getCursor(), Pos(1, 0));
1298
+ cm.setCursor(Pos(1, 12));
1299
+ cm.execCommand("goLineDown");
1300
+ eqPos(cm.getCursor(), Pos(2, 5));
1301
+ cm.execCommand("goLineDown");
1302
+ eqPos(cm.getCursor(), Pos(3, 0));
1303
+ cm.execCommand("goLineUp");
1304
+ eqPos(cm.getCursor(), Pos(2, 5));
1305
+ cm.execCommand("goLineUp");
1306
+ eqPos(cm.getCursor(), Pos(1, 12));
1307
+ cm.execCommand("goPageDown");
1308
+ eqPos(cm.getCursor(), Pos(5, 0));
1309
+ cm.execCommand("goPageDown"); cm.execCommand("goLineDown");
1310
+ eqPos(cm.getCursor(), Pos(5, 0));
1311
+ cm.execCommand("goPageUp");
1312
+ eqPos(cm.getCursor(), Pos(0, 0));
1313
+ }, {value: "line1\nlong long line2\nline3\n\nline5\n"});
1314
+
1315
+ testCM("verticalMovementCommandsWrapping", function(cm) {
1316
+ cm.setSize(120);
1317
+ cm.setCursor(Pos(0, 5));
1318
+ cm.execCommand("goLineDown");
1319
+ eq(cm.getCursor().line, 0);
1320
+ is(cm.getCursor().ch > 5, "moved beyond wrap");
1321
+ for (var i = 0; ; ++i) {
1322
+ is(i < 20, "no endless loop");
1323
+ cm.execCommand("goLineDown");
1324
+ var cur = cm.getCursor();
1325
+ if (cur.line == 1) eq(cur.ch, 5);
1326
+ if (cur.line == 2) { eq(cur.ch, 1); break; }
1327
+ }
1328
+ }, {value: "a very long line that wraps around somehow so that we can test cursor movement\nshortone\nk",
1329
+ lineWrapping: true});
1330
+
1331
+ testCM("rtlMovement", function(cm) {
1332
+ if (cm.getOption("inputStyle") != "textarea") return;
1333
+ forEach(["خحج", "خحabcخحج", "abخحخحجcd", "abخde", "abخح2342خ1حج", "خ1ح2خح3حxج",
1334
+ "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!", "foobarر", "خ ة ق",
1335
+ "<img src=\"/בדיקה3.jpg\">", "يتم السحب في 05 فبراير 2014"], function(line) {
1336
+ var inv = line.charCodeAt(0) > 128;
1337
+ cm.setValue(line + "\n"); cm.execCommand(inv ? "goLineEnd" : "goLineStart");
1338
+ var cursors = byClassName(cm.getWrapperElement(), "CodeMirror-cursors")[0];
1339
+ var cursor = cursors.firstChild;
1340
+ var prevX = cursor.offsetLeft, prevY = cursor.offsetTop;
1341
+ for (var i = 0; i <= line.length; ++i) {
1342
+ cm.execCommand("goCharRight");
1343
+ cursor = cursors.firstChild;
1344
+ if (i == line.length) is(cursor.offsetTop > prevY, "next line");
1345
+ else is(cursor.offsetLeft > prevX, "moved right");
1346
+ prevX = cursor.offsetLeft; prevY = cursor.offsetTop;
1347
+ }
1348
+ cm.setCursor(0, 0); cm.execCommand(inv ? "goLineStart" : "goLineEnd");
1349
+ prevX = cursors.firstChild.offsetLeft;
1350
+ for (var i = 0; i < line.length; ++i) {
1351
+ cm.execCommand("goCharLeft");
1352
+ cursor = cursors.firstChild;
1353
+ is(cursor.offsetLeft < prevX, "moved left");
1354
+ prevX = cursor.offsetLeft;
1355
+ }
1356
+ });
1357
+ }, null, ie_lt9);
1358
+
1359
+ // Verify that updating a line clears its bidi ordering
1360
+ testCM("bidiUpdate", function(cm) {
1361
+ cm.setCursor(Pos(0, 2));
1362
+ cm.replaceSelection("خحج", "start");
1363
+ cm.execCommand("goCharRight");
1364
+ eqPos(cm.getCursor(), Pos(0, 4));
1365
+ }, {value: "abcd\n"});
1366
+
1367
+ testCM("movebyTextUnit", function(cm) {
1368
+ cm.setValue("בְּרֵאשִ\nééé́\n");
1369
+ cm.execCommand("goLineEnd");
1370
+ for (var i = 0; i < 4; ++i) cm.execCommand("goCharRight");
1371
+ eqPos(cm.getCursor(), Pos(0, 0));
1372
+ cm.execCommand("goCharRight");
1373
+ eqPos(cm.getCursor(), Pos(1, 0));
1374
+ cm.execCommand("goCharRight");
1375
+ cm.execCommand("goCharRight");
1376
+ eqPos(cm.getCursor(), Pos(1, 4));
1377
+ cm.execCommand("goCharRight");
1378
+ eqPos(cm.getCursor(), Pos(1, 7));
1379
+ });
1380
+
1381
+ testCM("lineChangeEvents", function(cm) {
1382
+ addDoc(cm, 3, 5);
1383
+ var log = [], want = ["ch 0", "ch 1", "del 2", "ch 0", "ch 0", "del 1", "del 3", "del 4"];
1384
+ for (var i = 0; i < 5; ++i) {
1385
+ CodeMirror.on(cm.getLineHandle(i), "delete", function(i) {
1386
+ return function() {log.push("del " + i);};
1387
+ }(i));
1388
+ CodeMirror.on(cm.getLineHandle(i), "change", function(i) {
1389
+ return function() {log.push("ch " + i);};
1390
+ }(i));
1391
+ }
1392
+ cm.replaceRange("x", Pos(0, 1));
1393
+ cm.replaceRange("xy", Pos(1, 1), Pos(2));
1394
+ cm.replaceRange("foo\nbar", Pos(0, 1));
1395
+ cm.replaceRange("", Pos(0, 0), Pos(cm.lineCount()));
1396
+ eq(log.length, want.length, "same length");
1397
+ for (var i = 0; i < log.length; ++i)
1398
+ eq(log[i], want[i]);
1399
+ });
1400
+
1401
+ testCM("scrollEntirelyToRight", function(cm) {
1402
+ if (phantom || cm.getOption("inputStyle") != "textarea") return;
1403
+ addDoc(cm, 500, 2);
1404
+ cm.setCursor(Pos(0, 500));
1405
+ var wrap = cm.getWrapperElement(), cur = byClassName(wrap, "CodeMirror-cursor")[0];
1406
+ is(wrap.getBoundingClientRect().right > cur.getBoundingClientRect().left);
1407
+ });
1408
+
1409
+ testCM("lineWidgets", function(cm) {
1410
+ addDoc(cm, 500, 3);
1411
+ var last = cm.charCoords(Pos(2, 0));
1412
+ var node = document.createElement("div");
1413
+ node.innerHTML = "hi";
1414
+ var widget = cm.addLineWidget(1, node);
1415
+ is(last.top < cm.charCoords(Pos(2, 0)).top, "took up space");
1416
+ cm.setCursor(Pos(1, 1));
1417
+ cm.execCommand("goLineDown");
1418
+ eqPos(cm.getCursor(), Pos(2, 1));
1419
+ cm.execCommand("goLineUp");
1420
+ eqPos(cm.getCursor(), Pos(1, 1));
1421
+ });
1422
+
1423
+ testCM("lineWidgetFocus", function(cm) {
1424
+ var place = document.getElementById("testground");
1425
+ place.className = "offscreen";
1426
+ try {
1427
+ addDoc(cm, 500, 10);
1428
+ var node = document.createElement("input");
1429
+ var widget = cm.addLineWidget(1, node);
1430
+ node.focus();
1431
+ eq(document.activeElement, node);
1432
+ cm.replaceRange("new stuff", Pos(1, 0));
1433
+ eq(document.activeElement, node);
1434
+ } finally {
1435
+ place.className = "";
1436
+ }
1437
+ });
1438
+
1439
+ testCM("lineWidgetCautiousRedraw", function(cm) {
1440
+ var node = document.createElement("div");
1441
+ node.innerHTML = "hahah";
1442
+ var w = cm.addLineWidget(0, node);
1443
+ var redrawn = false;
1444
+ w.on("redraw", function() { redrawn = true; });
1445
+ cm.replaceSelection("0");
1446
+ is(!redrawn);
1447
+ }, {value: "123\n456"});
1448
+
1449
+
1450
+ var knownScrollbarWidth;
1451
+ function scrollbarWidth(measure) {
1452
+ if (knownScrollbarWidth != null) return knownScrollbarWidth;
1453
+ var div = document.createElement('div');
1454
+ div.style.cssText = "width: 50px; height: 50px; overflow-x: scroll";
1455
+ document.body.appendChild(div);
1456
+ knownScrollbarWidth = div.offsetHeight - div.clientHeight;
1457
+ document.body.removeChild(div);
1458
+ return knownScrollbarWidth || 0;
1459
+ }
1460
+
1461
+ testCM("lineWidgetChanged", function(cm) {
1462
+ addDoc(cm, 2, 300);
1463
+ var halfScrollbarWidth = scrollbarWidth(cm.display.measure)/2;
1464
+ cm.setOption('lineNumbers', true);
1465
+ cm.setSize(600, cm.defaultTextHeight() * 50);
1466
+ cm.scrollTo(null, cm.heightAtLine(125, "local"));
1467
+
1468
+ var expectedWidgetHeight = 60;
1469
+ var expectedLinesInWidget = 3;
1470
+ function w() {
1471
+ var node = document.createElement("div");
1472
+ // we use these children with just under half width of the line to check measurements are made with correct width
1473
+ // when placed in the measure div.
1474
+ // If the widget is measured at a width much narrower than it is displayed at, the underHalf children will span two lines and break the test.
1475
+ // If the widget is measured at a width much wider than it is displayed at, the overHalf children will combine and break the test.
1476
+ // Note that this test only checks widgets where coverGutter is true, because these require extra styling to get the width right.
1477
+ // It may also be worthwhile to check this for non-coverGutter widgets.
1478
+ // Visually:
1479
+ // Good:
1480
+ // | ------------- display width ------------- |
1481
+ // | ------- widget-width when measured ------ |
1482
+ // | | -- under-half -- | | -- under-half -- | |
1483
+ // | | --- over-half --- | |
1484
+ // | | --- over-half --- | |
1485
+ // Height: measured as 3 lines, same as it will be when actually displayed
1486
+
1487
+ // Bad (too narrow):
1488
+ // | ------------- display width ------------- |
1489
+ // | ------ widget-width when measured ----- | < -- uh oh
1490
+ // | | -- under-half -- | |
1491
+ // | | -- under-half -- | | < -- when measured, shoved to next line
1492
+ // | | --- over-half --- | |
1493
+ // | | --- over-half --- | |
1494
+ // Height: measured as 4 lines, more than expected . Will be displayed as 3 lines!
1495
+
1496
+ // Bad (too wide):
1497
+ // | ------------- display width ------------- |
1498
+ // | -------- widget-width when measured ------- | < -- uh oh
1499
+ // | | -- under-half -- | | -- under-half -- | |
1500
+ // | | --- over-half --- | | --- over-half --- | | < -- when measured, combined on one line
1501
+ // Height: measured as 2 lines, less than expected. Will be displayed as 3 lines!
1502
+
1503
+ var barelyUnderHalfWidthHtml = '<div style="display: inline-block; height: 1px; width: '+(285 - halfScrollbarWidth)+'px;"></div>';
1504
+ var barelyOverHalfWidthHtml = '<div style="display: inline-block; height: 1px; width: '+(305 - halfScrollbarWidth)+'px;"></div>';
1505
+ node.innerHTML = new Array(3).join(barelyUnderHalfWidthHtml) + new Array(3).join(barelyOverHalfWidthHtml);
1506
+ node.style.cssText = "background: yellow;font-size:0;line-height: " + (expectedWidgetHeight/expectedLinesInWidget) + "px;";
1507
+ return node;
1508
+ }
1509
+ var info0 = cm.getScrollInfo();
1510
+ var w0 = cm.addLineWidget(0, w(), { coverGutter: true });
1511
+ var w150 = cm.addLineWidget(150, w(), { coverGutter: true });
1512
+ var w300 = cm.addLineWidget(300, w(), { coverGutter: true });
1513
+ var info1 = cm.getScrollInfo();
1514
+ eq(info0.height + (3 * expectedWidgetHeight), info1.height);
1515
+ eq(info0.top + expectedWidgetHeight, info1.top);
1516
+ expectedWidgetHeight = 12;
1517
+ w0.node.style.lineHeight = w150.node.style.lineHeight = w300.node.style.lineHeight = (expectedWidgetHeight/expectedLinesInWidget) + "px";
1518
+ w0.changed(); w150.changed(); w300.changed();
1519
+ var info2 = cm.getScrollInfo();
1520
+ eq(info0.height + (3 * expectedWidgetHeight), info2.height);
1521
+ eq(info0.top + expectedWidgetHeight, info2.top);
1522
+ });
1523
+
1524
+ testCM("getLineNumber", function(cm) {
1525
+ addDoc(cm, 2, 20);
1526
+ var h1 = cm.getLineHandle(1);
1527
+ eq(cm.getLineNumber(h1), 1);
1528
+ cm.replaceRange("hi\nbye\n", Pos(0, 0));
1529
+ eq(cm.getLineNumber(h1), 3);
1530
+ cm.setValue("");
1531
+ eq(cm.getLineNumber(h1), null);
1532
+ });
1533
+
1534
+ testCM("jumpTheGap", function(cm) {
1535
+ if (phantom) return;
1536
+ var longLine = "abcdef ghiklmnop qrstuvw xyz ";
1537
+ longLine += longLine; longLine += longLine; longLine += longLine;
1538
+ cm.replaceRange(longLine, Pos(2, 0), Pos(2));
1539
+ cm.setSize("200px", null);
1540
+ cm.getWrapperElement().style.lineHeight = 2;
1541
+ cm.refresh();
1542
+ cm.setCursor(Pos(0, 1));
1543
+ cm.execCommand("goLineDown");
1544
+ eqPos(cm.getCursor(), Pos(1, 1));
1545
+ cm.execCommand("goLineDown");
1546
+ eqPos(cm.getCursor(), Pos(2, 1));
1547
+ cm.execCommand("goLineDown");
1548
+ eq(cm.getCursor().line, 2);
1549
+ is(cm.getCursor().ch > 1);
1550
+ cm.execCommand("goLineUp");
1551
+ eqPos(cm.getCursor(), Pos(2, 1));
1552
+ cm.execCommand("goLineUp");
1553
+ eqPos(cm.getCursor(), Pos(1, 1));
1554
+ var node = document.createElement("div");
1555
+ node.innerHTML = "hi"; node.style.height = "30px";
1556
+ cm.addLineWidget(0, node);
1557
+ cm.addLineWidget(1, node.cloneNode(true), {above: true});
1558
+ cm.setCursor(Pos(0, 2));
1559
+ cm.execCommand("goLineDown");
1560
+ eqPos(cm.getCursor(), Pos(1, 2));
1561
+ cm.execCommand("goLineUp");
1562
+ eqPos(cm.getCursor(), Pos(0, 2));
1563
+ }, {lineWrapping: true, value: "abc\ndef\nghi\njkl\n"});
1564
+
1565
+ testCM("addLineClass", function(cm) {
1566
+ function cls(line, text, bg, wrap, gutter) {
1567
+ var i = cm.lineInfo(line);
1568
+ eq(i.textClass, text);
1569
+ eq(i.bgClass, bg);
1570
+ eq(i.wrapClass, wrap);
1571
+ if (typeof i.handle.gutterClass !== 'undefined') {
1572
+ eq(i.handle.gutterClass, gutter);
1573
+ }
1574
+ }
1575
+ cm.addLineClass(0, "text", "foo");
1576
+ cm.addLineClass(0, "text", "bar");
1577
+ cm.addLineClass(1, "background", "baz");
1578
+ cm.addLineClass(1, "wrap", "foo");
1579
+ cm.addLineClass(1, "gutter", "gutter-class");
1580
+ cls(0, "foo bar", null, null, null);
1581
+ cls(1, null, "baz", "foo", "gutter-class");
1582
+ var lines = cm.display.lineDiv;
1583
+ eq(byClassName(lines, "foo").length, 2);
1584
+ eq(byClassName(lines, "bar").length, 1);
1585
+ eq(byClassName(lines, "baz").length, 1);
1586
+ eq(byClassName(lines, "gutter-class").length, 2); // Gutter classes are reflected in 2 nodes
1587
+ cm.removeLineClass(0, "text", "foo");
1588
+ cls(0, "bar", null, null, null);
1589
+ cm.removeLineClass(0, "text", "foo");
1590
+ cls(0, "bar", null, null, null);
1591
+ cm.removeLineClass(0, "text", "bar");
1592
+ cls(0, null, null, null);
1593
+
1594
+ cm.addLineClass(1, "wrap", "quux");
1595
+ cls(1, null, "baz", "foo quux", "gutter-class");
1596
+ cm.removeLineClass(1, "wrap");
1597
+ cls(1, null, "baz", null, "gutter-class");
1598
+ cm.removeLineClass(1, "gutter", "gutter-class");
1599
+ eq(byClassName(lines, "gutter-class").length, 0);
1600
+ cls(1, null, "baz", null, null);
1601
+
1602
+ cm.addLineClass(1, "gutter", "gutter-class");
1603
+ cls(1, null, "baz", null, "gutter-class");
1604
+ cm.removeLineClass(1, "gutter", "gutter-class");
1605
+ cls(1, null, "baz", null, null);
1606
+
1607
+ }, {value: "hohoho\n", lineNumbers: true});
1608
+
1609
+ testCM("atomicMarker", function(cm) {
1610
+ addDoc(cm, 10, 10);
1611
+ function atom(ll, cl, lr, cr, li, ri) {
1612
+ return cm.markText(Pos(ll, cl), Pos(lr, cr),
1613
+ {atomic: true, inclusiveLeft: li, inclusiveRight: ri});
1614
+ }
1615
+ var m = atom(0, 1, 0, 5);
1616
+ cm.setCursor(Pos(0, 1));
1617
+ cm.execCommand("goCharRight");
1618
+ eqPos(cm.getCursor(), Pos(0, 5));
1619
+ cm.execCommand("goCharLeft");
1620
+ eqPos(cm.getCursor(), Pos(0, 1));
1621
+ m.clear();
1622
+ m = atom(0, 0, 0, 5, true);
1623
+ eqPos(cm.getCursor(), Pos(0, 5), "pushed out");
1624
+ cm.execCommand("goCharLeft");
1625
+ eqPos(cm.getCursor(), Pos(0, 5));
1626
+ m.clear();
1627
+ m = atom(8, 4, 9, 10, false, true);
1628
+ cm.setCursor(Pos(9, 8));
1629
+ eqPos(cm.getCursor(), Pos(8, 4), "set");
1630
+ cm.execCommand("goCharRight");
1631
+ eqPos(cm.getCursor(), Pos(8, 4), "char right");
1632
+ cm.execCommand("goLineDown");
1633
+ eqPos(cm.getCursor(), Pos(8, 4), "line down");
1634
+ cm.execCommand("goCharLeft");
1635
+ eqPos(cm.getCursor(), Pos(8, 3));
1636
+ m.clear();
1637
+ m = atom(1, 1, 3, 8);
1638
+ cm.setCursor(Pos(0, 0));
1639
+ cm.setCursor(Pos(2, 0));
1640
+ eqPos(cm.getCursor(), Pos(3, 8));
1641
+ cm.execCommand("goCharLeft");
1642
+ eqPos(cm.getCursor(), Pos(1, 1));
1643
+ cm.execCommand("goCharRight");
1644
+ eqPos(cm.getCursor(), Pos(3, 8));
1645
+ cm.execCommand("goLineUp");
1646
+ eqPos(cm.getCursor(), Pos(1, 1));
1647
+ cm.execCommand("goLineDown");
1648
+ eqPos(cm.getCursor(), Pos(3, 8));
1649
+ cm.execCommand("delCharBefore");
1650
+ eq(cm.getValue().length, 80, "del chunk");
1651
+ m = atom(3, 0, 5, 5);
1652
+ cm.setCursor(Pos(3, 0));
1653
+ cm.execCommand("delWordAfter");
1654
+ eq(cm.getValue().length, 53, "del chunk");
1655
+ });
1656
+
1657
+ testCM("selectionBias", function(cm) {
1658
+ cm.markText(Pos(0, 1), Pos(0, 3), {atomic: true});
1659
+ cm.setCursor(Pos(0, 2));
1660
+ eqPos(cm.getCursor(), Pos(0, 3));
1661
+ cm.setCursor(Pos(0, 2));
1662
+ eqPos(cm.getCursor(), Pos(0, 1));
1663
+ cm.setCursor(Pos(0, 2), null, {bias: -1});
1664
+ eqPos(cm.getCursor(), Pos(0, 1));
1665
+ cm.setCursor(Pos(0, 4));
1666
+ cm.setCursor(Pos(0, 2), null, {bias: 1});
1667
+ eqPos(cm.getCursor(), Pos(0, 3));
1668
+ }, {value: "12345"});
1669
+
1670
+ testCM("selectionHomeEnd", function(cm) {
1671
+ cm.markText(Pos(1, 0), Pos(1, 1), {atomic: true, inclusiveLeft: true});
1672
+ cm.markText(Pos(1, 3), Pos(1, 4), {atomic: true, inclusiveRight: true});
1673
+ cm.setCursor(Pos(1, 2));
1674
+ cm.execCommand("goLineStart");
1675
+ eqPos(cm.getCursor(), Pos(1, 1));
1676
+ cm.execCommand("goLineEnd");
1677
+ eqPos(cm.getCursor(), Pos(1, 3));
1678
+ }, {value: "ab\ncdef\ngh"});
1679
+
1680
+ testCM("readOnlyMarker", function(cm) {
1681
+ function mark(ll, cl, lr, cr, at) {
1682
+ return cm.markText(Pos(ll, cl), Pos(lr, cr),
1683
+ {readOnly: true, atomic: at});
1684
+ }
1685
+ var m = mark(0, 1, 0, 4);
1686
+ cm.setCursor(Pos(0, 2));
1687
+ cm.replaceSelection("hi", "end");
1688
+ eqPos(cm.getCursor(), Pos(0, 2));
1689
+ eq(cm.getLine(0), "abcde");
1690
+ cm.execCommand("selectAll");
1691
+ cm.replaceSelection("oops", "around");
1692
+ eq(cm.getValue(), "oopsbcd");
1693
+ cm.undo();
1694
+ eqPos(m.find().from, Pos(0, 1));
1695
+ eqPos(m.find().to, Pos(0, 4));
1696
+ m.clear();
1697
+ cm.setCursor(Pos(0, 2));
1698
+ cm.replaceSelection("hi", "around");
1699
+ eq(cm.getLine(0), "abhicde");
1700
+ eqPos(cm.getCursor(), Pos(0, 4));
1701
+ m = mark(0, 2, 2, 2, true);
1702
+ cm.setSelection(Pos(1, 1), Pos(2, 4));
1703
+ cm.replaceSelection("t", "end");
1704
+ eqPos(cm.getCursor(), Pos(2, 3));
1705
+ eq(cm.getLine(2), "klto");
1706
+ cm.execCommand("goCharLeft");
1707
+ cm.execCommand("goCharLeft");
1708
+ eqPos(cm.getCursor(), Pos(0, 2));
1709
+ cm.setSelection(Pos(0, 1), Pos(0, 3));
1710
+ cm.replaceSelection("xx", "around");
1711
+ eqPos(cm.getCursor(), Pos(0, 3));
1712
+ eq(cm.getLine(0), "axxhicde");
1713
+ }, {value: "abcde\nfghij\nklmno\n"});
1714
+
1715
+ testCM("dirtyBit", function(cm) {
1716
+ eq(cm.isClean(), true);
1717
+ cm.replaceSelection("boo", null, "test");
1718
+ eq(cm.isClean(), false);
1719
+ cm.undo();
1720
+ eq(cm.isClean(), true);
1721
+ cm.replaceSelection("boo", null, "test");
1722
+ cm.replaceSelection("baz", null, "test");
1723
+ cm.undo();
1724
+ eq(cm.isClean(), false);
1725
+ cm.markClean();
1726
+ eq(cm.isClean(), true);
1727
+ cm.undo();
1728
+ eq(cm.isClean(), false);
1729
+ cm.redo();
1730
+ eq(cm.isClean(), true);
1731
+ });
1732
+
1733
+ testCM("changeGeneration", function(cm) {
1734
+ cm.replaceSelection("x");
1735
+ var softGen = cm.changeGeneration();
1736
+ cm.replaceSelection("x");
1737
+ cm.undo();
1738
+ eq(cm.getValue(), "");
1739
+ is(!cm.isClean(softGen));
1740
+ cm.replaceSelection("x");
1741
+ var hardGen = cm.changeGeneration(true);
1742
+ cm.replaceSelection("x");
1743
+ cm.undo();
1744
+ eq(cm.getValue(), "x");
1745
+ is(cm.isClean(hardGen));
1746
+ });
1747
+
1748
+ testCM("addKeyMap", function(cm) {
1749
+ function sendKey(code) {
1750
+ cm.triggerOnKeyDown({type: "keydown", keyCode: code,
1751
+ preventDefault: function(){}, stopPropagation: function(){}});
1752
+ }
1753
+
1754
+ sendKey(39);
1755
+ eqPos(cm.getCursor(), Pos(0, 1));
1756
+ var test = 0;
1757
+ var map1 = {Right: function() { ++test; }}, map2 = {Right: function() { test += 10; }}
1758
+ cm.addKeyMap(map1);
1759
+ sendKey(39);
1760
+ eqPos(cm.getCursor(), Pos(0, 1));
1761
+ eq(test, 1);
1762
+ cm.addKeyMap(map2, true);
1763
+ sendKey(39);
1764
+ eq(test, 2);
1765
+ cm.removeKeyMap(map1);
1766
+ sendKey(39);
1767
+ eq(test, 12);
1768
+ cm.removeKeyMap(map2);
1769
+ sendKey(39);
1770
+ eq(test, 12);
1771
+ eqPos(cm.getCursor(), Pos(0, 2));
1772
+ cm.addKeyMap({Right: function() { test = 55; }, name: "mymap"});
1773
+ sendKey(39);
1774
+ eq(test, 55);
1775
+ cm.removeKeyMap("mymap");
1776
+ sendKey(39);
1777
+ eqPos(cm.getCursor(), Pos(0, 3));
1778
+ }, {value: "abc"});
1779
+
1780
+ testCM("findPosH", function(cm) {
1781
+ forEach([{from: Pos(0, 0), to: Pos(0, 1), by: 1},
1782
+ {from: Pos(0, 0), to: Pos(0, 0), by: -1, hitSide: true},
1783
+ {from: Pos(0, 0), to: Pos(0, 4), by: 1, unit: "word"},
1784
+ {from: Pos(0, 0), to: Pos(0, 8), by: 2, unit: "word"},
1785
+ {from: Pos(0, 0), to: Pos(2, 0), by: 20, unit: "word", hitSide: true},
1786
+ {from: Pos(0, 7), to: Pos(0, 5), by: -1, unit: "word"},
1787
+ {from: Pos(0, 4), to: Pos(0, 8), by: 1, unit: "word"},
1788
+ {from: Pos(1, 0), to: Pos(1, 18), by: 3, unit: "word"},
1789
+ {from: Pos(1, 22), to: Pos(1, 5), by: -3, unit: "word"},
1790
+ {from: Pos(1, 15), to: Pos(1, 10), by: -5},
1791
+ {from: Pos(1, 15), to: Pos(1, 10), by: -5, unit: "column"},
1792
+ {from: Pos(1, 15), to: Pos(1, 0), by: -50, unit: "column", hitSide: true},
1793
+ {from: Pos(1, 15), to: Pos(1, 24), by: 50, unit: "column", hitSide: true},
1794
+ {from: Pos(1, 15), to: Pos(2, 0), by: 50, hitSide: true}], function(t) {
1795
+ var r = cm.findPosH(t.from, t.by, t.unit || "char");
1796
+ eqPos(r, t.to);
1797
+ eq(!!r.hitSide, !!t.hitSide);
1798
+ });
1799
+ }, {value: "line one\nline two.something.other\n"});
1800
+
1801
+ testCM("beforeChange", function(cm) {
1802
+ cm.on("beforeChange", function(cm, change) {
1803
+ var text = [];
1804
+ for (var i = 0; i < change.text.length; ++i)
1805
+ text.push(change.text[i].replace(/\s/g, "_"));
1806
+ change.update(null, null, text);
1807
+ });
1808
+ cm.setValue("hello, i am a\nnew document\n");
1809
+ eq(cm.getValue(), "hello,_i_am_a\nnew_document\n");
1810
+ CodeMirror.on(cm.getDoc(), "beforeChange", function(doc, change) {
1811
+ if (change.from.line == 0) change.cancel();
1812
+ });
1813
+ cm.setValue("oops"); // Canceled
1814
+ eq(cm.getValue(), "hello,_i_am_a\nnew_document\n");
1815
+ cm.replaceRange("hey hey hey", Pos(1, 0), Pos(2, 0));
1816
+ eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey");
1817
+ }, {value: "abcdefghijk"});
1818
+
1819
+ testCM("beforeChangeUndo", function(cm) {
1820
+ cm.replaceRange("hi", Pos(0, 0), Pos(0));
1821
+ cm.replaceRange("bye", Pos(0, 0), Pos(0));
1822
+ eq(cm.historySize().undo, 2);
1823
+ cm.on("beforeChange", function(cm, change) {
1824
+ is(!change.update);
1825
+ change.cancel();
1826
+ });
1827
+ cm.undo();
1828
+ eq(cm.historySize().undo, 0);
1829
+ eq(cm.getValue(), "bye\ntwo");
1830
+ }, {value: "one\ntwo"});
1831
+
1832
+ testCM("beforeSelectionChange", function(cm) {
1833
+ function notAtEnd(cm, pos) {
1834
+ var len = cm.getLine(pos.line).length;
1835
+ if (!len || pos.ch == len) return Pos(pos.line, pos.ch - 1);
1836
+ return pos;
1837
+ }
1838
+ cm.on("beforeSelectionChange", function(cm, obj) {
1839
+ obj.update([{anchor: notAtEnd(cm, obj.ranges[0].anchor),
1840
+ head: notAtEnd(cm, obj.ranges[0].head)}]);
1841
+ });
1842
+
1843
+ addDoc(cm, 10, 10);
1844
+ cm.execCommand("goLineEnd");
1845
+ eqPos(cm.getCursor(), Pos(0, 9));
1846
+ cm.execCommand("selectAll");
1847
+ eqPos(cm.getCursor("start"), Pos(0, 0));
1848
+ eqPos(cm.getCursor("end"), Pos(9, 9));
1849
+ });
1850
+
1851
+ testCM("change_removedText", function(cm) {
1852
+ cm.setValue("abc\ndef");
1853
+
1854
+ var removedText = [];
1855
+ cm.on("change", function(cm, change) {
1856
+ removedText.push(change.removed);
1857
+ });
1858
+
1859
+ cm.operation(function() {
1860
+ cm.replaceRange("xyz", Pos(0, 0), Pos(1,1));
1861
+ cm.replaceRange("123", Pos(0,0));
1862
+ });
1863
+
1864
+ eq(removedText.length, 2);
1865
+ eq(removedText[0].join("\n"), "abc\nd");
1866
+ eq(removedText[1].join("\n"), "");
1867
+
1868
+ var removedText = [];
1869
+ cm.undo();
1870
+ eq(removedText.length, 2);
1871
+ eq(removedText[0].join("\n"), "123");
1872
+ eq(removedText[1].join("\n"), "xyz");
1873
+
1874
+ var removedText = [];
1875
+ cm.redo();
1876
+ eq(removedText.length, 2);
1877
+ eq(removedText[0].join("\n"), "abc\nd");
1878
+ eq(removedText[1].join("\n"), "");
1879
+ });
1880
+
1881
+ testCM("lineStyleFromMode", function(cm) {
1882
+ CodeMirror.defineMode("test_mode", function() {
1883
+ return {token: function(stream) {
1884
+ if (stream.match(/^\[[^\]]*\]/)) return " line-brackets ";
1885
+ if (stream.match(/^\([^\)]*\)/)) return " line-background-parens ";
1886
+ if (stream.match(/^<[^>]*>/)) return " span line-line line-background-bg ";
1887
+ stream.match(/^\s+|^\S+/);
1888
+ }};
1889
+ });
1890
+ cm.setOption("mode", "test_mode");
1891
+ var bracketElts = byClassName(cm.getWrapperElement(), "brackets");
1892
+ eq(bracketElts.length, 1, "brackets count");
1893
+ eq(bracketElts[0].nodeName, "PRE");
1894
+ is(!/brackets.*brackets/.test(bracketElts[0].className));
1895
+ var parenElts = byClassName(cm.getWrapperElement(), "parens");
1896
+ eq(parenElts.length, 1, "parens count");
1897
+ eq(parenElts[0].nodeName, "DIV");
1898
+ is(!/parens.*parens/.test(parenElts[0].className));
1899
+ eq(parenElts[0].parentElement.nodeName, "DIV");
1900
+
1901
+ eq(byClassName(cm.getWrapperElement(), "bg").length, 1);
1902
+ eq(byClassName(cm.getWrapperElement(), "line").length, 1);
1903
+ var spanElts = byClassName(cm.getWrapperElement(), "cm-span");
1904
+ eq(spanElts.length, 2);
1905
+ is(/^\s*cm-span\s*$/.test(spanElts[0].className));
1906
+ }, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: <tag> <tag>"});
1907
+
1908
+ testCM("lineStyleFromBlankLine", function(cm) {
1909
+ CodeMirror.defineMode("lineStyleFromBlankLine_mode", function() {
1910
+ return {token: function(stream) { stream.skipToEnd(); return "comment"; },
1911
+ blankLine: function() { return "line-blank"; }};
1912
+ });
1913
+ cm.setOption("mode", "lineStyleFromBlankLine_mode");
1914
+ var blankElts = byClassName(cm.getWrapperElement(), "blank");
1915
+ eq(blankElts.length, 1);
1916
+ eq(blankElts[0].nodeName, "PRE");
1917
+ cm.replaceRange("x", Pos(1, 0));
1918
+ blankElts = byClassName(cm.getWrapperElement(), "blank");
1919
+ eq(blankElts.length, 0);
1920
+ }, {value: "foo\n\nbar"});
1921
+
1922
+ CodeMirror.registerHelper("xxx", "a", "A");
1923
+ CodeMirror.registerHelper("xxx", "b", "B");
1924
+ CodeMirror.defineMode("yyy", function() {
1925
+ return {
1926
+ token: function(stream) { stream.skipToEnd(); },
1927
+ xxx: ["a", "b", "q"]
1928
+ };
1929
+ });
1930
+ CodeMirror.registerGlobalHelper("xxx", "c", function(m) { return m.enableC; }, "C");
1931
+
1932
+ testCM("helpers", function(cm) {
1933
+ cm.setOption("mode", "yyy");
1934
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "A/B");
1935
+ cm.setOption("mode", {name: "yyy", modeProps: {xxx: "b", enableC: true}});
1936
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "B/C");
1937
+ cm.setOption("mode", "javascript");
1938
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "");
1939
+ });
1940
+
1941
+ testCM("selectionHistory", function(cm) {
1942
+ for (var i = 0; i < 3; i++) {
1943
+ cm.setExtending(true);
1944
+ cm.execCommand("goCharRight");
1945
+ cm.setExtending(false);
1946
+ cm.execCommand("goCharRight");
1947
+ cm.execCommand("goCharRight");
1948
+ }
1949
+ cm.execCommand("undoSelection");
1950
+ eq(cm.getSelection(), "c");
1951
+ cm.execCommand("undoSelection");
1952
+ eq(cm.getSelection(), "");
1953
+ eqPos(cm.getCursor(), Pos(0, 4));
1954
+ cm.execCommand("undoSelection");
1955
+ eq(cm.getSelection(), "b");
1956
+ cm.execCommand("redoSelection");
1957
+ eq(cm.getSelection(), "");
1958
+ eqPos(cm.getCursor(), Pos(0, 4));
1959
+ cm.execCommand("redoSelection");
1960
+ eq(cm.getSelection(), "c");
1961
+ cm.execCommand("redoSelection");
1962
+ eq(cm.getSelection(), "");
1963
+ eqPos(cm.getCursor(), Pos(0, 6));
1964
+ }, {value: "a b c d"});
1965
+
1966
+ testCM("selectionChangeReducesRedo", function(cm) {
1967
+ cm.replaceSelection("X");
1968
+ cm.execCommand("goCharRight");
1969
+ cm.undoSelection();
1970
+ cm.execCommand("selectAll");
1971
+ cm.undoSelection();
1972
+ eq(cm.getValue(), "Xabc");
1973
+ eqPos(cm.getCursor(), Pos(0, 1));
1974
+ cm.undoSelection();
1975
+ eq(cm.getValue(), "abc");
1976
+ }, {value: "abc"});
1977
+
1978
+ testCM("selectionHistoryNonOverlapping", function(cm) {
1979
+ cm.setSelection(Pos(0, 0), Pos(0, 1));
1980
+ cm.setSelection(Pos(0, 2), Pos(0, 3));
1981
+ cm.execCommand("undoSelection");
1982
+ eqPos(cm.getCursor("anchor"), Pos(0, 0));
1983
+ eqPos(cm.getCursor("head"), Pos(0, 1));
1984
+ }, {value: "1234"});
1985
+
1986
+ testCM("cursorMotionSplitsHistory", function(cm) {
1987
+ cm.replaceSelection("a");
1988
+ cm.execCommand("goCharRight");
1989
+ cm.replaceSelection("b");
1990
+ cm.replaceSelection("c");
1991
+ cm.undo();
1992
+ eq(cm.getValue(), "a1234");
1993
+ eqPos(cm.getCursor(), Pos(0, 2));
1994
+ cm.undo();
1995
+ eq(cm.getValue(), "1234");
1996
+ eqPos(cm.getCursor(), Pos(0, 0));
1997
+ }, {value: "1234"});
1998
+
1999
+ testCM("selChangeInOperationDoesNotSplit", function(cm) {
2000
+ for (var i = 0; i < 4; i++) {
2001
+ cm.operation(function() {
2002
+ cm.replaceSelection("x");
2003
+ cm.setCursor(Pos(0, cm.getCursor().ch - 1));
2004
+ });
2005
+ }
2006
+ eqPos(cm.getCursor(), Pos(0, 0));
2007
+ eq(cm.getValue(), "xxxxa");
2008
+ cm.undo();
2009
+ eq(cm.getValue(), "a");
2010
+ }, {value: "a"});
2011
+
2012
+ testCM("alwaysMergeSelEventWithChangeOrigin", function(cm) {
2013
+ cm.replaceSelection("U", null, "foo");
2014
+ cm.setSelection(Pos(0, 0), Pos(0, 1), {origin: "foo"});
2015
+ cm.undoSelection();
2016
+ eq(cm.getValue(), "a");
2017
+ cm.replaceSelection("V", null, "foo");
2018
+ cm.setSelection(Pos(0, 0), Pos(0, 1), {origin: "bar"});
2019
+ cm.undoSelection();
2020
+ eq(cm.getValue(), "Va");
2021
+ }, {value: "a"});
2022
+
2023
+ testCM("getTokenAt", function(cm) {
2024
+ var tokPlus = cm.getTokenAt(Pos(0, 2));
2025
+ eq(tokPlus.type, "operator");
2026
+ eq(tokPlus.string, "+");
2027
+ var toks = cm.getLineTokens(0);
2028
+ eq(toks.length, 3);
2029
+ forEach([["number", "1"], ["operator", "+"], ["number", "2"]], function(expect, i) {
2030
+ eq(toks[i].type, expect[0]);
2031
+ eq(toks[i].string, expect[1]);
2032
+ });
2033
+ }, {value: "1+2", mode: "javascript"});
2034
+
2035
+ testCM("getTokenTypeAt", function(cm) {
2036
+ eq(cm.getTokenTypeAt(Pos(0, 0)), "number");
2037
+ eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
2038
+ cm.addOverlay({
2039
+ token: function(stream) {
2040
+ if (stream.match("foo")) return "foo";
2041
+ else stream.next();
2042
+ }
2043
+ });
2044
+ eq(byClassName(cm.getWrapperElement(), "cm-foo").length, 1);
2045
+ eq(cm.getTokenTypeAt(Pos(0, 6)), "string");
2046
+ }, {value: "1 + 'foo'", mode: "javascript"});
2047
+
2048
+ testCM("resizeLineWidget", function(cm) {
2049
+ addDoc(cm, 200, 3);
2050
+ var widget = document.createElement("pre");
2051
+ widget.innerHTML = "imwidget";
2052
+ widget.style.background = "yellow";
2053
+ cm.addLineWidget(1, widget, {noHScroll: true});
2054
+ cm.setSize(40);
2055
+ is(widget.parentNode.offsetWidth < 42);
2056
+ });
2057
+
2058
+ testCM("combinedOperations", function(cm) {
2059
+ var place = document.getElementById("testground");
2060
+ var other = CodeMirror(place, {value: "123"});
2061
+ try {
2062
+ cm.operation(function() {
2063
+ cm.addLineClass(0, "wrap", "foo");
2064
+ other.addLineClass(0, "wrap", "foo");
2065
+ });
2066
+ eq(byClassName(cm.getWrapperElement(), "foo").length, 1);
2067
+ eq(byClassName(other.getWrapperElement(), "foo").length, 1);
2068
+ cm.operation(function() {
2069
+ cm.removeLineClass(0, "wrap", "foo");
2070
+ other.removeLineClass(0, "wrap", "foo");
2071
+ });
2072
+ eq(byClassName(cm.getWrapperElement(), "foo").length, 0);
2073
+ eq(byClassName(other.getWrapperElement(), "foo").length, 0);
2074
+ } finally {
2075
+ place.removeChild(other.getWrapperElement());
2076
+ }
2077
+ }, {value: "abc"});
2078
+
2079
+ testCM("eventOrder", function(cm) {
2080
+ var seen = [];
2081
+ cm.on("change", function() {
2082
+ if (!seen.length) cm.replaceSelection(".");
2083
+ seen.push("change");
2084
+ });
2085
+ cm.on("cursorActivity", function() {
2086
+ cm.replaceSelection("!");
2087
+ seen.push("activity");
2088
+ });
2089
+ cm.replaceSelection("/");
2090
+ eq(seen.join(","), "change,change,activity,change");
2091
+ });
2092
+
2093
+ testCM("splitSpaces_nonspecial", function(cm) {
2094
+ eq(byClassName(cm.getWrapperElement(), "cm-invalidchar").length, 0);
2095
+ }, {
2096
+ specialChars: /[\u00a0]/,
2097
+ value: "spaces -> <- between"
2098
+ });
2099
+
2100
+ test("core_rmClass", function() {
2101
+ var node = document.createElement("div");
2102
+ node.className = "foo-bar baz-quux yadda";
2103
+ CodeMirror.rmClass(node, "quux");
2104
+ eq(node.className, "foo-bar baz-quux yadda");
2105
+ CodeMirror.rmClass(node, "baz-quux");
2106
+ eq(node.className, "foo-bar yadda");
2107
+ CodeMirror.rmClass(node, "yadda");
2108
+ eq(node.className, "foo-bar");
2109
+ CodeMirror.rmClass(node, "foo-bar");
2110
+ eq(node.className, "");
2111
+ node.className = " foo ";
2112
+ CodeMirror.rmClass(node, "foo");
2113
+ eq(node.className, "");
2114
+ });
2115
+
2116
+ test("core_addClass", function() {
2117
+ var node = document.createElement("div");
2118
+ CodeMirror.addClass(node, "a");
2119
+ eq(node.className, "a");
2120
+ CodeMirror.addClass(node, "a");
2121
+ eq(node.className, "a");
2122
+ CodeMirror.addClass(node, "b");
2123
+ eq(node.className, "a b");
2124
+ CodeMirror.addClass(node, "a");
2125
+ CodeMirror.addClass(node, "b");
2126
+ eq(node.className, "a b");
2127
+ });
2128
+
2129
+ testCM("lineSeparator", function(cm) {
2130
+ eq(cm.lineCount(), 3);
2131
+ eq(cm.getLine(1), "bar\r");
2132
+ eq(cm.getLine(2), "baz\rquux");
2133
+ cm.setOption("lineSeparator", "\r");
2134
+ eq(cm.lineCount(), 5);
2135
+ eq(cm.getLine(4), "quux");
2136
+ eq(cm.getValue(), "foo\rbar\r\rbaz\rquux");
2137
+ eq(cm.getValue("\n"), "foo\nbar\n\nbaz\nquux");
2138
+ cm.setOption("lineSeparator", null);
2139
+ cm.setValue("foo\nbar\r\nbaz\rquux");
2140
+ eq(cm.lineCount(), 4);
2141
+ }, {value: "foo\nbar\r\nbaz\rquux",
2142
+ lineSeparator: "\n"});