locomotive_cms 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (607) hide show
  1. data/Gemfile +45 -0
  2. data/README.textile +23 -0
  3. data/app/controllers/admin/accounts_controller.rb +24 -0
  4. data/app/controllers/admin/asset_collections_controller.rb +66 -0
  5. data/app/controllers/admin/assets_controller.rb +48 -0
  6. data/app/controllers/admin/base_controller.rb +55 -0
  7. data/app/controllers/admin/content_types_controller.rb +52 -0
  8. data/app/controllers/admin/contents_controller.rb +72 -0
  9. data/app/controllers/admin/current_sites_controller.rb +33 -0
  10. data/app/controllers/admin/layouts_controller.rb +56 -0
  11. data/app/controllers/admin/memberships_controller.rb +39 -0
  12. data/app/controllers/admin/my_accounts_controller.rb +21 -0
  13. data/app/controllers/admin/page_parts_controller.rb +12 -0
  14. data/app/controllers/admin/pages_controller.rb +70 -0
  15. data/app/controllers/admin/passwords_controller.rb +11 -0
  16. data/app/controllers/admin/rendering_controller.rb +15 -0
  17. data/app/controllers/admin/sessions_controller.rb +17 -0
  18. data/app/controllers/admin/sites_controller.rb +48 -0
  19. data/app/controllers/admin/snippets_controller.rb +56 -0
  20. data/app/controllers/admin/theme_assets_controller.rb +79 -0
  21. data/app/controllers/application_controller.rb +3 -0
  22. data/app/controllers/home_controller.rb +7 -0
  23. data/app/helpers/admin/accounts_helper.rb +8 -0
  24. data/app/helpers/admin/assets_helper.rb +15 -0
  25. data/app/helpers/admin/base_helper.rb +54 -0
  26. data/app/helpers/admin/custom_fields_helper.rb +24 -0
  27. data/app/helpers/admin/login_helper.rb +17 -0
  28. data/app/helpers/admin/pages_helper.rb +23 -0
  29. data/app/helpers/admin/sites_helper.rb +24 -0
  30. data/app/models/account.rb +46 -0
  31. data/app/models/asset.rb +38 -0
  32. data/app/models/asset_collection.rb +60 -0
  33. data/app/models/content_instance.rb +29 -0
  34. data/app/models/content_type.rb +63 -0
  35. data/app/models/extensions/asset/vignette.rb +40 -0
  36. data/app/models/extensions/page/parts.rb +54 -0
  37. data/app/models/extensions/page/render.rb +19 -0
  38. data/app/models/extensions/page/tree.rb +97 -0
  39. data/app/models/layout.rb +49 -0
  40. data/app/models/liquid_template.rb +32 -0
  41. data/app/models/membership.rb +36 -0
  42. data/app/models/page.rb +87 -0
  43. data/app/models/page_part.rb +38 -0
  44. data/app/models/site.rb +93 -0
  45. data/app/models/snippet.rb +3 -0
  46. data/app/models/theme_asset.rb +101 -0
  47. data/app/uploaders/asset_uploader.rb +68 -0
  48. data/app/uploaders/theme_asset_uploader.rb +42 -0
  49. data/app/views/admin/accounts/new.html.haml +22 -0
  50. data/app/views/admin/asset_collections/_asset.html.haml +7 -0
  51. data/app/views/admin/asset_collections/edit.html.haml +30 -0
  52. data/app/views/admin/asset_collections/index.html.haml +8 -0
  53. data/app/views/admin/asset_collections/new.html.haml +17 -0
  54. data/app/views/admin/assets/_form.html.haml +18 -0
  55. data/app/views/admin/assets/edit.html.haml +15 -0
  56. data/app/views/admin/assets/new.html.haml +12 -0
  57. data/app/views/admin/content_types/_form.html.haml +13 -0
  58. data/app/views/admin/content_types/edit.html.haml +16 -0
  59. data/app/views/admin/content_types/new.html.haml +15 -0
  60. data/app/views/admin/contents/_form.html.haml +10 -0
  61. data/app/views/admin/contents/edit.html.haml +16 -0
  62. data/app/views/admin/contents/index.html.haml +35 -0
  63. data/app/views/admin/contents/new.html.haml +15 -0
  64. data/app/views/admin/current_sites/_form.html.haml +45 -0
  65. data/app/views/admin/current_sites/edit.html.haml +15 -0
  66. data/app/views/admin/layouts/_form.html.haml +10 -0
  67. data/app/views/admin/layouts/_layout.html.haml +7 -0
  68. data/app/views/admin/layouts/edit.html.haml +18 -0
  69. data/app/views/admin/layouts/index.html.haml +15 -0
  70. data/app/views/admin/layouts/new.html.haml +15 -0
  71. data/app/views/admin/memberships/new.html.haml +15 -0
  72. data/app/views/admin/my_accounts/edit.html.haml +42 -0
  73. data/app/views/admin/pages/_form.html.haml +37 -0
  74. data/app/views/admin/pages/_page.html.haml +16 -0
  75. data/app/views/admin/pages/edit.html.haml +15 -0
  76. data/app/views/admin/pages/index.html.haml +18 -0
  77. data/app/views/admin/pages/new.html.haml +12 -0
  78. data/app/views/admin/passwords/edit.html.haml +18 -0
  79. data/app/views/admin/passwords/new.html.haml +17 -0
  80. data/app/views/admin/sessions/new.html.haml +15 -0
  81. data/app/views/admin/shared/_custom_fields.html.haml +47 -0
  82. data/app/views/admin/shared/_footer.html.haml +5 -0
  83. data/app/views/admin/shared/_form_actions.html.haml +15 -0
  84. data/app/views/admin/shared/_head.html.haml +18 -0
  85. data/app/views/admin/shared/_header.html.haml +8 -0
  86. data/app/views/admin/shared/_menu.html.haml +5 -0
  87. data/app/views/admin/shared/menu/_assets.html.haml +7 -0
  88. data/app/views/admin/shared/menu/_contents.html.haml +27 -0
  89. data/app/views/admin/shared/menu/_settings.html.haml +6 -0
  90. data/app/views/admin/sites/_form.html.haml +35 -0
  91. data/app/views/admin/sites/new.html.haml +12 -0
  92. data/app/views/admin/snippets/_form.html.haml +11 -0
  93. data/app/views/admin/snippets/_snippet.html.haml +7 -0
  94. data/app/views/admin/snippets/edit.html.haml +15 -0
  95. data/app/views/admin/snippets/index.html.haml +15 -0
  96. data/app/views/admin/snippets/new.html.haml +12 -0
  97. data/app/views/admin/theme_assets/_asset.html.haml +12 -0
  98. data/app/views/admin/theme_assets/_form.html.haml +39 -0
  99. data/app/views/admin/theme_assets/edit.html.haml +15 -0
  100. data/app/views/admin/theme_assets/images.html.haml +15 -0
  101. data/app/views/admin/theme_assets/index.html.haml +27 -0
  102. data/app/views/admin/theme_assets/new.html.haml +12 -0
  103. data/app/views/devise/confirmations/new.html.haml +12 -0
  104. data/app/views/devise/mailer/confirmation_instructions.html.haml +8 -0
  105. data/app/views/devise/mailer/reset_password_instructions.html.haml +12 -0
  106. data/app/views/devise/mailer/unlock_instructions.html.haml +10 -0
  107. data/app/views/devise/registrations/edit.html.haml +35 -0
  108. data/app/views/devise/registrations/new.html.haml +20 -0
  109. data/app/views/devise/sessions/new.html.haml +22 -0
  110. data/app/views/devise/shared/_links.haml +20 -0
  111. data/app/views/devise/unlocks/new.html.haml +12 -0
  112. data/app/views/home/show.html.haml +4 -0
  113. data/app/views/layouts/admin/application.html.haml +26 -0
  114. data/app/views/layouts/admin/login.html.haml +17 -0
  115. data/app/views/layouts/application.html.haml +7 -0
  116. data/config/application.rb +48 -0
  117. data/config/boot.rb +17 -0
  118. data/config/cucumber.yml +8 -0
  119. data/config/database.yml +20 -0
  120. data/config/environment.rb +5 -0
  121. data/config/environments/development.rb +35 -0
  122. data/config/environments/production.rb +33 -0
  123. data/config/environments/test.rb +33 -0
  124. data/config/initializers/backtrace_silencers.rb +7 -0
  125. data/config/initializers/carrierwave.rb +57 -0
  126. data/config/initializers/devise.rb +119 -0
  127. data/config/initializers/formtastic.rb +5 -0
  128. data/config/initializers/inflections.rb +10 -0
  129. data/config/initializers/locomotive.rb +7 -0
  130. data/config/initializers/mime_types.rb +5 -0
  131. data/config/initializers/mongoid.rb +61 -0
  132. data/config/initializers/rspec_generator.rb +8 -0
  133. data/config/locales/admin_ui_en.yml +211 -0
  134. data/config/locales/admin_ui_fr.yml +21 -0
  135. data/config/locales/carrierwave_en.yml +4 -0
  136. data/config/locales/carrierwave_fr.yml +4 -0
  137. data/config/locales/default_en.yml +29 -0
  138. data/config/locales/default_fr.yml +30 -0
  139. data/config/locales/devise.en.yml +36 -0
  140. data/config/routes.rb +57 -0
  141. data/lib/core_ext.rb +32 -0
  142. data/lib/generators/locomotive_generator.rb +14 -0
  143. data/lib/locomotive.rb +35 -0
  144. data/lib/locomotive/configuration.rb +67 -0
  145. data/lib/locomotive/devise/sessions_controller.rb +2 -0
  146. data/lib/locomotive/engine.rb +21 -0
  147. data/lib/locomotive/liquid.rb +5 -0
  148. data/lib/locomotive/liquid/db_file_system.rb +18 -0
  149. data/lib/locomotive/liquid/drops/asset_collections.rb +19 -0
  150. data/lib/locomotive/liquid/drops/base.rb +50 -0
  151. data/lib/locomotive/liquid/drops/content.rb +19 -0
  152. data/lib/locomotive/liquid/drops/contents.rb +63 -0
  153. data/lib/locomotive/liquid/drops/javascripts.rb +18 -0
  154. data/lib/locomotive/liquid/drops/stylesheets.rb +19 -0
  155. data/lib/locomotive/liquid/filters/date.rb +30 -0
  156. data/lib/locomotive/liquid/filters/html.rb +114 -0
  157. data/lib/locomotive/liquid/filters/misc.rb +30 -0
  158. data/lib/locomotive/liquid/liquify_template.rb +57 -0
  159. data/lib/locomotive/liquid/tags/blueprint.rb +21 -0
  160. data/lib/locomotive/liquid/tags/jquery.rb +17 -0
  161. data/lib/locomotive/liquid/tags/paginate.rb +100 -0
  162. data/lib/locomotive/liquid/tags/snippet.rb +42 -0
  163. data/lib/locomotive/liquid/tags/with_scope.rb +39 -0
  164. data/lib/locomotive/mongoid.rb +2 -0
  165. data/lib/locomotive/mongoid/document.rb +20 -0
  166. data/lib/locomotive/mongoid/model_extensions.rb +1 -0
  167. data/lib/locomotive/patches.rb +2 -0
  168. data/lib/locomotive/regexps.rb +13 -0
  169. data/lib/locomotive/render.rb +59 -0
  170. data/lib/locomotive/routing/default_constraint.rb +45 -0
  171. data/lib/locomotive/routing/site_dispatcher.rb +48 -0
  172. data/lib/misc_form_builder.rb +35 -0
  173. data/lib/tasks/cucumber.rake +53 -0
  174. data/lib/tasks/rspec.rake +69 -0
  175. data/public/images/admin/background/body.png +0 -0
  176. data/public/images/admin/background/footer.png +0 -0
  177. data/public/images/admin/background/light.png +0 -0
  178. data/public/images/admin/buttons/action-left.png +0 -0
  179. data/public/images/admin/buttons/action-right.png +0 -0
  180. data/public/images/admin/buttons/add-left.png +0 -0
  181. data/public/images/admin/buttons/add-right.png +0 -0
  182. data/public/images/admin/buttons/dark-gray-left.png +0 -0
  183. data/public/images/admin/buttons/dark-gray-right.png +0 -0
  184. data/public/images/admin/buttons/emboss-left.png +0 -0
  185. data/public/images/admin/buttons/emboss-right.png +0 -0
  186. data/public/images/admin/buttons/gray-left.png +0 -0
  187. data/public/images/admin/buttons/gray-right.png +0 -0
  188. data/public/images/admin/buttons/light-gray-left.png +0 -0
  189. data/public/images/admin/buttons/light-gray-right.png +0 -0
  190. data/public/images/admin/buttons/search.png +0 -0
  191. data/public/images/admin/buttons/transparent-left.png +0 -0
  192. data/public/images/admin/buttons/transparent-right.png +0 -0
  193. data/public/images/admin/form/big_item.png +0 -0
  194. data/public/images/admin/form/error-arrow.png +0 -0
  195. data/public/images/admin/form/field.png +0 -0
  196. data/public/images/admin/form/folded-arrow-off.png +0 -0
  197. data/public/images/admin/form/folded-arrow-on.png +0 -0
  198. data/public/images/admin/form/folded.png +0 -0
  199. data/public/images/admin/form/footer.png +0 -0
  200. data/public/images/admin/form/growl-error.png +0 -0
  201. data/public/images/admin/form/growl-notice.png +0 -0
  202. data/public/images/admin/form/header-first-on.png +0 -0
  203. data/public/images/admin/form/header-left-on.png +0 -0
  204. data/public/images/admin/form/header-on.png +0 -0
  205. data/public/images/admin/form/header-right-on.png +0 -0
  206. data/public/images/admin/form/header.png +0 -0
  207. data/public/images/admin/form/icons/drag.png +0 -0
  208. data/public/images/admin/form/icons/spinner.gif +0 -0
  209. data/public/images/admin/form/icons/trash.png +0 -0
  210. data/public/images/admin/form/item.png +0 -0
  211. data/public/images/admin/form/pen.png +0 -0
  212. data/public/images/admin/icons/filetype/medium/AC3.png +0 -0
  213. data/public/images/admin/icons/filetype/medium/ACE.png +0 -0
  214. data/public/images/admin/icons/filetype/medium/ADE.png +0 -0
  215. data/public/images/admin/icons/filetype/medium/ADP.png +0 -0
  216. data/public/images/admin/icons/filetype/medium/AI.png +0 -0
  217. data/public/images/admin/icons/filetype/medium/AIFF.png +0 -0
  218. data/public/images/admin/icons/filetype/medium/AU.png +0 -0
  219. data/public/images/admin/icons/filetype/medium/AVI.png +0 -0
  220. data/public/images/admin/icons/filetype/medium/BAT.png +0 -0
  221. data/public/images/admin/icons/filetype/medium/BIN.png +0 -0
  222. data/public/images/admin/icons/filetype/medium/BMP.png +0 -0
  223. data/public/images/admin/icons/filetype/medium/BUP.png +0 -0
  224. data/public/images/admin/icons/filetype/medium/CAB.png +0 -0
  225. data/public/images/admin/icons/filetype/medium/CAT.png +0 -0
  226. data/public/images/admin/icons/filetype/medium/CHM.png +0 -0
  227. data/public/images/admin/icons/filetype/medium/CSS.png +0 -0
  228. data/public/images/admin/icons/filetype/medium/CUE.png +0 -0
  229. data/public/images/admin/icons/filetype/medium/DAT.png +0 -0
  230. data/public/images/admin/icons/filetype/medium/DCR.png +0 -0
  231. data/public/images/admin/icons/filetype/medium/DER.png +0 -0
  232. data/public/images/admin/icons/filetype/medium/DIC.png +0 -0
  233. data/public/images/admin/icons/filetype/medium/DIVX.png +0 -0
  234. data/public/images/admin/icons/filetype/medium/DIZ.png +0 -0
  235. data/public/images/admin/icons/filetype/medium/DLL.png +0 -0
  236. data/public/images/admin/icons/filetype/medium/DOC.png +0 -0
  237. data/public/images/admin/icons/filetype/medium/DOCX.png +0 -0
  238. data/public/images/admin/icons/filetype/medium/DOS.png +0 -0
  239. data/public/images/admin/icons/filetype/medium/DVD.png +0 -0
  240. data/public/images/admin/icons/filetype/medium/DWG.png +0 -0
  241. data/public/images/admin/icons/filetype/medium/DWT.png +0 -0
  242. data/public/images/admin/icons/filetype/medium/EMF.png +0 -0
  243. data/public/images/admin/icons/filetype/medium/EXC.png +0 -0
  244. data/public/images/admin/icons/filetype/medium/FON.png +0 -0
  245. data/public/images/admin/icons/filetype/medium/GIF.png +0 -0
  246. data/public/images/admin/icons/filetype/medium/HLP.png +0 -0
  247. data/public/images/admin/icons/filetype/medium/HTML.png +0 -0
  248. data/public/images/admin/icons/filetype/medium/IFO.png +0 -0
  249. data/public/images/admin/icons/filetype/medium/INF.png +0 -0
  250. data/public/images/admin/icons/filetype/medium/INI.png +0 -0
  251. data/public/images/admin/icons/filetype/medium/INS.png +0 -0
  252. data/public/images/admin/icons/filetype/medium/IP.png +0 -0
  253. data/public/images/admin/icons/filetype/medium/ISO.png +0 -0
  254. data/public/images/admin/icons/filetype/medium/ISP.png +0 -0
  255. data/public/images/admin/icons/filetype/medium/JAVA.png +0 -0
  256. data/public/images/admin/icons/filetype/medium/JFIF.png +0 -0
  257. data/public/images/admin/icons/filetype/medium/JPEG.png +0 -0
  258. data/public/images/admin/icons/filetype/medium/JPG.png +0 -0
  259. data/public/images/admin/icons/filetype/medium/LOG.png +0 -0
  260. data/public/images/admin/icons/filetype/medium/M4A.png +0 -0
  261. data/public/images/admin/icons/filetype/medium/MID.png +0 -0
  262. data/public/images/admin/icons/filetype/medium/MMF.png +0 -0
  263. data/public/images/admin/icons/filetype/medium/MMM.png +0 -0
  264. data/public/images/admin/icons/filetype/medium/MOV.png +0 -0
  265. data/public/images/admin/icons/filetype/medium/MOVIE.png +0 -0
  266. data/public/images/admin/icons/filetype/medium/MP2.png +0 -0
  267. data/public/images/admin/icons/filetype/medium/MP2V.png +0 -0
  268. data/public/images/admin/icons/filetype/medium/MP3.png +0 -0
  269. data/public/images/admin/icons/filetype/medium/MP4.png +0 -0
  270. data/public/images/admin/icons/filetype/medium/MPE.png +0 -0
  271. data/public/images/admin/icons/filetype/medium/MPEG.png +0 -0
  272. data/public/images/admin/icons/filetype/medium/MPG.png +0 -0
  273. data/public/images/admin/icons/filetype/medium/MPV2.png +0 -0
  274. data/public/images/admin/icons/filetype/medium/NFO.png +0 -0
  275. data/public/images/admin/icons/filetype/medium/PDD.png +0 -0
  276. data/public/images/admin/icons/filetype/medium/PDF.png +0 -0
  277. data/public/images/admin/icons/filetype/medium/PHP.png +0 -0
  278. data/public/images/admin/icons/filetype/medium/PNG.png +0 -0
  279. data/public/images/admin/icons/filetype/medium/PPT.png +0 -0
  280. data/public/images/admin/icons/filetype/medium/PPTX.png +0 -0
  281. data/public/images/admin/icons/filetype/medium/PSD.png +0 -0
  282. data/public/images/admin/icons/filetype/medium/RAR.png +0 -0
  283. data/public/images/admin/icons/filetype/medium/REG.png +0 -0
  284. data/public/images/admin/icons/filetype/medium/RTF.png +0 -0
  285. data/public/images/admin/icons/filetype/medium/SCP.png +0 -0
  286. data/public/images/admin/icons/filetype/medium/THEME.png +0 -0
  287. data/public/images/admin/icons/filetype/medium/TIF.png +0 -0
  288. data/public/images/admin/icons/filetype/medium/TIFF.png +0 -0
  289. data/public/images/admin/icons/filetype/medium/TLB.png +0 -0
  290. data/public/images/admin/icons/filetype/medium/TTF.png +0 -0
  291. data/public/images/admin/icons/filetype/medium/TXT.png +0 -0
  292. data/public/images/admin/icons/filetype/medium/Thumbs.db +0 -0
  293. data/public/images/admin/icons/filetype/medium/UIS.png +0 -0
  294. data/public/images/admin/icons/filetype/medium/URL.png +0 -0
  295. data/public/images/admin/icons/filetype/medium/VBS.png +0 -0
  296. data/public/images/admin/icons/filetype/medium/VCR.png +0 -0
  297. data/public/images/admin/icons/filetype/medium/VOB.png +0 -0
  298. data/public/images/admin/icons/filetype/medium/WAV.png +0 -0
  299. data/public/images/admin/icons/filetype/medium/WBA.png +0 -0
  300. data/public/images/admin/icons/filetype/medium/WMA.png +0 -0
  301. data/public/images/admin/icons/filetype/medium/WMV.png +0 -0
  302. data/public/images/admin/icons/filetype/medium/WPL.png +0 -0
  303. data/public/images/admin/icons/filetype/medium/WRI.png +0 -0
  304. data/public/images/admin/icons/filetype/medium/WTX.png +0 -0
  305. data/public/images/admin/icons/filetype/medium/XLS.png +0 -0
  306. data/public/images/admin/icons/filetype/medium/XLSX.png +0 -0
  307. data/public/images/admin/icons/filetype/medium/XML.png +0 -0
  308. data/public/images/admin/icons/filetype/medium/XSL.png +0 -0
  309. data/public/images/admin/icons/filetype/medium/ZAP.png +0 -0
  310. data/public/images/admin/icons/filetype/medium/ZIP.png +0 -0
  311. data/public/images/admin/icons/filetype/medium/unknown.png +0 -0
  312. data/public/images/admin/icons/filetype/thumb/AC3.png +0 -0
  313. data/public/images/admin/icons/filetype/thumb/ACE.png +0 -0
  314. data/public/images/admin/icons/filetype/thumb/ADE.png +0 -0
  315. data/public/images/admin/icons/filetype/thumb/ADP.png +0 -0
  316. data/public/images/admin/icons/filetype/thumb/AI.png +0 -0
  317. data/public/images/admin/icons/filetype/thumb/AIFF.png +0 -0
  318. data/public/images/admin/icons/filetype/thumb/AU.png +0 -0
  319. data/public/images/admin/icons/filetype/thumb/AVI.png +0 -0
  320. data/public/images/admin/icons/filetype/thumb/BAT.png +0 -0
  321. data/public/images/admin/icons/filetype/thumb/BIN.png +0 -0
  322. data/public/images/admin/icons/filetype/thumb/BMP.png +0 -0
  323. data/public/images/admin/icons/filetype/thumb/BUP.png +0 -0
  324. data/public/images/admin/icons/filetype/thumb/CAB.png +0 -0
  325. data/public/images/admin/icons/filetype/thumb/CAT.png +0 -0
  326. data/public/images/admin/icons/filetype/thumb/CHM.png +0 -0
  327. data/public/images/admin/icons/filetype/thumb/CSS.png +0 -0
  328. data/public/images/admin/icons/filetype/thumb/CUE.png +0 -0
  329. data/public/images/admin/icons/filetype/thumb/DAT.png +0 -0
  330. data/public/images/admin/icons/filetype/thumb/DCR.png +0 -0
  331. data/public/images/admin/icons/filetype/thumb/DER.png +0 -0
  332. data/public/images/admin/icons/filetype/thumb/DIC.png +0 -0
  333. data/public/images/admin/icons/filetype/thumb/DIVX.png +0 -0
  334. data/public/images/admin/icons/filetype/thumb/DIZ.png +0 -0
  335. data/public/images/admin/icons/filetype/thumb/DLL.png +0 -0
  336. data/public/images/admin/icons/filetype/thumb/DOC.png +0 -0
  337. data/public/images/admin/icons/filetype/thumb/DOCX.png +0 -0
  338. data/public/images/admin/icons/filetype/thumb/DOS.png +0 -0
  339. data/public/images/admin/icons/filetype/thumb/DVD.png +0 -0
  340. data/public/images/admin/icons/filetype/thumb/DWG.png +0 -0
  341. data/public/images/admin/icons/filetype/thumb/DWT.png +0 -0
  342. data/public/images/admin/icons/filetype/thumb/EMF.png +0 -0
  343. data/public/images/admin/icons/filetype/thumb/EXC.png +0 -0
  344. data/public/images/admin/icons/filetype/thumb/FON.png +0 -0
  345. data/public/images/admin/icons/filetype/thumb/GIF.png +0 -0
  346. data/public/images/admin/icons/filetype/thumb/HLP.png +0 -0
  347. data/public/images/admin/icons/filetype/thumb/HTML.png +0 -0
  348. data/public/images/admin/icons/filetype/thumb/IFO.png +0 -0
  349. data/public/images/admin/icons/filetype/thumb/INF.png +0 -0
  350. data/public/images/admin/icons/filetype/thumb/INI.png +0 -0
  351. data/public/images/admin/icons/filetype/thumb/INS.png +0 -0
  352. data/public/images/admin/icons/filetype/thumb/IP.png +0 -0
  353. data/public/images/admin/icons/filetype/thumb/ISO.png +0 -0
  354. data/public/images/admin/icons/filetype/thumb/ISP.png +0 -0
  355. data/public/images/admin/icons/filetype/thumb/JAVA.png +0 -0
  356. data/public/images/admin/icons/filetype/thumb/JFIF.png +0 -0
  357. data/public/images/admin/icons/filetype/thumb/JPEG.png +0 -0
  358. data/public/images/admin/icons/filetype/thumb/JPG.png +0 -0
  359. data/public/images/admin/icons/filetype/thumb/LOG.png +0 -0
  360. data/public/images/admin/icons/filetype/thumb/M4A.png +0 -0
  361. data/public/images/admin/icons/filetype/thumb/MID.png +0 -0
  362. data/public/images/admin/icons/filetype/thumb/MMF.png +0 -0
  363. data/public/images/admin/icons/filetype/thumb/MMM.png +0 -0
  364. data/public/images/admin/icons/filetype/thumb/MOV.png +0 -0
  365. data/public/images/admin/icons/filetype/thumb/MOVIE.png +0 -0
  366. data/public/images/admin/icons/filetype/thumb/MP2.png +0 -0
  367. data/public/images/admin/icons/filetype/thumb/MP2V.png +0 -0
  368. data/public/images/admin/icons/filetype/thumb/MP3.png +0 -0
  369. data/public/images/admin/icons/filetype/thumb/MP4.png +0 -0
  370. data/public/images/admin/icons/filetype/thumb/MPE.png +0 -0
  371. data/public/images/admin/icons/filetype/thumb/MPEG.png +0 -0
  372. data/public/images/admin/icons/filetype/thumb/MPG.png +0 -0
  373. data/public/images/admin/icons/filetype/thumb/MPV2.png +0 -0
  374. data/public/images/admin/icons/filetype/thumb/NFO.png +0 -0
  375. data/public/images/admin/icons/filetype/thumb/PDD.png +0 -0
  376. data/public/images/admin/icons/filetype/thumb/PDF.png +0 -0
  377. data/public/images/admin/icons/filetype/thumb/PHP.png +0 -0
  378. data/public/images/admin/icons/filetype/thumb/PNG.png +0 -0
  379. data/public/images/admin/icons/filetype/thumb/PPT.png +0 -0
  380. data/public/images/admin/icons/filetype/thumb/PPTX.png +0 -0
  381. data/public/images/admin/icons/filetype/thumb/PSD.png +0 -0
  382. data/public/images/admin/icons/filetype/thumb/RAR.png +0 -0
  383. data/public/images/admin/icons/filetype/thumb/REG.png +0 -0
  384. data/public/images/admin/icons/filetype/thumb/RTF.png +0 -0
  385. data/public/images/admin/icons/filetype/thumb/SCP.png +0 -0
  386. data/public/images/admin/icons/filetype/thumb/THEME.png +0 -0
  387. data/public/images/admin/icons/filetype/thumb/TIF.png +0 -0
  388. data/public/images/admin/icons/filetype/thumb/TIFF.png +0 -0
  389. data/public/images/admin/icons/filetype/thumb/TLB.png +0 -0
  390. data/public/images/admin/icons/filetype/thumb/TTF.png +0 -0
  391. data/public/images/admin/icons/filetype/thumb/TXT.png +0 -0
  392. data/public/images/admin/icons/filetype/thumb/UIS.png +0 -0
  393. data/public/images/admin/icons/filetype/thumb/URL.png +0 -0
  394. data/public/images/admin/icons/filetype/thumb/VBS.png +0 -0
  395. data/public/images/admin/icons/filetype/thumb/VCR.png +0 -0
  396. data/public/images/admin/icons/filetype/thumb/VOB.png +0 -0
  397. data/public/images/admin/icons/filetype/thumb/WAV.png +0 -0
  398. data/public/images/admin/icons/filetype/thumb/WBA.png +0 -0
  399. data/public/images/admin/icons/filetype/thumb/WMA.png +0 -0
  400. data/public/images/admin/icons/filetype/thumb/WMV.png +0 -0
  401. data/public/images/admin/icons/filetype/thumb/WPL.png +0 -0
  402. data/public/images/admin/icons/filetype/thumb/WRI.png +0 -0
  403. data/public/images/admin/icons/filetype/thumb/WTX.png +0 -0
  404. data/public/images/admin/icons/filetype/thumb/XLS.png +0 -0
  405. data/public/images/admin/icons/filetype/thumb/XLSX.png +0 -0
  406. data/public/images/admin/icons/filetype/thumb/XML.png +0 -0
  407. data/public/images/admin/icons/filetype/thumb/XSL.png +0 -0
  408. data/public/images/admin/icons/filetype/thumb/ZAP.png +0 -0
  409. data/public/images/admin/icons/filetype/thumb/ZIP.png +0 -0
  410. data/public/images/admin/icons/filetype/thumb/unknown.png +0 -0
  411. data/public/images/admin/icons/flags/en.png +0 -0
  412. data/public/images/admin/icons/flags/fr.png +0 -0
  413. data/public/images/admin/list/empty.png +0 -0
  414. data/public/images/admin/list/icons/cross.png +0 -0
  415. data/public/images/admin/list/icons/drag.png +0 -0
  416. data/public/images/admin/list/icons/node_closed.png +0 -0
  417. data/public/images/admin/list/icons/node_open.png +0 -0
  418. data/public/images/admin/list/icons/trash.png +0 -0
  419. data/public/images/admin/list/item-left.png +0 -0
  420. data/public/images/admin/list/item-right.png +0 -0
  421. data/public/images/admin/list/item.png +0 -0
  422. data/public/images/admin/list/none.png +0 -0
  423. data/public/images/admin/list/thumb.png +0 -0
  424. data/public/images/admin/login/bottom_panel_bg.png +0 -0
  425. data/public/images/admin/login/buttons/left_bg.png +0 -0
  426. data/public/images/admin/login/buttons/right_bg.png +0 -0
  427. data/public/images/admin/login/content_panel_bg.png +0 -0
  428. data/public/images/admin/login/input_bg.png +0 -0
  429. data/public/images/admin/login/light_bg.png +0 -0
  430. data/public/images/admin/login/top_panel_bg.png +0 -0
  431. data/public/images/admin/login/wrapper_bg.png +0 -0
  432. data/public/images/admin/menu/arrow.png +0 -0
  433. data/public/images/admin/menu/blue-bg.png +0 -0
  434. data/public/images/admin/menu/blue-border.png +0 -0
  435. data/public/images/admin/menu/gray-bg.png +0 -0
  436. data/public/images/admin/menu/gray-border.png +0 -0
  437. data/public/images/admin/menu/green-bg.png +0 -0
  438. data/public/images/admin/menu/green-border.png +0 -0
  439. data/public/images/admin/menu/icons/add.png +0 -0
  440. data/public/images/admin/menu/icons/bullet.png +0 -0
  441. data/public/images/admin/menu/icons/folder.png +0 -0
  442. data/public/images/admin/menu/icons/settings.png +0 -0
  443. data/public/images/admin/menu/left.png +0 -0
  444. data/public/images/admin/menu/popup-body.png +0 -0
  445. data/public/images/admin/menu/popup-footer.png +0 -0
  446. data/public/images/admin/menu/popup-header.png +0 -0
  447. data/public/images/admin/menu/right.png +0 -0
  448. data/public/images/admin/menu/shadow.png +0 -0
  449. data/public/images/admin/menu/top-left.png +0 -0
  450. data/public/images/admin/menu/top.png +0 -0
  451. data/public/images/admin/nocoffee.gif +0 -0
  452. data/public/images/admin/plugins/fancybox/blank.gif +0 -0
  453. data/public/images/admin/plugins/fancybox/fancy_close.png +0 -0
  454. data/public/images/admin/plugins/fancybox/fancy_loading.png +0 -0
  455. data/public/images/admin/plugins/fancybox/fancy_nav_left.png +0 -0
  456. data/public/images/admin/plugins/fancybox/fancy_nav_right.png +0 -0
  457. data/public/images/admin/plugins/fancybox/fancy_shadow_e.png +0 -0
  458. data/public/images/admin/plugins/fancybox/fancy_shadow_n.png +0 -0
  459. data/public/images/admin/plugins/fancybox/fancy_shadow_ne.png +0 -0
  460. data/public/images/admin/plugins/fancybox/fancy_shadow_nw.png +0 -0
  461. data/public/images/admin/plugins/fancybox/fancy_shadow_s.png +0 -0
  462. data/public/images/admin/plugins/fancybox/fancy_shadow_se.png +0 -0
  463. data/public/images/admin/plugins/fancybox/fancy_shadow_sw.png +0 -0
  464. data/public/images/admin/plugins/fancybox/fancy_shadow_w.png +0 -0
  465. data/public/images/admin/plugins/fancybox/fancy_title_left.png +0 -0
  466. data/public/images/admin/plugins/fancybox/fancy_title_main.png +0 -0
  467. data/public/images/admin/plugins/fancybox/fancy_title_over.png +0 -0
  468. data/public/images/admin/plugins/fancybox/fancy_title_right.png +0 -0
  469. data/public/images/admin/plugins/fancybox/fancybox-x.png +0 -0
  470. data/public/images/admin/plugins/fancybox/fancybox-y.png +0 -0
  471. data/public/images/admin/plugins/fancybox/fancybox.png +0 -0
  472. data/public/images/admin/plugins/toggle_handle-bg.png +0 -0
  473. data/public/images/admin/plugins/toggle_handle_left-bg.png +0 -0
  474. data/public/images/admin/plugins/toggle_handle_right-bg.png +0 -0
  475. data/public/images/admin/plugins/toggle_shadow-bg.png +0 -0
  476. data/public/images/admin/rails.png +0 -0
  477. data/public/javascripts/admin/application.js +105 -0
  478. data/public/javascripts/admin/asset_collections.js +50 -0
  479. data/public/javascripts/admin/content_types.js +16 -0
  480. data/public/javascripts/admin/contents.js +17 -0
  481. data/public/javascripts/admin/custom_fields.js +113 -0
  482. data/public/javascripts/admin/jquery.js +154 -0
  483. data/public/javascripts/admin/jquery.ui.js +404 -0
  484. data/public/javascripts/admin/page_parts.js +83 -0
  485. data/public/javascripts/admin/pages.js +67 -0
  486. data/public/javascripts/admin/plugins/codemirror/codemirror.js +469 -0
  487. data/public/javascripts/admin/plugins/codemirror/editor.js +1465 -0
  488. data/public/javascripts/admin/plugins/codemirror/highlight.js +68 -0
  489. data/public/javascripts/admin/plugins/codemirror/mirrorframe.js +81 -0
  490. data/public/javascripts/admin/plugins/codemirror/parsecss.js +155 -0
  491. data/public/javascripts/admin/plugins/codemirror/parsedummy.js +32 -0
  492. data/public/javascripts/admin/plugins/codemirror/parsehtmlmixed.js +74 -0
  493. data/public/javascripts/admin/plugins/codemirror/parsejavascript.js +352 -0
  494. data/public/javascripts/admin/plugins/codemirror/parseliquid.js +409 -0
  495. data/public/javascripts/admin/plugins/codemirror/parsesparql.js +162 -0
  496. data/public/javascripts/admin/plugins/codemirror/parsexml.js +286 -0
  497. data/public/javascripts/admin/plugins/codemirror/select.js +619 -0
  498. data/public/javascripts/admin/plugins/codemirror/stringstream.js +140 -0
  499. data/public/javascripts/admin/plugins/codemirror/tokenize.js +57 -0
  500. data/public/javascripts/admin/plugins/codemirror/tokenizejavascript.js +174 -0
  501. data/public/javascripts/admin/plugins/codemirror/undo.js +410 -0
  502. data/public/javascripts/admin/plugins/codemirror/util.js +130 -0
  503. data/public/javascripts/admin/plugins/cookie.js +96 -0
  504. data/public/javascripts/admin/plugins/fancybox.js +1077 -0
  505. data/public/javascripts/admin/plugins/growl.js +143 -0
  506. data/public/javascripts/admin/plugins/json2.js +478 -0
  507. data/public/javascripts/admin/plugins/plupload/gears_init.js +86 -0
  508. data/public/javascripts/admin/plugins/plupload/jquery.plupload.queue.min.js +1 -0
  509. data/public/javascripts/admin/plugins/plupload/plupload.browserplus.min.js +1 -0
  510. data/public/javascripts/admin/plugins/plupload/plupload.flash.min.js +1 -0
  511. data/public/javascripts/admin/plugins/plupload/plupload.flash.swf +0 -0
  512. data/public/javascripts/admin/plugins/plupload/plupload.full.js +1 -0
  513. data/public/javascripts/admin/plugins/plupload/plupload.gears.min.js +1 -0
  514. data/public/javascripts/admin/plugins/plupload/plupload.html4.min.js +1 -0
  515. data/public/javascripts/admin/plugins/plupload/plupload.html5.min.js +1 -0
  516. data/public/javascripts/admin/plugins/plupload/plupload.js +1 -0
  517. data/public/javascripts/admin/plugins/plupload/plupload.silverlight.min.js +1 -0
  518. data/public/javascripts/admin/plugins/plupload/plupload.silverlight.xap +0 -0
  519. data/public/javascripts/admin/plugins/scrollTo.js +11 -0
  520. data/public/javascripts/admin/plugins/toggle.js +109 -0
  521. data/public/javascripts/admin/plugins/wslide.js +125 -0
  522. data/public/javascripts/admin/rails.js +127 -0
  523. data/public/javascripts/admin/site.js +36 -0
  524. data/public/javascripts/admin/snippets.js +16 -0
  525. data/public/javascripts/admin/theme_assets.js +103 -0
  526. data/public/stylesheets/admin/application.css +257 -0
  527. data/public/stylesheets/admin/blueprint/ie.css +26 -0
  528. data/public/stylesheets/admin/blueprint/plugins/buttons/icons/cross.png +0 -0
  529. data/public/stylesheets/admin/blueprint/plugins/buttons/icons/key.png +0 -0
  530. data/public/stylesheets/admin/blueprint/plugins/buttons/icons/tick.png +0 -0
  531. data/public/stylesheets/admin/blueprint/plugins/buttons/readme.txt +32 -0
  532. data/public/stylesheets/admin/blueprint/plugins/buttons/screen.css +97 -0
  533. data/public/stylesheets/admin/blueprint/plugins/fancy-type/readme.txt +14 -0
  534. data/public/stylesheets/admin/blueprint/plugins/fancy-type/screen.css +71 -0
  535. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/doc.png +0 -0
  536. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/email.png +0 -0
  537. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/external.png +0 -0
  538. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/feed.png +0 -0
  539. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/im.png +0 -0
  540. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/pdf.png +0 -0
  541. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/visited.png +0 -0
  542. data/public/stylesheets/admin/blueprint/plugins/link-icons/icons/xls.png +0 -0
  543. data/public/stylesheets/admin/blueprint/plugins/link-icons/readme.txt +18 -0
  544. data/public/stylesheets/admin/blueprint/plugins/link-icons/screen.css +40 -0
  545. data/public/stylesheets/admin/blueprint/plugins/rtl/readme.txt +10 -0
  546. data/public/stylesheets/admin/blueprint/plugins/rtl/screen.css +109 -0
  547. data/public/stylesheets/admin/blueprint/print.css +30 -0
  548. data/public/stylesheets/admin/blueprint/screen.css +253 -0
  549. data/public/stylesheets/admin/blueprint/src/forms.css +49 -0
  550. data/public/stylesheets/admin/blueprint/src/grid.css +213 -0
  551. data/public/stylesheets/admin/blueprint/src/grid.png +0 -0
  552. data/public/stylesheets/admin/blueprint/src/ie.css +59 -0
  553. data/public/stylesheets/admin/blueprint/src/print.css +85 -0
  554. data/public/stylesheets/admin/blueprint/src/reset.css +38 -0
  555. data/public/stylesheets/admin/blueprint/src/typography.css +105 -0
  556. data/public/stylesheets/admin/box.css +14 -0
  557. data/public/stylesheets/admin/buttons.css +67 -0
  558. data/public/stylesheets/admin/formtastic.css +137 -0
  559. data/public/stylesheets/admin/formtastic_changes.css +461 -0
  560. data/public/stylesheets/admin/layout.css +175 -0
  561. data/public/stylesheets/admin/login.css +141 -0
  562. data/public/stylesheets/admin/menu.css +241 -0
  563. data/public/stylesheets/admin/page_parts.css +60 -0
  564. data/public/stylesheets/admin/plugins/codemirror/csscolors.css +51 -0
  565. data/public/stylesheets/admin/plugins/codemirror/docs.css +50 -0
  566. data/public/stylesheets/admin/plugins/codemirror/javascriptcolors.css +56 -0
  567. data/public/stylesheets/admin/plugins/codemirror/jscolors.css +59 -0
  568. data/public/stylesheets/admin/plugins/codemirror/liquidcolors.css +35 -0
  569. data/public/stylesheets/admin/plugins/codemirror/people.jpg +0 -0
  570. data/public/stylesheets/admin/plugins/codemirror/sparqlcolors.css +43 -0
  571. data/public/stylesheets/admin/plugins/codemirror/xmlcolors.css +55 -0
  572. data/public/stylesheets/admin/plugins/fancybox.css +363 -0
  573. data/public/stylesheets/admin/plugins/toggle.css +42 -0
  574. data/spec/factories.rb +77 -0
  575. data/spec/lib/locomotive/liquid/filters/html_spec.rb +82 -0
  576. data/spec/lib/locomotive/liquid/filters/misc_spec.rb +36 -0
  577. data/spec/lib/locomotive/liquid/tags/paginate_spec.rb +99 -0
  578. data/spec/lib/locomotive/liquid/tags/snippet_spec.rb +20 -0
  579. data/spec/lib/locomotive/liquid/tags/with_scope_spec.rb +20 -0
  580. data/spec/lib/locomotive/render_spec.rb +85 -0
  581. data/spec/models/account_spec.rb +65 -0
  582. data/spec/models/asset_collections_spec.rb +174 -0
  583. data/spec/models/content_instance_spec.rb +33 -0
  584. data/spec/models/content_type_spec.rb +49 -0
  585. data/spec/models/layout_spec.rb +64 -0
  586. data/spec/models/liquid_template_spec.rb +19 -0
  587. data/spec/models/membership_spec.rb +55 -0
  588. data/spec/models/page_spec.rb +329 -0
  589. data/spec/models/site_spec.rb +143 -0
  590. data/spec/models/snippet_spec.rb +9 -0
  591. data/spec/models/theme_asset_spec.rb +89 -0
  592. data/spec/spec_helper.rb +17 -0
  593. data/spec/support/be_valid.rb +31 -0
  594. data/spec/support/carrierwave.rb +32 -0
  595. data/spec/support/locomotive.rb +41 -0
  596. data/vendor/plugins/custom_fields/MIT-LICENSE +20 -0
  597. data/vendor/plugins/custom_fields/README +13 -0
  598. data/vendor/plugins/custom_fields/Rakefile +23 -0
  599. data/vendor/plugins/custom_fields/init.rb +2 -0
  600. data/vendor/plugins/custom_fields/install.rb +1 -0
  601. data/vendor/plugins/custom_fields/lib/custom_fields.rb +14 -0
  602. data/vendor/plugins/custom_fields/lib/custom_fields/custom_field.rb +84 -0
  603. data/vendor/plugins/custom_fields/lib/custom_fields/custom_fields_for.rb +49 -0
  604. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/embeds_many.rb +24 -0
  605. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/document.rb +35 -0
  606. data/vendor/plugins/custom_fields/uninstall.rb +1 -0
  607. metadata +848 -0
