erp_app 3.0.7 → 3.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (537) hide show
  1. data/README.md +23 -0
  2. data/app/controllers/erp_app/application_controller.rb +1 -0
  3. data/app/controllers/erp_app/desktop/file_manager/base_controller.rb +33 -23
  4. data/app/controllers/erp_app/public_controller.rb +2 -3
  5. data/app/controllers/erp_app/shared/configuration_controller.rb +1 -0
  6. data/app/controllers/erp_app/shared/notes_controller.rb +1 -0
  7. data/app/controllers/erp_app/shared/profile_management_controller.rb +22 -0
  8. data/app/controllers/erp_app/widget_proxy_controller.rb +2 -1
  9. data/app/models/configuration.rb +7 -0
  10. data/app/views/erp_app/desktop/base/index.erb +2 -3
  11. data/app/views/erp_app/login/index.erb +1 -1
  12. data/app/views/erp_app/mobile/base/index.erb +1 -0
  13. data/app/views/erp_app/organizer/base/index.erb +2 -3
  14. data/config/routes.rb +1 -1
  15. data/lib/active_ext/ext_helpers/column_builder.rb +118 -118
  16. data/lib/erp_app/config.rb +8 -4
  17. data/lib/erp_app/extensions/railties/action_view/base.rb +0 -1
  18. data/lib/erp_app/extensions/railties/action_view/helpers/include_helper.rb +18 -3
  19. data/lib/erp_app/version.rb +1 -1
  20. data/lib/erp_app/widgets/base.rb +5 -4
  21. data/lib/erp_app/widgets/loader.rb +2 -2
  22. data/public/images/btn/left_panel/left_panel_16x16.png +0 -0
  23. data/public/images/btn/left_right_panel/left_right_panel_16x16.png +0 -0
  24. data/public/images/btn/right_panel/right_panel_16x16.png +0 -0
  25. data/public/images/btn/save/save_16x16.png +0 -0
  26. data/public/images/btn/save_all/save_all_16x16.png +0 -0
  27. data/public/javascripts/erp_app/ckeditor/ckeditor.js +138 -135
  28. data/public/javascripts/erp_app/ckeditor/config.js +1 -1
  29. data/public/javascripts/erp_app/ckeditor/contents.css +1 -1
  30. data/public/javascripts/erp_app/ckeditor/lang/_languages.js +1 -1
  31. data/public/javascripts/erp_app/ckeditor/lang/_translationstatus.txt +62 -59
  32. data/public/javascripts/erp_app/ckeditor/lang/af.js +2 -2
  33. data/public/javascripts/erp_app/ckeditor/lang/ar.js +2 -2
  34. data/public/javascripts/erp_app/ckeditor/lang/bg.js +2 -2
  35. data/public/javascripts/erp_app/ckeditor/lang/bn.js +2 -2
  36. data/public/javascripts/erp_app/ckeditor/lang/bs.js +2 -2
  37. data/public/javascripts/erp_app/ckeditor/lang/ca.js +2 -2
  38. data/public/javascripts/erp_app/ckeditor/lang/cs.js +2 -2
  39. data/public/javascripts/erp_app/ckeditor/lang/cy.js +2 -2
  40. data/public/javascripts/erp_app/ckeditor/lang/da.js +2 -2
  41. data/public/javascripts/erp_app/ckeditor/lang/de.js +2 -2
  42. data/public/javascripts/erp_app/ckeditor/lang/el.js +2 -2
  43. data/public/javascripts/erp_app/ckeditor/lang/en-au.js +2 -2
  44. data/public/javascripts/erp_app/ckeditor/lang/en-ca.js +2 -2
  45. data/public/javascripts/erp_app/ckeditor/lang/en-gb.js +2 -2
  46. data/public/javascripts/erp_app/ckeditor/lang/en.js +2 -2
  47. data/public/javascripts/erp_app/ckeditor/lang/eo.js +2 -2
  48. data/public/javascripts/erp_app/ckeditor/lang/es.js +2 -2
  49. data/public/javascripts/erp_app/ckeditor/lang/et.js +2 -2
  50. data/public/javascripts/erp_app/ckeditor/lang/eu.js +2 -2
  51. data/public/javascripts/erp_app/ckeditor/lang/fa.js +2 -2
  52. data/public/javascripts/erp_app/ckeditor/lang/fi.js +2 -2
  53. data/public/javascripts/erp_app/ckeditor/lang/fo.js +2 -2
  54. data/public/javascripts/erp_app/ckeditor/lang/fr-ca.js +2 -2
  55. data/public/javascripts/erp_app/ckeditor/lang/fr.js +2 -2
  56. data/public/javascripts/erp_app/ckeditor/lang/gl.js +2 -2
  57. data/public/javascripts/erp_app/ckeditor/lang/gu.js +2 -2
  58. data/public/javascripts/erp_app/ckeditor/lang/he.js +2 -2
  59. data/public/javascripts/erp_app/ckeditor/lang/hi.js +2 -2
  60. data/public/javascripts/erp_app/ckeditor/lang/hr.js +2 -2
  61. data/public/javascripts/erp_app/ckeditor/lang/hu.js +2 -2
  62. data/public/javascripts/erp_app/ckeditor/lang/id.js +6 -0
  63. data/public/javascripts/erp_app/ckeditor/lang/is.js +2 -2
  64. data/public/javascripts/erp_app/ckeditor/lang/it.js +2 -2
  65. data/public/javascripts/erp_app/ckeditor/lang/ja.js +2 -2
  66. data/public/javascripts/erp_app/ckeditor/lang/ka.js +2 -2
  67. data/public/javascripts/erp_app/ckeditor/lang/km.js +2 -2
  68. data/public/javascripts/erp_app/ckeditor/lang/ko.js +2 -2
  69. data/public/javascripts/erp_app/ckeditor/lang/lt.js +2 -2
  70. data/public/javascripts/erp_app/ckeditor/lang/lv.js +2 -2
  71. data/public/javascripts/erp_app/ckeditor/lang/mk.js +6 -0
  72. data/public/javascripts/erp_app/ckeditor/lang/mn.js +2 -2
  73. data/public/javascripts/erp_app/ckeditor/lang/ms.js +2 -2
  74. data/public/javascripts/erp_app/ckeditor/lang/nb.js +2 -2
  75. data/public/javascripts/erp_app/ckeditor/lang/nl.js +2 -2
  76. data/public/javascripts/erp_app/ckeditor/lang/no.js +2 -2
  77. data/public/javascripts/erp_app/ckeditor/lang/pl.js +2 -2
  78. data/public/javascripts/erp_app/ckeditor/lang/pt-br.js +2 -2
  79. data/public/javascripts/erp_app/ckeditor/lang/pt.js +2 -2
  80. data/public/javascripts/erp_app/ckeditor/lang/ro.js +2 -2
  81. data/public/javascripts/erp_app/ckeditor/lang/ru.js +2 -2
  82. data/public/javascripts/erp_app/ckeditor/lang/sk.js +2 -2
  83. data/public/javascripts/erp_app/ckeditor/lang/sl.js +2 -2
  84. data/public/javascripts/erp_app/ckeditor/lang/sr-latn.js +2 -2
  85. data/public/javascripts/erp_app/ckeditor/lang/sr.js +2 -2
  86. data/public/javascripts/erp_app/ckeditor/lang/sv.js +2 -2
  87. data/public/javascripts/erp_app/ckeditor/lang/th.js +2 -2
  88. data/public/javascripts/erp_app/ckeditor/lang/tr.js +2 -2
  89. data/public/javascripts/erp_app/ckeditor/lang/ug.js +6 -0
  90. data/public/javascripts/erp_app/ckeditor/lang/uk.js +2 -2
  91. data/public/javascripts/erp_app/ckeditor/lang/vi.js +2 -2
  92. data/public/javascripts/erp_app/ckeditor/lang/zh-cn.js +2 -2
  93. data/public/javascripts/erp_app/ckeditor/lang/zh.js +2 -2
  94. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js +1 -1
  95. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/_translationstatus.txt +25 -0
  96. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/cs.js +6 -0
  97. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/cy.js +6 -0
  98. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/da.js +6 -0
  99. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/de.js +6 -0
  100. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/el.js +6 -0
  101. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/en.js +2 -2
  102. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/eo.js +6 -0
  103. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/fa.js +6 -0
  104. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/fi.js +6 -0
  105. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/fr.js +6 -0
  106. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/gu.js +6 -0
  107. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/he.js +2 -2
  108. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/it.js +6 -0
  109. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/mk.js +6 -0
  110. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/nb.js +6 -0
  111. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/nl.js +6 -0
  112. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/no.js +6 -0
  113. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/pt-br.js +6 -0
  114. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/ro.js +6 -0
  115. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/tr.js +6 -0
  116. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/ug.js +6 -0
  117. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/vi.js +6 -0
  118. data/public/javascripts/erp_app/ckeditor/plugins/a11yhelp/lang/zh-cn.js +6 -0
  119. data/public/javascripts/erp_app/ckeditor/plugins/about/dialogs/about.js +1 -1
  120. data/public/javascripts/erp_app/ckeditor/plugins/adobeair/plugin.js +1 -1
  121. data/public/javascripts/erp_app/ckeditor/plugins/ajax/plugin.js +1 -1
  122. data/public/javascripts/erp_app/ckeditor/plugins/autogrow/plugin.js +2 -2
  123. data/public/javascripts/erp_app/ckeditor/plugins/bbcode/plugin.js +1 -1
  124. data/public/javascripts/erp_app/ckeditor/plugins/clipboard/dialogs/paste.js +2 -2
  125. data/public/javascripts/erp_app/ckeditor/plugins/colordialog/dialogs/colordialog.js +3 -3
  126. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/_translationstatus.txt +28 -0
  127. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/bg.js +6 -0
  128. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/cs.js +6 -0
  129. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/cy.js +6 -0
  130. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/da.js +6 -0
  131. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/de.js +6 -0
  132. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/el.js +6 -0
  133. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/en.js +1 -1
  134. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/eo.js +6 -0
  135. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/et.js +6 -0
  136. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/fa.js +6 -0
  137. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/fi.js +6 -0
  138. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/fr.js +6 -0
  139. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/gu.js +6 -0
  140. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/he.js +6 -0
  141. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/hr.js +6 -0
  142. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/it.js +6 -0
  143. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/nb.js +6 -0
  144. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/nl.js +6 -0
  145. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/no.js +6 -0
  146. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/pl.js +6 -0
  147. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/pt-br.js +6 -0
  148. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/tr.js +6 -0
  149. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/ug.js +6 -0
  150. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/uk.js +6 -0
  151. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/vi.js +6 -0
  152. data/public/javascripts/erp_app/ckeditor/plugins/devtools/lang/zh-cn.js +6 -0
  153. data/public/javascripts/erp_app/ckeditor/plugins/devtools/plugin.js +2 -2
  154. data/public/javascripts/erp_app/ckeditor/plugins/dialog/dialogDefinition.js +1 -1
  155. data/public/javascripts/erp_app/ckeditor/plugins/div/dialogs/div.js +1 -1
  156. data/public/javascripts/erp_app/ckeditor/plugins/docprops/dialogs/docprops.js +1 -1
  157. data/public/javascripts/erp_app/ckeditor/plugins/docprops/plugin.js +1 -1
  158. data/public/javascripts/erp_app/ckeditor/plugins/find/dialogs/find.js +3 -3
  159. data/public/javascripts/erp_app/ckeditor/plugins/flash/dialogs/flash.js +4 -4
  160. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/button.js +1 -1
  161. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/checkbox.js +1 -1
  162. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/form.js +1 -1
  163. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/hiddenfield.js +1 -1
  164. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/radio.js +1 -1
  165. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/select.js +1 -1
  166. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/textarea.js +1 -1
  167. data/public/javascripts/erp_app/ckeditor/plugins/forms/dialogs/textfield.js +1 -1
  168. data/public/javascripts/erp_app/ckeditor/plugins/iframe/dialogs/iframe.js +1 -1
  169. data/public/javascripts/erp_app/ckeditor/plugins/iframedialog/plugin.js +1 -1
  170. data/public/javascripts/erp_app/ckeditor/plugins/image/dialogs/image.js +9 -9
  171. data/public/javascripts/erp_app/ckeditor/plugins/inlineeditsave/plugin.js +40 -0
  172. data/public/javascripts/erp_app/ckeditor/plugins/link/dialogs/anchor.js +2 -2
  173. data/public/javascripts/erp_app/ckeditor/plugins/link/dialogs/link.js +5 -5
  174. data/public/javascripts/erp_app/ckeditor/plugins/liststyle/dialogs/liststyle.js +1 -1
  175. data/public/javascripts/erp_app/ckeditor/plugins/pastefromword/filter/default.js +1 -1
  176. data/public/javascripts/erp_app/ckeditor/plugins/pastetext/dialogs/pastetext.js +1 -1
  177. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/dialogs/placeholder.js +1 -1
  178. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/_translationstatus.txt +27 -0
  179. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/bg.js +6 -0
  180. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/cs.js +6 -0
  181. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/cy.js +6 -0
  182. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/da.js +6 -0
  183. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/de.js +6 -0
  184. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/el.js +6 -0
  185. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/en.js +1 -1
  186. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/eo.js +6 -0
  187. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/et.js +6 -0
  188. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/fa.js +6 -0
  189. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/fi.js +6 -0
  190. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/fr.js +6 -0
  191. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/he.js +1 -1
  192. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/hr.js +6 -0
  193. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/it.js +6 -0
  194. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/nb.js +6 -0
  195. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/nl.js +6 -0
  196. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/no.js +6 -0
  197. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/pl.js +6 -0
  198. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/pt-br.js +6 -0
  199. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/tr.js +6 -0
  200. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/ug.js +6 -0
  201. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/uk.js +6 -0
  202. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/vi.js +6 -0
  203. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/lang/zh-cn.js +6 -0
  204. data/public/javascripts/erp_app/ckeditor/plugins/placeholder/plugin.js +2 -2
  205. data/public/javascripts/erp_app/ckeditor/plugins/preview/preview.html +10 -0
  206. data/public/javascripts/erp_app/ckeditor/plugins/scayt/dialogs/options.js +1 -1
  207. data/public/javascripts/erp_app/ckeditor/plugins/scayt/dialogs/toolbar.css +1 -1
  208. data/public/javascripts/erp_app/ckeditor/plugins/smiley/dialogs/smiley.js +1 -1
  209. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/dialogs/specialchar.js +1 -1
  210. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/_translationstatus.txt +22 -0
  211. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/cs.js +6 -0
  212. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/cy.js +6 -0
  213. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/de.js +6 -0
  214. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/el.js +6 -0
  215. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/en.js +1 -1
  216. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/eo.js +6 -0
  217. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/et.js +6 -0
  218. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/fa.js +6 -0
  219. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/fi.js +6 -0
  220. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/fr.js +6 -0
  221. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/he.js +6 -0
  222. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/hr.js +6 -0
  223. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/it.js +6 -0
  224. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/nb.js +6 -0
  225. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/nl.js +6 -0
  226. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/no.js +6 -0
  227. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/pt-br.js +6 -0
  228. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/tr.js +6 -0
  229. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/ug.js +6 -0
  230. data/public/javascripts/erp_app/ckeditor/plugins/specialchar/lang/zh-cn.js +6 -0
  231. data/public/javascripts/erp_app/ckeditor/plugins/styles/styles/default.js +1 -1
  232. data/public/javascripts/erp_app/ckeditor/plugins/stylesheetparser/plugin.js +1 -1
  233. data/public/javascripts/erp_app/ckeditor/plugins/table/dialogs/table.js +5 -5
  234. data/public/javascripts/erp_app/ckeditor/plugins/tableresize/plugin.js +1 -1
  235. data/public/javascripts/erp_app/ckeditor/plugins/tabletools/dialogs/tableCell.js +3 -3
  236. data/public/javascripts/erp_app/ckeditor/plugins/templates/dialogs/templates.js +1 -1
  237. data/public/javascripts/erp_app/ckeditor/plugins/templates/templates/default.js +1 -1
  238. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/dialogs/uicolor.js +1 -1
  239. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/_translationstatus.txt +28 -0
  240. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/bg.js +6 -0
  241. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/cs.js +6 -0
  242. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/cy.js +6 -0
  243. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/da.js +6 -0
  244. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/de.js +6 -0
  245. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/el.js +6 -0
  246. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/en.js +1 -1
  247. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/eo.js +6 -0
  248. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/et.js +6 -0
  249. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/fa.js +6 -0
  250. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/fi.js +6 -0
  251. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/fr.js +6 -0
  252. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/he.js +1 -1
  253. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/hr.js +6 -0
  254. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/it.js +6 -0
  255. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/mk.js +6 -0
  256. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/nb.js +6 -0
  257. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/nl.js +6 -0
  258. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/no.js +6 -0
  259. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/pl.js +6 -0
  260. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/pt-br.js +6 -0
  261. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/tr.js +6 -0
  262. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/ug.js +6 -0
  263. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/uk.js +6 -0
  264. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/vi.js +6 -0
  265. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/lang/zh-cn.js +6 -0
  266. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/plugin.js +2 -2
  267. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/yui/assets/yui.css +1 -1
  268. data/public/javascripts/erp_app/ckeditor/plugins/uicolor/yui/yui.js +1 -1
  269. data/public/javascripts/erp_app/ckeditor/plugins/wsc/dialogs/ciframe.html +1 -1
  270. data/public/javascripts/erp_app/ckeditor/plugins/wsc/dialogs/tmpFrameset.html +1 -1
  271. data/public/javascripts/erp_app/ckeditor/plugins/wsc/dialogs/wsc.css +1 -1
  272. data/public/javascripts/erp_app/ckeditor/plugins/wsc/dialogs/wsc.js +1 -1
  273. data/public/javascripts/erp_app/ckeditor/plugins/xml/plugin.js +1 -1
  274. data/public/javascripts/erp_app/ckeditor/skins/kama/dialog.css +6 -6
  275. data/public/javascripts/erp_app/ckeditor/skins/kama/editor.css +1 -1
  276. data/public/javascripts/erp_app/ckeditor/skins/kama/skin.js +1 -1
  277. data/public/javascripts/erp_app/ckeditor/skins/kama/templates.css +1 -1
  278. data/public/javascripts/erp_app/ckeditor/skins/office2003/dialog.css +6 -5
  279. data/public/javascripts/erp_app/ckeditor/skins/office2003/editor.css +1 -1
  280. data/public/javascripts/erp_app/ckeditor/skins/office2003/skin.js +1 -1
  281. data/public/javascripts/erp_app/ckeditor/skins/office2003/templates.css +1 -1
  282. data/public/javascripts/erp_app/ckeditor/skins/v2/dialog.css +5 -5
  283. data/public/javascripts/erp_app/ckeditor/skins/v2/editor.css +1 -1
  284. data/public/javascripts/erp_app/ckeditor/skins/v2/skin.js +1 -1
  285. data/public/javascripts/erp_app/ckeditor/skins/v2/templates.css +1 -1
  286. data/public/javascripts/erp_app/ckeditor/themes/default/theme.js +1 -1
  287. data/public/javascripts/erp_app/ckeditor_example_config_override.js +2 -1
  288. data/public/javascripts/erp_app/codemirror/LICENSE +5 -1
  289. data/public/javascripts/erp_app/codemirror/README.md +6 -4
  290. data/public/javascripts/erp_app/codemirror/{css → doc}/baboon.png +0 -0
  291. data/public/javascripts/erp_app/codemirror/{css → doc}/baboon_vector.svg +0 -0
  292. data/public/javascripts/erp_app/codemirror/doc/compress.html +155 -0
  293. data/public/javascripts/erp_app/codemirror/{css → doc}/docs.css +0 -0
  294. data/public/javascripts/erp_app/codemirror/doc/internals.html +494 -0
  295. data/public/javascripts/erp_app/codemirror/{manual.html → doc/manual.html} +465 -167
  296. data/public/javascripts/erp_app/codemirror/doc/oldrelease.html +267 -0
  297. data/public/javascripts/erp_app/codemirror/doc/reporting.html +57 -0
  298. data/public/javascripts/erp_app/codemirror/doc/upgrade_v2.2.html +95 -0
  299. data/public/javascripts/erp_app/codemirror/keymap/emacs.js +29 -0
  300. data/public/javascripts/erp_app/codemirror/keymap/vim.js +785 -0
  301. data/public/javascripts/erp_app/codemirror/lib/codemirror.css +116 -14
  302. data/public/javascripts/erp_app/codemirror/lib/codemirror.js +2128 -1054
  303. data/public/javascripts/erp_app/codemirror/lib/util/closetag.js +164 -0
  304. data/public/javascripts/erp_app/codemirror/lib/util/dialog.css +27 -0
  305. data/public/javascripts/erp_app/codemirror/lib/util/dialog.js +67 -0
  306. data/public/javascripts/erp_app/codemirror/lib/util/foldcode.js +196 -0
  307. data/public/javascripts/erp_app/codemirror/lib/util/formatting.js +299 -0
  308. data/public/javascripts/erp_app/codemirror/lib/util/javascript-hint.js +134 -0
  309. data/public/javascripts/erp_app/codemirror/lib/util/loadmode.js +51 -0
  310. data/public/javascripts/erp_app/codemirror/lib/util/match-highlighter.js +44 -0
  311. data/public/javascripts/erp_app/codemirror/lib/util/multiplex.js +81 -0
  312. data/public/javascripts/erp_app/codemirror/lib/{overlay.js → util/overlay.js} +3 -2
  313. data/public/javascripts/erp_app/codemirror/lib/util/pig-hint.js +123 -0
  314. data/public/javascripts/erp_app/codemirror/lib/util/runmode.js +49 -0
  315. data/public/javascripts/erp_app/codemirror/lib/util/search.js +118 -0
  316. data/public/javascripts/erp_app/codemirror/lib/util/searchcursor.js +117 -0
  317. data/public/javascripts/erp_app/codemirror/lib/util/simple-hint.css +16 -0
  318. data/public/javascripts/erp_app/codemirror/lib/util/simple-hint.js +76 -0
  319. data/public/javascripts/erp_app/codemirror/lib/util/xml-hint.js +137 -0
  320. data/public/javascripts/erp_app/codemirror/mode/clike/clike.js +50 -17
  321. data/public/javascripts/erp_app/codemirror/mode/clike/index.html +4 -5
  322. data/public/javascripts/erp_app/codemirror/mode/clike/scala.html +765 -0
  323. data/public/javascripts/erp_app/codemirror/mode/clojure/clojure.js +207 -0
  324. data/public/javascripts/erp_app/codemirror/mode/clojure/index.html +66 -0
  325. data/public/javascripts/erp_app/codemirror/mode/coffeescript/coffeescript.js +101 -63
  326. data/public/javascripts/erp_app/codemirror/mode/coffeescript/index.html +9 -4
  327. data/public/javascripts/erp_app/codemirror/mode/css/css.js +4 -4
  328. data/public/javascripts/erp_app/codemirror/mode/css/index.html +3 -4
  329. data/public/javascripts/erp_app/codemirror/mode/diff/diff.js +24 -5
  330. data/public/javascripts/erp_app/codemirror/mode/diff/index.html +12 -7
  331. data/public/javascripts/erp_app/codemirror/mode/ecl/ecl.js +203 -0
  332. data/public/javascripts/erp_app/codemirror/mode/ecl/index.html +42 -0
  333. data/public/javascripts/erp_app/codemirror/mode/erlang/erlang.js +463 -0
  334. data/public/javascripts/erp_app/codemirror/mode/erlang/index.html +62 -0
  335. data/public/javascripts/erp_app/codemirror/mode/gfm/gfm.js +144 -0
  336. data/public/javascripts/erp_app/codemirror/mode/gfm/index.html +47 -0
  337. data/public/javascripts/erp_app/codemirror/mode/go/go.js +170 -0
  338. data/public/javascripts/erp_app/codemirror/mode/go/index.html +72 -0
  339. data/public/javascripts/erp_app/codemirror/mode/groovy/groovy.js +210 -0
  340. data/public/javascripts/erp_app/codemirror/mode/groovy/index.html +71 -0
  341. data/public/javascripts/erp_app/codemirror/mode/haskell/index.html +3 -3
  342. data/public/javascripts/erp_app/codemirror/mode/haxe/haxe.js +432 -0
  343. data/public/javascripts/erp_app/codemirror/mode/haxe/index.html +90 -0
  344. data/public/javascripts/erp_app/codemirror/mode/htmlembedded/htmlembedded.js +68 -0
  345. data/public/javascripts/erp_app/codemirror/mode/htmlembedded/index.html +49 -0
  346. data/public/javascripts/erp_app/codemirror/mode/htmlmixed/htmlmixed.js +8 -2
  347. data/public/javascripts/erp_app/codemirror/mode/htmlmixed/index.html +3 -4
  348. data/public/javascripts/erp_app/codemirror/mode/javascript/index.html +3 -4
  349. data/public/javascripts/erp_app/codemirror/mode/javascript/javascript.js +26 -13
  350. data/public/javascripts/erp_app/codemirror/mode/jinja2/index.html +37 -0
  351. data/public/javascripts/erp_app/codemirror/mode/jinja2/jinja2.js +42 -0
  352. data/public/javascripts/erp_app/codemirror/mode/less/index.html +618 -0
  353. data/public/javascripts/erp_app/codemirror/mode/less/less.js +232 -0
  354. data/public/javascripts/erp_app/codemirror/mode/lua/index.html +3 -3
  355. data/public/javascripts/erp_app/codemirror/mode/lua/lua.js +5 -3
  356. data/public/javascripts/erp_app/codemirror/mode/markdown/index.html +340 -0
  357. data/public/javascripts/erp_app/codemirror/mode/markdown/markdown.js +268 -0
  358. data/public/javascripts/erp_app/codemirror/mode/mysql/index.html +41 -0
  359. data/public/javascripts/erp_app/codemirror/mode/mysql/mysql.js +186 -0
  360. data/public/javascripts/erp_app/codemirror/mode/ntriples/index.html +32 -0
  361. data/public/javascripts/erp_app/codemirror/mode/ntriples/ntriples.js +172 -0
  362. data/public/javascripts/erp_app/codemirror/mode/ocaml/index.html +130 -0
  363. data/public/javascripts/erp_app/codemirror/mode/ocaml/ocaml.js +114 -0
  364. data/public/javascripts/erp_app/codemirror/mode/pascal/LICENSE +7 -0
  365. data/public/javascripts/erp_app/codemirror/mode/pascal/index.html +48 -0
  366. data/public/javascripts/erp_app/codemirror/mode/pascal/pascal.js +94 -0
  367. data/public/javascripts/erp_app/codemirror/mode/perl/LICENSE +19 -0
  368. data/public/javascripts/erp_app/codemirror/mode/perl/index.html +62 -0
  369. data/public/javascripts/erp_app/codemirror/mode/perl/perl.js +816 -0
  370. data/public/javascripts/erp_app/codemirror/mode/php/index.html +4 -5
  371. data/public/javascripts/erp_app/codemirror/mode/php/php.js +62 -27
  372. data/public/javascripts/erp_app/codemirror/mode/pig/index.html +42 -0
  373. data/public/javascripts/erp_app/codemirror/mode/pig/pig.js +172 -0
  374. data/public/javascripts/erp_app/codemirror/mode/plsql/index.html +3 -4
  375. data/public/javascripts/erp_app/codemirror/mode/plsql/plsql.js +2 -2
  376. data/public/javascripts/erp_app/codemirror/mode/properties/index.html +40 -0
  377. data/public/javascripts/erp_app/codemirror/mode/properties/properties.js +63 -0
  378. data/public/javascripts/erp_app/codemirror/mode/python/index.html +3 -4
  379. data/public/javascripts/erp_app/codemirror/mode/python/python.js +59 -42
  380. data/public/javascripts/erp_app/codemirror/mode/r/index.html +5 -5
  381. data/public/javascripts/erp_app/codemirror/mode/r/r.js +9 -2
  382. data/public/javascripts/erp_app/codemirror/mode/rpm/changes/changes.js +19 -0
  383. data/public/javascripts/erp_app/codemirror/mode/rpm/changes/index.html +53 -0
  384. data/public/javascripts/erp_app/codemirror/mode/rpm/spec/index.html +99 -0
  385. data/public/javascripts/erp_app/codemirror/mode/rpm/spec/spec.css +5 -0
  386. data/public/javascripts/erp_app/codemirror/mode/rpm/spec/spec.js +66 -0
  387. data/public/javascripts/erp_app/codemirror/mode/rst/index.html +4 -5
  388. data/public/javascripts/erp_app/codemirror/mode/rst/rst.js +15 -22
  389. data/public/javascripts/erp_app/codemirror/mode/ruby/index.html +3 -4
  390. data/public/javascripts/erp_app/codemirror/mode/ruby/ruby.js +49 -36
  391. data/public/javascripts/erp_app/codemirror/mode/rust/index.html +48 -0
  392. data/public/javascripts/erp_app/codemirror/mode/rust/rust.js +432 -0
  393. data/public/javascripts/erp_app/codemirror/mode/scheme/index.html +3 -4
  394. data/public/javascripts/erp_app/codemirror/mode/scheme/scheme.js +71 -23
  395. data/public/javascripts/erp_app/codemirror/mode/shell/index.html +50 -0
  396. data/public/javascripts/erp_app/codemirror/mode/shell/shell.js +118 -0
  397. data/public/javascripts/erp_app/codemirror/mode/smalltalk/index.html +3 -4
  398. data/public/javascripts/erp_app/codemirror/mode/smalltalk/smalltalk.js +137 -120
  399. data/public/javascripts/erp_app/codemirror/mode/smarty/index.html +82 -0
  400. data/public/javascripts/erp_app/codemirror/mode/smarty/smarty.js +148 -0
  401. data/public/javascripts/erp_app/codemirror/mode/sparql/index.html +3 -4
  402. data/public/javascripts/erp_app/codemirror/mode/stex/index.html +4 -5
  403. data/public/javascripts/erp_app/codemirror/mode/stex/stex.js +22 -7
  404. data/public/javascripts/erp_app/codemirror/mode/stex/test.html +263 -0
  405. data/public/javascripts/erp_app/codemirror/mode/tiddlywiki/index.html +140 -0
  406. data/public/javascripts/erp_app/codemirror/mode/tiddlywiki/tiddlywiki.css +14 -0
  407. data/public/javascripts/erp_app/codemirror/mode/tiddlywiki/tiddlywiki.js +384 -0
  408. data/public/javascripts/erp_app/codemirror/mode/tiki/index.html +82 -0
  409. data/public/javascripts/erp_app/codemirror/mode/tiki/tiki.css +26 -0
  410. data/public/javascripts/erp_app/codemirror/mode/tiki/tiki.js +316 -0
  411. data/public/javascripts/erp_app/codemirror/mode/vb/LICENSE.txt +21 -0
  412. data/public/javascripts/erp_app/codemirror/mode/vb/index.html +88 -0
  413. data/public/javascripts/erp_app/codemirror/mode/vb/vb.js +260 -0
  414. data/public/javascripts/erp_app/codemirror/mode/vbscript/index.html +42 -0
  415. data/public/javascripts/erp_app/codemirror/mode/vbscript/vbscript.js +26 -0
  416. data/public/javascripts/erp_app/codemirror/mode/velocity/index.html +3 -3
  417. data/public/javascripts/erp_app/codemirror/mode/verilog/index.html +210 -0
  418. data/public/javascripts/erp_app/codemirror/mode/verilog/verilog.js +194 -0
  419. data/public/javascripts/erp_app/codemirror/mode/xml/index.html +7 -5
  420. data/public/javascripts/erp_app/codemirror/mode/xml/xml.js +127 -32
  421. data/public/javascripts/erp_app/codemirror/mode/xquery/LICENSE +20 -0
  422. data/public/javascripts/erp_app/codemirror/mode/xquery/index.html +222 -0
  423. data/public/javascripts/erp_app/codemirror/mode/xquery/test/index.html +27 -0
  424. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testBase.js +42 -0
  425. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testEmptySequenceKeyword.js +16 -0
  426. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testMultiAttr.js +16 -0
  427. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testNamespaces.js +91 -0
  428. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testProcessingInstructions.js +16 -0
  429. data/public/javascripts/erp_app/codemirror/mode/xquery/test/testQuotes.js +19 -0
  430. data/public/javascripts/erp_app/codemirror/mode/xquery/xquery.js +448 -0
  431. data/public/javascripts/erp_app/codemirror/mode/yaml/index.html +3 -4
  432. data/public/javascripts/erp_app/codemirror/package.json +29 -0
  433. data/public/javascripts/erp_app/codemirror/test/driver.js +42 -0
  434. data/public/javascripts/erp_app/codemirror/test/index.html +55 -0
  435. data/public/javascripts/erp_app/codemirror/test/mode_test.css +22 -0
  436. data/public/javascripts/erp_app/codemirror/test/mode_test.js +164 -0
  437. data/public/javascripts/erp_app/codemirror/test/test.js +467 -0
  438. data/public/javascripts/erp_app/codemirror/theme/ambiance.css +81 -0
  439. data/public/javascripts/erp_app/codemirror/theme/blackboard.css +25 -0
  440. data/public/javascripts/erp_app/codemirror/theme/cobalt.css +18 -0
  441. data/public/javascripts/erp_app/codemirror/theme/eclipse.css +25 -0
  442. data/public/javascripts/erp_app/codemirror/theme/elegant.css +3 -2
  443. data/public/javascripts/erp_app/codemirror/theme/erlang-dark.css +21 -0
  444. data/public/javascripts/erp_app/codemirror/theme/lesser-dark.css +44 -0
  445. data/public/javascripts/erp_app/codemirror/theme/monokai.css +28 -0
  446. data/public/javascripts/erp_app/codemirror/theme/neat.css +4 -3
  447. data/public/javascripts/erp_app/codemirror/theme/night.css +2 -1
  448. data/public/javascripts/erp_app/codemirror/theme/rubyblue.css +21 -0
  449. data/public/javascripts/erp_app/codemirror/theme/vibrant-ink.css +27 -0
  450. data/public/javascripts/erp_app/codemirror/theme/xq-dark.css +46 -0
  451. data/public/javascripts/erp_app/codemirror_highlight.js +17 -0
  452. data/public/javascripts/erp_app/desktop/applications/audit_log_viewer/module.js +1 -57
  453. data/public/javascripts/erp_app/desktop/applications/control_panel/application_management_panel.js +1 -2
  454. data/public/javascripts/erp_app/desktop/applications/control_panel/module.js +1 -1
  455. data/public/javascripts/erp_app/desktop/applications/file_manager/module.js +12 -1
  456. data/public/javascripts/erp_app/desktop/ext_ux_desktop_module.js +9 -1
  457. data/public/javascripts/erp_app/jquery_support.js +6 -1
  458. data/public/javascripts/erp_app/login/window.js +1 -1
  459. data/public/javascripts/erp_app/organizer/default_menu_tree_panel.js +3 -1
  460. data/public/javascripts/erp_app/organizer/layout.js +92 -79
  461. data/public/javascripts/erp_app/organizer/preference_window.js +1 -1
  462. data/public/javascripts/erp_app/{desktop/applications/audit_log_viewer → shared/audit_log}/audit_log_grid_panel.js +1 -0
  463. data/public/javascripts/erp_app/{desktop/applications/audit_log_viewer → shared/audit_log}/audit_log_item_grid_panel.js +0 -0
  464. data/public/javascripts/erp_app/shared/audit_log/audit_log_tab_panel.js +52 -0
  465. data/public/javascripts/erp_app/shared/compass_ckeditor.js +51 -1
  466. data/public/javascripts/erp_app/shared/compass_codemirror.js +2 -8
  467. data/public/javascripts/erp_app/shared/configuration/configuration_panel.js +24 -22
  468. data/public/javascripts/erp_app/shared/dynamic_editable_grid.js +1 -0
  469. data/public/javascripts/erp_app/shared/dynamic_editable_grid_loader_panel.js +5 -1
  470. data/public/javascripts/erp_app/shared/file_manager_tree.js +358 -270
  471. data/public/javascripts/erp_app/shared/file_upload/Ext.ux.panel.UploadPanel.js +580 -0
  472. data/public/javascripts/erp_app/shared/file_upload/plupload.flash.swf +0 -0
  473. data/public/javascripts/erp_app/shared/file_upload/plupload.full.js +2 -0
  474. data/public/javascripts/erp_app/shared/file_upload/plupload.silverlight.xap +0 -0
  475. data/public/javascripts/erp_app/shared/file_upload/upload_window.js +19 -212
  476. data/public/javascripts/erp_app/{desktop/applications/control_panel → shared}/profile_management_panel.js +14 -23
  477. data/public/javascripts/erp_app/utility.js +340 -272
  478. data/public/javascripts/erp_app/widgets.js +2 -2
  479. data/public/javascripts/extjs/MultiCellSelectionModel.js +490 -0
  480. data/public/javascripts/jquery_plugins/jquery.address.min.js +21 -24
  481. data/public/stylesheets/erp_app/desktop/base.css +3 -1
  482. data/public/stylesheets/erp_app/shared/compass-ext-all.css +29 -0
  483. data/public/stylesheets/erp_app/shared/hover_finger.css +4 -0
  484. metadata +267 -71
  485. data/app/controllers/erp_app/desktop/control_panel/profile_management_controller.rb +0 -23
  486. data/app/models/extensions/party.rb +0 -39
  487. data/public/images/icons/add/Thumbs.db +0 -0
  488. data/public/images/icons/calendar/Thumbs.db +0 -0
  489. data/public/images/icons/copy/Thumbs.db +0 -0
  490. data/public/images/icons/cut/Thumbs.db +0 -0
  491. data/public/images/icons/delete/Thumbs.db +0 -0
  492. data/public/images/icons/edit/Thumbs.db +0 -0
  493. data/public/images/icons/folder/Thumbs.db +0 -0
  494. data/public/images/icons/gear/Thumbs.db +0 -0
  495. data/public/images/icons/globe/Thumbs.db +0 -0
  496. data/public/images/icons/grid/Thumbs.db +0 -0
  497. data/public/images/icons/help/Thumbs.db +0 -0
  498. data/public/images/icons/information/Thumbs.db +0 -0
  499. data/public/images/icons/key/Thumbs.db +0 -0
  500. data/public/images/icons/log_out/Thumbs.db +0 -0
  501. data/public/images/icons/mail/Thumbs.db +0 -0
  502. data/public/images/icons/new/Thumbs.db +0 -0
  503. data/public/images/icons/next/Thumbs.db +0 -0
  504. data/public/images/icons/open/Thumbs.db +0 -0
  505. data/public/images/icons/paste/Thumbs.db +0 -0
  506. data/public/images/icons/picture/Thumbs.db +0 -0
  507. data/public/images/icons/presentation/Thumbs.db +0 -0
  508. data/public/images/icons/preview/Thumbs.db +0 -0
  509. data/public/images/icons/previous/Thumbs.db +0 -0
  510. data/public/images/icons/print/Thumbs.db +0 -0
  511. data/public/images/icons/properties/Thumbs.db +0 -0
  512. data/public/images/icons/redo/Thumbs.db +0 -0
  513. data/public/images/icons/refresh/Thumbs.db +0 -0
  514. data/public/images/icons/remove/Thumbs.db +0 -0
  515. data/public/images/icons/rename/Thumbs.db +0 -0
  516. data/public/images/icons/save/Thumbs.db +0 -0
  517. data/public/images/icons/search/Thumbs.db +0 -0
  518. data/public/images/icons/send/Thumbs.db +0 -0
  519. data/public/images/icons/settings/Thumbs.db +0 -0
  520. data/public/images/icons/synchronize/Thumbs.db +0 -0
  521. data/public/images/icons/undo/Thumbs.db +0 -0
  522. data/public/images/icons/upload/Thumbs.db +0 -0
  523. data/public/images/icons/user/Thumbs.db +0 -0
  524. data/public/images/icons/zoom_in/Thumbs.db +0 -0
  525. data/public/images/icons/zoom_out/Thumbs.db +0 -0
  526. data/public/javascripts/erp_app/ckeditor/plugins/jwplayer/jwplayer/Thumbs.db +0 -0
  527. data/public/javascripts/erp_app/codemirror/lib/runmode.js +0 -27
  528. data/public/javascripts/erp_app/codemirror/mode/diff/diff.css +0 -3
  529. data/public/javascripts/erp_app/codemirror/mode/rst/rst.css +0 -75
  530. data/public/javascripts/erp_app/codemirror/mode/xmlpure/index.html +0 -60
  531. data/public/javascripts/erp_app/codemirror/mode/xmlpure/xmlpure.js +0 -481
  532. data/public/javascripts/erp_app/codemirror/theme/default.css +0 -19
  533. data/public/javascripts/erp_app/shared/file_upload/Ext.ux.AwesomeUploader.js +0 -511
  534. data/public/javascripts/erp_app/shared/file_upload/Ext.ux.AwesomeUploaderLocalization.js +0 -45
  535. data/public/javascripts/erp_app/shared/file_upload/Ext.ux.XHRUpload.js +0 -138
  536. data/public/javascripts/erp_app/tinymce/Ext.ux.TinyMCE.js +0 -689
  537. data/public/javascripts/erp_app/tinymce/center_region.js +0 -611
@@ -1,10 +1,12 @@
1
+ // CodeMirror version 2.32
2
+ //
1
3
  // All functions that need access to the editor's state live inside
2
4
  // the CodeMirror function. Below that, at the bottom of the file,
3
5
  // some utilities are defined.
4
6
 
5
7
  // CodeMirror is the only global var we claim
6
8
  var CodeMirror = (function() {
7
- // This is the function that produces an editor instance. It's
9
+ // This is the function that produces an editor instance. Its
8
10
  // closure is used to store the editor state.
9
11
  function CodeMirror(place, givenOptions) {
10
12
  // Determine effective options based on given values and defaults.
@@ -13,158 +15,249 @@ var CodeMirror = (function() {
13
15
  if (defaults.hasOwnProperty(opt))
14
16
  options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15
17
 
16
- var targetDocument = options["document"];
17
18
  // The element in which the editor lives.
18
- var wrapper = targetDocument.createElement("div");
19
- wrapper.className = "CodeMirror";
19
+ var wrapper = document.createElement("div");
20
+ wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
20
21
  // This mess creates the base DOM structure for the editor.
21
22
  wrapper.innerHTML =
22
- '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23
- '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
24
- '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
23
+ '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
24
+ '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
25
+ 'autocorrect="off" autocapitalize="off"></textarea></div>' +
26
+ '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
27
+ '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
28
+ '</div></div>' + // This must be before the scroll area because it's float-right.
29
+ '<div class="CodeMirror-scroll" tabindex="-1">' +
25
30
  '<div style="position: relative">' + // Set to the height of the text, causes scrolling
26
- '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
27
31
  '<div style="position: relative">' + // Moved around its parent to cover visible view
28
32
  '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29
33
  // Provides positioning relative to (visible) text origin
30
- '<div class="CodeMirror-lines"><div style="position: relative">' +
34
+ '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
35
+ // Used to measure text size
36
+ '<div style="position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;"></div>' +
31
37
  '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32
- '<div></div>' + // This DIV contains the actual code
38
+ '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width
39
+ '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
33
40
  '</div></div></div></div></div>';
34
41
  if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
35
42
  // I've never seen more elegant code in my life.
36
43
  var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
37
44
  scroller = wrapper.lastChild, code = scroller.firstChild,
38
- measure = code.firstChild, mover = measure.nextSibling,
39
- gutter = mover.firstChild, gutterText = gutter.firstChild,
40
- lineSpace = gutter.nextSibling.firstChild,
41
- cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
42
- if (options.tabindex != null) input.tabindex = options.tabindex;
45
+ mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
46
+ lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
47
+ cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
48
+ selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
49
+ scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
50
+ themeChanged(); keyMapChanged();
51
+ // Needed to hide big blue blinking cursor on Mobile Safari
52
+ if (ios) input.style.width = "0px";
53
+ if (!webkit) scroller.draggable = true;
54
+ lineSpace.style.outline = "none";
55
+ if (options.tabindex != null) input.tabIndex = options.tabindex;
56
+ if (options.autofocus) focusInput();
43
57
  if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
58
+ // Needed to handle Tab key in KHTML
59
+ if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
60
+
61
+ // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
62
+ // make it overlap the content. (But we only do this if the scrollbar doesn't already
63
+ // have a natural width. If the mouse is plugged in or the user sets the system pref
64
+ // to always show scrollbars, the scrollbar shouldn't overlap.)
65
+ if (mac_geLion) {
66
+ scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
67
+ } else if (ie_lt8) {
68
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
69
+ scrollbar.className += " cm-sb-ie7";
70
+ }
71
+
72
+ // Check for problem with IE innerHTML not working when we have a
73
+ // P (or similar) parent node.
74
+ try { stringWidth("x"); }
75
+ catch (e) {
76
+ if (e.message.match(/runtime/i))
77
+ e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
78
+ throw e;
79
+ }
44
80
 
45
81
  // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
46
82
  var poll = new Delayed(), highlight = new Delayed(), blinker;
47
83
 
48
- // mode holds a mode API object. lines an array of Line objects
49
- // (see Line constructor), work an array of lines that should be
50
- // parsed, and history the undo history (instance of History
51
- // constructor).
52
- var mode, lines = [new Line("")], work, history = new History(), focused;
84
+ // mode holds a mode API object. doc is the tree of Line objects,
85
+ // work an array of lines that should be parsed, and history the
86
+ // undo history (instance of History constructor).
87
+ var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused;
53
88
  loadMode();
54
89
  // The selection. These are always maintained to point at valid
55
90
  // positions. Inverted is used to remember that the user is
56
91
  // selecting bottom-to-top.
57
92
  var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
58
93
  // Selection-related flags. shiftSelecting obviously tracks
59
- // whether the user is holding shift. reducedSelection is a hack
60
- // to get around the fact that we can't create inverted
61
- // selections. See below.
62
- var shiftSelecting, reducedSelection, lastDoubleClick;
94
+ // whether the user is holding shift.
95
+ var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
96
+ overwrite = false, suppressEdits = false;
63
97
  // Variables used by startOperation/endOperation to track what
64
98
  // happened during the operation.
65
- var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
99
+ var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
100
+ gutterDirty, callbacks;
66
101
  // Current visible range (may be bigger than the view window).
67
- var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
68
- // editing will hold an object describing the things we put in the
69
- // textarea, to help figure out whether something changed.
70
- // bracketHighlighted is used to remember that a backet has been
102
+ var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
103
+ // bracketHighlighted is used to remember that a bracket has been
71
104
  // marked.
72
- var editing, bracketHighlighted;
105
+ var bracketHighlighted;
73
106
  // Tracks the maximum line length so that the horizontal scrollbar
74
107
  // can be kept static when scrolling.
75
- var maxLine = "", maxWidth;
108
+ var maxLine = "", updateMaxLine = false, maxLineChanged = true;
109
+ var tabCache = {};
76
110
 
77
111
  // Initialize the content.
78
112
  operation(function(){setValue(options.value || ""); updateInput = false;})();
113
+ var history = new History();
79
114
 
80
115
  // Register our event handlers.
81
116
  connect(scroller, "mousedown", operation(onMouseDown));
117
+ connect(scroller, "dblclick", operation(onDoubleClick));
118
+ connect(lineSpace, "selectstart", e_preventDefault);
82
119
  // Gecko browsers fire contextmenu *after* opening the menu, at
83
120
  // which point we can't mess with it anymore. Context menu is
84
121
  // handled in onMouseDown for Gecko.
85
122
  if (!gecko) connect(scroller, "contextmenu", onContextMenu);
86
- connect(code, "dblclick", operation(onDblClick));
87
- connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
123
+ connect(scroller, "scroll", onScroll);
124
+ connect(scrollbar, "scroll", onScroll);
125
+ connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);});
126
+ connect(scroller, "mousewheel", onMouseWheel);
127
+ connect(scroller, "DOMMouseScroll", onMouseWheel);
88
128
  connect(window, "resize", function() {updateDisplay(true);});
89
129
  connect(input, "keyup", operation(onKeyUp));
130
+ connect(input, "input", fastPoll);
90
131
  connect(input, "keydown", operation(onKeyDown));
91
132
  connect(input, "keypress", operation(onKeyPress));
92
133
  connect(input, "focus", onFocus);
93
134
  connect(input, "blur", onBlur);
94
135
 
95
- connect(scroller, "dragenter", e_stop);
96
- connect(scroller, "dragover", e_stop);
97
- connect(scroller, "drop", operation(onDrop));
136
+ if (options.dragDrop) {
137
+ connect(scroller, "dragstart", onDragStart);
138
+ function drag_(e) {
139
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
140
+ e_stop(e);
141
+ }
142
+ connect(scroller, "dragenter", drag_);
143
+ connect(scroller, "dragover", drag_);
144
+ connect(scroller, "drop", operation(onDrop));
145
+ }
98
146
  connect(scroller, "paste", function(){focusInput(); fastPoll();});
99
- connect(input, "paste", function(){fastPoll();});
100
- connect(input, "cut", function(){fastPoll();});
101
-
102
- // IE throws unspecified error in certain cases, when
147
+ connect(input, "paste", fastPoll);
148
+ connect(input, "cut", operation(function(){
149
+ if (!options.readOnly) replaceSelection("");
150
+ }));
151
+
152
+ // Needed to handle Tab key in KHTML
153
+ if (khtml) connect(code, "mouseup", function() {
154
+ if (document.activeElement == input) input.blur();
155
+ focusInput();
156
+ });
157
+
158
+ // IE throws unspecified error in certain cases, when
103
159
  // trying to access activeElement before onload
104
- var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
105
- if (hasFocus) setTimeout(onFocus, 20);
160
+ var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
161
+ if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
106
162
  else onBlur();
107
163
 
108
- function isLine(l) {return l >= 0 && l < lines.length;}
164
+ function isLine(l) {return l >= 0 && l < doc.size;}
109
165
  // The instance object that we'll return. Mostly calls out to
110
166
  // local functions in the CodeMirror function. Some do some extra
111
167
  // range checking and/or clipping. operation is used to wrap the
112
168
  // call so that changes it makes are tracked, and the display is
113
169
  // updated afterwards.
114
- var instance = {
170
+ var instance = wrapper.CodeMirror = {
115
171
  getValue: getValue,
116
172
  setValue: operation(setValue),
117
173
  getSelection: getSelection,
118
174
  replaceSelection: operation(replaceSelection),
119
- focus: function(){focusInput(); onFocus(); fastPoll();},
175
+ focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
120
176
  setOption: function(option, value) {
177
+ var oldVal = options[option];
121
178
  options[option] = value;
122
- if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber") gutterChanged();
123
- else if (option == "mode" || option == "indentUnit") loadMode();
124
- else if (option == "readOnly" && value == "nocursor") input.blur();
125
- else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
179
+ if (option == "mode" || option == "indentUnit") loadMode();
180
+ else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();}
181
+ else if (option == "readOnly" && !value) {resetInput(true);}
182
+ else if (option == "theme") themeChanged();
183
+ else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
184
+ else if (option == "tabSize") updateDisplay(true);
185
+ else if (option == "keyMap") keyMapChanged();
186
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
187
+ gutterChanged();
188
+ updateDisplay(true);
189
+ }
126
190
  },
127
191
  getOption: function(option) {return options[option];},
128
192
  undo: operation(undo),
129
193
  redo: operation(redo),
130
194
  indentLine: operation(function(n, dir) {
131
- if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
195
+ if (typeof dir != "string") {
196
+ if (dir == null) dir = options.smartIndent ? "smart" : "prev";
197
+ else dir = dir ? "add" : "subtract";
198
+ }
199
+ if (isLine(n)) indentLine(n, dir);
132
200
  }),
201
+ indentSelection: operation(indentSelected),
133
202
  historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
203
+ clearHistory: function() {history = new History();},
204
+ setHistory: function(histData) {
205
+ history = new History();
206
+ history.done = histData.done;
207
+ history.undone = histData.undone;
208
+ },
209
+ getHistory: function() {
210
+ history.time = 0;
211
+ return {done: history.done.concat([]), undone: history.undone.concat([])};
212
+ },
134
213
  matchBrackets: operation(function(){matchBrackets(true);}),
135
- getTokenAt: function(pos) {
214
+ getTokenAt: operation(function(pos) {
136
215
  pos = clipPos(pos);
137
- return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
138
- },
216
+ return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch);
217
+ }),
139
218
  getStateAfter: function(line) {
140
- line = clipLine(line == null ? lines.length - 1: line);
219
+ line = clipLine(line == null ? doc.size - 1: line);
141
220
  return getStateBefore(line + 1);
142
221
  },
143
- cursorCoords: function(start){
222
+ cursorCoords: function(start, mode) {
144
223
  if (start == null) start = sel.inverted;
145
- return pageCoords(start ? sel.from : sel.to);
224
+ return this.charCoords(start ? sel.from : sel.to, mode);
225
+ },
226
+ charCoords: function(pos, mode) {
227
+ pos = clipPos(pos);
228
+ if (mode == "local") return localCoords(pos, false);
229
+ if (mode == "div") return localCoords(pos, true);
230
+ return pageCoords(pos);
146
231
  },
147
- charCoords: function(pos){return pageCoords(clipPos(pos));},
148
232
  coordsChar: function(coords) {
149
233
  var off = eltOffset(lineSpace);
150
- var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
151
- return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
234
+ return coordsChar(coords.x - off.left, coords.y - off.top);
152
235
  },
153
- getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
154
- markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
155
- setMarker: addGutterMarker,
156
- clearMarker: removeGutterMarker,
236
+ markText: operation(markText),
237
+ setBookmark: setBookmark,
238
+ findMarksAt: findMarksAt,
239
+ setMarker: operation(addGutterMarker),
240
+ clearMarker: operation(removeGutterMarker),
157
241
  setLineClass: operation(setLineClass),
242
+ hideLine: operation(function(h) {return setLineHidden(h, true);}),
243
+ showLine: operation(function(h) {return setLineHidden(h, false);}),
244
+ onDeleteLine: function(line, f) {
245
+ if (typeof line == "number") {
246
+ if (!isLine(line)) return null;
247
+ line = getLine(line);
248
+ }
249
+ (line.handlers || (line.handlers = [])).push(f);
250
+ return line;
251
+ },
158
252
  lineInfo: lineInfo,
159
- addWidget: function(pos, node, scroll, where) {
253
+ addWidget: function(pos, node, scroll, vert, horiz) {
160
254
  pos = localCoords(clipPos(pos));
161
255
  var top = pos.yBot, left = pos.x;
162
256
  node.style.position = "absolute";
163
257
  code.appendChild(node);
164
- node.style.left = left + "px";
165
- if (where == "over") top = pos.y;
166
- else if (where == "near") {
167
- var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
258
+ if (vert == "over") top = pos.y;
259
+ else if (vert == "near") {
260
+ var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
168
261
  hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
169
262
  if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
170
263
  top = pos.y - node.offsetHeight;
@@ -172,75 +265,166 @@ var CodeMirror = (function() {
172
265
  left = hspace - node.offsetWidth;
173
266
  }
174
267
  node.style.top = (top + paddingTop()) + "px";
175
- node.style.left = (left + paddingLeft()) + "px";
268
+ node.style.left = node.style.right = "";
269
+ if (horiz == "right") {
270
+ left = code.clientWidth - node.offsetWidth;
271
+ node.style.right = "0px";
272
+ } else {
273
+ if (horiz == "left") left = 0;
274
+ else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2;
275
+ node.style.left = (left + paddingLeft()) + "px";
276
+ }
176
277
  if (scroll)
177
278
  scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
178
279
  },
179
280
 
180
- lineCount: function() {return lines.length;},
281
+ lineCount: function() {return doc.size;},
282
+ clipPos: clipPos,
181
283
  getCursor: function(start) {
182
284
  if (start == null) start = sel.inverted;
183
285
  return copyPos(start ? sel.from : sel.to);
184
286
  },
185
287
  somethingSelected: function() {return !posEq(sel.from, sel.to);},
186
- setCursor: operation(function(line, ch) {
187
- if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
188
- else setCursor(line, ch);
288
+ setCursor: operation(function(line, ch, user) {
289
+ if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user);
290
+ else setCursor(line, ch, user);
189
291
  }),
190
- setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
191
- getLine: function(line) {if (isLine(line)) return lines[line].text;},
292
+ setSelection: operation(function(from, to, user) {
293
+ (user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from));
294
+ }),
295
+ getLine: function(line) {if (isLine(line)) return getLine(line).text;},
296
+ getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
192
297
  setLine: operation(function(line, text) {
193
- if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
298
+ if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
194
299
  }),
195
300
  removeLine: operation(function(line) {
196
301
  if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
197
302
  }),
198
303
  replaceRange: operation(replaceRange),
199
- getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
304
+ getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);},
305
+
306
+ triggerOnKeyDown: operation(onKeyDown),
307
+ execCommand: function(cmd) {return commands[cmd](instance);},
308
+ // Stuff used by commands, probably not much use to outside code.
309
+ moveH: operation(moveH),
310
+ deleteH: operation(deleteH),
311
+ moveV: operation(moveV),
312
+ toggleOverwrite: function() {
313
+ if(overwrite){
314
+ overwrite = false;
315
+ cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
316
+ } else {
317
+ overwrite = true;
318
+ cursor.className += " CodeMirror-overwrite";
319
+ }
320
+ },
321
+
322
+ posFromIndex: function(off) {
323
+ var lineNo = 0, ch;
324
+ doc.iter(0, doc.size, function(line) {
325
+ var sz = line.text.length + 1;
326
+ if (sz > off) { ch = off; return true; }
327
+ off -= sz;
328
+ ++lineNo;
329
+ });
330
+ return clipPos({line: lineNo, ch: ch});
331
+ },
332
+ indexFromPos: function (coords) {
333
+ if (coords.line < 0 || coords.ch < 0) return 0;
334
+ var index = coords.ch;
335
+ doc.iter(0, coords.line, function (line) {
336
+ index += line.text.length + 1;
337
+ });
338
+ return index;
339
+ },
340
+ scrollTo: function(x, y) {
341
+ if (x != null) scroller.scrollLeft = x;
342
+ if (y != null) scrollbar.scrollTop = y;
343
+ updateDisplay([]);
344
+ },
345
+ getScrollInfo: function() {
346
+ return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
347
+ height: scrollbar.scrollHeight, width: scroller.scrollWidth};
348
+ },
349
+ setSize: function(width, height) {
350
+ function interpret(val) {
351
+ val = String(val);
352
+ return /^\d+$/.test(val) ? val + "px" : val;
353
+ }
354
+ if (width != null) wrapper.style.width = interpret(width);
355
+ if (height != null) scroller.style.height = interpret(height);
356
+ },
200
357
 
201
358
  operation: function(f){return operation(f)();},
202
- refresh: function(){updateDisplay(true);},
359
+ compoundChange: function(f){return compoundChange(f);},
360
+ refresh: function(){
361
+ updateDisplay(true, null, lastScrollTop);
362
+ if (scrollbar.scrollHeight > lastScrollTop)
363
+ scrollbar.scrollTop = lastScrollTop;
364
+ },
203
365
  getInputField: function(){return input;},
204
366
  getWrapperElement: function(){return wrapper;},
205
367
  getScrollerElement: function(){return scroller;},
206
368
  getGutterElement: function(){return gutter;}
207
369
  };
208
370
 
371
+ function getLine(n) { return getLineAt(doc, n); }
372
+ function updateLineHeight(line, height) {
373
+ gutterDirty = true;
374
+ var diff = height - line.height;
375
+ for (var n = line; n; n = n.parent) n.height += diff;
376
+ }
377
+
209
378
  function setValue(code) {
210
- history = null;
211
379
  var top = {line: 0, ch: 0};
212
- updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
380
+ updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length},
213
381
  splitLines(code), top, top);
214
- history = new History();
382
+ updateInput = true;
215
383
  }