@@ -0,0 +1,140 @@
1
+ /* String streams are the things fed to parsers (which can feed them
2
+ * to a tokenizer if they want). They provide peek and next methods
3
+ * for looking at the current character (next 'consumes' this
4
+ * character, peek does not), and a get method for retrieving all the
5
+ * text that was consumed since the last time get was called.
6
+ *
7
+ * An easy mistake to make is to let a StopIteration exception finish
8
+ * the token stream while there are still characters pending in the
9
+ * string stream (hitting the end of the buffer while parsing a
10
+ * token). To make it easier to detect such errors, the stringstreams
11
+ * throw an exception when this happens.
12
+ */
13
+
14
+ // Make a stringstream stream out of an iterator that returns strings.
15
+ // This is applied to the result of traverseDOM (see codemirror.js),
16
+ // and the resulting stream is fed to the parser.
17
+ var stringStream = function(source){
18
+ // String that's currently being iterated over.
19
+ var current = "";
20
+ // Position in that string.
21
+ var pos = 0;
22
+ // Accumulator for strings that have been iterated over but not
23
+ // get()-ed yet.
24
+ var accum = "";
25
+ // Make sure there are more characters ready, or throw
26
+ // StopIteration.
27
+ function ensureChars() {
28
+ while (pos == current.length) {
29
+ accum += current;
30
+ current = ""; // In case source.next() throws
31
+ pos = 0;
32
+ try {current = source.next();}
33
+ catch (e) {
34
+ if (e != StopIteration) throw e;
35
+ else return false;
36
+ }
37
+ }
38
+ return true;
39
+ }
40
+
41
+ return {
42
+ // Return the next character in the stream.
43
+ peek: function() {
44
+ if (!ensureChars()) return null;
45
+ return current.charAt(pos);
46
+ },
47
+ // Get the next character, throw StopIteration if at end, check
48
+ // for unused content.
49
+ next: function() {
50
+ if (!ensureChars()) {
51
+ if (accum.length > 0)
52
+ throw "End of stringstream reached without emptying buffer ('" + accum + "').";
53
+ else
54
+ throw StopIteration;
55
+ }
56
+ return current.charAt(pos++);
57
+ },
58
+ // Return the characters iterated over since the last call to
59
+ // .get().
60
+ get: function() {
61
+ var temp = accum;
62
+ accum = "";
63
+ if (pos > 0){
64
+ temp += current.slice(0, pos);
65
+ current = current.slice(pos);
66
+ pos = 0;
67
+ }
68
+ return temp;
69
+ },
70
+ // Push a string back into the stream.
71
+ push: function(str) {
72
+ current = current.slice(0, pos) + str + current.slice(pos);
73
+ },
74
+ lookAhead: function(str, consume, skipSpaces, caseInsensitive) {
75
+ function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
76
+ str = cased(str);
77
+ var found = false;
78
+
79
+ var _accum = accum, _pos = pos;
80
+ if (skipSpaces) this.nextWhileMatches(/[\s\u00a0]/);
81
+
82
+ while (true) {
83
+ var end = pos + str.length, left = current.length - pos;
84
+ if (end <= current.length) {
85
+ found = str == cased(current.slice(pos, end));
86
+ pos = end;
87
+ break;
88
+ }
89
+ else if (str.slice(0, left) == cased(current.slice(pos))) {
90
+ accum += current; current = "";
91
+ try {current = source.next();}
92
+ catch (e) {break;}
93
+ pos = 0;
94
+ str = str.slice(left);
95
+ }
96
+ else {
97
+ break;
98
+ }
99
+ }
100
+
101
+ if (!(found && consume)) {
102
+ current = accum.slice(_accum.length) + current;
103
+ pos = _pos;
104
+ accum = _accum;
105
+ }
106
+
107
+ return found;
108
+ },
109
+
110
+ // Utils built on top of the above
111
+ more: function() {
112
+ return this.peek() !== null;
113
+ },
114
+ applies: function(test) {
115
+ var next = this.peek();
116
+ return (next !== null && test(next));
117
+ },
118
+ nextWhile: function(test) {
119
+ var next;
120
+ while ((next = this.peek()) !== null && test(next))
121
+ this.next();
122
+ },
123
+ matches: function(re) {
124
+ var next = this.peek();
125
+ return (next !== null && re.test(next));
126
+ },
127
+ nextWhileMatches: function(re) {
128
+ var next;
129
+ while ((next = this.peek()) !== null && re.test(next))
130
+ this.next();
131
+ },
132
+ equals: function(ch) {
133
+ return ch === this.peek();
134
+ },
135
+ endOfLine: function() {
136
+ var next = this.peek();
137
+ return next == null || next == "\n";
138
+ }
139
+ };
140
+ };
@@ -0,0 +1,57 @@
1
+ // A framework for simple tokenizers. Takes care of newlines and
2
+ // white-space, and of getting the text from the source stream into
3
+ // the token object. A state is a function of two arguments -- a
4
+ // string stream and a setState function. The second can be used to
5
+ // change the tokenizer's state, and can be ignored for stateless
6
+ // tokenizers. This function should advance the stream over a token
7
+ // and return a string or object containing information about the next
8
+ // token, or null to pass and have the (new) state be called to finish
9
+ // the token. When a string is given, it is wrapped in a {style, type}
10
+ // object. In the resulting object, the characters consumed are stored
11
+ // under the content property. Any whitespace following them is also
12
+ // automatically consumed, and added to the value property. (Thus,
13
+ // content is the actual meaningful part of the token, while value
14
+ // contains all the text it spans.)
15
+
16
+ function tokenizer(source, state) {
17
+ // Newlines are always a separate token.
18
+ function isWhiteSpace(ch) {
19
+ // The messy regexp is because IE's regexp matcher is of the
20
+ // opinion that non-breaking spaces are no whitespace.
21
+ return ch != "\n" && /^[\s\u00a0]*$/.test(ch);
22
+ }
23
+
24
+ var tokenizer = {
25
+ state: state,
26
+
27
+ take: function(type) {
28
+ if (typeof(type) == "string")
29
+ type = {style: type, type: type};
30
+
31
+ type.content = (type.content || "") + source.get();
32
+ if (!/\n$/.test(type.content))
33
+ source.nextWhile(isWhiteSpace);
34
+ type.value = type.content + source.get();
35
+ return type;
36
+ },
37
+
38
+ next: function () {
39
+ if (!source.more()) throw StopIteration;
40
+
41
+ var type;
42
+ if (source.equals("\n")) {
43
+ source.next();
44
+ return this.take("whitespace");
45
+ }
46
+
47
+ if (source.applies(isWhiteSpace))
48
+ type = "whitespace";
49
+ else
50
+ while (!type)
51
+ type = this.state(source, function(s) {tokenizer.state = s;});
52
+
53
+ return this.take(type);
54
+ }
55
+ };
56
+ return tokenizer;
57
+ }
@@ -0,0 +1,174 @@
1
+ /* Tokenizer for JavaScript code */
2
+
3
+ var tokenizeJavaScript = (function() {
4
+ // Advance the stream until the given character (not preceded by a
5
+ // backslash) is encountered, or the end of the line is reached.
6
+ function nextUntilUnescaped(source, end) {
7
+ var escaped = false;
8
+ while (!source.endOfLine()) {
9
+ var next = source.next();
10
+ if (next == end && !escaped)
11
+ return false;
12
+ escaped = !escaped && next == "\\";
13
+ }
14
+ return escaped;
15
+ }
16
+
17
+ // A map of JavaScript's keywords. The a/b/c keyword distinction is
18
+ // very rough, but it gives the parser enough information to parse
19
+ // correct code correctly (we don't care that much how we parse
20
+ // incorrect code). The style information included in these objects
21
+ // is used by the highlighter to pick the correct CSS style for a
22
+ // token.
23
+ var keywords = function(){
24
+ function result(type, style){
25
+ return {type: type, style: "js-" + style};
26
+ }
27
+ // keywords that take a parenthised expression, and then a
28
+ // statement (if)
29
+ var keywordA = result("keyword a", "keyword");
30
+ // keywords that take just a statement (else)
31
+ var keywordB = result("keyword b", "keyword");
32
+ // keywords that optionally take an expression, and form a
33
+ // statement (return)
34
+ var keywordC = result("keyword c", "keyword");
35
+ var operator = result("operator", "keyword");
36
+ var atom = result("atom", "atom");
37
+ return {
38
+ "if": keywordA, "while": keywordA, "with": keywordA,
39
+ "else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB,
40
+ "return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "delete": keywordC, "throw": keywordC,
41
+ "in": operator, "typeof": operator, "instanceof": operator,
42
+ "var": result("var", "keyword"), "function": result("function", "keyword"), "catch": result("catch", "keyword"),
43
+ "for": result("for", "keyword"), "switch": result("switch", "keyword"),
44
+ "case": result("case", "keyword"), "default": result("default", "keyword"),
45
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
46
+ };
47
+ }();
48
+
49
+ // Some helper regexps
50
+ var isOperatorChar = /[+\-*&%=<>!?|]/;
51
+ var isHexDigit = /[0-9A-Fa-f]/;
52
+ var isWordChar = /[\w\$_]/;
53
+
54
+ // Wrapper around jsToken that helps maintain parser state (whether
55
+ // we are inside of a multi-line comment and whether the next token
56
+ // could be a regular expression).
57
+ function jsTokenState(inside, regexp) {
58
+ return function(source, setState) {
59
+ var newInside = inside;
60
+ var type = jsToken(inside, regexp, source, function(c) {newInside = c;});
61
+ var newRegexp = type.type == "operator" || type.type == "keyword c" || type.type.match(/^[\[{}\(,;:]$/);
62
+ if (newRegexp != regexp || newInside != inside)
63
+ setState(jsTokenState(newInside, newRegexp));
64
+ return type;
65
+ };
66
+ }
67
+
68
+ // The token reader, intended to be used by the tokenizer from
69
+ // tokenize.js (through jsTokenState). Advances the source stream
70
+ // over a token, and returns an object containing the type and style
71
+ // of that token.
72
+ function jsToken(inside, regexp, source, setInside) {
73
+ function readHexNumber(){
74
+ source.next(); // skip the 'x'
75
+ source.nextWhileMatches(isHexDigit);
76
+ return {type: "number", style: "js-atom"};
77
+ }
78
+
79
+ function readNumber() {
80
+ source.nextWhileMatches(/[0-9]/);
81
+ if (source.equals(".")){
82
+ source.next();
83
+ source.nextWhileMatches(/[0-9]/);
84
+ }
85
+ if (source.equals("e") || source.equals("E")){
86
+ source.next();
87
+ if (source.equals("-"))
88
+ source.next();
89
+ source.nextWhileMatches(/[0-9]/);
90
+ }
91
+ return {type: "number", style: "js-atom"};
92
+ }
93
+ // Read a word, look it up in keywords. If not found, it is a
94
+ // variable, otherwise it is a keyword of the type found.
95
+ function readWord() {
96
+ source.nextWhileMatches(isWordChar);
97
+ var word = source.get();
98
+ var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
99
+ return known ? {type: known.type, style: known.style, content: word} :
100
+ {type: "variable", style: "js-variable", content: word};
101
+ }
102
+ function readRegexp() {
103
+ nextUntilUnescaped(source, "/");
104
+ source.nextWhileMatches(/[gi]/);
105
+ return {type: "regexp", style: "js-string"};
106
+ }
107
+ // Mutli-line comments are tricky. We want to return the newlines
108
+ // embedded in them as regular newline tokens, and then continue
109
+ // returning a comment token for every line of the comment. So
110
+ // some state has to be saved (inside) to indicate whether we are
111
+ // inside a /* */ sequence.
112
+ function readMultilineComment(start){
113
+ var newInside = "/*";
114
+ var maybeEnd = (start == "*");
115
+ while (true) {
116
+ if (source.endOfLine())
117
+ break;
118
+ var next = source.next();
119
+ if (next == "/" && maybeEnd){
120
+ newInside = null;
121
+ break;
122
+ }
123
+ maybeEnd = (next == "*");
124
+ }
125
+ setInside(newInside);
126
+ return {type: "comment", style: "js-comment"};
127
+ }
128
+ function readOperator() {
129
+ source.nextWhileMatches(isOperatorChar);
130
+ return {type: "operator", style: "js-operator"};
131
+ }
132
+ function readString(quote) {
133
+ var endBackSlash = nextUntilUnescaped(source, quote);
134
+ setInside(endBackSlash ? quote : null);
135
+ return {type: "string", style: "js-string"};
136
+ }
137
+
138
+ // Fetch the next token. Dispatches on first character in the
139
+ // stream, or first two characters when the first is a slash.
140
+ if (inside == "\"" || inside == "'")
141
+ return readString(inside);
142
+ var ch = source.next();
143
+ if (inside == "/*")
144
+ return readMultilineComment(ch);
145
+ else if (ch == "\"" || ch == "'")
146
+ return readString(ch);
147
+ // with punctuation, the type of the token is the symbol itself
148
+ else if (/[\[\]{}\(\),;\:\.]/.test(ch))
149
+ return {type: ch, style: "js-punctuation"};
150
+ else if (ch == "0" && (source.equals("x") || source.equals("X")))
151
+ return readHexNumber();
152
+ else if (/[0-9]/.test(ch))
153
+ return readNumber();
154
+ else if (ch == "/"){
155
+ if (source.equals("*"))
156
+ { source.next(); return readMultilineComment(ch); }
157
+ else if (source.equals("/"))
158
+ { nextUntilUnescaped(source, null); return {type: "comment", style: "js-comment"};}
159
+ else if (regexp)
160
+ return readRegexp();
161
+ else
162
+ return readOperator();
163
+ }
164
+ else if (isOperatorChar.test(ch))
165
+ return readOperator();
166
+ else
167
+ return readWord();
168
+ }
169
+
170
+ // The external interface to the tokenizer.
171
+ return function(source, startState) {
172
+ return tokenizer(source, startState || jsTokenState(false, true));
173
+ };
174
+ })();
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Storage and control for undo information within a CodeMirror
3
+ * editor. 'Why on earth is such a complicated mess required for
4
+ * that?', I hear you ask. The goal, in implementing this, was to make
5
+ * the complexity of storing and reverting undo information depend
6
+ * only on the size of the edited or restored content, not on the size
7
+ * of the whole document. This makes it necessary to use a kind of
8
+ * 'diff' system, which, when applied to a DOM tree, causes some
9
+ * complexity and hackery.
10
+ *
11
+ * In short, the editor 'touches' BR elements as it parses them, and
12
+ * the History stores these. When nothing is touched in commitDelay
13
+ * milliseconds, the changes are committed: It goes over all touched
14
+ * nodes, throws out the ones that did not change since last commit or
15
+ * are no longer in the document, and assembles the rest into zero or
16
+ * more 'chains' -- arrays of adjacent lines. Links back to these
17
+ * chains are added to the BR nodes, while the chain that previously
18
+ * spanned these nodes is added to the undo history. Undoing a change
19
+ * means taking such a chain off the undo history, restoring its
20
+ * content (text is saved per line) and linking it back into the
21
+ * document.
22
+ */
23
+
24
+ // A history object needs to know about the DOM container holding the
25
+ // document, the maximum amount of undo levels it should store, the
26
+ // delay (of no input) after which it commits a set of changes, and,
27
+ // unfortunately, the 'parent' window -- a window that is not in
28
+ // designMode, and on which setTimeout works in every browser.
29
+ function History(container, maxDepth, commitDelay, editor) {
30
+ this.container = container;
31
+ this.maxDepth = maxDepth; this.commitDelay = commitDelay;
32
+ this.editor = editor; this.parent = editor.parent;
33
+ // This line object represents the initial, empty editor.
34
+ var initial = {text: "", from: null, to: null};
35
+ // As the borders between lines are represented by BR elements, the
36
+ // start of the first line and the end of the last one are
37
+ // represented by null. Since you can not store any properties
38
+ // (links to line objects) in null, these properties are used in
39
+ // those cases.
40
+ this.first = initial; this.last = initial;
41
+ // Similarly, a 'historyTouched' property is added to the BR in
42
+ // front of lines that have already been touched, and 'firstTouched'
43
+ // is used for the first line.
44
+ this.firstTouched = false;
45
+ // History is the set of committed changes, touched is the set of
46
+ // nodes touched since the last commit.
47
+ this.history = []; this.redoHistory = []; this.touched = [];
48
+ }
49
+
50
+ History.prototype = {
51
+ // Schedule a commit (if no other touches come in for commitDelay
52
+ // milliseconds).
53
+ scheduleCommit: function() {
54
+ var self = this;
55
+ this.parent.clearTimeout(this.commitTimeout);
56
+ this.commitTimeout = this.parent.setTimeout(function(){self.tryCommit();}, this.commitDelay);
57
+ },
58
+
59
+ // Mark a node as touched. Null is a valid argument.
60
+ touch: function(node) {
61
+ this.setTouched(node);
62
+ this.scheduleCommit();
63
+ },
64
+
65
+ // Undo the last change.
66
+ undo: function() {
67
+ // Make sure pending changes have been committed.
68
+ this.commit();
69
+
70
+ if (this.history.length) {
71
+ // Take the top diff from the history, apply it, and store its
72
+ // shadow in the redo history.
73
+ var item = this.history.pop();
74
+ this.redoHistory.push(this.updateTo(item, "applyChain"));
75
+ this.notifyEnvironment();
76
+ return this.chainNode(item);
77
+ }
78
+ },
79
+
80
+ // Redo the last undone change.
81
+ redo: function() {
82
+ this.commit();
83
+ if (this.redoHistory.length) {
84
+ // The inverse of undo, basically.
85
+ var item = this.redoHistory.pop();
86
+ this.addUndoLevel(this.updateTo(item, "applyChain"));
87
+ this.notifyEnvironment();
88
+ return this.chainNode(item);
89
+ }
90
+ },
91
+
92
+ clear: function() {
93
+ this.history = [];
94
+ this.redoHistory = [];
95
+ },
96
+
97
+ // Ask for the size of the un/redo histories.
98
+ historySize: function() {
99
+ return {undo: this.history.length, redo: this.redoHistory.length};
100
+ },
101
+
102
+ // Push a changeset into the document.
103
+ push: function(from, to, lines) {
104
+ var chain = [];
105
+ for (var i = 0; i < lines.length; i++) {
106
+ var end = (i == lines.length - 1) ? to : this.container.ownerDocument.createElement("BR");
107
+ chain.push({from: from, to: end, text: cleanText(lines[i])});
108
+ from = end;
109
+ }
110
+ this.pushChains([chain], from == null && to == null);
111
+ this.notifyEnvironment();
112
+ },
113
+
114
+ pushChains: function(chains, doNotHighlight) {
115
+ this.commit(doNotHighlight);
116
+ this.addUndoLevel(this.updateTo(chains, "applyChain"));
117
+ this.redoHistory = [];
118
+ },
119
+
120
+ // Retrieve a DOM node from a chain (for scrolling to it after undo/redo).
121
+ chainNode: function(chains) {
122
+ for (var i = 0; i < chains.length; i++) {
123
+ var start = chains[i][0], node = start && (start.from || start.to);
124
+ if (node) return node;
125
+ }
126
+ },
127
+
128
+ // Clear the undo history, make the current document the start
129
+ // position.
130
+ reset: function() {
131
+ this.history = []; this.redoHistory = [];
132
+ },
133
+
134
+ textAfter: function(br) {
135
+ return this.after(br).text;
136
+ },
137
+
138
+ nodeAfter: function(br) {
139
+ return this.after(br).to;
140
+ },
141
+
142
+ nodeBefore: function(br) {
143
+ return this.before(br).from;
144
+ },
145
+
146
+ // Commit unless there are pending dirty nodes.
147
+ tryCommit: function() {
148
+ if (!window.History) return; // Stop when frame has been unloaded
149
+ if (this.editor.highlightDirty()) this.commit(true);
150
+ else this.scheduleCommit();
151
+ },
152
+
153
+ // Check whether the touched nodes hold any changes, if so, commit
154
+ // them.
155
+ commit: function(doNotHighlight) {
156
+ this.parent.clearTimeout(this.commitTimeout);
157
+ // Make sure there are no pending dirty nodes.
158
+ if (!doNotHighlight) this.editor.highlightDirty(true);
159
+ // Build set of chains.
160
+ var chains = this.touchedChains(), self = this;
161
+
162
+ if (chains.length) {
163
+ this.addUndoLevel(this.updateTo(chains, "linkChain"));
164
+ this.redoHistory = [];
165
+ this.notifyEnvironment();
166
+ }
167
+ },
168
+
169
+ // [ end of public interface ]
170
+
171
+ // Update the document with a given set of chains, return its
172
+ // shadow. updateFunc should be "applyChain" or "linkChain". In the
173
+ // second case, the chains are taken to correspond the the current
174
+ // document, and only the state of the line data is updated. In the
175
+ // first case, the content of the chains is also pushed iinto the
176
+ // document.
177
+ updateTo: function(chains, updateFunc) {
178
+ var shadows = [], dirty = [];
179
+ for (var i = 0; i < chains.length; i++) {
180
+ shadows.push(this.shadowChain(chains[i]));
181
+ dirty.push(this[updateFunc](chains[i]));
182
+ }
183
+ if (updateFunc == "applyChain")
184
+ this.notifyDirty(dirty);
185
+ return shadows;
186
+ },
187
+
188
+ // Notify the editor that some nodes have changed.
189
+ notifyDirty: function(nodes) {
190
+ forEach(nodes, method(this.editor, "addDirtyNode"))
191
+ this.editor.scheduleHighlight();
192
+ },
193
+
194
+ notifyEnvironment: function() {
195
+ // Used by the line-wrapping line-numbering code.
196
+ if (window.frameElement && window.frameElement.CodeMirror.updateNumbers)
197
+ window.frameElement.CodeMirror.updateNumbers();
198
+ if (this.onChange) this.onChange();
199
+ },
200
+
201
+ // Link a chain into the DOM nodes (or the first/last links for null
202
+ // nodes).
203
+ linkChain: function(chain) {
204
+ for (var i = 0; i < chain.length; i++) {
205
+ var line = chain[i];
206
+ if (line.from) line.from.historyAfter = line;
207
+ else this.first = line;
208
+ if (line.to) line.to.historyBefore = line;
209
+ else this.last = line;
210
+ }
211
+ },
212
+
213
+ // Get the line object after/before a given node.
214
+ after: function(node) {
215
+ return node ? node.historyAfter : this.first;
216
+ },
217
+ before: function(node) {
218
+ return node ? node.historyBefore : this.last;
219
+ },
220
+
221
+ // Mark a node as touched if it has not already been marked.
222
+ setTouched: function(node) {
223
+ if (node) {
224
+ if (!node.historyTouched) {
225
+ this.touched.push(node);
226
+ node.historyTouched = true;
227
+ }
228
+ }
229
+ else {
230
+ this.firstTouched = true;
231
+ }
232
+ },
233
+
234
+ // Store a new set of undo info, throw away info if there is more of
235
+ // it than allowed.
236
+ addUndoLevel: function(diffs) {
237
+ this.history.push(diffs);
238
+ if (this.history.length > this.maxDepth)
239
+ this.history.shift();
240
+ },
241
+
242
+ // Build chains from a set of touched nodes.
243
+ touchedChains: function() {
244
+ var self = this;
245
+
246
+ // The temp system is a crummy hack to speed up determining
247
+ // whether a (currently touched) node has a line object associated
248
+ // with it. nullTemp is used to store the object for the first
249
+ // line, other nodes get it stored in their historyTemp property.
250
+ var nullTemp = null;
251
+ function temp(node) {return node ? node.historyTemp : nullTemp;}
252
+ function setTemp(node, line) {
253
+ if (node) node.historyTemp = line;
254
+ else nullTemp = line;
255
+ }
256
+
257
+ function buildLine(node) {
258
+ var text = [];
259
+ for (var cur = node ? node.nextSibling : self.container.firstChild;
260
+ cur && !isBR(cur); cur = cur.nextSibling)
261
+ if (cur.currentText) text.push(cur.currentText);
262
+ return {from: node, to: cur, text: cleanText(text.join(""))};
263
+ }
264
+
265
+ // Filter out unchanged lines and nodes that are no longer in the
266
+ // document. Build up line objects for remaining nodes.
267
+ var lines = [];
268
+ if (self.firstTouched) self.touched.push(null);
269
+ forEach(self.touched, function(node) {
270
+ if (node && node.parentNode != self.container) return;
271
+
272
+ if (node) node.historyTouched = false;
273
+ else self.firstTouched = false;
274
+
275
+ var line = buildLine(node), shadow = self.after(node);
276
+ if (!shadow || shadow.text != line.text || shadow.to != line.to) {
277
+ lines.push(line);
278
+ setTemp(node, line);
279
+ }
280
+ });
281
+
282
+ // Get the BR element after/before the given node.
283
+ function nextBR(node, dir) {
284
+ var link = dir + "Sibling", search = node[link];
285
+ while (search && !isBR(search))
286
+ search = search[link];
287
+ return search;
288
+ }
289
+
290
+ // Assemble line objects into chains by scanning the DOM tree
291
+ // around them.
292
+ var chains = []; self.touched = [];
293
+ forEach(lines, function(line) {
294
+ // Note that this makes the loop skip line objects that have
295
+ // been pulled into chains by lines before them.
296
+ if (!temp(line.from)) return;
297
+
298
+ var chain = [], curNode = line.from, safe = true;
299
+ // Put any line objects (referred to by temp info) before this
300
+ // one on the front of the array.
301
+ while (true) {
302
+ var curLine = temp(curNode);
303
+ if (!curLine) {
304
+ if (safe) break;
305
+ else curLine = buildLine(curNode);
306
+ }
307
+ chain.unshift(curLine);
308
+ setTemp(curNode, null);
309
+ if (!curNode) break;
310
+ safe = self.after(curNode);
311
+ curNode = nextBR(curNode, "previous");
312
+ }
313
+ curNode = line.to; safe = self.before(line.from);
314
+ // Add lines after this one at end of array.
315
+ while (true) {
316
+ if (!curNode) break;
317
+ var curLine = temp(curNode);
318
+ if (!curLine) {
319
+ if (safe) break;
320
+ else curLine = buildLine(curNode);
321
+ }
322
+ chain.push(curLine);
323
+ setTemp(curNode, null);
324
+ safe = self.before(curNode);
325
+ curNode = nextBR(curNode, "next");
326
+ }
327
+ chains.push(chain);
328
+ });
329
+
330
+ return chains;
331
+ },
332
+
333
+ // Find the 'shadow' of a given chain by following the links in the
334
+ // DOM nodes at its start and end.
335
+ shadowChain: function(chain) {
336
+ var shadows = [], next = this.after(chain[0].from), end = chain[chain.length - 1].to;
337
+ while (true) {
338
+ shadows.push(next);
339
+ var nextNode = next.to;
340
+ if (!nextNode || nextNode == end)
341
+ break;
342
+ else
343
+ next = nextNode.historyAfter || this.before(end);
344
+ // (The this.before(end) is a hack -- FF sometimes removes
345
+ // properties from BR nodes, in which case the best we can hope
346
+ // for is to not break.)
347
+ }
348
+ return shadows;
349
+ },
350
+
351
+ // Update the DOM tree to contain the lines specified in a given
352
+ // chain, link this chain into the DOM nodes.
353
+ applyChain: function(chain) {
354
+ // Some attempt is made to prevent the cursor from jumping
355
+ // randomly when an undo or redo happens. It still behaves a bit
356
+ // strange sometimes.
357
+ var cursor = select.cursorPos(this.container, false), self = this;
358
+
359
+ // Remove all nodes in the DOM tree between from and to (null for
360
+ // start/end of container).
361
+ function removeRange(from, to) {
362
+ var pos = from ? from.nextSibling : self.container.firstChild;
363
+ while (pos != to) {
364
+ var temp = pos.nextSibling;
365
+ removeElement(pos);
366
+ pos = temp;
367
+ }
368
+ }
369
+
370
+ var start = chain[0].from, end = chain[chain.length - 1].to;
371
+ // Clear the space where this change has to be made.
372
+ removeRange(start, end);
373
+
374
+ // Insert the content specified by the chain into the DOM tree.
375
+ for (var i = 0; i < chain.length; i++) {
376
+ var line = chain[i];
377
+ // The start and end of the space are already correct, but BR
378
+ // tags inside it have to be put back.
379
+ if (i > 0)
380
+ self.container.insertBefore(line.from, end);
381
+
382
+ // Add the text.
383
+ var node = makePartSpan(fixSpaces(line.text), this.container.ownerDocument);
384
+ self.container.insertBefore(node, end);
385
+ // See if the cursor was on this line. Put it back, adjusting
386
+ // for changed line length, if it was.
387
+ if (cursor && cursor.node == line.from) {
388
+ var cursordiff = 0;
389
+ var prev = this.after(line.from);
390
+ if (prev && i == chain.length - 1) {
391
+ // Only adjust if the cursor is after the unchanged part of
392
+ // the line.
393
+ for (var match = 0; match < cursor.offset &&
394
+ line.text.charAt(match) == prev.text.charAt(match); match++);
395
+ if (cursor.offset > match)
396
+ cursordiff = line.text.length - prev.text.length;
397
+ }
398
+ select.setCursorPos(this.container, {node: line.from, offset: Math.max(0, cursor.offset + cursordiff)});
399
+ }
400
+ // Cursor was in removed line, this is last new line.
401
+ else if (cursor && (i == chain.length - 1) && cursor.node && cursor.node.parentNode != this.container) {
402
+ select.setCursorPos(this.container, {node: line.from, offset: line.text.length});
403
+ }
404
+ }
405
+
406
+ // Anchor the chain in the DOM tree.
407
+ this.linkChain(chain);
408
+ return start;
409
+ }
410
+ };