216
- function getValue(code) {
384
+ function getValue(lineSep) {
217
385
  var text = [];
218
- for (var i = 0, l = lines.length; i < l; ++i)
219
- text.push(lines[i].text);
220
- return text.join("\n");
386
+ doc.iter(0, doc.size, function(line) { text.push(line.text); });
387
+ return text.join(lineSep || "\n");
388
+ }
389
+
390
+ function onScroll(e) {
391
+ if (scroller.scrollTop) {
392
+ scrollbar.scrollTop += scroller.scrollTop;
393
+ scroller.scrollTop = 0;
394
+ }
395
+ if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
396
+ lastScrollTop = scrollbar.scrollTop;
397
+ lastScrollLeft = scroller.scrollLeft;
398
+ updateDisplay([]);
399
+ if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
400
+ if (options.onScroll) options.onScroll(instance);
401
+ }
221
402
  }
222
403
 
223
404
  function onMouseDown(e) {
405
+ setShift(e_prop(e, "shiftKey"));
224
406
  // Check whether this is a click in a widget
225
407
  for (var n = e_target(e); n != wrapper; n = n.parentNode)
226
408
  if (n.parentNode == code && n != mover) return;
227
- var ld = lastDoubleClick; lastDoubleClick = null;
228
- // First, see if this is a click in the gutter
409
+
410
+ // See if this is a click in the gutter
229
411
  for (var n = e_target(e); n != wrapper; n = n.parentNode)
230
412
  if (n.parentNode == gutterText) {
231
413
  if (options.onGutterClick)
232
- options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
414
+ options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e);
233
415
  return e_preventDefault(e);
234
416
  }
235
417
 
236
418
  var start = posFromMouse(e);
237
-
419
+
238
420
  switch (e_button(e)) {
239
421
  case 3:
240
- if (gecko && !mac) onContextMenu(e);
422
+ if (gecko) onContextMenu(e);
241
423
  return;
242
424
  case 2:
243
425
  if (start) setCursor(start.line, start.ch, true);
426
+ setTimeout(focusInput, 20);
427
+ e_preventDefault(e);
244
428
  return;
245
429
  }
246
430
  // For button 1, if it was clicked inside the editor
@@ -249,24 +433,67 @@ var CodeMirror = (function() {
249
433
  if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
250
434
 
251
435
  if (!focused) onFocus();
252
- e_preventDefault(e);
253
- if (ld && +new Date - ld < 400) return selectLine(start.line);
254
436
 
255
- setCursor(start.line, start.ch, true);
437
+ var now = +new Date, type = "single";
438
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
439
+ type = "triple";
440
+ e_preventDefault(e);
441
+ setTimeout(focusInput, 20);
442
+ selectLine(start.line);
443
+ } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
444
+ type = "double";
445
+ lastDoubleClick = {time: now, pos: start};
446
+ e_preventDefault(e);
447
+ var word = findWordAt(start);
448
+ setSelectionUser(word.from, word.to);
449
+ } else { lastClick = {time: now, pos: start}; }
450
+
256
451
  var last = start, going;
257
- // And then we have to see if it's a drag event, in which case
258
- // the dragged-over text must be selected.
259
- function end() {
260
- focusInput();
261
- updateInput = true;
262
- move(); up();
452
+ if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
453
+ !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
454
+ // Let the drag handler handle this.
455
+ if (webkit) scroller.draggable = true;
456
+ function dragEnd(e2) {
457
+ if (webkit) scroller.draggable = false;
458
+ draggingText = false;
459
+ up(); drop();
460
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
461
+ e_preventDefault(e2);
462
+ setCursor(start.line, start.ch, true);
463
+ focusInput();
464
+ }
465
+ }
466
+ var up = connect(document, "mouseup", operation(dragEnd), true);
467
+ var drop = connect(scroller, "drop", operation(dragEnd), true);
468
+ draggingText = true;
469
+ // IE's approach to draggable
470
+ if (scroller.dragDrop) scroller.dragDrop();
471
+ return;
263
472
  }
473
+ e_preventDefault(e);
474
+ if (type == "single") setCursor(start.line, start.ch, true);
475
+
476
+ var startstart = sel.from, startend = sel.to;
477
+
478
+ function doSelect(cur) {
479
+ if (type == "single") {
480
+ setSelectionUser(start, cur);
481
+ } else if (type == "double") {
482
+ var word = findWordAt(cur);
483
+ if (posLess(cur, startstart)) setSelectionUser(word.from, startend);
484
+ else setSelectionUser(startstart, word.to);
485
+ } else if (type == "triple") {
486
+ if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0}));
487
+ else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0}));
488
+ }
489
+ }
490
+
264
491
  function extend(e) {
265
492
  var cur = posFromMouse(e, true);
266
493
  if (cur && !posEq(cur, last)) {
267
494
  if (!focused) onFocus();
268
495
  last = cur;
269
- setSelectionUser(start, cur);
496
+ doSelect(cur);
270
497
  updateInput = false;
271
498
  var visible = visibleLines();
272
499
  if (cur.line >= visible.to || cur.line < visible.from)
@@ -274,27 +501,30 @@ var CodeMirror = (function() {
274
501
  }
275
502
  }
276
503
 
277
- var move = connect(targetDocument, "mousemove", operation(function(e) {
504
+ function done(e) {
278
505
  clearTimeout(going);
506
+ var cur = posFromMouse(e);
507
+ if (cur) doSelect(cur);
279
508
  e_preventDefault(e);
280
- extend(e);
281
- }), true);
282
- var up = connect(targetDocument, "mouseup", operation(function(e) {
509
+ focusInput();
510
+ updateInput = true;
511
+ move(); up();
512
+ }
513
+ var move = connect(document, "mousemove", operation(function(e) {
283
514
  clearTimeout(going);
284
- var cur = posFromMouse(e);
285
- if (cur) setSelectionUser(start, cur);
286
515
  e_preventDefault(e);
287
- end();
516
+ if (!ie && !e_button(e)) done(e);
517
+ else extend(e);
288
518
  }), true);
519
+ var up = connect(document, "mouseup", operation(done), true);
289
520
  }
290
- function onDblClick(e) {
291
- var pos = posFromMouse(e);
292
- if (!pos) return;
293
- selectWordAt(pos);
521
+ function onDoubleClick(e) {
522
+ for (var n = e_target(e); n != wrapper; n = n.parentNode)
523
+ if (n.parentNode == gutterText) return e_preventDefault(e);
294
524
  e_preventDefault(e);
295
- lastDoubleClick = +new Date;
296
525
  }
297
526
  function onDrop(e) {
527
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
298
528
  e.preventDefault();
299
529
  var pos = posFromMouse(e, true), files = e.dataTransfer.files;
300
530
  if (!pos || options.readOnly) return;
@@ -303,86 +533,148 @@ var CodeMirror = (function() {
303
533
  var reader = new FileReader;
304
534
  reader.onload = function() {
305
535
  text[i] = reader.result;
306
- if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
536
+ if (++read == n) {
537
+ pos = clipPos(pos);
538
+ operation(function() {
539
+ var end = replaceRange(text.join(""), pos, pos);
540
+ setSelectionUser(pos, end);
541
+ })();
542
+ }
307
543
  };
308
544
  reader.readAsText(file);
309
545
  }
310
546
  var n = files.length, text = Array(n), read = 0;
311
547
  for (var i = 0; i < n; ++i) loadFile(files[i], i);
312
- }
313
- else {
548
+ } else {
549
+ // Don't do a replace if the drop happened inside of the selected text.
550
+ if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
314
551
  try {
315
552
  var text = e.dataTransfer.getData("Text");
316
- if (text) replaceRange(text, pos, pos);
553
+ if (text) {
554
+ compoundChange(function() {
555
+ var curFrom = sel.from, curTo = sel.to;
556
+ setSelectionUser(pos, pos);
557
+ if (draggingText) replaceRange("", curFrom, curTo);
558
+ replaceSelection(text);
559
+ focusInput();
560
+ });
561
+ }
317
562
  }
318
563
  catch(e){}
319
564
  }
320
565
  }
321
- function onKeyDown(e) {
322
- if (!focused) onFocus();
323
-
324
- var code = e.keyCode;
325
- // IE does strange things with escape.
326
- if (ie && code == 27) { e.returnValue = false; }
327
- // Tries to detect ctrl on non-mac, cmd on mac.
328
- var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
329
- if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
330
- else shiftSelecting = null;
331
- // First give onKeyEvent option a chance to handle this.
332
- if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
333
-
334
- if (code == 33 || code == 34) {scrollPage(code == 34); return e_preventDefault(e);} // page up/down
335
- if (mod && ((code == 36 || code == 35) || // ctrl-home/end
336
- mac && (code == 38 || code == 40))) { // cmd-up/down
337
- scrollEnd(code == 36 || code == 38); return e_preventDefault(e);
338
- }
339
- if (mod && code == 65) {selectAll(); return e_preventDefault(e);} // ctrl-a
340
- if (!options.readOnly) {
341
- if (!anyMod && code == 13) {return;} // enter
342
- if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
343
- if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
344
- if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
345
- }
346
- if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
347
-
348
- // Key id to use in the movementKeys map. We also pass it to
349
- // fastPoll in order to 'self learn'. We need this because
350
- // reducedSelection, the hack where we collapse the selection to
351
- // its start when it is inverted and a movement key is pressed
352
- // (and later restore it again), shouldn't be used for
353
- // non-movement keys.
354
- curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
355
- if (sel.inverted && movementKeys[curKeyId] === true) {
356
- var range = selRange(input);
357
- if (range) {
358
- reducedSelection = {anchor: range.start};
359
- setSelRange(input, range.start, range.start);
566
+ function onDragStart(e) {
567
+ var txt = getSelection();
568
+ e.dataTransfer.setData("Text", txt);
569
+
570
+ // Use dummy image instead of default browsers image.
571
+ if (gecko || chrome || opera) {
572
+ var img = document.createElement('img');
573
+ img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
574
+ e.dataTransfer.setDragImage(img, 0, 0);
575
+ }
576
+ }
577
+
578
+ function doHandleBinding(bound, dropShift) {
579
+ if (typeof bound == "string") {
580
+ bound = commands[bound];
581
+ if (!bound) return false;
582
+ }
583
+ var prevShift = shiftSelecting;
584
+ try {
585
+ if (options.readOnly) suppressEdits = true;
586
+ if (dropShift) shiftSelecting = null;
587
+ bound(instance);
588
+ } catch(e) {
589
+ if (e != Pass) throw e;
590
+ return false;
591
+ } finally {
592
+ shiftSelecting = prevShift;
593
+ suppressEdits = false;
594
+ }
595
+ return true;
596
+ }
597
+ function handleKeyBinding(e) {
598
+ // Handle auto keymap transitions
599
+ var startMap = getKeyMap(options.keyMap), next = startMap.auto;
600
+ clearTimeout(maybeTransition);
601
+ if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
602
+ if (getKeyMap(options.keyMap) == startMap) {
603
+ options.keyMap = (next.call ? next.call(null, instance) : next);
360
604
  }
605
+ }, 50);
606
+
607
+ var name = keyNames[e_prop(e, "keyCode")], handled = false;
608
+ if (name == null || e.altGraphKey) return false;
609
+ if (e_prop(e, "altKey")) name = "Alt-" + name;
610
+ if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
611
+ if (e_prop(e, "metaKey")) name = "Cmd-" + name;
612
+
613
+ var stopped = false;
614
+ function stop() { stopped = true; }
615
+
616
+ if (e_prop(e, "shiftKey")) {
617
+ handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
618
+ function(b) {return doHandleBinding(b, true);}, stop)
619
+ || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
620
+ if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
621
+ }, stop);
622
+ } else {
623
+ handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
361
624
  }
362
- // Don't save the key as a movementkey unless it had a modifier
363
- if (!mod && !e.altKey) curKeyId = null;
364
- fastPoll(curKeyId);
625
+ if (stopped) handled = false;
626
+ if (handled) {
627
+ e_preventDefault(e);
628
+ restartBlink();
629
+ if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
630
+ }
631
+ return handled;
365
632
  }
366
- function onKeyUp(e) {
633
+ function handleCharBinding(e, ch) {
634
+ var handled = lookupKey("'" + ch + "'", options.extraKeys,
635
+ options.keyMap, function(b) { return doHandleBinding(b, true); });
636
+ if (handled) {
637
+ e_preventDefault(e);
638
+ restartBlink();
639
+ }
640
+ return handled;
641
+ }
642
+
643
+ var lastStoppedKey = null, maybeTransition;
644
+ function onKeyDown(e) {
645
+ if (!focused) onFocus();
646
+ if (ie && e.keyCode == 27) { e.returnValue = false; }
647
+ if (pollingFast) { if (readInput()) pollingFast = false; }
367
648
  if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
368
- if (reducedSelection) {
369
- reducedSelection = null;
370
- updateInput = true;
649
+ var code = e_prop(e, "keyCode");
650
+ // IE does strange things with escape.
651
+ setShift(code == 16 || e_prop(e, "shiftKey"));
652
+ // First give onKeyEvent option a chance to handle this.
653
+ var handled = handleKeyBinding(e);
654
+ if (opera) {
655
+ lastStoppedKey = handled ? code : null;
656
+ // Opera has no cut event... we try to at least catch the key combo
657
+ if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
658
+ replaceSelection("");
371
659
  }
372
- if (e.keyCode == 16) shiftSelecting = null;
373
660
  }
374
661
  function onKeyPress(e) {
662
+ if (pollingFast) readInput();
375
663
  if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
376
- if (options.electricChars && mode.electricChars) {
377
- var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode);
664
+ var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
665
+ if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
666
+ if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
667
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
668
+ if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
378
669
  if (mode.electricChars.indexOf(ch) > -1)
379
- setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
670
+ setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
380
671
  }
381
- var code = e.keyCode;
382
- // Re-stop tab and enter. Necessary on some browsers.
383
- if (code == 13) {if (!options.readOnly) handleEnter(); e_preventDefault(e);}
384
- else if (!e.ctrlKey && !e.altKey && !e.metaKey && code == 9 && options.tabMode != "default") e_preventDefault(e);
385
- else fastPoll(curKeyId);
672
+ if (handleCharBinding(e, ch)) return;
673
+ fastPoll();
674
+ }
675
+ function onKeyUp(e) {
676
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
677
+ if (e_prop(e, "keyCode") == 16) shiftSelecting = null;
386
678
  }
387
679
 
388
680
  function onFocus() {
@@ -390,9 +682,9 @@ var CodeMirror = (function() {
390
682
  if (!focused) {
391
683
  if (options.onFocus) options.onFocus(instance);
392
684
  focused = true;
393
- if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
394
- wrapper.className += " CodeMirror-focused";
395
- if (!leaveInputAlone) prepareInput();
685
+ if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
686
+ scroller.className += " CodeMirror-focused";
687
+ if (!leaveInputAlone) resetInput(true);
396
688
  }
397
689
  slowPoll();
398
690
  restartBlink();
@@ -401,86 +693,149 @@ var CodeMirror = (function() {
401
693
  if (focused) {
402
694
  if (options.onBlur) options.onBlur(instance);
403
695
  focused = false;
404
- wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
696
+ if (bracketHighlighted)
697
+ operation(function(){
698
+ if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
699
+ })();
700
+ scroller.className = scroller.className.replace(" CodeMirror-focused", "");
405
701
  }
406
702
  clearInterval(blinker);
407
703
  setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
408
704
  }
409
705
 
706
+ function chopDelta(delta) {
707
+ // Make sure we always scroll a little bit for any nonzero delta.
708
+ if (delta > 0.0 && delta < 1.0) return 1;
709
+ else if (delta > -1.0 && delta < 0.0) return -1;
710
+ else return Math.round(delta);
711
+ }
712
+
713
+ function onMouseWheel(e) {
714
+ var deltaX = 0, deltaY = 0;
715
+ if (e.type == "DOMMouseScroll") { // Firefox
716
+ var delta = -e.detail * 8.0;
717
+ if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
718
+ else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
719
+ } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
720
+ deltaX = e.wheelDeltaX / 3.0;
721
+ deltaY = e.wheelDeltaY / 3.0;
722
+ } else if (e.wheelDelta !== undefined) { // IE or Opera
723
+ deltaY = e.wheelDelta / 3.0;
724
+ }
725
+
726
+ var scrolled = false;
727
+ deltaX = chopDelta(deltaX);
728
+ deltaY = chopDelta(deltaY);
729
+ if ((deltaX > 0 && scroller.scrollLeft > 0) ||
730
+ (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
731
+ scroller.scrollLeft -= deltaX;
732
+ scrolled = true;
733
+ }
734
+ if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
735
+ (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
736
+ scrollbar.scrollTop -= deltaY;
737
+ scrolled = true;
738
+ }
739
+ if (scrolled) e_stop(e);
740
+ }
741
+
410
742
  // Replace the range from from to to by the strings in newText.
411
743
  // Afterwards, set the selection to selFrom, selTo.
412
744
  function updateLines(from, to, newText, selFrom, selTo) {
745
+ if (suppressEdits) return;
413
746
  if (history) {
414
747
  var old = [];
415
- for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
748
+ doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
416
749
  history.addChange(from.line, newText.length, old);
417
750
  while (history.done.length > options.undoDepth) history.done.shift();
418
751
  }
419
752
  updateLinesNoUndo(from, to, newText, selFrom, selTo);
420
753
  }
421
754
  function unredoHelper(from, to) {
422
- var change = from.pop();
423
- if (change) {
755
+ if (!from.length) return;
756
+ var set = from.pop(), out = [];
757
+ for (var i = set.length - 1; i >= 0; i -= 1) {
758
+ var change = set[i];
424
759
  var replaced = [], end = change.start + change.added;
425
- for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
426
- to.push({start: change.start, added: change.old.length, old: replaced});
427
- var pos = clipPos({line: change.start + change.old.length - 1,
428
- ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
429
- updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
430
- updateInput = true;
760
+ doc.iter(change.start, end, function(line) { replaced.push(line.text); });
761
+ out.push({start: change.start, added: change.old.length, old: replaced});
762
+ var pos = {line: change.start + change.old.length - 1,
763
+ ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
764
+ updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
431
765
  }
766
+ updateInput = true;
767
+ to.push(out);
432
768
  }
433
769
  function undo() {unredoHelper(history.done, history.undone);}
434
770
  function redo() {unredoHelper(history.undone, history.done);}
435
771
 
436
772
  function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
773
+ if (suppressEdits) return;
437
774
  var recomputeMaxLength = false, maxLineLength = maxLine.length;
438
- for (var i = from.line; i <= to.line; ++i) {
439
- if (lines[i].text.length == maxLineLength) {recomputeMaxLength = true; break;}
440
- }
775
+ if (!options.lineWrapping)
776
+ doc.iter(from.line, to.line + 1, function(line) {
777
+ if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
778
+ });
779
+ if (from.line != to.line || newText.length > 1) gutterDirty = true;
441
780
 
442
- var nlines = to.line - from.line, firstLine = lines[from.line], lastLine = lines[to.line];
781
+ var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
443
782
  // First adjust the line structure, taking some care to leave highlighting intact.
444
- if (firstLine == lastLine) {
783
+ if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") {
784
+ // This is a whole-line replace. Treated specially to make
785
+ // sure line objects move the way they are supposed to.
786
+ var added = [], prevLine = null;
787
+ if (from.line) {
788
+ prevLine = getLine(from.line - 1);
789
+ prevLine.fixMarkEnds(lastLine);
790
+ } else lastLine.fixMarkStarts();
791
+ for (var i = 0, e = newText.length - 1; i < e; ++i)
792
+ added.push(Line.inheritMarks(newText[i], prevLine));
793
+ if (nlines) doc.remove(from.line, nlines, callbacks);
794
+ if (added.length) doc.insert(from.line, added);
795
+ } else if (firstLine == lastLine) {
445
796
  if (newText.length == 1)
446
797
  firstLine.replace(from.ch, to.ch, newText[0]);
447
798
  else {
448
799
  lastLine = firstLine.split(to.ch, newText[newText.length-1]);
449
- var spliceargs = [from.line + 1, nlines];
450
- firstLine.replace(from.ch, firstLine.text.length, newText[0]);
451
- for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
452
- spliceargs.push(lastLine);
453
- lines.splice.apply(lines, spliceargs);
800
+ firstLine.replace(from.ch, null, newText[0]);
801
+ firstLine.fixMarkEnds(lastLine);
802
+ var added = [];
803
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
804
+ added.push(Line.inheritMarks(newText[i], firstLine));
805
+ added.push(lastLine);
806
+ doc.insert(from.line + 1, added);
454
807
  }
455
- }
456
- else if (newText.length == 1) {
457
- firstLine.replace(from.ch, firstLine.text.length, newText[0] + lastLine.text.slice(to.ch));
458
- lines.splice(from.line + 1, nlines);
459
- }
460
- else {
461
- var spliceargs = [from.line + 1, nlines - 1];
462
- firstLine.replace(from.ch, firstLine.text.length, newText[0]);
463
- lastLine.replace(0, to.ch, newText[newText.length-1]);
464
- for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
465
- lines.splice.apply(lines, spliceargs);
466
- }
467
-
468
-
469
- for (var i = from.line, e = i + newText.length; i < e; ++i) {
470
- var l = lines[i].text;
471
- if (l.length > maxLineLength) {
472
- maxLine = l; maxLineLength = l.length; maxWidth = null;
473
- recomputeMaxLength = false;
474
- }
475
- }
476
- if (recomputeMaxLength) {
477
- maxLineLength = 0; maxLine = ""; maxWidth = null;
478
- for (var i = 0, e = lines.length; i < e; ++i) {
479
- var l = lines[i].text;
480
- if (l.length > maxLineLength) {
481
- maxLineLength = l.length; maxLine = l;
808
+ } else if (newText.length == 1) {
809
+ firstLine.replace(from.ch, null, newText[0]);
810
+ lastLine.replace(null, to.ch, "");
811
+ firstLine.append(lastLine);
812
+ doc.remove(from.line + 1, nlines, callbacks);
813
+ } else {
814
+ var added = [];
815
+ firstLine.replace(from.ch, null, newText[0]);
816
+ lastLine.replace(null, to.ch, newText[newText.length-1]);
817
+ firstLine.fixMarkEnds(lastLine);
818
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
819
+ added.push(Line.inheritMarks(newText[i], firstLine));
820
+ if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
821
+ doc.insert(from.line + 1, added);
822
+ }
823
+ if (options.lineWrapping) {
824
+ var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
825
+ doc.iter(from.line, from.line + newText.length, function(line) {
826
+ if (line.hidden) return;
827
+ var guess = Math.ceil(line.text.length / perLine) || 1;
828
+ if (guess != line.height) updateLineHeight(line, guess);
829
+ });
830
+ } else {
831
+ doc.iter(from.line, from.line + newText.length, function(line) {
832
+ var l = line.text;
833
+ if (!line.hidden && l.length > maxLineLength) {
834
+ maxLine = l; maxLineLength = l.length; maxLineChanged = true;
835
+ recomputeMaxLength = false;
482
836
  }
483
- }
837
+ });
838
+ if (recomputeMaxLength) updateMaxLine = true;
484
839
  }
485
840
 
486
841
  // Add these lines to the work array, so that they will be
@@ -491,24 +846,70 @@ var CodeMirror = (function() {
491
846
  if (task < from.line) newWork.push(task);
492
847
  else if (task > to.line) newWork.push(task + lendiff);
493
848
  }
494
- if (newText.length < 5) {
495
- highlightLines(from.line, from.line + newText.length);
496
- newWork.push(from.line + newText.length);
497
- } else {
498
- newWork.push(from.line);
499
- }
849
+ var hlEnd = from.line + Math.min(newText.length, 500);
850
+ highlightLines(from.line, hlEnd);
851
+ newWork.push(hlEnd);
500
852
  work = newWork;
501
853
  startWorker(100);
502
854
  // Remember that these lines changed, for updating the display
503
855
  changes.push({from: from.line, to: to.line + 1, diff: lendiff});
504
- textChanged = {from: from, to: to, text: newText};
856
+ var changeObj = {from: from, to: to, text: newText};
857
+ if (textChanged) {
858
+ for (var cur = textChanged; cur.next; cur = cur.next) {}
859
+ cur.next = changeObj;
860
+ } else textChanged = changeObj;
505
861
 
506
862
  // Update the selection
507
863
  function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
508
- setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
864
+ setSelection(clipPos(selFrom), clipPos(selTo),
865
+ updateLine(sel.from.line), updateLine(sel.to.line));
866
+ }
867
+
868
+ function needsScrollbar() {
869
+ var realHeight = doc.height * textHeight() + 2 * paddingTop();
870
+ return realHeight - 1 > scroller.offsetHeight ? realHeight : false;
871
+ }
872
+
873
+ function updateVerticalScroll(scrollTop) {
874
+ var scrollHeight = needsScrollbar();
875
+ scrollbar.style.display = scrollHeight ? "block" : "none";
876
+ if (scrollHeight) {
877
+ scrollbarInner.style.height = scrollHeight + "px";
878
+ scrollbar.style.height = scroller.offsetHeight + "px";
879
+ if (scrollTop != null) scrollbar.scrollTop = scrollTop;
880
+ }
881
+ // Position the mover div to align with the current virtual scroll position
882
+ mover.style.top = (displayOffset * textHeight() - scrollbar.scrollTop) + "px";
883
+ }
884
+
885
+ // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring
886
+ // the width of a div with a scrollbar in it. If the width is <= 1, then
887
+ // the mouse isn't plugged in and scrollbars should overlap the content.
888
+ function overlapScrollbars() {
889
+ var tmpSb = document.createElement('div'),
890
+ tmpSbInner = document.createElement('div');
891
+ tmpSb.className = "CodeMirror-scrollbar";
892
+ tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
893
+ tmpSbInner.className = "CodeMirror-scrollbar-inner";
894
+ tmpSbInner.style.height = "200px";
895
+ tmpSb.appendChild(tmpSbInner);
896
+
897
+ document.body.appendChild(tmpSb);
898
+ var result = (tmpSb.offsetWidth <= 1);
899
+ document.body.removeChild(tmpSb);
900
+ return result;
901
+ }
509
902
 
510
- // Make sure the scroll-size div has the correct height.
511
- code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
903
+ function computeMaxLength() {
904
+ var maxLineLength = 0;
905
+ maxLine = ""; maxLineChanged = true;
906
+ doc.iter(0, doc.size, function(line) {
907
+ var l = line.text;
908
+ if (!line.hidden && l.length > maxLineLength) {
909
+ maxLineLength = l.length; maxLine = l;
910
+ }
911
+ });
912
+ updateMaxLine = false;
512
913
  }
513
914
 
514
915
  function replaceRange(code, from, to) {
@@ -544,193 +945,233 @@ var CodeMirror = (function() {
544
945
  updateLines(from, to, code, newSel.from, newSel.to);
545
946
  }
546
947
 
547
- function getRange(from, to) {
948
+ function getRange(from, to, lineSep) {
548
949
  var l1 = from.line, l2 = to.line;
549
- if (l1 == l2) return lines[l1].text.slice(from.ch, to.ch);
550
- var code = [lines[l1].text.slice(from.ch)];
551
- for (var i = l1 + 1; i < l2; ++i) code.push(lines[i].text);
552
- code.push(lines[l2].text.slice(0, to.ch));
553
- return code.join("\n");
950
+ if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
951
+ var code = [getLine(l1).text.slice(from.ch)];
952
+ doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
953
+ code.push(getLine(l2).text.slice(0, to.ch));
954
+ return code.join(lineSep || "\n");
554
955
  }
555
- function getSelection() {
556
- return getRange(sel.from, sel.to);
956
+ function getSelection(lineSep) {
957
+ return getRange(sel.from, sel.to, lineSep);
557
958
  }
558
959
 
559
960
  var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
560
961
  function slowPoll() {
561
962
  if (pollingFast) return;
562
- poll.set(2000, function() {
963
+ poll.set(options.pollInterval, function() {
563
964
  startOperation();
564
965
  readInput();
565
966
  if (focused) slowPoll();
566
967
  endOperation();
567
968
  });
568
969
  }
569
- function fastPoll(keyId) {
970
+ function fastPoll() {
570
971
  var missed = false;
571
972
  pollingFast = true;
572
973
  function p() {
573
974
  startOperation();
574
975
  var changed = readInput();
575
- if (changed && keyId) {
576
- if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
577
- if (changed == "changed") movementKeys[keyId] = false;
578
- }
579
- if (!changed && !missed) {missed = true; poll.set(80, p);}
976
+ if (!changed && !missed) {missed = true; poll.set(60, p);}
580
977
  else {pollingFast = false; slowPoll();}
581
978
  endOperation();
582
979
  }
583
980
  poll.set(20, p);
584
981
  }
585
982
 
586
- // Inspects the textarea, compares its state (content, selection)
587
- // to the data in the editing variable, and updates the editor
588
- // content or cursor if something changed.
983
+ // Previnput is a hack to work with IME. If we reset the textarea
984
+ // on every change, that breaks IME. So we look for changes
985
+ // compared to the previous content instead. (Modern browsers have
986
+ // events that indicate IME taking place, but these are not widely
987
+ // supported or compatible enough yet to rely on.)
988
+ var prevInput = "";
589
989
  function readInput() {
590
- if (leaveInputAlone || !focused) return;
591
- var changed = false, text = input.value, sr = selRange(input);
592
- if (!sr) return false;
593
- var changed = editing.text != text, rs = reducedSelection;
594
- var moved = changed || sr.start != editing.start || sr.end != (rs ? editing.start : editing.end);
595
- if (!moved && !rs) return false;
596
- if (changed) {
597
- shiftSelecting = reducedSelection = null;
598
- if (options.readOnly) {updateInput = true; return "changed";}
599
- }
600
-
601
- // Compute selection start and end based on start/end offsets in textarea
602
- function computeOffset(n, startLine) {
603
- var pos = 0;
604
- for (;;) {
605
- var found = text.indexOf("\n", pos);
606
- if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
607
- return {line: startLine, ch: n - pos};
608
- ++startLine;
609
- pos = found + 1;
610
- }
611
- }
612
- var from = computeOffset(sr.start, editing.from),
613
- to = computeOffset(sr.end, editing.from);
614
- // Here we have to take the reducedSelection hack into account,
615
- // so that you can, for example, press shift-up at the start of
616
- // your selection and have the right thing happen.
617
- if (rs) {
618
- var head = sr.start == rs.anchor ? to : from;
619
- var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
620
- if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
621
- else { reducedSelection = null; from = tail; to = head; }
622
- }
623
-
624
- // In some cases (cursor on same line as before), we don't have
625
- // to update the textarea content at all.
626
- if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
627
- updateInput = false;
628
-
629
- // Magic mess to extract precise edited range from the changed
630
- // string.
631
- if (changed) {
632
- var start = 0, end = text.length, len = Math.min(end, editing.text.length);
633
- var c, line = editing.from, nl = -1;
634
- while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
635
- ++start;
636
- if (c == "\n") {line++; nl = start;}
637
- }
638
- var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
639
- for (;;) {
640
- c = editing.text.charAt(edend);
641
- if (text.charAt(end) != c) {++end; ++edend; break;}
642
- if (c == "\n") endline--;
643
- if (edend <= start || end <= start) break;
644
- --end; --edend;
645
- }
646
- var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
647
- updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
648
- if (line != endline || from.line != line) updateInput = true;
649
- }
650
- else setSelection(from, to);
651
-
652
- editing.text = text; editing.start = sr.start; editing.end = sr.end;
653
- return changed ? "changed" : moved ? "moved" : false;
990
+ if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false;
991
+ var text = input.value;
992
+ if (text == prevInput) return false;
993
+ shiftSelecting = null;
994
+ var same = 0, l = Math.min(prevInput.length, text.length);
995
+ while (same < l && prevInput[same] == text[same]) ++same;
996
+ if (same < prevInput.length)
997
+ sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
998
+ else if (overwrite && posEq(sel.from, sel.to))
999
+ sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
1000
+ replaceSelection(text.slice(same), "end");
1001
+ if (text.length > 1000) { input.value = prevInput = ""; }
1002
+ else prevInput = text;
1003
+ return true;
654
1004
  }
655
-
656
- // Set the textarea content and selection range to match the
657
- // editor state.
658
- function prepareInput() {
659
- var text = [];
660
- var from = Math.max(0, sel.from.line - 1), to = Math.min(lines.length, sel.to.line + 2);
661
- for (var i = from; i < to; ++i) text.push(lines[i].text);
662
- text = input.value = text.join(lineSep);
663
- var startch = sel.from.ch, endch = sel.to.ch;
664
- for (var i = from; i < sel.from.line; ++i)
665
- startch += lineSep.length + lines[i].text.length;
666
- for (var i = from; i < sel.to.line; ++i)
667
- endch += lineSep.length + lines[i].text.length;
668
- editing = {text: text, from: from, to: to, start: startch, end: endch};
669
- setSelRange(input, startch, reducedSelection ? startch : endch);
1005
+ function resetInput(user) {
1006
+ if (!posEq(sel.from, sel.to)) {
1007
+ prevInput = "";
1008
+ input.value = getSelection();
1009
+ selectInput(input);
1010
+ } else if (user) prevInput = input.value = "";
670
1011
  }
1012
+
671
1013
  function focusInput() {
672
1014
  if (options.readOnly != "nocursor") input.focus();
673
1015
  }
674
1016
 
675
1017
  function scrollEditorIntoView() {
676
- if (!cursor.getBoundingClientRect) return;
677
1018
  var rect = cursor.getBoundingClientRect();
678
- var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
679
- if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
1019
+ // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
1020
+ if (ie && rect.top == rect.bottom) return;
1021
+ var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
1022
+ if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
680
1023
  }
681
1024
  function scrollCursorIntoView() {
1025
+ var coords = calculateCursorCoords();
1026
+ return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
1027
+ }
1028
+ function calculateCursorCoords() {
682
1029
  var cursor = localCoords(sel.inverted ? sel.from : sel.to);
683
- return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
1030
+ var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
1031
+ return {x: x, y: cursor.y, yBot: cursor.yBot};
684
1032
  }
685
1033
  function scrollIntoView(x1, y1, x2, y2) {
686
- var pl = paddingLeft(), pt = paddingTop(), lh = lineHeight();
1034
+ var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
1035
+ if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
1036
+ if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
1037
+ if (scrolled && options.onScroll) options.onScroll(instance);
1038
+ }
1039
+ function calculateScrollPos(x1, y1, x2, y2) {
1040
+ var pl = paddingLeft(), pt = paddingTop();
687
1041
  y1 += pt; y2 += pt; x1 += pl; x2 += pl;
688
- var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
689
- if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
690
- else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
1042
+ var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
1043
+ var docBottom = scroller.scrollHeight;
1044
+ var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;;
1045
+ if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
1046
+ else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
691
1047
 
692
1048
  var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
693
- if (x1 < screenleft) {
694
- if (x1 < 50) x1 = 0;
695
- scroller.scrollLeft = Math.max(0, x1 - 10);
696
- scrolled = true;
1049
+ var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
1050
+ var atLeft = x1 < gutterw + pl + 10;
1051
+ if (x1 < screenleft + gutterw || atLeft) {
1052
+ if (atLeft) x1 = 0;
1053
+ result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
1054
+ } else if (x2 > screenw + screenleft - 3) {
1055
+ result.scrollLeft = x2 + 10 - screenw;
697
1056
  }
698
- else if (x2 > screenw + screenleft) {
699
- scroller.scrollLeft = x2 + 10 - screenw;
700
- scrolled = true;
701
- if (x2 > code.clientWidth) result = false;
702
- }
703
- if (scrolled && options.onScroll) options.onScroll(instance);
704
1057
  return result;
705
1058
  }
706
1059
 
707
- function visibleLines() {
708
- var lh = lineHeight(), top = scroller.scrollTop - paddingTop();
709
- return {from: Math.min(lines.length, Math.max(0, Math.floor(top / lh))),
710
- to: Math.min(lines.length, Math.ceil((top + scroller.clientHeight) / lh))};
1060
+ function visibleLines(scrollTop) {
1061
+ var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
1062
+ var fromHeight = Math.max(0, Math.floor(top / lh));
1063
+ var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
1064
+ return {from: lineAtHeight(doc, fromHeight),
1065
+ to: lineAtHeight(doc, toHeight)};
711
1066
  }
712
1067
  // Uses a set of changes plus the current scroll position to
713
1068
  // determine which DOM updates have to be made, and makes the
714
1069
  // updates.
715
- function updateDisplay(changes) {
1070
+ function updateDisplay(changes, suppressCallback, scrollTop) {
716
1071
  if (!scroller.clientWidth) {
717
- showingFrom = showingTo = 0;
1072
+ showingFrom = showingTo = displayOffset = 0;
1073
+ return;
1074
+ }
1075
+ // Compute the new visible window
1076
+ // If scrollTop is specified, use that to determine which lines
1077
+ // to render instead of the current scrollbar position.
1078
+ var visible = visibleLines(scrollTop);
1079
+ // Bail out if the visible area is already rendered and nothing changed.
1080
+ if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
1081
+ updateVerticalScroll(scrollTop);
1082
+ return;
1083
+ }
1084
+ var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
1085
+ if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
1086
+ if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
1087
+
1088
+ // Create a range of theoretically intact lines, and punch holes
1089
+ // in that using the change info.
1090
+ var intact = changes === true ? [] :
1091
+ computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes);
1092
+ // Clip off the parts that won't be visible
1093
+ var intactLines = 0;
1094
+ for (var i = 0; i < intact.length; ++i) {
1095
+ var range = intact[i];
1096
+ if (range.from < from) {range.domStart += (from - range.from); range.from = from;}
1097
+ if (range.to > to) range.to = to;
1098
+ if (range.from >= range.to) intact.splice(i--, 1);
1099
+ else intactLines += range.to - range.from;
1100
+ }
1101
+ if (intactLines == to - from && from == showingFrom && to == showingTo) {
1102
+ updateVerticalScroll(scrollTop);
718
1103
  return;
719
1104
  }
720
- // First create a range of theoretically intact lines, and punch
721
- // holes in that using the change info.
722
- var intact = changes === true ? [] : [{from: showingFrom, to: showingTo, domStart: 0}];
1105
+ intact.sort(function(a, b) {return a.domStart - b.domStart;});
1106
+
1107
+ var th = textHeight(), gutterDisplay = gutter.style.display;
1108
+ lineDiv.style.display = "none";
1109
+ patchDisplay(from, to, intact);
1110
+ lineDiv.style.display = gutter.style.display = "";
1111
+
1112
+ var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
1113
+ // This is just a bogus formula that detects when the editor is
1114
+ // resized or the font size changes.
1115
+ if (different) lastSizeC = scroller.clientHeight + th;
1116
+ showingFrom = from; showingTo = to;
1117
+ displayOffset = heightAtLine(doc, from);
1118
+
1119
+ // Since this is all rather error prone, it is honoured with the
1120
+ // only assertion in the whole file.
1121
+ if (lineDiv.childNodes.length != showingTo - showingFrom)
1122
+ throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
1123
+ " nodes=" + lineDiv.childNodes.length);
1124
+
1125
+ function checkHeights() {
1126
+ var curNode = lineDiv.firstChild, heightChanged = false;
1127
+ doc.iter(showingFrom, showingTo, function(line) {
1128
+ if (!line.hidden) {
1129
+ var height = Math.round(curNode.offsetHeight / th) || 1;
1130
+ if (line.height != height) {
1131
+ updateLineHeight(line, height);
1132
+ gutterDirty = heightChanged = true;
1133
+ }
1134
+ }
1135
+ curNode = curNode.nextSibling;
1136
+ });
1137
+ return heightChanged;
1138
+ }
1139
+
1140
+ if (options.lineWrapping) {
1141
+ checkHeights();
1142
+ var scrollHeight = needsScrollbar();
1143
+ var shouldHaveScrollbar = scrollHeight ? "block" : "none";
1144
+ if (scrollbar.style.display != shouldHaveScrollbar) {
1145
+ scrollbar.style.display = shouldHaveScrollbar;
1146
+ if (scrollHeight) scrollbarInner.style.height = scrollHeight + "px";
1147
+ checkHeights();
1148
+ }
1149
+ }
1150
+
1151
+ gutter.style.display = gutterDisplay;
1152
+ if (different || gutterDirty) {
1153
+ // If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
1154
+ updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
1155
+ }
1156
+ updateVerticalScroll(scrollTop);
1157
+ updateSelection();
1158
+ if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
1159
+ return true;
1160
+ }
1161
+
1162
+ function computeIntact(intact, changes) {
723
1163
  for (var i = 0, l = changes.length || 0; i < l; ++i) {
724
1164
  var change = changes[i], intact2 = [], diff = change.diff || 0;
725
1165
  for (var j = 0, l2 = intact.length; j < l2; ++j) {
726
1166
  var range = intact[j];
727
- if (change.to <= range.from)
728
- intact2.push({from: range.from + diff, to: range.to + diff, domStart: range.domStart});
729
- else if (range.to <= change.from)
1167
+ if (change.to <= range.from && change.diff)
1168
+ intact2.push({from: range.from + diff, to: range.to + diff,
1169
+ domStart: range.domStart});
1170
+ else if (change.to <= range.from || change.from >= range.to)
730
1171
  intact2.push(range);
731
1172
  else {
732
1173
  if (change.from > range.from)
733
- intact2.push({from: range.from, to: change.from, domStart: range.domStart})
1174
+ intact2.push({from: range.from, to: change.from, domStart: range.domStart});
734
1175
  if (change.to < range.to)
735
1176
  intact2.push({from: change.to + diff, to: range.to + diff,
736
1177
  domStart: range.domStart + (change.to - range.from)});
@@ -738,165 +1179,130 @@ var CodeMirror = (function() {
738
1179
  }
739
1180
  intact = intact2;
740
1181
  }
741
-
742
- // Then, determine which lines we'd want to see, and which
743
- // updates have to be made to get there.
744
- var visible = visibleLines();
745
- var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
746
- to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
747
- updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
748
-
749
- for (var i = 0, l = intact.length; i < l; ++i) {
750
- var range = intact[i];
751
- if (range.to <= from) continue;
752
- if (range.from >= to) break;
753
- if (range.domStart > domPos || range.from > pos) {
754
- updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
755
- changedLines += range.from - pos;
756
- }
757
- pos = range.to;
758
- domPos = range.domStart + (range.to - range.from);
759
- }
760
- if (domPos != domEnd || pos != to) {
761
- changedLines += Math.abs(to - pos);
762
- updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
763
- }
764
-
765
- if (!updates.length) return;
766
- lineDiv.style.display = "none";
767
- // If more than 30% of the screen needs update, just do a full
768
- // redraw (which is quicker than patching)
769
- if (changedLines > (visible.to - visible.from) * .3)
770
- refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
771
- // Otherwise, only update the stuff that needs updating.
772
- else
773
- patchDisplay(updates);
774
- lineDiv.style.display = "";
775
-
776
- // Position the mover div to align with the lines it's supposed
777
- // to be showing (which will cover the visible display)
778
- var different = from != showingFrom || to != showingTo || lastHeight != scroller.clientHeight;
779
- showingFrom = from; showingTo = to;
780
- mover.style.top = (from * lineHeight()) + "px";
781
- if (different) {
782
- lastHeight = scroller.clientHeight;
783
- code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
784
- }
785
- if (different || updates.length) updateGutter();
786
-
787
- if (maxWidth == null) maxWidth = stringWidth(maxLine);
788
- if (maxWidth > scroller.clientWidth) {
789
- lineSpace.style.width = maxWidth + "px";
790
- // Needed to prevent odd wrapping/hiding of widgets placed in here.
791
- code.style.width = "";
792
- code.style.width = scroller.scrollWidth + "px";
793
- } else {
794
- lineSpace.style.width = code.style.width = "";
795
- }
796
-
797
- // Since this is all rather error prone, it is honoured with the
798
- // only assertion in the whole file.
799
- if (lineDiv.childNodes.length != showingTo - showingFrom)
800
- throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
801
- " nodes=" + lineDiv.childNodes.length);
802
- updateCursor();
1182
+ return intact;
803
1183
  }
804
1184
 
805
- function refreshDisplay(from, to) {
806
- var html = [], start = {line: from, ch: 0}, inSel = posLess(sel.from, start) && !posLess(sel.to, start);
807
- for (var i = from; i < to; ++i) {
808
- var ch1 = null, ch2 = null;
809
- if (inSel) {
810
- ch1 = 0;
811
- if (sel.to.line == i) {inSel = false; ch2 = sel.to.ch;}
812
- }
813
- else if (sel.from.line == i) {
814
- if (sel.to.line == i) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
815
- else {inSel = true; ch1 = sel.from.ch;}
1185
+ function patchDisplay(from, to, intact) {
1186
+ // The first pass removes the DOM nodes that aren't intact.
1187
+ if (!intact.length) lineDiv.innerHTML = "";
1188
+ else {
1189
+ function killNode(node) {
1190
+ var tmp = node.nextSibling;
1191
+ node.parentNode.removeChild(node);
1192
+ return tmp;
816
1193
  }
817
- html.push(lines[i].getHTML(ch1, ch2, true));
818
- }
819
- lineDiv.innerHTML = html.join("");
820
- }
821
- function patchDisplay(updates) {
822
- // Slightly different algorithm for IE (badInnerHTML), since
823
- // there .innerHTML on PRE nodes is dumb, and discards
824
- // whitespace.
825
- var sfrom = sel.from.line, sto = sel.to.line, off = 0,
826
- scratch = badInnerHTML && targetDocument.createElement("div");
827
- for (var i = 0, e = updates.length; i < e; ++i) {
828
- var rec = updates[i];
829
- var extra = (rec.to - rec.from) - rec.domSize;
830
- var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
831
- if (badInnerHTML)
832
- for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
833
- lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
834
- else if (extra) {
835
- for (var j = Math.max(0, extra); j > 0; --j)
836
- lineDiv.insertBefore(targetDocument.createElement("pre"), nodeAfter);
837
- for (var j = Math.max(0, -extra); j > 0; --j)
838
- lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
1194
+ var domPos = 0, curNode = lineDiv.firstChild, n;
1195
+ for (var i = 0; i < intact.length; ++i) {
1196
+ var cur = intact[i];
1197
+ while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;}
1198
+ for (var j = 0, e = cur.to - cur.from; j < e; ++j) {curNode = curNode.nextSibling; domPos++;}
839
1199
  }
840
- var node = lineDiv.childNodes[rec.domStart + off], inSel = sfrom < rec.from && sto >= rec.from;
841
- for (var j = rec.from; j < rec.to; ++j) {
842
- var ch1 = null, ch2 = null;
843
- if (inSel) {
844
- ch1 = 0;
845
- if (sto == j) {inSel = false; ch2 = sel.to.ch;}
846
- }
847
- else if (sfrom == j) {
848
- if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
849
- else {inSel = true; ch1 = sel.from.ch;}
850
- }
851
- if (badInnerHTML) {
852
- scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
853
- lineDiv.insertBefore(scratch.firstChild, nodeAfter);
854
- }
1200
+ while (curNode) curNode = killNode(curNode);
1201
+ }
1202
+ // This pass fills in the lines that actually changed.
1203
+ var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
1204
+ var scratch = document.createElement("div");
1205
+ doc.iter(from, to, function(line) {
1206
+ if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
1207
+ if (!nextIntact || nextIntact.from > j) {
1208
+ if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
855
1209
  else {
856
- node.innerHTML = lines[j].getHTML(ch1, ch2, false);
857
- node.className = lines[j].className || "";
858
- node = node.nextSibling;
1210
+ var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>'
1211
+ + line.getHTML(makeTab) + '</pre>';
1212
+ // Kludge to make sure the styled element lies behind the selection (by z-index)
1213
+ if (line.bgClassName)
1214
+ html = '<div style="position: relative"><pre class="' + line.bgClassName +
1215
+ '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
859
1216
  }
1217
+ scratch.innerHTML = html;
1218
+ lineDiv.insertBefore(scratch.firstChild, curNode);
1219
+ } else {
1220
+ curNode = curNode.nextSibling;
860
1221
  }
861
- off += extra;
862
- }
1222
+ ++j;
1223
+ });
863
1224
  }
864
1225
 
865
1226
  function updateGutter() {
866
1227
  if (!options.gutter && !options.lineNumbers) return;
867
1228
  var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
868
1229
  gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
869
- var html = [];
870
- for (var i = showingFrom; i < Math.max(showingTo, showingFrom + 1); ++i) {
871
- var marker = lines[i].gutterMarker;
872
- var text = options.lineNumbers ? i + options.firstLineNumber : null;
873
- if (marker && marker.text)
874
- text = marker.text.replace("%N%", text != null ? text : "");
875
- else if (text == null)
876
- text = "\u00a0";
877
- html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text, "</pre>");
878
- }
1230
+ var html = [], i = showingFrom, normalNode;
1231
+ doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
1232
+ if (line.hidden) {
1233
+ html.push("<pre></pre>");
1234
+ } else {
1235
+ var marker = line.gutterMarker;
1236
+ var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
1237
+ if (marker && marker.text)
1238
+ text = marker.text.replace("%N%", text != null ? text : "");
1239
+ else if (text == null)
1240
+ text = "\u00a0";
1241
+ html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
1242
+ for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
1243
+ html.push("</pre>");
1244
+ if (!marker) normalNode = i;
1245
+ }
1246
+ ++i;
1247
+ });
879
1248
  gutter.style.display = "none";
880
1249
  gutterText.innerHTML = html.join("");
881
- var minwidth = String(lines.length).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
882
- while (val.length + pad.length < minwidth) pad += "\u00a0";
883
- if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
1250
+ // Make sure scrolling doesn't cause number gutter size to pop
1251
+ if (normalNode != null && options.lineNumbers) {
1252
+ var node = gutterText.childNodes[normalNode - showingFrom];
1253
+ var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
1254
+ while (val.length + pad.length < minwidth) pad += "\u00a0";
1255
+ if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
1256
+ }
884
1257
  gutter.style.display = "";
1258
+ var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
885
1259
  lineSpace.style.marginLeft = gutter.offsetWidth + "px";
886
- }
887
- function updateCursor() {
888
- var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
889
- var x = charX(head.line, head.ch);
890
- inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
891
- inputDiv.style.left = (x - scroller.scrollLeft) + "px";
892
- if (posEq(sel.from, sel.to)) {
893
- cursor.style.top = (head.line - showingFrom) * lh + "px";
894
- cursor.style.left = x + "px";
1260
+ gutterDirty = false;
1261
+ return resized;
1262
+ }
1263
+ function updateSelection() {
1264
+ var collapsed = posEq(sel.from, sel.to);
1265
+ var fromPos = localCoords(sel.from, true);
1266
+ var toPos = collapsed ? fromPos : localCoords(sel.to, true);
1267
+ var headPos = sel.inverted ? fromPos : toPos, th = textHeight();
1268
+ var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
1269
+ inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px";
1270
+ inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px";
1271
+ if (collapsed) {
1272
+ cursor.style.top = headPos.y + "px";
1273
+ cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px";
895
1274
  cursor.style.display = "";
1275
+ selectionDiv.style.display = "none";
1276
+ } else {
1277
+ var sameLine = fromPos.y == toPos.y, html = "";
1278
+ var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
1279
+ var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
1280
+ function add(left, top, right, height) {
1281
+ var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
1282
+ : "right: " + right + "px";
1283
+ html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
1284
+ 'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
1285
+ }
1286
+ if (sel.from.ch && fromPos.y >= 0) {
1287
+ var right = sameLine ? clientWidth - toPos.x : 0;
1288
+ add(fromPos.x, fromPos.y, right, th);
1289
+ }
1290
+ var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
1291
+ var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
1292
+ if (middleHeight > 0.2 * th)
1293
+ add(0, middleStart, 0, middleHeight);
1294
+ if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
1295
+ add(0, toPos.y, clientWidth - toPos.x, th);
1296
+ selectionDiv.innerHTML = html;
1297
+ cursor.style.display = "none";
1298
+ selectionDiv.style.display = "";
896
1299
  }
897
- else cursor.style.display = "none";
898
1300
  }
899
1301
 
1302
+ function setShift(val) {
1303
+ if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
1304
+ else shiftSelecting = null;
1305
+ }
900
1306
  function setSelectionUser(from, to) {
901
1307
  var sh = shiftSelecting && clipPos(shiftSelecting);
902
1308
  if (sh) {
@@ -904,232 +1310,371 @@ var CodeMirror = (function() {
904
1310
  else if (posLess(to, sh)) to = sh;
905
1311
  }
906
1312
  setSelection(from, to);
1313
+ userSelChange = true;
907
1314
  }
908
1315
  // Update the selection. Last two args are only used by
909
1316
  // updateLines, since they have to be expressed in the line
910
1317
  // numbers before the update.
911
1318
  function setSelection(from, to, oldFrom, oldTo) {
1319
+ goalColumn = null;
1320
+ if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
912
1321
  if (posEq(sel.from, from) && posEq(sel.to, to)) return;
913
1322
  if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
914
1323
 
1324
+ // Skip over hidden lines.
1325
+ if (from.line != oldFrom) {
1326
+ var from1 = skipHidden(from, oldFrom, sel.from.ch);
1327
+ // If there is no non-hidden line left, force visibility on current line
1328
+ if (!from1) setLineHidden(from.line, false);
1329
+ else from = from1;
1330
+ }
1331
+ if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
1332
+
915
1333
  if (posEq(from, to)) sel.inverted = false;
916
1334
  else if (posEq(from, sel.to)) sel.inverted = false;
917
1335
  else if (posEq(to, sel.from)) sel.inverted = true;
918
1336
 
919
- // Some ugly logic used to only mark the lines that actually did
920
- // see a change in selection as changed, rather than the whole
921
- // selected range.
922
- if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
923
- if (posEq(from, to)) {
924
- if (!posEq(sel.from, sel.to))
925
- changes.push({from: oldFrom, to: oldTo + 1});
926
- }
927
- else if (posEq(sel.from, sel.to)) {
928
- changes.push({from: from.line, to: to.line + 1});
929
- }
930
- else {
931
- if (!posEq(from, sel.from)) {
932
- if (from.line < oldFrom)
933
- changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
934
- else
935
- changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
936
- }
937
- if (!posEq(to, sel.to)) {
938
- if (to.line < oldTo)
939
- changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
940
- else
941
- changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
1337
+ if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
1338
+ var head = sel.inverted ? from : to;
1339
+ if (head.line != sel.from.line && sel.from.line < doc.size) {
1340
+ var oldLine = getLine(sel.from.line);
1341
+ if (/^\s+$/.test(oldLine.text))
1342
+ setTimeout(operation(function() {
1343
+ if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
1344
+ var no = lineNo(oldLine);
1345
+ replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
1346
+ }
1347
+ }, 10));
942
1348
  }
943
1349
  }
1350
+
944
1351
  sel.from = from; sel.to = to;
945
1352
  selectionChanged = true;
946
1353
  }
1354
+ function skipHidden(pos, oldLine, oldCh) {
1355
+ function getNonHidden(dir) {
1356
+ var lNo = pos.line + dir, end = dir == 1 ? doc.size : -1;
1357
+ while (lNo != end) {
1358
+ var line = getLine(lNo);
1359
+ if (!line.hidden) {
1360
+ var ch = pos.ch;
1361
+ if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
1362
+ return {line: lNo, ch: ch};
1363
+ }
1364
+ lNo += dir;
1365
+ }
1366
+ }
1367
+ var line = getLine(pos.line);
1368
+ var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
1369
+ if (!line.hidden) return pos;
1370
+ if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
1371
+ else return getNonHidden(-1) || getNonHidden(1);
1372
+ }
947
1373
  function setCursor(line, ch, user) {
948
1374
  var pos = clipPos({line: line, ch: ch || 0});
949
1375
  (user ? setSelectionUser : setSelection)(pos, pos);
950
1376
  }
951
1377
 
952
- function clipLine(n) {return Math.max(0, Math.min(n, lines.length-1));}
1378
+ function clipLine(n) {return Math.max(0, Math.min(n, doc.size-1));}
953
1379
  function clipPos(pos) {
954
1380
  if (pos.line < 0) return {line: 0, ch: 0};
955
- if (pos.line >= lines.length) return {line: lines.length-1, ch: lines[lines.length-1].text.length};
956
- var ch = pos.ch, linelen = lines[pos.line].text.length;
1381
+ if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc.size-1).text.length};
1382
+ var ch = pos.ch, linelen = getLine(pos.line).text.length;
957
1383
  if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
958
1384
  else if (ch < 0) return {line: pos.line, ch: 0};
959
1385
  else return pos;
960
1386
  }
961
1387
 
962
- function scrollPage(down) {
963
- var linesPerPage = Math.floor(scroller.clientHeight / lineHeight()), head = sel.inverted ? sel.from : sel.to;
964
- setCursor(head.line + (Math.max(linesPerPage - 1, 1) * (down ? 1 : -1)), head.ch, true);
965
- }
966
- function scrollEnd(top) {
967
- var pos = top ? {line: 0, ch: 0} : {line: lines.length - 1, ch: lines[lines.length-1].text.length};
968
- setSelectionUser(pos, pos);
969
- }
970
- function selectAll() {
971
- var endLine = lines.length - 1;
972
- setSelection({line: 0, ch: 0}, {line: endLine, ch: lines[endLine].text.length});
973
- }
974
- function selectWordAt(pos) {
975
- var line = lines[pos.line].text;
976
- var start = pos.ch, end = pos.ch;
977
- while (start > 0 && /\w/.test(line.charAt(start - 1))) --start;
978
- while (end < line.length && /\w/.test(line.charAt(end))) ++end;
979
- setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
980
- }
981
- function selectLine(line) {
982
- setSelectionUser({line: line, ch: 0}, {line: line, ch: lines[line].text.length});
983
- }
984
- function handleEnter() {
985
- replaceSelection("\n", "end");
986
- if (options.enterMode != "flat")
987
- indentLine(sel.from.line, options.enterMode == "keep" ? "prev" : "smart");
988
- }
989
- function handleTab(shift) {
990
- function indentSelected(mode) {
991
- if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
992
- var e = sel.to.line - (sel.to.ch ? 0 : 1);
993
- for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
1388
+ function findPosH(dir, unit) {
1389
+ var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch;
1390
+ var lineObj = getLine(line);
1391
+ function findNextLine() {
1392
+ for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) {
1393
+ var lo = getLine(l);
1394
+ if (!lo.hidden) { line = l; lineObj = lo; return true; }
1395
+ }
994
1396
  }
995
- shiftSelecting = null;
996
- switch (options.tabMode) {
997
- case "default":
998
- return false;
999
- case "indent":
1000
- indentSelected("smart");
1001
- break;
1002
- case "classic":
1003
- if (posEq(sel.from, sel.to)) {
1004
- if (shift) indentLine(sel.from.line, "smart");
1005
- else replaceSelection("\t", "end");
1006
- break;
1397
+ function moveOnce(boundToLine) {
1398
+ if (ch == (dir < 0 ? 0 : lineObj.text.length)) {
1399
+ if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0;
1400
+ else return false;
1401
+ } else ch += dir;
1402
+ return true;
1403
+ }
1404
+ if (unit == "char") moveOnce();
1405
+ else if (unit == "column") moveOnce(true);
1406
+ else if (unit == "word") {
1407
+ var sawWord = false;
1408
+ for (;;) {
1409
+ if (dir < 0) if (!moveOnce()) break;
1410
+ if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
1411
+ else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
1412
+ if (dir > 0) if (!moveOnce()) break;
1007
1413
  }
1008
- case "shift":
1009
- indentSelected(shift ? "subtract" : "add");
1010
- break;
1011
1414
  }
1012
- return true;
1415
+ return {line: line, ch: ch};
1416
+ }
1417
+ function moveH(dir, unit) {
1418
+ var pos = dir < 0 ? sel.from : sel.to;
1419
+ if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit);
1420
+ setCursor(pos.line, pos.ch, true);
1421
+ }
1422
+ function deleteH(dir, unit) {
1423
+ if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to);
1424
+ else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to);
1425
+ else replaceRange("", sel.from, findPosH(dir, unit));
1426
+ userSelChange = true;
1427
+ }
1428
+ var goalColumn = null;
1429
+ function moveV(dir, unit) {
1430
+ var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
1431
+ if (goalColumn != null) pos.x = goalColumn;
1432
+ if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
1433
+ else if (unit == "line") dist = textHeight();
1434
+ var target = coordsChar(pos.x, pos.y + dist * dir + 2);
1435
+ if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
1436
+ setCursor(target.line, target.ch, true);
1437
+ goalColumn = pos.x;
1438
+ }
1439
+
1440
+ function findWordAt(pos) {
1441
+ var line = getLine(pos.line).text;
1442
+ var start = pos.ch, end = pos.ch;
1443
+ var check = isWordChar(line.charAt(start < line.length ? start : start - 1)) ?
1444
+ isWordChar : function(ch) {return !isWordChar(ch);};
1445
+ while (start > 0 && check(line.charAt(start - 1))) --start;
1446
+ while (end < line.length && check(line.charAt(end))) ++end;
1447
+ return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
1448
+ }
1449
+ function selectLine(line) {
1450
+ setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
1013
1451
  }
1014
- function smartHome() {
1015
- var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
1016
- setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
1452
+ function indentSelected(mode) {
1453
+ if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
1454
+ var e = sel.to.line - (sel.to.ch ? 0 : 1);
1455
+ for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
1017
1456
  }
1018
1457
 
1019
1458
  function indentLine(n, how) {
1459
+ if (!how) how = "add";
1020
1460
  if (how == "smart") {
1021
1461
  if (!mode.indent) how = "prev";
1022
1462
  else var state = getStateBefore(n);
1023
1463
  }
1024
1464
 
1025
- var line = lines[n], curSpace = line.indentation(), curSpaceString = line.text.match(/^\s*/)[0], indentation;
1465
+ var line = getLine(n), curSpace = line.indentation(options.tabSize),
1466
+ curSpaceString = line.text.match(/^\s*/)[0], indentation;
1467
+ if (how == "smart") {
1468
+ indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
1469
+ if (indentation == Pass) how = "prev";
1470
+ }
1026
1471
  if (how == "prev") {
1027
- if (n) indentation = lines[n-1].indentation();
1472
+ if (n) indentation = getLine(n-1).indentation(options.tabSize);
1028
1473
  else indentation = 0;
1029
1474
  }
1030
- else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
1031
1475
  else if (how == "add") indentation = curSpace + options.indentUnit;
1032
1476
  else if (how == "subtract") indentation = curSpace - options.indentUnit;
1033
1477
  indentation = Math.max(0, indentation);
1034
1478
  var diff = indentation - curSpace;
1035
1479
 
1036
- if (!diff) {
1037
- if (sel.from.line != n && sel.to.line != n) return;
1038
- var indentString = curSpaceString;
1039
- }
1040
- else {
1041
- var indentString = "", pos = 0;
1042
- if (options.indentWithTabs)
1043
- for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
1044
- while (pos < indentation) {++pos; indentString += " ";}
1045
- }
1480
+ var indentString = "", pos = 0;
1481
+ if (options.indentWithTabs)
1482
+ for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
1483
+ while (pos < indentation) {++pos; indentString += " ";}
1046
1484
 
1047
1485
  replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1048
1486
  }
1049
1487
 
1050
1488
  function loadMode() {
1051
1489
  mode = CodeMirror.getMode(options, options.mode);
1052
- for (var i = 0, l = lines.length; i < l; ++i)
1053
- lines[i].stateAfter = null;
1490
+ doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
1054
1491
  work = [0];
1055
1492
  startWorker();
1056
1493
  }
1057
1494
  function gutterChanged() {
1058
1495
  var visible = options.gutter || options.lineNumbers;
1059
1496
  gutter.style.display = visible ? "" : "none";
1060
- if (visible) updateGutter();
1497
+ if (visible) gutterDirty = true;
1061
1498
  else lineDiv.parentNode.style.marginLeft = 0;
1062
1499
  }
1500
+ function wrappingChanged(from, to) {
1501
+ if (options.lineWrapping) {
1502
+ wrapper.className += " CodeMirror-wrap";
1503
+ var perLine = scroller.clientWidth / charWidth() - 3;
1504
+ doc.iter(0, doc.size, function(line) {
1505
+ if (line.hidden) return;
1506
+ var guess = Math.ceil(line.text.length / perLine) || 1;
1507
+ if (guess != 1) updateLineHeight(line, guess);
1508
+ });
1509
+ lineSpace.style.width = code.style.width = "";
1510
+ widthForcer.style.left = "";
1511
+ } else {
1512
+ wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
1513
+ maxLine = ""; maxLineChanged = true;
1514
+ doc.iter(0, doc.size, function(line) {
1515
+ if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
1516
+ if (line.text.length > maxLine.length) maxLine = line.text;
1517
+ });
1518
+ }
1519
+ changes.push({from: 0, to: doc.size});
1520
+ }
1521
+ function makeTab(col) {
1522
+ var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
1523
+ if (cached) return cached;
1524
+ for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
1525
+ return (tabCache[w] = {html: str + "</span>", width: w});
1526
+ }
1527
+ function themeChanged() {
1528
+ scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
1529
+ options.theme.replace(/(^|\s)\s*/g, " cm-s-");
1530
+ }
1531
+ function keyMapChanged() {
1532
+ var style = keyMap[options.keyMap].style;
1533
+ wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
1534
+ (style ? " cm-keymap-" + style : "");
1535
+ }
1536
+
1537
+ function TextMarker() { this.set = []; }
1538
+ TextMarker.prototype.clear = operation(function() {
1539
+ var min = Infinity, max = -Infinity;
1540
+ for (var i = 0, e = this.set.length; i < e; ++i) {
1541
+ var line = this.set[i], mk = line.marked;
1542
+ if (!mk || !line.parent) continue;
1543
+ var lineN = lineNo(line);
1544
+ min = Math.min(min, lineN); max = Math.max(max, lineN);
1545
+ for (var j = 0; j < mk.length; ++j)
1546
+ if (mk[j].marker == this) mk.splice(j--, 1);
1547
+ }
1548
+ if (min != Infinity)
1549
+ changes.push({from: min, to: max + 1});
1550
+ });
1551
+ TextMarker.prototype.find = function() {
1552
+ var from, to;
1553
+ for (var i = 0, e = this.set.length; i < e; ++i) {
1554
+ var line = this.set[i], mk = line.marked;
1555
+ for (var j = 0; j < mk.length; ++j) {
1556
+ var mark = mk[j];
1557
+ if (mark.marker == this) {
1558
+ if (mark.from != null || mark.to != null) {
1559
+ var found = lineNo(line);
1560
+ if (found != null) {
1561
+ if (mark.from != null) from = {line: found, ch: mark.from};
1562
+ if (mark.to != null) to = {line: found, ch: mark.to};
1563
+ }
1564
+ }
1565
+ }
1566
+ }
1567
+ }
1568
+ return {from: from, to: to};
1569
+ };
1063
1570
 
1064
1571
  function markText(from, to, className) {
1065
1572
  from = clipPos(from); to = clipPos(to);
1066
- var accum = [];
1573
+ var tm = new TextMarker();
1574
+ if (!posLess(from, to)) return tm;
1067
1575
  function add(line, from, to, className) {
1068
- var line = lines[line], mark = line.addMark(from, to, className);
1069
- mark.line = line;
1070
- accum.push(mark);
1576
+ getLine(line).addMark(new MarkedText(from, to, className, tm));
1071
1577
  }
1072
1578
  if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1073
1579
  else {
1074
1580
  add(from.line, from.ch, null, className);
1075
1581
  for (var i = from.line + 1, e = to.line; i < e; ++i)
1076
- add(i, 0, null, className);
1077
- add(to.line, 0, to.ch, className);
1582
+ add(i, null, null, className);
1583
+ add(to.line, null, to.ch, className);
1078
1584
  }
1079
1585
  changes.push({from: from.line, to: to.line + 1});
1080
- return function() {
1081
- var start, end;
1082
- for (var i = 0; i < accum.length; ++i) {
1083
- var mark = accum[i], found = indexOf(lines, mark.line);
1084
- mark.line.removeMark(mark);
1085
- if (found > -1) {
1086
- if (start == null) start = found;
1087
- end = found;
1088
- }
1089
- }
1090
- if (start != null) changes.push({from: start, to: end + 1});
1091
- };
1586
+ return tm;
1587
+ }
1588
+
1589
+ function setBookmark(pos) {
1590
+ pos = clipPos(pos);
1591
+ var bm = new Bookmark(pos.ch);
1592
+ getLine(pos.line).addMark(bm);
1593
+ return bm;
1594
+ }
1595
+
1596
+ function findMarksAt(pos) {
1597
+ pos = clipPos(pos);
1598
+ var markers = [], marked = getLine(pos.line).marked;
1599
+ if (!marked) return markers;
1600
+ for (var i = 0, e = marked.length; i < e; ++i) {
1601
+ var m = marked[i];
1602
+ if ((m.from == null || m.from <= pos.ch) &&
1603
+ (m.to == null || m.to >= pos.ch))
1604
+ markers.push(m.marker || m);
1605
+ }
1606
+ return markers;
1092
1607
  }
1093
1608
 
1094
1609
  function addGutterMarker(line, text, className) {
1095
- if (typeof line == "number") line = lines[clipLine(line)];
1610
+ if (typeof line == "number") line = getLine(clipLine(line));
1096
1611
  line.gutterMarker = {text: text, style: className};
1097
- updateGutter();
1612
+ gutterDirty = true;
1098
1613
  return line;
1099
1614
  }
1100
1615
  function removeGutterMarker(line) {
1101
- if (typeof line == "number") line = lines[clipLine(line)];
1616
+ if (typeof line == "number") line = getLine(clipLine(line));
1102
1617
  line.gutterMarker = null;
1103
- updateGutter();
1618
+ gutterDirty = true;
1104
1619
  }
1105
- function setLineClass(line, className) {
1106
- if (typeof line == "number") {
1107
- var no = line;
1108
- line = lines[clipLine(line)];
1109
- }
1110
- else {
1111
- var no = indexOf(lines, line);
1112
- if (no == -1) return null;
1113
- }
1114
- if (line.className != className) {
1115
- line.className = className;
1116
- changes.push({from: no, to: no + 1});
1117
- }
1620
+
1621
+ function changeLine(handle, op) {
1622
+ var no = handle, line = handle;
1623
+ if (typeof handle == "number") line = getLine(clipLine(handle));
1624
+ else no = lineNo(handle);
1625
+ if (no == null) return null;
1626
+ if (op(line, no)) changes.push({from: no, to: no + 1});
1627
+ else return null;
1118
1628
  return line;
1119
1629
  }
1630
+ function setLineClass(handle, className, bgClassName) {
1631
+ return changeLine(handle, function(line) {
1632
+ if (line.className != className || line.bgClassName != bgClassName) {
1633
+ line.className = className;
1634
+ line.bgClassName = bgClassName;
1635
+ return true;
1636
+ }
1637
+ });
1638
+ }
1639
+ function setLineHidden(handle, hidden) {
1640
+ return changeLine(handle, function(line, no) {
1641
+ if (line.hidden != hidden) {
1642
+ line.hidden = hidden;
1643
+ if (!options.lineWrapping) {
1644
+ var l = line.text;
1645
+ if (hidden && l.length == maxLine.length) {
1646
+ updateMaxLine = true;
1647
+ } else if (!hidden && l.length > maxLine.length) {
1648
+ maxLine = l; updateMaxLine = false;
1649
+ }
1650
+ }
1651
+ updateLineHeight(line, hidden ? 0 : 1);
1652
+ var fline = sel.from.line, tline = sel.to.line;
1653
+ if (hidden && (fline == no || tline == no)) {
1654
+ var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
1655
+ var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
1656
+ // Can't hide the last visible line, we'd have no place to put the cursor
1657
+ if (!to) return;
1658
+ setSelection(from, to);
1659
+ }
1660
+ return (gutterDirty = true);
1661
+ }
1662
+ });
1663
+ }
1120
1664
 
1121
1665
  function lineInfo(line) {
1122
1666
  if (typeof line == "number") {
1667
+ if (!isLine(line)) return null;
1123
1668
  var n = line;
1124
- line = lines[line];
1669
+ line = getLine(line);
1125
1670
  if (!line) return null;
1126
- }
1127
- else {
1128
- var n = indexOf(lines, line);
1129
- if (n == -1) return null;
1671
+ } else {
1672
+ var n = lineNo(line);
1673
+ if (n == null) return null;
1130
1674
  }
1131
1675
  var marker = line.gutterMarker;
1132
- return {line: n, text: line.text, markerText: marker && marker.text, markerClass: marker && marker.style};
1676
+ return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
1677
+ markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
1133
1678
  }
1134
1679
 
1135
1680
  function stringWidth(str) {
@@ -1139,21 +1684,15 @@ var CodeMirror = (function() {
1139
1684
  }
1140
1685
  // These are used to go from pixel positions to character
1141
1686
  // positions, taking varying character widths into account.
1142
- function charX(line, pos) {
1143
- if (pos == 0) return 0;
1144
- measure.innerHTML = "<pre><span>" + lines[line].getHTML(null, null, false, pos) + "</span></pre>";
1145
- return measure.firstChild.firstChild.offsetWidth;
1146
- }
1147
1687
  function charFromX(line, x) {
1148
1688
  if (x <= 0) return 0;
1149
- var lineObj = lines[line], text = lineObj.text;
1689
+ var lineObj = getLine(line), text = lineObj.text;
1150
1690
  function getX(len) {
1151
- measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, len) + "</span></pre>";
1152
- return measure.firstChild.firstChild.offsetWidth;
1691
+ return measureLine(lineObj, len).left;
1153
1692
  }
1154
1693
  var from = 0, fromX = 0, to = text.length, toX;
1155
1694
  // Guess a suitable upper bound for our search.
1156
- var estimated = Math.min(to, Math.ceil(x / stringWidth("x")));
1695
+ var estimated = Math.min(to, Math.ceil(x / charWidth()));
1157
1696
  for (;;) {
1158
1697
  var estX = getX(estimated);
1159
1698
  if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
@@ -1172,20 +1711,95 @@ var CodeMirror = (function() {
1172
1711
  }
1173
1712
  }
1174
1713
 
1714
+ var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
1715
+ function measureLine(line, ch) {
1716
+ if (ch == 0) return {top: 0, left: 0};
1717
+ var wbr = options.lineWrapping && ch < line.text.length &&
1718
+ spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1719
+ measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
1720
+ var elt = document.getElementById(tempId);
1721
+ var top = elt.offsetTop, left = elt.offsetLeft;
1722
+ // Older IEs report zero offsets for spans directly after a wrap
1723
+ if (ie && top == 0 && left == 0) {
1724
+ var backup = document.createElement("span");
1725
+ backup.innerHTML = "x";
1726
+ elt.parentNode.insertBefore(backup, elt.nextSibling);
1727
+ top = backup.offsetTop;
1728
+ }
1729
+ return {top: top, left: left};
1730
+ }
1175
1731
  function localCoords(pos, inLineWrap) {
1176
- var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
1177
- return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
1732
+ var x, lh = textHeight(), y = lh * (heightAtLine(doc, pos.line) - (inLineWrap ? displayOffset : 0));
1733
+ if (pos.ch == 0) x = 0;
1734
+ else {
1735
+ var sp = measureLine(getLine(pos.line), pos.ch);
1736
+ x = sp.left;
1737
+ if (options.lineWrapping) y += Math.max(0, sp.top);
1738
+ }
1739
+ return {x: x, y: y, yBot: y + lh};
1740
+ }
1741
+ // Coords must be lineSpace-local
1742
+ function coordsChar(x, y) {
1743
+ if (y < 0) y = 0;
1744
+ var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
1745
+ var lineNo = lineAtHeight(doc, heightPos);
1746
+ if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
1747
+ var lineObj = getLine(lineNo), text = lineObj.text;
1748
+ var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
1749
+ if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
1750
+ function getX(len) {
1751
+ var sp = measureLine(lineObj, len);
1752
+ if (tw) {
1753
+ var off = Math.round(sp.top / th);
1754
+ return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
1755
+ }
1756
+ return sp.left;
1757
+ }
1758
+ var from = 0, fromX = 0, to = text.length, toX;
1759
+ // Guess a suitable upper bound for our search.
1760
+ var estimated = Math.min(to, Math.ceil((x + innerOff * scroller.clientWidth * .9) / cw));
1761
+ for (;;) {
1762
+ var estX = getX(estimated);
1763
+ if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
1764
+ else {toX = estX; to = estimated; break;}
1765
+ }
1766
+ if (x > toX) return {line: lineNo, ch: to};
1767
+ // Try to guess a suitable lower bound as well.
1768
+ estimated = Math.floor(to * 0.8); estX = getX(estimated);
1769
+ if (estX < x) {from = estimated; fromX = estX;}
1770
+ // Do a binary search between these bounds.
1771
+ for (;;) {
1772
+ if (to - from <= 1) return {line: lineNo, ch: (toX - x > x - fromX) ? from : to};
1773
+ var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
1774
+ if (middleX > x) {to = middle; toX = middleX;}
1775
+ else {from = middle; fromX = middleX;}
1776
+ }
1178
1777
  }
1179
1778
  function pageCoords(pos) {
1180
1779
  var local = localCoords(pos, true), off = eltOffset(lineSpace);
1181
1780
  return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
1182
1781
  }
1183
1782
 
1184
- function lineHeight() {
1185
- var nlines = lineDiv.childNodes.length;
1186
- if (nlines) return (lineDiv.offsetHeight / nlines) || 1;
1187
- measure.innerHTML = "<pre>x</pre>";
1188
- return measure.firstChild.offsetHeight || 1;
1783
+ var cachedHeight, cachedHeightFor, measureText;
1784
+ function textHeight() {
1785
+ if (measureText == null) {
1786
+ measureText = "<pre>";
1787
+ for (var i = 0; i < 49; ++i) measureText += "x<br/>";
1788
+ measureText += "x</pre>";
1789
+ }
1790
+ var offsetHeight = lineDiv.clientHeight;
1791
+ if (offsetHeight == cachedHeightFor) return cachedHeight;
1792
+ cachedHeightFor = offsetHeight;
1793
+ measure.innerHTML = measureText;
1794
+ cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
1795
+ measure.innerHTML = "";
1796
+ return cachedHeight;
1797
+ }
1798
+ var cachedWidth, cachedWidthFor = 0;
1799
+ function charWidth() {
1800
+ if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
1801
+ cachedWidthFor = scroller.clientWidth;
1802
+ return (cachedWidth = stringWidth("x"));
1189
1803
  }
1190
1804
  function paddingTop() {return lineSpace.offsetTop;}
1191
1805
  function paddingLeft() {return lineSpace.offsetLeft;}
@@ -1200,12 +1814,11 @@ var CodeMirror = (function() {
1200
1814
  if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
1201
1815
  return null;
1202
1816
  var offL = eltOffset(lineSpace, true);
1203
- var line = showingFrom + Math.floor((y - offL.top) / lineHeight());
1204
- return clipPos({line: line, ch: charFromX(clipLine(line), x - offL.left)});
1817
+ return coordsChar(x - offL.left, y - offL.top);
1205
1818
  }
1206
1819
  function onContextMenu(e) {
1207
- var pos = posFromMouse(e);
1208
- if (!pos || window.opera) return; // Opera is difficult.
1820
+ var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
1821
+ if (!pos || opera) return; // Opera is difficult.
1209
1822
  if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1210
1823
  operation(setCursor)(pos.line, pos.ch);
1211
1824
 
@@ -1217,25 +1830,25 @@ var CodeMirror = (function() {
1217
1830
  leaveInputAlone = true;
1218
1831
  var val = input.value = getSelection();
1219
1832
  focusInput();
1220
- setSelRange(input, 0, input.value.length);
1833
+ selectInput(input);
1221
1834
  function rehide() {
1222
1835
  var newVal = splitLines(input.value).join("\n");
1223
- if (newVal != val) operation(replaceSelection)(newVal, "end");
1836
+ if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
1224
1837
  inputDiv.style.position = "relative";
1225
1838
  input.style.cssText = oldCSS;
1839
+ if (ie_lt9) scrollbar.scrollTop = scrollPos;
1226
1840
  leaveInputAlone = false;
1227
- prepareInput();
1841
+ resetInput(true);
1228
1842
  slowPoll();
1229
1843
  }
1230
-
1844
+
1231
1845
  if (gecko) {
1232
1846
  e_stop(e);
1233
1847
  var mouseup = connect(window, "mouseup", function() {
1234
1848
  mouseup();
1235
1849
  setTimeout(rehide, 20);
1236
1850
  }, true);
1237
- }
1238
- else {
1851
+ } else {
1239
1852
  setTimeout(rehide, 50);
1240
1853
  }
1241
1854
  }
@@ -1252,7 +1865,7 @@ var CodeMirror = (function() {
1252
1865
 
1253
1866
  var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
1254
1867
  function matchBrackets(autoclear) {
1255
- var head = sel.inverted ? sel.from : sel.to, line = lines[head.line], pos = head.ch - 1;
1868
+ var head = sel.inverted ? sel.from : sel.to, line = getLine(head.line), pos = head.ch - 1;
1256
1869
  var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
1257
1870
  if (!match) return;
1258
1871
  var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
@@ -1265,7 +1878,7 @@ var CodeMirror = (function() {
1265
1878
  var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1266
1879
  for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1267
1880
  var text = st[i];
1268
- if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1881
+ if (st[i+1] != style) {pos += d * text.length; continue;}
1269
1882
  for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1270
1883
  if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1271
1884
  var match = matching[cur];
@@ -1276,18 +1889,16 @@ var CodeMirror = (function() {
1276
1889
  }
1277
1890
  }
1278
1891
  }
1279
- for (var i = head.line, e = forward ? Math.min(i + 100, lines.length) : Math.max(-1, i - 100); i != e; i+=d) {
1280
- var line = lines[i], first = i == head.line;
1892
+ for (var i = head.line, e = forward ? Math.min(i + 100, doc.size) : Math.max(-1, i - 100); i != e; i+=d) {
1893
+ var line = getLine(i), first = i == head.line;
1281
1894
  var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
1282
1895
  if (found) break;
1283
1896
  }
1284
1897
  if (!found) found = {pos: null, match: false};
1285
1898
  var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1286
1899
  var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
1287
- two = found.pos != null
1288
- ? markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style)
1289
- : function() {};
1290
- var clear = operation(function(){one(); two();});
1900
+ two = found.pos != null && markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style);
1901
+ var clear = operation(function(){one.clear(); two && two.clear();});
1291
1902
  if (autoclear) setTimeout(clear, 800);
1292
1903
  else bracketHighlighted = clear;
1293
1904
  }
@@ -1301,9 +1912,9 @@ var CodeMirror = (function() {
1301
1912
  var minindent, minline;
1302
1913
  for (var search = n, lim = n - 40; search > lim; --search) {
1303
1914
  if (search == 0) return 0;
1304
- var line = lines[search-1];
1915
+ var line = getLine(search-1);
1305
1916
  if (line.stateAfter) return search;
1306
- var indented = line.indentation();
1917
+ var indented = line.indentation(options.tabSize);
1307
1918
  if (minline == null || minindent > indented) {
1308
1919
  minline = search - 1;
1309
1920
  minindent = indented;
@@ -1312,55 +1923,62 @@ var CodeMirror = (function() {
1312
1923
  return minline;
1313
1924
  }
1314
1925
  function getStateBefore(n) {
1315
- var start = findStartLine(n), state = start && lines[start-1].stateAfter;
1926
+ var start = findStartLine(n), state = start && getLine(start-1).stateAfter;
1316
1927
  if (!state) state = startState(mode);
1317
1928
  else state = copyState(mode, state);
1318
- for (var i = start; i < n; ++i) {
1319
- var line = lines[i];
1320
- line.highlight(mode, state);
1929
+ doc.iter(start, n, function(line) {
1930
+ line.highlight(mode, state, options.tabSize);
1321
1931
  line.stateAfter = copyState(mode, state);
1322
- }
1323
- if (n < lines.length && !lines[n].stateAfter) work.push(n);
1932
+ });
1933
+ if (start < n) changes.push({from: start, to: n});
1934
+ if (n < doc.size && !getLine(n).stateAfter) work.push(n);
1324
1935
  return state;
1325
1936
  }
1326
1937
  function highlightLines(start, end) {
1327
1938
  var state = getStateBefore(start);
1328
- for (var i = start; i < end; ++i) {
1329
- var line = lines[i];
1330
- line.highlight(mode, state);
1939
+ doc.iter(start, end, function(line) {
1940
+ line.highlight(mode, state, options.tabSize);
1331
1941
  line.stateAfter = copyState(mode, state);
1332
- }
1942
+ });
1333
1943
  }
1334
1944
  function highlightWorker() {
1335
1945
  var end = +new Date + options.workTime;
1336
1946
  var foundWork = work.length;
1337
1947
  while (work.length) {
1338
- if (!lines[showingFrom].stateAfter) var task = showingFrom;
1948
+ if (!getLine(showingFrom).stateAfter) var task = showingFrom;
1339
1949
  else var task = work.pop();
1340
- if (task >= lines.length) continue;
1341
- var start = findStartLine(task), state = start && lines[start-1].stateAfter;
1950
+ if (task >= doc.size) continue;
1951
+ var start = findStartLine(task), state = start && getLine(start-1).stateAfter;
1342
1952
  if (state) state = copyState(mode, state);
1343
1953
  else state = startState(mode);
1344
1954
 
1345
- var unchanged = 0, compare = mode.compareStates, realChange = false;
1346
- for (var i = start, l = lines.length; i < l; ++i) {
1347
- var line = lines[i], hadState = line.stateAfter;
1955
+ var unchanged = 0, compare = mode.compareStates, realChange = false,
1956
+ i = start, bail = false;
1957
+ doc.iter(i, doc.size, function(line) {
1958
+ var hadState = line.stateAfter;
1348
1959
  if (+new Date > end) {
1349
1960
  work.push(i);
1350
1961
  startWorker(options.workDelay);
1351
1962
  if (realChange) changes.push({from: task, to: i + 1});
1352
- return;
1963
+ return (bail = true);
1353
1964
  }
1354
- var changed = line.highlight(mode, state);
1965
+ var changed = line.highlight(mode, state, options.tabSize);
1355
1966
  if (changed) realChange = true;
1356
1967
  line.stateAfter = copyState(mode, state);
1968
+ var done = null;
1357
1969
  if (compare) {
1358
- if (hadState && compare(hadState, state)) break;
1359
- } else {
1970
+ var same = hadState && compare(hadState, state);
1971
+ if (same != Pass) done = !!same;
1972
+ }
1973
+ if (done == null) {
1360
1974
  if (changed !== false || !hadState) unchanged = 0;
1361
- else if (++unchanged > 3) break;
1975
+ else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1976
+ done = true;
1362
1977
  }
1363
- }
1978
+ if (done) return true;
1979
+ ++i;
1980
+ });
1981
+ if (bail) return;
1364
1982
  if (realChange) changes.push({from: task, to: i + 1});
1365
1983
  }
1366
1984
  if (foundWork && options.onHighlightComplete)
@@ -1376,32 +1994,46 @@ var CodeMirror = (function() {
1376
1994
  // be awkward, slow, and error-prone), but instead updates are
1377
1995
  // batched and then all combined and executed at once.
1378
1996
  function startOperation() {
1379
- updateInput = null; changes = []; textChanged = selectionChanged = false;
1997
+ updateInput = userSelChange = textChanged = null;
1998
+ changes = []; selectionChanged = false; callbacks = [];
1380
1999
  }
1381
2000
  function endOperation() {
1382
- var reScroll = false;
1383
- if (selectionChanged) reScroll = !scrollCursorIntoView();
1384
- if (changes.length) updateDisplay(changes);
1385
- else if (selectionChanged) updateCursor();
1386
- if (reScroll) scrollCursorIntoView();
2001
+ if (updateMaxLine) computeMaxLength();
2002
+ if (maxLineChanged && !options.lineWrapping) {
2003
+ var cursorWidth = widthForcer.offsetWidth, left = stringWidth(maxLine);
2004
+ widthForcer.style.left = left + "px";
2005
+ lineSpace.style.minWidth = (left + cursorWidth) + "px";
2006
+ maxLineChanged = false;
2007
+ }
2008
+ var newScrollPos, updated;
2009
+ if (selectionChanged) {
2010
+ var coords = calculateCursorCoords();
2011
+ newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
2012
+ }
2013
+ if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
2014
+ else {
2015
+ if (selectionChanged) updateSelection();
2016
+ if (gutterDirty) updateGutter();
2017
+ }
2018
+ if (newScrollPos) scrollCursorIntoView();
1387
2019
  if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1388
2020
 
1389
- // updateInput can be set to a boolean value to force/prevent an
1390
- // update.
1391
2021
  if (focused && !leaveInputAlone &&
1392
2022
  (updateInput === true || (updateInput !== false && selectionChanged)))
1393
- prepareInput();
2023
+ resetInput(userSelChange);
1394
2024
 
1395
2025
  if (selectionChanged && options.matchBrackets)
1396
2026
  setTimeout(operation(function() {
1397
2027
  if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1398
- matchBrackets(false);
2028
+ if (posEq(sel.from, sel.to)) matchBrackets(false);
1399
2029
  }), 20);
1400
- var tc = textChanged; // textChanged can be reset by cursoractivity callback
1401
- if (selectionChanged && options.onCursorActivity)
2030
+ var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
2031
+ if (textChanged && options.onChange && instance)
2032
+ options.onChange(instance, textChanged);
2033
+ if (sc && options.onCursorActivity)
1402
2034
  options.onCursorActivity(instance);
1403
- if (tc && options.onChange && instance)
1404
- options.onChange(instance, tc);
2035
+ for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
2036
+ if (updated && options.onUpdate) options.onUpdate(instance);
1405
2037
  }
1406
2038
  var nestedOperation = 0;
1407
2039
  function operation(f) {
@@ -1413,120 +2045,11 @@ var CodeMirror = (function() {
1413
2045
  };
1414
2046
  }
1415
2047
 
1416
- function SearchCursor(query, pos, caseFold) {
1417
- this.atOccurrence = false;
1418
- if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
1419
-
1420
- if (pos && typeof pos == "object") pos = clipPos(pos);
1421
- else pos = {line: 0, ch: 0};
1422
- this.pos = {from: pos, to: pos};
1423
-
1424
- // The matches method is filled in based on the type of query.
1425
- // It takes a position and a direction, and returns an object
1426
- // describing the next occurrence of the query, or null if no
1427
- // more matches were found.
1428
- if (typeof query != "string") // Regexp match
1429
- this.matches = function(reverse, pos) {
1430
- if (reverse) {
1431
- var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
1432
- while (match) {
1433
- var ind = line.indexOf(match[0]);
1434
- start += ind;
1435
- line = line.slice(ind + 1);
1436
- var newmatch = line.match(query);
1437
- if (newmatch) match = newmatch;
1438
- else break;
1439
- start++;
1440
- }
1441
- }
1442
- else {
1443
- var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
1444
- start = match && pos.ch + line.indexOf(match[0]);
1445
- }
1446
- if (match)
1447
- return {from: {line: pos.line, ch: start},
1448
- to: {line: pos.line, ch: start + match[0].length},
1449
- match: match};
1450
- };
1451
- else { // String query
1452
- if (caseFold) query = query.toLowerCase();
1453
- var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
1454
- var target = query.split("\n");
1455
- // Different methods for single-line and multi-line queries
1456
- if (target.length == 1)
1457
- this.matches = function(reverse, pos) {
1458
- var line = fold(lines[pos.line].text), len = query.length, match;
1459
- if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
1460
- : (match = line.indexOf(query, pos.ch)) != -1)
1461
- return {from: {line: pos.line, ch: match},
1462
- to: {line: pos.line, ch: match + len}};
1463
- };
1464
- else
1465
- this.matches = function(reverse, pos) {
1466
- var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
1467
- var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
1468
- if (reverse ? offsetA >= pos.ch || offsetA != match.length
1469
- : offsetA <= pos.ch || offsetA != line.length - match.length)
1470
- return;
1471
- for (;;) {
1472
- if (reverse ? !ln : ln == lines.length - 1) return;
1473
- line = fold(lines[ln += reverse ? -1 : 1].text);
1474
- match = target[reverse ? --idx : ++idx];
1475
- if (idx > 0 && idx < target.length - 1) {
1476
- if (line != match) return;
1477
- else continue;
1478
- }
1479
- var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
1480
- if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
1481
- return;
1482
- var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
1483
- return {from: reverse ? end : start, to: reverse ? start : end};
1484
- }
1485
- };
1486
- }
2048
+ function compoundChange(f) {
2049
+ history.startCompound();
2050
+ try { return f(); } finally { history.endCompound(); }
1487
2051
  }
1488
2052
 
1489
- SearchCursor.prototype = {
1490
- findNext: function() {return this.find(false);},
1491
- findPrevious: function() {return this.find(true);},
1492
-
1493
- find: function(reverse) {
1494
- var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
1495
- function savePosAndFail(line) {
1496
- var pos = {line: line, ch: 0};
1497
- self.pos = {from: pos, to: pos};
1498
- self.atOccurrence = false;
1499
- return false;
1500
- }
1501
-
1502
- for (;;) {
1503
- if (this.pos = this.matches(reverse, pos)) {
1504
- this.atOccurrence = true;
1505
- return this.pos.match || true;
1506
- }
1507
- if (reverse) {
1508
- if (!pos.line) return savePosAndFail(0);
1509
- pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
1510
- }
1511
- else {
1512
- if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
1513
- pos = {line: pos.line+1, ch: 0};
1514
- }
1515
- }
1516
- },
1517
-
1518
- from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
1519
- to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
1520
-
1521
- replace: function(newText) {
1522
- var self = this;
1523
- if (this.atOccurrence)
1524
- operation(function() {
1525
- self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
1526
- })();
1527
- }
1528
- };
1529
-
1530
2053
  for (var ext in extensions)
1531
2054
  if (extensions.propertyIsEnumerable(ext) &&
1532
2055
  !instance.propertyIsEnumerable(ext))
@@ -1541,50 +2064,67 @@ var CodeMirror = (function() {
1541
2064
  theme: "default",
1542
2065
  indentUnit: 2,
1543
2066
  indentWithTabs: false,
1544
- tabMode: "classic",
1545
- enterMode: "indent",
2067
+ smartIndent: true,
2068
+ tabSize: 4,
2069
+ keyMap: "default",
2070
+ extraKeys: null,
1546
2071
  electricChars: true,
2072
+ autoClearEmptyLines: false,
1547
2073
  onKeyEvent: null,
2074
+ onDragEvent: null,
2075
+ lineWrapping: false,
1548
2076
  lineNumbers: false,
1549
2077
  gutter: false,
2078
+ fixedGutter: false,
1550
2079
  firstLineNumber: 1,
1551
2080
  readOnly: false,
1552
- smartHome: true,
2081
+ dragDrop: true,
1553
2082
  onChange: null,
1554
2083
  onCursorActivity: null,
1555
2084
  onGutterClick: null,
1556
2085
  onHighlightComplete: null,
2086
+ onUpdate: null,
1557
2087
  onFocus: null, onBlur: null, onScroll: null,
1558
2088
  matchBrackets: false,
1559
2089
  workTime: 100,
1560
2090
  workDelay: 200,
2091
+ pollInterval: 100,
1561
2092
  undoDepth: 40,
1562
2093
  tabindex: null,
1563
- document: window.document
2094
+ autofocus: null,
2095
+ lineNumberFormatter: function(integer) { return integer; }
1564
2096
  };
1565
2097
 
2098
+ var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
2099
+ var mac = ios || /Mac/.test(navigator.platform);
2100
+ var win = /Win/.test(navigator.platform);
2101
+
1566
2102
  // Known modes, by name and by MIME
1567
- var modes = {}, mimeModes = {};
2103
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
1568
2104
  CodeMirror.defineMode = function(name, mode) {
1569
2105
  if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
2106
+ if (arguments.length > 2) {
2107
+ mode.dependencies = [];
2108
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
2109
+ }
1570
2110
  modes[name] = mode;
1571
2111
  };
1572
2112
  CodeMirror.defineMIME = function(mime, spec) {
1573
2113
  mimeModes[mime] = spec;
1574
2114
  };
1575
- CodeMirror.getMode = function(options, spec) {
2115
+ CodeMirror.resolveMode = function(spec) {
1576
2116
  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1577
2117
  spec = mimeModes[spec];
1578
- if (typeof spec == "string")
1579
- var mname = spec, config = {};
1580
- else if (spec != null)
1581
- var mname = spec.name, config = spec;
1582
- var mfactory = modes[mname];
1583
- if (!mfactory) {
1584
- if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1585
- return CodeMirror.getMode(options, "text/plain");
1586
- }
1587
- return mfactory(options, config || {});
2118
+ else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
2119
+ return CodeMirror.resolveMode("application/xml");
2120
+ if (typeof spec == "string") return {name: spec};
2121
+ else return spec || {name: "null"};
2122
+ };
2123
+ CodeMirror.getMode = function(options, spec) {
2124
+ var spec = CodeMirror.resolveMode(spec);
2125
+ var mfactory = modes[spec.name];
2126
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
2127
+ return mfactory(options, spec);
1588
2128
  };
1589
2129
  CodeMirror.listModes = function() {
1590
2130
  var list = [];
@@ -1595,20 +2135,141 @@ var CodeMirror = (function() {
1595
2135
  CodeMirror.listMIMEs = function() {
1596
2136
  var list = [];
1597
2137
  for (var m in mimeModes)
1598
- if (mimeModes.propertyIsEnumerable(m)) list.push(m);
2138
+ if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]});
1599
2139
  return list;
1600
2140
  };
1601
2141
 
1602
- var extensions = {};
2142
+ var extensions = CodeMirror.extensions = {};
1603
2143
  CodeMirror.defineExtension = function(name, func) {
1604
2144
  extensions[name] = func;
1605
2145
  };
1606
2146
 
2147
+ var commands = CodeMirror.commands = {
2148
+ selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
2149
+ killLine: function(cm) {
2150
+ var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
2151
+ if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0});
2152
+ else cm.replaceRange("", from, sel ? to : {line: from.line});
2153
+ },
2154
+ deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});},
2155
+ undo: function(cm) {cm.undo();},
2156
+ redo: function(cm) {cm.redo();},
2157
+ goDocStart: function(cm) {cm.setCursor(0, 0, true);},
2158
+ goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);},
2159
+ goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);},
2160
+ goLineStartSmart: function(cm) {
2161
+ var cur = cm.getCursor();
2162
+ var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/));
2163
+ cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true);
2164
+ },
2165
+ goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);},
2166
+ goLineUp: function(cm) {cm.moveV(-1, "line");},
2167
+ goLineDown: function(cm) {cm.moveV(1, "line");},
2168
+ goPageUp: function(cm) {cm.moveV(-1, "page");},
2169
+ goPageDown: function(cm) {cm.moveV(1, "page");},
2170
+ goCharLeft: function(cm) {cm.moveH(-1, "char");},
2171
+ goCharRight: function(cm) {cm.moveH(1, "char");},
2172
+ goColumnLeft: function(cm) {cm.moveH(-1, "column");},
2173
+ goColumnRight: function(cm) {cm.moveH(1, "column");},
2174
+ goWordLeft: function(cm) {cm.moveH(-1, "word");},
2175
+ goWordRight: function(cm) {cm.moveH(1, "word");},
2176
+ delCharLeft: function(cm) {cm.deleteH(-1, "char");},
2177
+ delCharRight: function(cm) {cm.deleteH(1, "char");},
2178
+ delWordLeft: function(cm) {cm.deleteH(-1, "word");},
2179
+ delWordRight: function(cm) {cm.deleteH(1, "word");},
2180
+ indentAuto: function(cm) {cm.indentSelection("smart");},
2181
+ indentMore: function(cm) {cm.indentSelection("add");},
2182
+ indentLess: function(cm) {cm.indentSelection("subtract");},
2183
+ insertTab: function(cm) {cm.replaceSelection("\t", "end");},
2184
+ defaultTab: function(cm) {
2185
+ if (cm.somethingSelected()) cm.indentSelection("add");
2186
+ else cm.replaceSelection("\t", "end");
2187
+ },
2188
+ transposeChars: function(cm) {
2189
+ var cur = cm.getCursor(), line = cm.getLine(cur.line);
2190
+ if (cur.ch > 0 && cur.ch < line.length - 1)
2191
+ cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
2192
+ {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
2193
+ },
2194
+ newlineAndIndent: function(cm) {
2195
+ cm.replaceSelection("\n", "end");
2196
+ cm.indentLine(cm.getCursor().line);
2197
+ },
2198
+ toggleOverwrite: function(cm) {cm.toggleOverwrite();}
2199
+ };
2200
+
2201
+ var keyMap = CodeMirror.keyMap = {};
2202
+ keyMap.basic = {
2203
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
2204
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
2205
+ "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
2206
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
2207
+ };
2208
+ // Note that the save and find-related commands aren't defined by
2209
+ // default. Unknown commands are simply ignored.
2210
+ keyMap.pcDefault = {
2211
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
2212
+ "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
2213
+ "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
2214
+ "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
2215
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
2216
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
2217
+ fallthrough: "basic"
2218
+ };
2219
+ keyMap.macDefault = {
2220
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
2221
+ "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
2222
+ "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
2223
+ "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
2224
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
2225
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore",
2226
+ fallthrough: ["basic", "emacsy"]
2227
+ };
2228
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
2229
+ keyMap.emacsy = {
2230
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
2231
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
2232
+ "Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
2233
+ "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
2234
+ };
2235
+
2236
+ function getKeyMap(val) {
2237
+ if (typeof val == "string") return keyMap[val];
2238
+ else return val;
2239
+ }
2240
+ function lookupKey(name, extraMap, map, handle, stop) {
2241
+ function lookup(map) {
2242
+ map = getKeyMap(map);
2243
+ var found = map[name];
2244
+ if (found != null && handle(found)) return true;
2245
+ if (map.nofallthrough) {
2246
+ if (stop) stop();
2247
+ return true;
2248
+ }
2249
+ var fallthrough = map.fallthrough;
2250
+ if (fallthrough == null) return false;
2251
+ if (Object.prototype.toString.call(fallthrough) != "[object Array]")
2252
+ return lookup(fallthrough);
2253
+ for (var i = 0, e = fallthrough.length; i < e; ++i) {
2254
+ if (lookup(fallthrough[i])) return true;
2255
+ }
2256
+ return false;
2257
+ }
2258
+ if (extraMap && lookup(extraMap)) return true;
2259
+ return lookup(map);
2260
+ }
2261
+ function isModifierKey(event) {
2262
+ var name = keyNames[e_prop(event, "keyCode")];
2263
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
2264
+ }
2265
+
1607
2266
  CodeMirror.fromTextArea = function(textarea, options) {
1608
2267
  if (!options) options = {};
1609
2268
  options.value = textarea.value;
1610
2269
  if (!options.tabindex && textarea.tabindex)
1611
2270
  options.tabindex = textarea.tabindex;
2271
+ if (options.autofocus == null && textarea.getAttribute("autofocus") != null)
2272
+ options.autofocus = true;
1612
2273
 
1613
2274
  function save() {textarea.value = instance.getValue();}
1614
2275
  if (textarea.form) {
@@ -1631,6 +2292,7 @@ var CodeMirror = (function() {
1631
2292
  textarea.parentNode.insertBefore(node, textarea.nextSibling);
1632
2293
  }, options);
1633
2294
  instance.save = save;
2295
+ instance.getTextArea = function() { return textarea; };
1634
2296
  instance.toTextArea = function() {
1635
2297
  save();
1636
2298
  textarea.parentNode.removeChild(instance.getWrapperElement());
@@ -1657,16 +2319,17 @@ var CodeMirror = (function() {
1657
2319
  }
1658
2320
  return nstate;
1659
2321
  }
1660
- CodeMirror.startState = startState;
2322
+ CodeMirror.copyState = copyState;
1661
2323
  function startState(mode, a1, a2) {
1662
2324
  return mode.startState ? mode.startState(a1, a2) : true;
1663
2325
  }
1664
- CodeMirror.copyState = copyState;
2326
+ CodeMirror.startState = startState;
1665
2327
 
1666
2328
  // The character stream used by a mode's parser.
1667
- function StringStream(string) {
2329
+ function StringStream(string, tabSize) {
1668
2330
  this.pos = this.start = 0;
1669
2331
  this.string = string;
2332
+ this.tabSize = tabSize || 8;
1670
2333
  }
1671
2334
  StringStream.prototype = {
1672
2335
  eol: function() {return this.pos >= this.string.length;},
@@ -1698,8 +2361,8 @@ var CodeMirror = (function() {
1698
2361
  if (found > -1) {this.pos = found; return true;}
1699
2362
  },
1700
2363
  backUp: function(n) {this.pos -= n;},
1701
- column: function() {return countColumn(this.string, this.start);},
1702
- indentation: function() {return countColumn(this.string);},
2364
+ column: function() {return countColumn(this.string, this.start, this.tabSize);},
2365
+ indentation: function() {return countColumn(this.string, null, this.tabSize);},
1703
2366
  match: function(pattern, consume, caseInsensitive) {
1704
2367
  if (typeof pattern == "string") {
1705
2368
  function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
@@ -1707,8 +2370,7 @@ var CodeMirror = (function() {
1707
2370
  if (consume !== false) this.pos += pattern.length;
1708
2371
  return true;
1709
2372
  }
1710
- }
1711
- else {
2373
+ } else {
1712
2374
  var match = this.string.slice(this.pos).match(pattern);
1713
2375
  if (match && consume !== false) this.pos += match[0].length;
1714
2376
  return match;
@@ -1718,18 +2380,95 @@ var CodeMirror = (function() {
1718
2380
  };
1719
2381
  CodeMirror.StringStream = StringStream;
1720
2382
 
2383
+ function MarkedText(from, to, className, marker) {
2384
+ this.from = from; this.to = to; this.style = className; this.marker = marker;
2385
+ }
2386
+ MarkedText.prototype = {
2387
+ attach: function(line) { this.marker.set.push(line); },
2388
+ detach: function(line) {
2389
+ var ix = indexOf(this.marker.set, line);
2390
+ if (ix > -1) this.marker.set.splice(ix, 1);
2391
+ },
2392
+ split: function(pos, lenBefore) {
2393
+ if (this.to <= pos && this.to != null) return null;
2394
+ var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
2395
+ var to = this.to == null ? null : this.to - pos + lenBefore;
2396
+ return new MarkedText(from, to, this.style, this.marker);
2397
+ },
2398
+ dup: function() { return new MarkedText(null, null, this.style, this.marker); },
2399
+ clipTo: function(fromOpen, from, toOpen, to, diff) {
2400
+ if (fromOpen && to > this.from && (to < this.to || this.to == null))
2401
+ this.from = null;
2402
+ else if (this.from != null && this.from >= from)
2403
+ this.from = Math.max(to, this.from) + diff;
2404
+ if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
2405
+ this.to = null;
2406
+ else if (this.to != null && this.to > from)
2407
+ this.to = to < this.to ? this.to + diff : from;
2408
+ },
2409
+ isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
2410
+ sameSet: function(x) { return this.marker == x.marker; }
2411
+ };
2412
+
2413
+ function Bookmark(pos) {
2414
+ this.from = pos; this.to = pos; this.line = null;
2415
+ }
2416
+ Bookmark.prototype = {
2417
+ attach: function(line) { this.line = line; },
2418
+ detach: function(line) { if (this.line == line) this.line = null; },
2419
+ split: function(pos, lenBefore) {
2420
+ if (pos < this.from) {
2421
+ this.from = this.to = (this.from - pos) + lenBefore;
2422
+ return this;
2423
+ }
2424
+ },
2425
+ isDead: function() { return this.from > this.to; },
2426
+ clipTo: function(fromOpen, from, toOpen, to, diff) {
2427
+ if ((fromOpen || from < this.from) && (toOpen || to > this.to)) {
2428
+ this.from = 0; this.to = -1;
2429
+ } else if (this.from > from) {
2430
+ this.from = this.to = Math.max(to, this.from) + diff;
2431
+ }
2432
+ },
2433
+ sameSet: function(x) { return false; },
2434
+ find: function() {
2435
+ if (!this.line || !this.line.parent) return null;
2436
+ return {line: lineNo(this.line), ch: this.from};
2437
+ },
2438
+ clear: function() {
2439
+ if (this.line) {
2440
+ var found = indexOf(this.line.marked, this);
2441
+ if (found != -1) this.line.marked.splice(found, 1);
2442
+ this.line = null;
2443
+ }
2444
+ }
2445
+ };
2446
+
1721
2447
  // Line objects. These hold state related to a line, including
1722
2448
  // highlighting info (the styles array).
1723
2449
  function Line(text, styles) {
1724
2450
  this.styles = styles || [text, null];
1725
- this.stateAfter = null;
1726
2451
  this.text = text;
1727
- this.marked = this.gutterMarker = this.className = null;
2452
+ this.height = 1;
2453
+ this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null;
2454
+ this.stateAfter = this.parent = this.hidden = null;
2455
+ }
2456
+ Line.inheritMarks = function(text, orig) {
2457
+ var ln = new Line(text), mk = orig && orig.marked;
2458
+ if (mk) {
2459
+ for (var i = 0; i < mk.length; ++i) {
2460
+ if (mk[i].to == null && mk[i].style) {
2461
+ var newmk = ln.marked || (ln.marked = []), mark = mk[i];
2462
+ var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln);
2463
+ }
2464
+ }
2465
+ }
2466
+ return ln;
1728
2467
  }
1729
2468
  Line.prototype = {
1730
2469
  // Replace a piece of a line, keeping the styles around it intact.
1731
- replace: function(from, to, text) {
1732
- var st = [], mk = this.marked;
2470
+ replace: function(from, to_, text) {
2471
+ var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
1733
2472
  copyStyles(0, from, this.styles, st);
1734
2473
  if (text) st.push(text, null);
1735
2474
  copyStyles(to, this.text.length, this.styles, st);
@@ -1737,40 +2476,102 @@ var CodeMirror = (function() {
1737
2476
  this.text = this.text.slice(0, from) + text + this.text.slice(to);
1738
2477
  this.stateAfter = null;
1739
2478
  if (mk) {
1740
- var diff = text.length - (to - from), end = this.text.length;
1741
- function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
2479
+ var diff = text.length - (to - from);
1742
2480
  for (var i = 0; i < mk.length; ++i) {
1743
- var mark = mk[i], del = false;
1744
- if (mark.from >= end) del = true;
1745
- else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
1746
- if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
2481
+ var mark = mk[i];
2482
+ mark.clipTo(from == null, from || 0, to_ == null, to, diff);
2483
+ if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
1747
2484
  }
1748
2485
  }
1749
2486
  },
1750
- // Split a line in two, again keeping styles intact.
2487
+ // Split a part off a line, keeping styles and markers intact.
1751
2488
  split: function(pos, textBefore) {
1752
- var st = [textBefore, null];
2489
+ var st = [textBefore, null], mk = this.marked;
1753
2490
  copyStyles(pos, this.text.length, this.styles, st);
1754
- return new Line(textBefore + this.text.slice(pos), st);
2491
+ var taken = new Line(textBefore + this.text.slice(pos), st);
2492
+ if (mk) {
2493
+ for (var i = 0; i < mk.length; ++i) {
2494
+ var mark = mk[i];
2495
+ var newmark = mark.split(pos, textBefore.length);
2496
+ if (newmark) {
2497
+ if (!taken.marked) taken.marked = [];
2498
+ taken.marked.push(newmark); newmark.attach(taken);
2499
+ if (newmark == mark) mk.splice(i--, 1);
2500
+ }
2501
+ }
2502
+ }
2503
+ return taken;
1755
2504
  },
1756
- addMark: function(from, to, style) {
1757
- var mk = this.marked, mark = {from: from, to: to, style: style};
1758
- if (this.marked == null) this.marked = [];
1759
- this.marked.push(mark);
1760
- this.marked.sort(function(a, b){return a.from - b.from;});
1761
- return mark;
2505
+ append: function(line) {
2506
+ var mylen = this.text.length, mk = line.marked, mymk = this.marked;
2507
+ this.text += line.text;
2508
+ copyStyles(0, line.text.length, line.styles, this.styles);
2509
+ if (mymk) {
2510
+ for (var i = 0; i < mymk.length; ++i)
2511
+ if (mymk[i].to == null) mymk[i].to = mylen;
2512
+ }
2513
+ if (mk && mk.length) {
2514
+ if (!mymk) this.marked = mymk = [];
2515
+ outer: for (var i = 0; i < mk.length; ++i) {
2516
+ var mark = mk[i];
2517
+ if (!mark.from) {
2518
+ for (var j = 0; j < mymk.length; ++j) {
2519
+ var mymark = mymk[j];
2520
+ if (mymark.to == mylen && mymark.sameSet(mark)) {
2521
+ mymark.to = mark.to == null ? null : mark.to + mylen;
2522
+ if (mymark.isDead()) {
2523
+ mymark.detach(this);
2524
+ mk.splice(i--, 1);
2525
+ }
2526
+ continue outer;
2527
+ }
2528
+ }
2529
+ }
2530
+ mymk.push(mark);
2531
+ mark.attach(this);
2532
+ mark.from += mylen;
2533
+ if (mark.to != null) mark.to += mylen;
2534
+ }
2535
+ }
1762
2536
  },
1763
- removeMark: function(mark) {
2537
+ fixMarkEnds: function(other) {
2538
+ var mk = this.marked, omk = other.marked;
2539
+ if (!mk) return;
2540
+ outer: for (var i = 0; i < mk.length; ++i) {
2541
+ var mark = mk[i], close = mark.to == null;
2542
+ if (close && omk) {
2543
+ for (var j = 0; j < omk.length; ++j) {
2544
+ var om = omk[j];
2545
+ if (!om.sameSet(mark) || om.from != null) continue
2546
+ if (mark.from == this.text.length && om.to == 0) {
2547
+ omk.splice(j, 1);
2548
+ mk.splice(i--, 1);
2549
+ continue outer;
2550
+ } else {
2551
+ close = false; break;
2552
+ }
2553
+ }
2554
+ }
2555
+ if (close) mark.to = this.text.length;
2556
+ }
2557
+ },
2558
+ fixMarkStarts: function() {
1764
2559
  var mk = this.marked;
1765
2560
  if (!mk) return;
1766
2561
  for (var i = 0; i < mk.length; ++i)
1767
- if (mk[i] == mark) {mk.splice(i, 1); break;}
2562
+ if (mk[i].from == null) mk[i].from = 0;
2563
+ },
2564
+ addMark: function(mark) {
2565
+ mark.attach(this);
2566
+ if (this.marked == null) this.marked = [];
2567
+ this.marked.push(mark);
2568
+ this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);});
1768
2569
  },
1769
2570
  // Run the given mode's parser over a line, update the styles
1770
2571
  // array, which contains alternating fragments of text and CSS
1771
2572
  // classes.
1772
- highlight: function(mode, state) {
1773
- var stream = new StringStream(this.text), st = this.styles, pos = 0;
2573
+ highlight: function(mode, state, tabSize) {
2574
+ var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
1774
2575
  var changed = false, curWord = st[0], prevWord;
1775
2576
  if (this.text == "" && mode.blankLine) mode.blankLine(state);
1776
2577
  while (!stream.eol()) {
@@ -1811,74 +2612,131 @@ var CodeMirror = (function() {
1811
2612
  className: style || null,
1812
2613
  state: state};
1813
2614
  },
1814
- indentation: function() {return countColumn(this.text);},
2615
+ indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
1815
2616
  // Produces an HTML fragment for the line, taking selection,
1816
2617
  // marking, and highlighting into account.
1817
- getHTML: function(sfrom, sto, includePre, endAt) {
1818
- var html = [];
1819
- if (includePre)
1820
- html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
1821
- function span(text, style) {
2618
+ getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
2619
+ var html = [], first = true, col = 0;
2620
+ function span_(text, style) {
1822
2621
  if (!text) return;
1823
- if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
1824
- else html.push(htmlEscape(text));
2622
+ // Work around a bug where, in some compat modes, IE ignores leading spaces
2623
+ if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
2624
+ first = false;
2625
+ if (text.indexOf("\t") == -1) {
2626
+ col += text.length;
2627
+ var escaped = htmlEscape(text);
2628
+ } else {
2629
+ var escaped = "";
2630
+ for (var pos = 0;;) {
2631
+ var idx = text.indexOf("\t", pos);
2632
+ if (idx == -1) {
2633
+ escaped += htmlEscape(text.slice(pos));
2634
+ col += text.length - pos;
2635
+ break;
2636
+ } else {
2637
+ col += idx - pos;
2638
+ var tab = makeTab(col);
2639
+ escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
2640
+ col += tab.width;
2641
+ pos = idx + 1;
2642
+ }
2643
+ }
2644
+ }
2645
+ if (style) html.push('<span class="', style, '">', escaped, "</span>");
2646
+ else html.push(escaped);
2647
+ }
2648
+ var span = span_;
2649
+ if (wrapAt != null) {
2650
+ var outPos = 0, open = "<span id=\"" + wrapId + "\">";
2651
+ span = function(text, style) {
2652
+ var l = text.length;
2653
+ if (wrapAt >= outPos && wrapAt < outPos + l) {
2654
+ if (wrapAt > outPos) {
2655
+ span_(text.slice(0, wrapAt - outPos), style);
2656
+ // See comment at the definition of spanAffectsWrapping
2657
+ if (wrapWBR) html.push("<wbr>");
2658
+ }
2659
+ html.push(open);
2660
+ var cut = wrapAt - outPos;
2661
+ span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
2662
+ html.push("</span>");
2663
+ if (opera) span_(text.slice(cut + 1), style);
2664
+ wrapAt--;
2665
+ outPos += l;
2666
+ } else {
2667
+ outPos += l;
2668
+ span_(text, style);
2669
+ // Output empty wrapper when at end of line
2670
+ // (Gecko and IE8+ do strange wrapping when adding a space
2671
+ // to the end of the line. Other browsers don't react well
2672
+ // to zero-width spaces. So we do hideous browser sniffing
2673
+ // to determine which to use.)
2674
+ if (outPos == wrapAt && outPos == len)
2675
+ html.push(open + (gecko || (ie && !ie_lt8) ? "&#x200b;" : " ") + "</span>");
2676
+ // Stop outputting HTML when gone sufficiently far beyond measure
2677
+ else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
2678
+ }
2679
+ }
1825
2680
  }
2681
+
1826
2682
  var st = this.styles, allText = this.text, marked = this.marked;
1827
- if (sfrom == sto) sfrom = null;
1828
2683
  var len = allText.length;
1829
- if (endAt != null) len = Math.min(endAt, len);
2684
+ function styleToClass(style) {
2685
+ if (!style) return null;
2686
+ return "cm-" + style.replace(/ +/g, " cm-");
2687
+ }
1830
2688
 
1831
- if (!allText && endAt == null)
1832
- span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
1833
- else if (!marked && sfrom == null)
2689
+ if (!allText && wrapAt == null) {
2690
+ span(" ");
2691
+ } else if (!marked || !marked.length) {
1834
2692
  for (var i = 0, ch = 0; ch < len; i+=2) {
1835
- var str = st[i], l = str.length;
2693
+ var str = st[i], style = st[i+1], l = str.length;
1836
2694
  if (ch + l > len) str = str.slice(0, len - ch);
1837
2695
  ch += l;
1838
- span(str, "cm-" + st[i+1]);
2696
+ span(str, styleToClass(style));
1839
2697
  }
1840
- else {
2698
+ } else {
1841
2699
  var pos = 0, i = 0, text = "", style, sg = 0;
1842
- var markpos = -1, mark = null;
1843
- function nextMark() {
1844
- if (marked) {
1845
- markpos += 1;
1846
- mark = (markpos < marked.length) ? marked[markpos] : null;
2700
+ var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2701
+ function advanceMarks() {
2702
+ var m;
2703
+ while (markpos < marked.length &&
2704
+ ((m = marked[markpos]).from == pos || m.from == null)) {
2705
+ if (m.style != null) marks.push(m);
2706
+ ++markpos;
2707
+ }
2708
+ nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
2709
+ for (var i = 0; i < marks.length; ++i) {
2710
+ var to = marks[i].to;
2711
+ if (to == null) to = Infinity;
2712
+ if (to == pos) marks.splice(i--, 1);
2713
+ else nextChange = Math.min(to, nextChange);
1847
2714
  }
1848
2715
  }
1849
- nextMark();
2716
+ var m = 0;
1850
2717
  while (pos < len) {
1851
- var upto = len;
1852
- var extraStyle = "";
1853
- if (sfrom != null) {
1854
- if (sfrom > pos) upto = sfrom;
1855
- else if (sto == null || sto > pos) {
1856
- extraStyle = " CodeMirror-selected";
1857
- if (sto != null) upto = Math.min(upto, sto);
1858
- }
1859
- }
1860
- while (mark && mark.to != null && mark.to <= pos) nextMark();
1861
- if (mark) {
1862
- if (mark.from > pos) upto = Math.min(upto, mark.from);
1863
- else {
1864
- extraStyle += " " + mark.style;
1865
- if (mark.to != null) upto = Math.min(upto, mark.to);
2718
+ if (nextChange == pos) advanceMarks();
2719
+ var upto = Math.min(len, nextChange);
2720
+ while (true) {
2721
+ if (text) {
2722
+ var end = pos + text.length;
2723
+ var appliedStyle = style;
2724
+ for (var j = 0; j < marks.length; ++j)
2725
+ appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style;
2726
+ span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
2727
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
2728
+ pos = end;
1866
2729
  }
1867
- }
1868
- for (;;) {
1869
- var end = pos + text.length;
1870
- var appliedStyle = style;
1871
- if (extraStyle) appliedStyle = style ? style + extraStyle : extraStyle;
1872
- span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
1873
- if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
1874
- pos = end;
1875
- text = st[i++]; style = "cm-" + st[i++];
2730
+ text = st[i++]; style = styleToClass(st[i++]);
1876
2731
  }
1877
2732
  }
1878
- if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
1879
2733
  }
1880
- if (includePre) html.push("</pre>");
1881
2734
  return html.join("");
2735
+ },
2736
+ cleanUp: function() {
2737
+ this.parent = null;
2738
+ if (this.marked)
2739
+ for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this);
1882
2740
  }
1883
2741
  };
1884
2742
  // Utility used by replace and split above
@@ -1888,8 +2746,7 @@ var CodeMirror = (function() {
1888
2746
  if (state == 0) {
1889
2747
  if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
1890
2748
  if (end >= from) state = 1;
1891
- }
1892
- else if (state == 1) {
2749
+ } else if (state == 1) {
1893
2750
  if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
1894
2751
  else dest.push(part, source[i+1]);
1895
2752
  }
@@ -1897,36 +2754,229 @@ var CodeMirror = (function() {
1897
2754
  }
1898
2755
  }
1899
2756
 
2757
+ // Data structure that holds the sequence of lines.
2758
+ function LeafChunk(lines) {
2759
+ this.lines = lines;
2760
+ this.parent = null;
2761
+ for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
2762
+ lines[i].parent = this;
2763
+ height += lines[i].height;
2764
+ }
2765
+ this.height = height;
2766
+ }
2767
+ LeafChunk.prototype = {
2768
+ chunkSize: function() { return this.lines.length; },
2769
+ remove: function(at, n, callbacks) {
2770
+ for (var i = at, e = at + n; i < e; ++i) {
2771
+ var line = this.lines[i];
2772
+ this.height -= line.height;
2773
+ line.cleanUp();
2774
+ if (line.handlers)
2775
+ for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]);
2776
+ }
2777
+ this.lines.splice(at, n);
2778
+ },
2779
+ collapse: function(lines) {
2780
+ lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
2781
+ },
2782
+ insertHeight: function(at, lines, height) {
2783
+ this.height += height;
2784
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
2785
+ for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
2786
+ },
2787
+ iterN: function(at, n, op) {
2788
+ for (var e = at + n; at < e; ++at)
2789
+ if (op(this.lines[at])) return true;
2790
+ }
2791
+ };
2792
+ function BranchChunk(children) {
2793
+ this.children = children;
2794
+ var size = 0, height = 0;
2795
+ for (var i = 0, e = children.length; i < e; ++i) {
2796
+ var ch = children[i];
2797
+ size += ch.chunkSize(); height += ch.height;
2798
+ ch.parent = this;
2799
+ }
2800
+ this.size = size;
2801
+ this.height = height;
2802
+ this.parent = null;
2803
+ }
2804
+ BranchChunk.prototype = {
2805
+ chunkSize: function() { return this.size; },
2806
+ remove: function(at, n, callbacks) {
2807
+ this.size -= n;
2808
+ for (var i = 0; i < this.children.length; ++i) {
2809
+ var child = this.children[i], sz = child.chunkSize();
2810
+ if (at < sz) {
2811
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
2812
+ child.remove(at, rm, callbacks);
2813
+ this.height -= oldHeight - child.height;
2814
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
2815
+ if ((n -= rm) == 0) break;
2816
+ at = 0;
2817
+ } else at -= sz;
2818
+ }
2819
+ if (this.size - n < 25) {
2820
+ var lines = [];
2821
+ this.collapse(lines);
2822
+ this.children = [new LeafChunk(lines)];
2823
+ this.children[0].parent = this;
2824
+ }
2825
+ },
2826
+ collapse: function(lines) {
2827
+ for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
2828
+ },
2829
+ insert: function(at, lines) {
2830
+ var height = 0;
2831
+ for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
2832
+ this.insertHeight(at, lines, height);
2833
+ },
2834
+ insertHeight: function(at, lines, height) {
2835
+ this.size += lines.length;
2836
+ this.height += height;
2837
+ for (var i = 0, e = this.children.length; i < e; ++i) {
2838
+ var child = this.children[i], sz = child.chunkSize();
2839
+ if (at <= sz) {
2840
+ child.insertHeight(at, lines, height);
2841
+ if (child.lines && child.lines.length > 50) {
2842
+ while (child.lines.length > 50) {
2843
+ var spilled = child.lines.splice(child.lines.length - 25, 25);
2844
+ var newleaf = new LeafChunk(spilled);
2845
+ child.height -= newleaf.height;
2846
+ this.children.splice(i + 1, 0, newleaf);
2847
+ newleaf.parent = this;
2848
+ }
2849
+ this.maybeSpill();
2850
+ }
2851
+ break;
2852
+ }
2853
+ at -= sz;
2854
+ }
2855
+ },
2856
+ maybeSpill: function() {
2857
+ if (this.children.length <= 10) return;
2858
+ var me = this;
2859
+ do {
2860
+ var spilled = me.children.splice(me.children.length - 5, 5);
2861
+ var sibling = new BranchChunk(spilled);
2862
+ if (!me.parent) { // Become the parent node
2863
+ var copy = new BranchChunk(me.children);
2864
+ copy.parent = me;
2865
+ me.children = [copy, sibling];
2866
+ me = copy;
2867
+ } else {
2868
+ me.size -= sibling.size;
2869
+ me.height -= sibling.height;
2870
+ var myIndex = indexOf(me.parent.children, me);
2871
+ me.parent.children.splice(myIndex + 1, 0, sibling);
2872
+ }
2873
+ sibling.parent = me.parent;
2874
+ } while (me.children.length > 10);
2875
+ me.parent.maybeSpill();
2876
+ },
2877
+ iter: function(from, to, op) { this.iterN(from, to - from, op); },
2878
+ iterN: function(at, n, op) {
2879
+ for (var i = 0, e = this.children.length; i < e; ++i) {
2880
+ var child = this.children[i], sz = child.chunkSize();
2881
+ if (at < sz) {
2882
+ var used = Math.min(n, sz - at);
2883
+ if (child.iterN(at, used, op)) return true;
2884
+ if ((n -= used) == 0) break;
2885
+ at = 0;
2886
+ } else at -= sz;
2887
+ }
2888
+ }
2889
+ };
2890
+
2891
+ function getLineAt(chunk, n) {
2892
+ while (!chunk.lines) {
2893
+ for (var i = 0;; ++i) {
2894
+ var child = chunk.children[i], sz = child.chunkSize();
2895
+ if (n < sz) { chunk = child; break; }
2896
+ n -= sz;
2897
+ }
2898
+ }
2899
+ return chunk.lines[n];
2900
+ }
2901
+ function lineNo(line) {
2902
+ if (line.parent == null) return null;
2903
+ var cur = line.parent, no = indexOf(cur.lines, line);
2904
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
2905
+ for (var i = 0, e = chunk.children.length; ; ++i) {
2906
+ if (chunk.children[i] == cur) break;
2907
+ no += chunk.children[i].chunkSize();
2908
+ }
2909
+ }
2910
+ return no;
2911
+ }
2912
+ function lineAtHeight(chunk, h) {
2913
+ var n = 0;
2914
+ outer: do {
2915
+ for (var i = 0, e = chunk.children.length; i < e; ++i) {
2916
+ var child = chunk.children[i], ch = child.height;
2917
+ if (h < ch) { chunk = child; continue outer; }
2918
+ h -= ch;
2919
+ n += child.chunkSize();
2920
+ }
2921
+ return n;
2922
+ } while (!chunk.lines);
2923
+ for (var i = 0, e = chunk.lines.length; i < e; ++i) {
2924
+ var line = chunk.lines[i], lh = line.height;
2925
+ if (h < lh) break;
2926
+ h -= lh;
2927
+ }
2928
+ return n + i;
2929
+ }
2930
+ function heightAtLine(chunk, n) {
2931
+ var h = 0;
2932
+ outer: do {
2933
+ for (var i = 0, e = chunk.children.length; i < e; ++i) {
2934
+ var child = chunk.children[i], sz = child.chunkSize();
2935
+ if (n < sz) { chunk = child; continue outer; }
2936
+ n -= sz;
2937
+ h += child.height;
2938
+ }
2939
+ return h;
2940
+ } while (!chunk.lines);
2941
+ for (var i = 0; i < n; ++i) h += chunk.lines[i].height;
2942
+ return h;
2943
+ }
2944
+
1900
2945
  // The history object 'chunks' changes that are made close together
1901
2946
  // and at almost the same time into bigger undoable units.
1902
2947
  function History() {
1903
2948
  this.time = 0;
1904
2949
  this.done = []; this.undone = [];
2950
+ this.compound = 0;
2951
+ this.closed = false;
1905
2952
  }
1906
2953
  History.prototype = {
1907
2954
  addChange: function(start, added, old) {
1908
2955
  this.undone.length = 0;
1909
- var time = +new Date, last = this.done[this.done.length - 1];
1910
- if (time - this.time > 400 || !last ||
1911
- last.start > start + added || last.start + last.added < start - last.added + last.old.length)
1912
- this.done.push({start: start, added: added, old: old});
1913
- else {
1914
- var oldoff = 0;
1915
- if (start < last.start) {
1916
- for (var i = last.start - start - 1; i >= 0; --i)
1917
- last.old.unshift(old[i]);
1918
- last.added += last.start - start;
1919
- last.start = start;
1920
- }
1921
- else if (last.start < start) {
1922
- oldoff = start - last.start;
1923
- added += oldoff;
1924
- }
1925
- for (var i = last.added - oldoff, e = old.length; i < e; ++i)
1926
- last.old.push(old[i]);
1927
- if (last.added < added) last.added = added;
2956
+ var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2957
+ var dtime = time - this.time;
2958
+
2959
+ if (this.compound && cur && !this.closed) {
2960
+ cur.push({start: start, added: added, old: old});
2961
+ } else if (dtime > 400 || !last || this.closed ||
2962
+ last.start > start + old.length || last.start + last.added < start) {
2963
+ this.done.push([{start: start, added: added, old: old}]);
2964
+ this.closed = false;
2965
+ } else {
2966
+ var startBefore = Math.max(0, last.start - start),
2967
+ endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
2968
+ for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
2969
+ for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
2970
+ if (startBefore) last.start = start;
2971
+ last.added += added - (old.length - startBefore - endAfter);
1928
2972
  }
1929
2973
  this.time = time;
2974
+ },
2975
+ startCompound: function() {
2976
+ if (!this.compound++) this.closed = true;
2977
+ },
2978
+ endCompound: function() {
2979
+ if (!--this.compound) this.closed = true;
1930
2980
  }
1931
2981
  };
1932
2982
 
@@ -1946,59 +2996,92 @@ var CodeMirror = (function() {
1946
2996
  else e.cancelBubble = true;
1947
2997
  }
1948
2998
  function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
2999
+ CodeMirror.e_stop = e_stop;
3000
+ CodeMirror.e_preventDefault = e_preventDefault;
3001
+ CodeMirror.e_stopPropagation = e_stopPropagation;
3002
+
1949
3003
  function e_target(e) {return e.target || e.srcElement;}
1950
3004
  function e_button(e) {
1951
- if (e.which) return e.which;
1952
- else if (e.button & 1) return 1;
1953
- else if (e.button & 2) return 3;
1954
- else if (e.button & 4) return 2;
3005
+ var b = e.which;
3006
+ if (b == null) {
3007
+ if (e.button & 1) b = 1;
3008
+ else if (e.button & 2) b = 3;
3009
+ else if (e.button & 4) b = 2;
3010
+ }
3011
+ if (mac && e.ctrlKey && b == 1) b = 3;
3012
+ return b;
3013
+ }
3014
+
3015
+ // Allow 3rd-party code to override event properties by adding an override
3016
+ // object to an event object.
3017
+ function e_prop(e, prop) {
3018
+ var overridden = e.override && e.override.hasOwnProperty(prop);
3019
+ return overridden ? e.override[prop] : e[prop];
1955
3020
  }
1956
3021
 
1957
3022
  // Event handler registration. If disconnect is true, it'll return a
1958
3023
  // function that unregisters the handler.
1959
3024
  function connect(node, type, handler, disconnect) {
1960
- function wrapHandler(event) {handler(event || window.event);}
1961
3025
  if (typeof node.addEventListener == "function") {
1962
- node.addEventListener(type, wrapHandler, false);
1963
- if (disconnect) return function() {node.removeEventListener(type, wrapHandler, false);};
1964
- }
1965
- else {
3026
+ node.addEventListener(type, handler, false);
3027
+ if (disconnect) return function() {node.removeEventListener(type, handler, false);};
3028
+ } else {
3029
+ var wrapHandler = function(event) {handler(event || window.event);};
1966
3030
  node.attachEvent("on" + type, wrapHandler);
1967
3031
  if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
1968
3032
  }
1969
3033
  }
3034
+ CodeMirror.connect = connect;
1970
3035
 
1971
3036
  function Delayed() {this.id = null;}
1972
3037
  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
1973
3038
 
1974
- // Some IE versions don't preserve whitespace when setting the
1975
- // innerHTML of a PRE tag.
1976
- var badInnerHTML = (function() {
1977
- var pre = document.createElement("pre");
1978
- pre.innerHTML = " "; return !pre.innerHTML;
1979
- })();
3039
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
1980
3040
 
1981
3041
  var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
1982
3042
  var ie = /MSIE \d/.test(navigator.userAgent);
3043
+ var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
3044
+ var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
3045
+ var quirksMode = ie && document.documentMode == 5;
3046
+ var webkit = /WebKit\//.test(navigator.userAgent);
3047
+ var chrome = /Chrome\//.test(navigator.userAgent);
3048
+ var opera = /Opera\//.test(navigator.userAgent);
1983
3049
  var safari = /Apple Computer/.test(navigator.vendor);
3050
+ var khtml = /KHTML\//.test(navigator.userAgent);
3051
+ var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
3052
+
3053
+ // Detect drag-and-drop
3054
+ var dragAndDrop = function() {
3055
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
3056
+ // couldn't get it to work yet.
3057
+ if (ie_lt9) return false;
3058
+ var div = document.createElement('div');
3059
+ return "draggable" in div || "dragDrop" in div;
3060
+ }();
1984
3061
 
1985
- var lineSep = "\n";
1986
3062
  // Feature-detect whether newlines in textareas are converted to \r\n
1987
- (function () {
3063
+ var lineSep = function () {
1988
3064
  var te = document.createElement("textarea");
1989
3065
  te.value = "foo\nbar";
1990
- if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
1991
- }());
1992
-
1993
- var tabSize = 8;
1994
- var mac = /Mac/.test(navigator.platform);
1995
- var movementKeys = {};
1996
- for (var i = 35; i <= 40; ++i)
1997
- movementKeys[i] = movementKeys["c" + i] = true;
3066
+ if (te.value.indexOf("\r") > -1) return "\r\n";
3067
+ return "\n";
3068
+ }();
3069
+
3070
+ // For a reason I have yet to figure out, some browsers disallow
3071
+ // word wrapping between certain characters *only* if a new inline
3072
+ // element is started between them. This makes it hard to reliably
3073
+ // measure the position of things, since that requires inserting an
3074
+ // extra span. This terribly fragile set of regexps matches the
3075
+ // character combinations that suffer from this phenomenon on the
3076
+ // various browsers.
3077
+ var spanAffectsWrapping = /^$/; // Won't match any two-character string
3078
+ if (gecko) spanAffectsWrapping = /$'/;
3079
+ else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
3080
+ else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
1998
3081
 
1999
3082
  // Counts the column offset in a string, taking tabs into account.
2000
3083
  // Used mostly to find indentation.
2001
- function countColumn(string, end) {
3084
+ function countColumn(string, end, tabSize) {
2002
3085
  if (end == null) {
2003
3086
  end = string.search(/[^\s\u00a0]/);
2004
3087
  if (end == -1) end = string.length;
@@ -2014,42 +3097,67 @@ var CodeMirror = (function() {
2014
3097
  if (elt.currentStyle) return elt.currentStyle;
2015
3098
  return window.getComputedStyle(elt, null);
2016
3099
  }
2017
- // Find the position of an element by following the offsetParent chain.
2018
- // If screen==true, it returns screen (rather than page) coordinates.
3100
+
2019
3101
  function eltOffset(node, screen) {
2020
- var doc = node.ownerDocument.body;
2021
- var x = 0, y = 0, skipDoc = false;
2022
- for (var n = node; n; n = n.offsetParent) {
2023
- x += n.offsetLeft; y += n.offsetTop;
2024
- if (screen && computedStyle(n).position == "fixed")
2025
- skipDoc = true;
2026
- }
2027
- var e = screen && !skipDoc ? null : doc;
2028
- for (var n = node.parentNode; n != e; n = n.parentNode)
2029
- if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
2030
- return {left: x, top: y};
3102
+ // Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
3103
+ // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
3104
+ try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
3105
+ catch(e) { box = {top: 0, left: 0}; }
3106
+ if (!screen) {
3107
+ // Get the toplevel scroll, working around browser differences.
3108
+ if (window.pageYOffset == null) {
3109
+ var t = document.documentElement || document.body.parentNode;
3110
+ if (t.scrollTop == null) t = document.body;
3111
+ box.top += t.scrollTop; box.left += t.scrollLeft;
3112
+ } else {
3113
+ box.top += window.pageYOffset; box.left += window.pageXOffset;
3114
+ }
3115
+ }
3116
+ return box;
2031
3117
  }
3118
+
2032
3119
  // Get a node's text content.
2033
3120
  function eltText(node) {
2034
3121
  return node.textContent || node.innerText || node.nodeValue || "";
2035
3122
  }
3123
+ function selectInput(node) {
3124
+ if (ios) { // Mobile Safari apparently has a bug where select() is broken.
3125
+ node.selectionStart = 0;
3126
+ node.selectionEnd = node.value.length;
3127
+ } else node.select();
3128
+ }
2036
3129
 
2037
3130
  // Operations on {line, ch} objects.
2038
3131
  function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
2039
3132
  function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
2040
3133
  function copyPos(x) {return {line: x.line, ch: x.ch};}
2041
3134
 
2042
- var escapeElement = document.createElement("div");
3135
+ var escapeElement = document.createElement("pre");
2043
3136
  function htmlEscape(str) {
2044
- escapeElement.innerText = escapeElement.textContent = str;
3137
+ escapeElement.textContent = str;
2045
3138
  return escapeElement.innerHTML;
2046
3139
  }
3140
+ // Recent (late 2011) Opera betas insert bogus newlines at the start
3141
+ // of the textContent, so we strip those.
3142
+ if (htmlEscape("a") == "\na") {
3143
+ htmlEscape = function(str) {
3144
+ escapeElement.textContent = str;
3145
+ return escapeElement.innerHTML.slice(1);
3146
+ };
3147
+ // Some IEs don't preserve tabs through innerHTML
3148
+ } else if (htmlEscape("\t") != "\t") {
3149
+ htmlEscape = function(str) {
3150
+ escapeElement.innerHTML = "";
3151
+ escapeElement.appendChild(document.createTextNode(str));
3152
+ return escapeElement.innerHTML;
3153
+ };
3154
+ }
2047
3155
  CodeMirror.htmlEscape = htmlEscape;
2048
3156
 
2049
3157
  // Used to position the cursor after an undo/redo by finding the
2050
3158
  // last edited character.
2051
3159
  function editEnd(from, to) {
2052
- if (!to) return from ? from.length : 0;
3160
+ if (!to) return 0;
2053
3161
  if (!from) return to.length;
2054
3162
  for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
2055
3163
  if (from.charAt(i) != to.charAt(j)) break;
@@ -2062,96 +3170,62 @@ var CodeMirror = (function() {
2062
3170
  if (collection[i] == elt) return i;
2063
3171
  return -1;
2064
3172
  }
3173
+ function isWordChar(ch) {
3174
+ return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
3175
+ }
2065
3176
 
2066
3177
  // See if "".split is the broken IE version, if so, provide an
2067
3178
  // alternative way to split lines.
2068
- var splitLines, selRange, setSelRange;
2069
- if ("\n\nb".split(/\n/).length != 3)
2070
- splitLines = function(string) {
2071
- var pos = 0, nl, result = [];
2072
- while ((nl = string.indexOf("\n", pos)) > -1) {
2073
- result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
3179
+ var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
3180
+ var pos = 0, result = [], l = string.length;
3181
+ while (pos <= l) {
3182
+ var nl = string.indexOf("\n", pos);
3183
+ if (nl == -1) nl = string.length;
3184
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
3185
+ var rt = line.indexOf("\r");
3186
+ if (rt != -1) {
3187
+ result.push(line.slice(0, rt));
3188
+ pos += rt + 1;
3189
+ } else {
3190
+ result.push(line);
2074
3191
  pos = nl + 1;
2075
3192
  }
2076
- result.push(string.slice(pos));
2077
- return result;
2078
- };
2079
- else
2080
- splitLines = function(string){return string.split(/\r?\n/);};
3193
+ }
3194
+ return result;
3195
+ } : function(string){return string.split(/\r\n?|\n/);};
2081
3196
  CodeMirror.splitLines = splitLines;
2082
3197
 
2083
- // Sane model of finding and setting the selection in a textarea
2084
- if (window.getSelection) {
2085
- selRange = function(te) {
2086
- try {return {start: te.selectionStart, end: te.selectionEnd};}
2087
- catch(e) {return null;}
2088
- };
2089
- if (safari)
2090
- // On Safari, selection set with setSelectionRange are in a sort
2091
- // of limbo wrt their anchor. If you press shift-left in them,
2092
- // the anchor is put at the end, and the selection expanded to
2093
- // the left. If you press shift-right, the anchor ends up at the
2094
- // front. This is not what CodeMirror wants, so it does a
2095
- // spurious modify() call to get out of limbo.
2096
- setSelRange = function(te, start, end) {
2097
- if (start == end)
2098
- te.setSelectionRange(start, end);
2099
- else {
2100
- te.setSelectionRange(start, end - 1);
2101
- window.getSelection().modify("extend", "forward", "character");
2102
- }
2103
- };
2104
- else
2105
- setSelRange = function(te, start, end) {
2106
- try {te.setSelectionRange(start, end);}
2107
- catch(e) {} // Fails on Firefox when textarea isn't part of the document
2108
- };
2109
- }
2110
- // IE model. Don't ask.
2111
- else {
2112
- selRange = function(te) {
2113
- try {var range = te.ownerDocument.selection.createRange();}
2114
- catch(e) {return null;}
2115
- if (!range || range.parentElement() != te) return null;
2116
- var val = te.value, len = val.length, localRange = te.createTextRange();
2117
- localRange.moveToBookmark(range.getBookmark());
2118
- var endRange = te.createTextRange();
2119
- endRange.collapse(false);
2120
-
2121
- if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
2122
- return {start: len, end: len};
2123
-
2124
- var start = -localRange.moveStart("character", -len);
2125
- for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
2126
-
2127
- if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
2128
- return {start: start, end: len};
2129
-
2130
- var end = -localRange.moveEnd("character", -len);
2131
- for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
2132
- return {start: start, end: end};
2133
- };
2134
- setSelRange = function(te, start, end) {
2135
- var range = te.createTextRange();
2136
- range.collapse(true);
2137
- var endrange = range.duplicate();
2138
- var newlines = 0, txt = te.value;
2139
- for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
2140
- ++newlines;
2141
- range.move("character", start - newlines);
2142
- for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
2143
- ++newlines;
2144
- endrange.move("character", end - newlines);
2145
- range.setEndPoint("EndToEnd", endrange);
2146
- range.select();
2147
- };
2148
- }
3198
+ var hasSelection = window.getSelection ? function(te) {
3199
+ try { return te.selectionStart != te.selectionEnd; }
3200
+ catch(e) { return false; }
3201
+ } : function(te) {
3202
+ try {var range = te.ownerDocument.selection.createRange();}
3203
+ catch(e) {}
3204
+ if (!range || range.parentElement() != te) return false;
3205
+ return range.compareEndPoints("StartToEnd", range) != 0;
3206
+ };
2149
3207
 
2150
3208
  CodeMirror.defineMode("null", function() {
2151
3209
  return {token: function(stream) {stream.skipToEnd();}};
2152
3210
  });
2153
3211
  CodeMirror.defineMIME("text/plain", "null");
2154
3212
 
3213
+ var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
3214
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
3215
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
3216
+ 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
3217
+ 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
3218
+ 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
3219
+ 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
3220
+ CodeMirror.keyNames = keyNames;
3221
+ (function() {
3222
+ // Number keys
3223
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
3224
+ // Alphabetic keys
3225
+ for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
3226
+ // Function keys
3227
+ for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
3228
+ })();
3229
+
2155
3230
  return CodeMirror;
2156
- })()
2157
- ;
3231
+ })();