ela 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (300) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.gitlab-ci.yml +23 -0
  4. data/Gemfile +7 -0
  5. data/Gemfile.lock +139 -0
  6. data/Guardfile +25 -0
  7. data/LICENSE.txt +205 -0
  8. data/README.de.md +195 -0
  9. data/README.md +66 -0
  10. data/Rakefile +96 -0
  11. data/app/css/screen.styl +425 -0
  12. data/app/css/vendor/stackedit.styl +140 -0
  13. data/app/fonts/Roboto-Italic-webfont.eot +0 -0
  14. data/app/fonts/Roboto-Italic-webfont.svg +642 -0
  15. data/app/fonts/Roboto-Italic-webfont.ttf +0 -0
  16. data/app/fonts/Roboto-Italic-webfont.woff +0 -0
  17. data/app/fonts/Roboto-Light-webfont.eot +0 -0
  18. data/app/fonts/Roboto-Light-webfont.svg +641 -0
  19. data/app/fonts/Roboto-Light-webfont.ttf +0 -0
  20. data/app/fonts/Roboto-Light-webfont.woff +0 -0
  21. data/app/fonts/Roboto-LightItalic-webfont.eot +0 -0
  22. data/app/fonts/Roboto-LightItalic-webfont.svg +641 -0
  23. data/app/fonts/Roboto-LightItalic-webfont.ttf +0 -0
  24. data/app/fonts/Roboto-LightItalic-webfont.woff +0 -0
  25. data/app/fonts/Roboto-Medium-webfont.eot +0 -0
  26. data/app/fonts/Roboto-Medium-webfont.svg +593 -0
  27. data/app/fonts/Roboto-Medium-webfont.ttf +0 -0
  28. data/app/fonts/Roboto-Medium-webfont.woff +0 -0
  29. data/app/fonts/Roboto-MediumItalic-webfont.eot +0 -0
  30. data/app/fonts/Roboto-MediumItalic-webfont.svg +642 -0
  31. data/app/fonts/Roboto-MediumItalic-webfont.ttf +0 -0
  32. data/app/fonts/Roboto-MediumItalic-webfont.woff +0 -0
  33. data/app/fonts/Roboto-Regular-webfont.eot +0 -0
  34. data/app/fonts/Roboto-Regular-webfont.svg +621 -0
  35. data/app/fonts/Roboto-Regular-webfont.ttf +0 -0
  36. data/app/fonts/Roboto-Regular-webfont.woff +0 -0
  37. data/app/fonts/Roboto-Thin-webfont.eot +0 -0
  38. data/app/fonts/Roboto-Thin-webfont.svg +631 -0
  39. data/app/fonts/Roboto-Thin-webfont.ttf +0 -0
  40. data/app/fonts/Roboto-Thin-webfont.woff +0 -0
  41. data/app/fonts/Roboto-ThinItalic-webfont.eot +0 -0
  42. data/app/fonts/Roboto-ThinItalic-webfont.svg +631 -0
  43. data/app/fonts/Roboto-ThinItalic-webfont.ttf +0 -0
  44. data/app/fonts/Roboto-ThinItalic-webfont.woff +0 -0
  45. data/app/fonts/droid_sans_regular.typeface.svg +1 -0
  46. data/app/fonts/fontawesome-webfont.eot +0 -0
  47. data/app/fonts/fontawesome-webfont.svg +2671 -0
  48. data/app/fonts/fontawesome-webfont.ttf +0 -0
  49. data/app/fonts/fontawesome-webfont.woff +0 -0
  50. data/app/fonts/fontawesome-webfont.woff2 +0 -0
  51. data/app/js/lib/application.coffee +83 -0
  52. data/app/js/lib/bootstrap_data.coffee +70 -0
  53. data/app/js/lib/collections/00_limited_collection.coffee +85 -0
  54. data/app/js/lib/collections/curves.coffee +3 -0
  55. data/app/js/lib/collections/named_object_collection.coffee +7 -0
  56. data/app/js/lib/mathjaxConfig.coffee +241 -0
  57. data/app/js/lib/models/app.coffee +58 -0
  58. data/app/js/lib/models/base_app.coffee +62 -0
  59. data/app/js/lib/models/base_app_model.coffee +61 -0
  60. data/app/js/lib/models/base_calculator.coffee +212 -0
  61. data/app/js/lib/models/base_subapp_container.coffee +35 -0
  62. data/app/js/lib/models/curve.coffee +179 -0
  63. data/app/js/lib/router.coffee +26 -0
  64. data/app/js/lib/views/app.coffee +56 -0
  65. data/app/js/lib/views/base_app.coffee +274 -0
  66. data/app/js/lib/views/base_aside.coffee +9 -0
  67. data/app/js/lib/views/base_graph.coffee +477 -0
  68. data/app/js/lib/views/base_subapp_container.coffee +44 -0
  69. data/app/js/lib/views/canvas.coffee +73 -0
  70. data/app/js/lib/views/curve_graph.coffee +163 -0
  71. data/app/js/lib/views/curves_aside.coffee +21 -0
  72. data/app/js/lib/views/curves_list_item.coffee +8 -0
  73. data/app/js/lib/views/grouped_parameters_aside.coffee +14 -0
  74. data/app/js/lib/views/headup.coffee +15 -0
  75. data/app/js/lib/views/help.coffee +86 -0
  76. data/app/js/lib/views/interpolated_graph.coffee +281 -0
  77. data/app/js/lib/views/legend.coffee +138 -0
  78. data/app/js/lib/views/legend_handler.coffee +51 -0
  79. data/app/js/lib/views/overview.coffee +85 -0
  80. data/app/js/lib/views/overview_tile.coffee +18 -0
  81. data/app/js/lib/views/parameters_aside.coffee +12 -0
  82. data/app/js/lib/views/three_graph.coffee +92 -0
  83. data/app/js/vendor/Markdown.Converter.js +1519 -0
  84. data/app/js/vendor/Markdown.Extra.js +874 -0
  85. data/app/js/vendor/Markdown.Toc.coffee +79 -0
  86. data/app/js/vendor/backbone-1.3.3.min.js +2 -0
  87. data/app/js/vendor/backbone-validation-0.11.5.js +8 -0
  88. data/app/js/vendor/backbone.poised/form.coffee +156 -0
  89. data/app/js/vendor/backbone.poised/form/anchor.coffee +26 -0
  90. data/app/js/vendor/backbone.poised/form/base_control.coffee +42 -0
  91. data/app/js/vendor/backbone.poised/form/linked_control.coffee +79 -0
  92. data/app/js/vendor/backbone.poised/form/linked_number_control.coffee +27 -0
  93. data/app/js/vendor/backbone.poised/form/linked_range_control.coffee +53 -0
  94. data/app/js/vendor/backbone.poised/form/linked_select_control.coffee +18 -0
  95. data/app/js/vendor/backbone.poised/form/linked_string_control.coffee +27 -0
  96. data/app/js/vendor/backbone.poised/form/number_control.coffee +25 -0
  97. data/app/js/vendor/backbone.poised/form/range_control.coffee +48 -0
  98. data/app/js/vendor/backbone.poised/form/select_control.coffee +16 -0
  99. data/app/js/vendor/backbone.poised/form/selectbox.coffee +78 -0
  100. data/app/js/vendor/backbone.poised/form/slider.coffee +109 -0
  101. data/app/js/vendor/backbone.poised/form/string_control.coffee +23 -0
  102. data/app/js/vendor/backbone.poised/form/submit_control.coffee +39 -0
  103. data/app/js/vendor/backbone.poised/form/textarea.coffee +36 -0
  104. data/app/js/vendor/backbone.poised/form/textfield.coffee +86 -0
  105. data/app/js/vendor/backbone.poised/form/value.coffee +33 -0
  106. data/app/js/vendor/backbone.poised/form/value_control.coffee +15 -0
  107. data/app/js/vendor/backbone.poised/linked_form.coffee +43 -0
  108. data/app/js/vendor/backbone.poised/list.coffee +97 -0
  109. data/app/js/vendor/backbone.poised/list/add_button.coffee +16 -0
  110. data/app/js/vendor/backbone.poised/list/anchor.coffee +32 -0
  111. data/app/js/vendor/backbone.poised/list/item.coffee +68 -0
  112. data/app/js/vendor/backbone.poised/list/searchfield.coffee +26 -0
  113. data/app/js/vendor/backbone.poised/list/selectable_item.coffee +65 -0
  114. data/app/js/vendor/backbone.poised/patches.coffee +6 -0
  115. data/app/js/vendor/backbone.poised/string_mixin.coffee +23 -0
  116. data/app/js/vendor/backbone.poised/underscore_ext.coffee +2 -0
  117. data/app/js/vendor/backbone.poised/view.coffee +59 -0
  118. data/app/js/vendor/gaussianElimination.coffee +40 -0
  119. data/app/js/vendor/hammer-2.0.8.min.js +7 -0
  120. data/app/js/vendor/jquery-3.1.1.min.js +4 -0
  121. data/app/js/vendor/jquery.after-transition.coffee +20 -0
  122. data/app/js/vendor/jquery.backbone-hammer.coffee +28 -0
  123. data/app/js/vendor/jquery.keyboard-modifiers.coffee +22 -0
  124. data/app/js/vendor/jquery.mark-5.2.3.min.js +7 -0
  125. data/app/js/vendor/jquery.scrollTo-2.1.2.min.js +7 -0
  126. data/app/js/vendor/js-yaml-3.4.3.min.js +3 -0
  127. data/app/js/vendor/markup_text.coffee +95 -0
  128. data/app/js/vendor/mathjax/MathJax.js +19 -0
  129. data/app/js/vendor/mathjax/extensions/MathEvents.js +19 -0
  130. data/app/js/vendor/mathjax/extensions/tex2jax.js +19 -0
  131. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot +0 -0
  132. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot +0 -0
  133. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot +0 -0
  134. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot +0 -0
  135. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot +0 -0
  136. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot +0 -0
  137. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot +0 -0
  138. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot +0 -0
  139. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot +0 -0
  140. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot +0 -0
  141. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Regular.eot +0 -0
  142. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot +0 -0
  143. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot +0 -0
  144. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot +0 -0
  145. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot +0 -0
  146. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot +0 -0
  147. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot +0 -0
  148. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot +0 -0
  149. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot +0 -0
  150. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot +0 -0
  151. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_WinIE6-Regular.eot +0 -0
  152. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf +0 -0
  153. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf +0 -0
  154. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf +0 -0
  155. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf +0 -0
  156. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf +0 -0
  157. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf +0 -0
  158. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf +0 -0
  159. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf +0 -0
  160. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf +0 -0
  161. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf +0 -0
  162. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Regular.otf +0 -0
  163. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf +0 -0
  164. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf +0 -0
  165. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf +0 -0
  166. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf +0 -0
  167. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf +0 -0
  168. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf +0 -0
  169. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf +0 -0
  170. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf +0 -0
  171. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf +0 -0
  172. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinChrome-Regular.otf +0 -0
  173. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinIE6-Regular.otf +0 -0
  174. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_AMS-Regular.svg +765 -0
  175. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Bold.svg +136 -0
  176. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Regular.svg +134 -0
  177. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Bold.svg +319 -0
  178. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Regular.svg +309 -0
  179. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Bold.svg +656 -0
  180. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Italic.svg +374 -0
  181. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Regular.svg +659 -0
  182. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-BoldItalic.svg +331 -0
  183. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Italic.svg +331 -0
  184. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Regular.svg +330 -0
  185. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Bold.svg +280 -0
  186. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Italic.svg +245 -0
  187. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Regular.svg +211 -0
  188. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Script-Regular.svg +160 -0
  189. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size1-Regular.svg +110 -0
  190. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size2-Regular.svg +109 -0
  191. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size3-Regular.svg +49 -0
  192. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size4-Regular.svg +102 -0
  193. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Typewriter-Regular.svg +322 -0
  194. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_WinChrome-Regular.svg +39 -0
  195. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff +0 -0
  196. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff +0 -0
  197. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff +0 -0
  198. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff +0 -0
  199. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff +0 -0
  200. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff +0 -0
  201. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff +0 -0
  202. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff +0 -0
  203. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff +0 -0
  204. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff +0 -0
  205. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Regular.woff +0 -0
  206. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff +0 -0
  207. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff +0 -0
  208. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff +0 -0
  209. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff +0 -0
  210. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff +0 -0
  211. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff +0 -0
  212. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff +0 -0
  213. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff +0 -0
  214. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff +0 -0
  215. data/app/js/vendor/mathjax/jax/element/mml/jax.js +19 -0
  216. data/app/js/vendor/mathjax/jax/element/mml/optable/Arrows.js +19 -0
  217. data/app/js/vendor/mathjax/jax/element/mml/optable/BasicLatin.js +19 -0
  218. data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiacritMarks.js +19 -0
  219. data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiactForSymbols.js +19 -0
  220. data/app/js/vendor/mathjax/jax/element/mml/optable/Dingbats.js +19 -0
  221. data/app/js/vendor/mathjax/jax/element/mml/optable/GeneralPunctuation.js +19 -0
  222. data/app/js/vendor/mathjax/jax/element/mml/optable/GeometricShapes.js +19 -0
  223. data/app/js/vendor/mathjax/jax/element/mml/optable/GreekAndCoptic.js +19 -0
  224. data/app/js/vendor/mathjax/jax/element/mml/optable/Latin1Supplement.js +19 -0
  225. data/app/js/vendor/mathjax/jax/element/mml/optable/LetterlikeSymbols.js +19 -0
  226. data/app/js/vendor/mathjax/jax/element/mml/optable/MathOperators.js +19 -0
  227. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsA.js +19 -0
  228. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsB.js +19 -0
  229. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscSymbolsAndArrows.js +19 -0
  230. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscTechnical.js +19 -0
  231. data/app/js/vendor/mathjax/jax/element/mml/optable/SpacingModLetters.js +19 -0
  232. data/app/js/vendor/mathjax/jax/element/mml/optable/SuppMathOperators.js +19 -0
  233. data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsA.js +19 -0
  234. data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsB.js +19 -0
  235. data/app/js/vendor/mathjax/jax/input/TeX/config.js +19 -0
  236. data/app/js/vendor/mathjax/jax/input/TeX/jax.js +19 -0
  237. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/annotation-xml.js +19 -0
  238. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/maction.js +19 -0
  239. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/menclose.js +19 -0
  240. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mglyph.js +19 -0
  241. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mmultiscripts.js +19 -0
  242. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/ms.js +19 -0
  243. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mtable.js +19 -0
  244. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/multiline.js +19 -0
  245. data/app/js/vendor/mathjax/jax/output/CommonHTML/config.js +19 -0
  246. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/AMS-Regular.js +19 -0
  247. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Caligraphic-Bold.js +19 -0
  248. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Bold.js +19 -0
  249. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Regular.js +19 -0
  250. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Main-Bold.js +19 -0
  251. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Math-BoldItalic.js +19 -0
  252. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Bold.js +19 -0
  253. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Italic.js +19 -0
  254. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Regular.js +19 -0
  255. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Script-Regular.js +19 -0
  256. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Typewriter-Regular.js +19 -0
  257. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata-extra.js +19 -0
  258. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata.js +19 -0
  259. data/app/js/vendor/mathjax/jax/output/CommonHTML/jax.js +19 -0
  260. data/app/js/vendor/modernizr-custom-3.3.1.min.js +3 -0
  261. data/app/js/vendor/persistjs-git.js +1136 -0
  262. data/app/js/vendor/poised/poised.general.coffee +21 -0
  263. data/app/js/vendor/poised/poised.tabs.coffee +31 -0
  264. data/app/js/vendor/poised/utils.coffee +11 -0
  265. data/app/js/vendor/request_animation_frame.coffee +19 -0
  266. data/app/js/vendor/three-82.min.js +15 -0
  267. data/app/js/vendor/three-CanvasRenderer-82.js +1118 -0
  268. data/app/js/vendor/three-Projector-82.js +929 -0
  269. data/app/js/vendor/underscore-1.8.3.min.js +6 -0
  270. data/app/js/vendor/webfontloader-1.6.26.min.js +33 -0
  271. data/app/views/aliasing/legend.jst.hamlc +6 -0
  272. data/app/views/composites/composites_list_item_label.jst.hamlc +3 -0
  273. data/app/views/composites/import_composites_aside.jst.hamlc +6 -0
  274. data/app/views/composites/mix_preset_list_item_label.jst.hamlc +8 -0
  275. data/app/views/composites/share_aside.jst.hamlc +7 -0
  276. data/app/views/doc/airplanes_list_item_label.jst.hamlc +3 -0
  277. data/app/views/doc/import_airplanes_aside.jst.hamlc +6 -0
  278. data/app/views/doc/share_aside.jst.hamlc +7 -0
  279. data/app/views/general/app.jst.hamlc +42 -0
  280. data/app/views/general/curves_list_item_label.jst.hamlc +5 -0
  281. data/app/views/general/help.jst.hamlc +7 -0
  282. data/app/views/general/tabs.jst.hamlc +6 -0
  283. data/app/views/index.haml +24 -0
  284. data/app/views/overview/app.jst.hamlc +7 -0
  285. data/app/views/overview/tile.jst.hamlc +4 -0
  286. data/bin/console +14 -0
  287. data/bin/setup +8 -0
  288. data/ela.gemspec +50 -0
  289. data/exe/ela +59 -0
  290. data/lib/ela.rb +8 -0
  291. data/lib/ela/jasmine.rb +87 -0
  292. data/lib/ela/server.rb +136 -0
  293. data/lib/ela/utils.rb +131 -0
  294. data/lib/ela/version.rb +3 -0
  295. data/package-lock.json +899 -0
  296. data/package.json +11 -0
  297. data/support/project/Guardfile +64 -0
  298. data/support/project/jasmine.yml +3 -0
  299. data/support/server.ru +5 -0
  300. metadata +4365 -0
@@ -0,0 +1,138 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.Legend extends Backbone.Poised.View
3
+ valueCurveColumnTemplate: _.template '
4
+ <div class="values col<%= activeClass %>"
5
+ data-index="<%= curveIndex %>"
6
+ style="color: <%= strokeColor %>; <%= borderStyle %>">
7
+ <div class="label"><%= label %></div>
8
+ </div>
9
+ '
10
+
11
+ simpleCurveColumnTemplate: _.template '
12
+ <div class="curve">
13
+ <div class="line" style="border-color: <%= strokeColor %>"></div>
14
+ <%= label %>
15
+ </div>
16
+ '
17
+
18
+ useValueAtRange: false
19
+
20
+ initialize: (options) ->
21
+ @model.on 'change:axisLabelingForCurve', @render
22
+ @model.curves.on 'change:selected', =>
23
+ @bindCalculatorEvents()
24
+ @render()
25
+ @model.on 'change:calculators', =>
26
+ @bindCalculatorEvents()
27
+ @render()
28
+ @bindCalculatorEvents()
29
+ @useValueAtRange = options.useValueAtRange
30
+ @valueAtRangeAxis = options.valueAtRangeAxis or 'x'
31
+ @valueAtRangeAttribute = options.valueAtRangeAttribute or 'valueAtRange'
32
+
33
+ @model.on "change:#{@valueAtRangeAttribute}", @render
34
+
35
+ events:
36
+ 'click .values.col': 'selectCurveForAxisLabeling'
37
+
38
+ selectCurveForAxisLabeling: (e) ->
39
+ index = parseInt($(e.currentTarget).data('index'))
40
+ @model.set
41
+ axisLabelingForCurve: @model.curves.at(index)
42
+
43
+ bindCalculatorEvents: ->
44
+ @stopListening()
45
+ for calc in @model.get('calculators')
46
+ for curve in @model.curves.models
47
+ @listenTo calc, "change:#{curve.get('function')}", @render
48
+
49
+ # Stub: Renders the header column.
50
+ # Override in your custom Legend view.
51
+ renderValueHeaderColumn: =>
52
+
53
+ # Returns the curves axis label according to the value of
54
+ # `@valueAtRangeAxis`.
55
+ #
56
+ # @return String The label for the specific axis.
57
+ curveLabel: (curve) =>
58
+ switch @valueAtRangeAxis
59
+ when 'x' then @Present(curve).fullYAxisLabel()
60
+ when 'y' then @Present(curve).fullXAxisLabel()
61
+
62
+ # Renders a simple curve column with values at range.
63
+ # This renders the `#valueCurveColumnTemplate`.
64
+ #
65
+ # @param [ELA.Models.Curve] curve The curve to render
66
+ renderValueCurveColumn: (curve) =>
67
+ return unless curve.showInLegend()
68
+
69
+ func = @calculatorFunction(curve)
70
+ ref = @calcs[0]?[func]?(@range)
71
+ isActive = curve is @labelingCurve
72
+ $curve = $ @valueCurveColumnTemplate
73
+ activeClass: if isActive then ' active' else ''
74
+ curveIndex: @model.curves.indexOf(curve)
75
+ strokeColor: curve.strokeStyle()
76
+ borderStyle: "border-color: #{curve.strokeStyle()}" if isActive
77
+ label: @curveLabel(curve)
78
+
79
+ for calc, i in @calcs
80
+ val = calc[func](@range)
81
+ if val?
82
+ unitValue = @Present(curve).unitValue(val)
83
+ if _.isArray(unitValue)
84
+ unitValue = _.compact(unitValue)
85
+ unitValue = _.map(unitValue, (v) -> v.toFixed(2))
86
+ label = "{#{unitValue.join(', ')}}"
87
+ else
88
+ label = unitValue.toFixed(2)
89
+ if ref and i > 0
90
+ diff = (val / ref * 100) - 100
91
+ label += " (#{diff.toFixed(2)}%)"
92
+ $curve.append("<div>#{label}</div>")
93
+ else
94
+ $curve.append("<div>#{t('legend.notAvailable')}</div>")
95
+ @$wrapper.append($curve)
96
+
97
+ # Renders the simple curve column without values at range.
98
+ # This renders the `#simpleCurveColumnTemplate`.
99
+ #
100
+ # @param [ELA.Models.Curve] curve The curve to render
101
+ # @param [Number] curveIndex The index in the legends curve list
102
+ renderSimpleCurveColumn: (curve, curveIndex) =>
103
+ return unless curve.showInLegend()
104
+ @$el.append $ @simpleCurveColumnTemplate
105
+ strokeColor: curve.strokeStyle()
106
+ label: @Present(curve).fullLabel()
107
+
108
+ # Used to determine which function to display.
109
+ # For interpolated Graphs you typically append `_value` to the curve
110
+ # function.
111
+ #
112
+ # @param [Curve] curve The curve to find the calulator function for
113
+ #
114
+ # @return [String] The identifier of the calculator function
115
+ calculatorFunction: (curve) ->
116
+ "#{curve.get('function')}_value"
117
+
118
+ render: =>
119
+ if @useValueAtRange
120
+ @range = @model.get(@valueAtRangeAttribute)
121
+ if @range?
122
+ @labelingCurve = @model.get('axisLabelingForCurve')
123
+ @calcs = @model.get('calculators')
124
+ @$wrapper = $('<div class="values-at-range scroll-x">')
125
+
126
+ @renderValueHeaderColumn()
127
+
128
+ _.each @model.curves.whereInHistory(), @renderValueCurveColumn
129
+
130
+ # Replace keeping horizontal scroll position
131
+ scrollLeft = @$el.find('.scroll-x').scrollLeft()
132
+ @$el.html(@$wrapper)
133
+ @$el.find('.scroll-x').scrollLeft(scrollLeft)
134
+ this
135
+ else
136
+ @$el.empty().addClass('legend-simple')
137
+ _.each @model.curves.whereInHistory(), @renderSimpleCurveColumn
138
+ this
@@ -0,0 +1,51 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.LegendHandler extends Backbone.Poised.View
3
+ events:
4
+ 'pan': 'updateRange'
5
+ 'tap': 'updateRange'
6
+
7
+ hammerjs:
8
+ recognizers: [
9
+ [Hammer.Rotate, { enable: false }],
10
+ [Hammer.Pinch, { enable: false }, ['rotate']],
11
+ [Hammer.Swipe, { enable: false }],
12
+ [Hammer.Pan, { direction: Hammer.DIRECTION_ALL, threshold: 1 }, ['swipe']],
13
+ [Hammer.Tap, { threshold: 5 }],
14
+ [Hammer.Press, { enable: false }]
15
+ ]
16
+
17
+ initialize: (options) ->
18
+ super
19
+ @axis = options.axis or 'x'
20
+ @attribute = options.attribute or @axis
21
+ @precision = @model.get('valueAtRangePrecision') # TODO: Make this obsolete
22
+ @precision ?= options.precision
23
+ @precision ?= 2
24
+
25
+ @listenTo @model, "change:#{@attribute}", @renderText
26
+
27
+ updateRange: (e) =>
28
+ origin = @model.displayParams.get("#{@axis}Origin")
29
+ range = @model.displayParams.get("#{@axis}Range")
30
+ if @axis is 'x'
31
+ width = @model.displayParams.get('width')
32
+ point = (range / width) * (e.gesture.pointers[0].clientX - origin)
33
+ else
34
+ height = @model.displayParams.get('height')
35
+ y = e.gesture.pointers[0].clientY - @$el.offset().top
36
+ y = Math.min(Math.max(y, 0), height)
37
+ point = (range / height) * (origin - y)
38
+
39
+ pow = Math.pow(10, @precision)
40
+ point = Math.round(point * pow) / pow
41
+ @model.set(@attribute, point)
42
+
43
+ renderText: =>
44
+ @$el.find('span').text(t(@model.name + '.legendHandler.label', 'legendHandler.label', value: @model.get(@attribute).toFixed(@precision)))
45
+
46
+ render: =>
47
+ @$el.html('<span class="hint"></span>')
48
+ @$el.toggleClass('orientation-x', @axis is 'x')
49
+ @$el.toggleClass('orientation-y', @axis is 'y')
50
+ @renderText()
51
+ this
@@ -0,0 +1,85 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.Overview extends Backbone.Poised.View
3
+ id: 'overview'
4
+ tagName: 'section'
5
+ className: 'active'
6
+
7
+ template: JST['overview/app']
8
+
9
+ events:
10
+ 'tap header .help.icon': 'showHelp'
11
+
12
+ hammerjs: true
13
+
14
+ keep: true
15
+
16
+ initialize: ->
17
+ $(window).resize @adjustDimensions
18
+
19
+ # Split the apps into their respective groups for easy grouping in
20
+ # Poised.List.
21
+ apps = _.chain(ELA.settings.apps)
22
+ .sortBy (app) ->
23
+ app.name
24
+ .map (app) ->
25
+ groups = ELA.settings[app].groups
26
+ if groups? and groups.length > 0
27
+ for group in groups
28
+ name: app
29
+ group: group
30
+ else
31
+ name: app
32
+ .flatten()
33
+ .value()
34
+
35
+ @collection = new Backbone.Collection(apps)
36
+
37
+ setActive: (val) ->
38
+ @$el.toggleClass('active', val)
39
+
40
+ activate: =>
41
+ @$el.toggleClass('active', true)
42
+
43
+ deactivate: =>
44
+ @$el.toggleClass('active', false)
45
+
46
+ showHelp: =>
47
+ ELA.router.navigate('about', trigger: true)
48
+
49
+ calculateTileSize: =>
50
+ # ul has 14px padding
51
+ width = @$el.width() - 2 * 14
52
+
53
+ # Stylus variables
54
+ tileSize = 200
55
+
56
+ columns = Math.ceil(width / tileSize)
57
+ Math.floor(Math.min(width / columns, tileSize))
58
+
59
+ adjustDimensions: =>
60
+ size = @calculateTileSize()
61
+ @$('.tile').each (i, elem) ->
62
+ $(elem).css
63
+ height: "#{size}px"
64
+ width: "#{size}px"
65
+
66
+ render: ->
67
+ @$el.html(@template())
68
+
69
+ if /Android.*Chrome/.test(navigator.userAgent)
70
+ @$('#chrome-android-flag-hint').css display: 'block'
71
+
72
+ @list = new Backbone.Poised.List
73
+ filterAttributes: []
74
+ collection: @collection
75
+ itemClass: ELA.Views.OverviewTile
76
+ group:
77
+ by: 'group'
78
+ sorting: ELA.settings.appGroups
79
+ collapsible: true
80
+ localePrefix: 'overview'
81
+ @$('article ul').replaceWith(@list.render().el)
82
+
83
+ delay @adjustDimensions
84
+
85
+ this
@@ -0,0 +1,18 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.OverviewTile extends Backbone.Poised.List.Item
3
+ tagName: 'li'
4
+ className: 'tile'
5
+ template: JST['overview/tile']
6
+
7
+ events:
8
+ 'click': 'loadApp'
9
+
10
+ loadApp: =>
11
+ if App = ELA[@model.get('name').toCapitalCamel()]?.Models.App
12
+ ELA.router.navigate("app/#{App::path}", trigger: true)
13
+ else
14
+ alert(t('overview.messages.not_implemented'))
15
+
16
+ render: =>
17
+ @$el.html @template @model.toJSON()
18
+ this
@@ -0,0 +1,12 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.ParametersAside extends ELA.Views.BaseAside
3
+ render: =>
4
+ @$el.addClass('scroll-y')
5
+ subview = @subviews.form = new Backbone.Poised.Form
6
+ model: @model
7
+ liveForm: true
8
+ parentView: this
9
+ localePrefix: @model.localePrefix()
10
+ @$el.html(subview.render().el)
11
+
12
+ this
@@ -0,0 +1,92 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.ThreeGraph extends ELA.Views.Canvas
3
+ class @Params extends Backbone.Model
4
+ serializedAttributes: ['zoom']
5
+
6
+ serialize: ->
7
+ _.pick(@attributes, @serializedAttributes)
8
+
9
+ deserialize: (attributes) ->
10
+ @set(attributes)
11
+
12
+ # A variable that contains temporary information about the pinch
13
+ # or pan action that is currently performed.
14
+ start: {}
15
+
16
+ events:
17
+ 'pinchstart': 'pinchstart'
18
+ 'pinch': 'pinch'
19
+ 'pinchend': 'pinchend'
20
+ 'mousewheel': 'mousewheel'
21
+ 'DOMMouseScroll': 'mousewheel'
22
+ 'doubletap': 'resetCanvas'
23
+
24
+ defaults:
25
+ zoom: 1
26
+
27
+ initialize: ->
28
+ if Modernizr.webgl
29
+ @renderer = new THREE.WebGLRenderer(canvas: @$el[0])
30
+ else
31
+ _.defer -> alert(t('messages.noWebGL'))
32
+ @renderer = new THREE.CanvasRenderer(canvas: @$el[0])
33
+ @renderer.setClearColor(0xffffff)
34
+
35
+ @camera = new THREE.PerspectiveCamera(45, null, 100, 1000)
36
+ @camera.position.z = 500
37
+
38
+ @scene = new THREE.Scene()
39
+ fog = new THREE.Fog(0xffffff, ELA.settings.laminateDeformation.graph.fogMinimumDistance, ELA.settings.laminateDeformation.graph.fogMaximumDistance)
40
+ @scene.fog = fog
41
+
42
+ super
43
+
44
+ @params.on('change:zoom', @requestRepaint)
45
+
46
+ new THREE.FontLoader().load(
47
+ 'ela/fonts/droid_sans_regular.typeface.svg'
48
+ (font) =>
49
+ @_droidSansRegularFont = font
50
+ @trigger('threeJsFontLoaded')
51
+ )
52
+
53
+ setCanvasResolution: ->
54
+ @renderer.setPixelRatio((window.devicePixelRatio || 1) * 2)
55
+
56
+ width = @params.get('width')
57
+ height = @params.get('height')
58
+
59
+ @renderer.setSize(width, height)
60
+ @camera.aspect = width / height
61
+ @requestRepaint()
62
+
63
+ mousewheel: (e) =>
64
+ e.preventDefault()
65
+ zoom = @params.get('zoom')
66
+ if e.originalEvent.wheelDelta > 0 or e.originalEvent.detail < 0
67
+ @params.set(zoom: zoom + 0.06)
68
+ else
69
+ return if zoom <= 0.06
70
+ @params.set(zoom: zoom - 0.06)
71
+
72
+ pinchstart: (e) =>
73
+ @start.zoom = @params.get('zoom')
74
+
75
+ pinch: (e) =>
76
+ if @params.get('zoom') > 0.01 or scale > 1
77
+ @params.set(zoom: @start.zoom * e.gesture.scale)
78
+
79
+ pinchend: (e) =>
80
+ # Do not call pan events on transformend
81
+ @hammer.stop()
82
+
83
+ resetCanvas: =>
84
+ @params.set
85
+ zoom: @defaults.zoom
86
+
87
+ render: =>
88
+ @camera.zoom = @params.get('zoom')
89
+ @camera.updateProjectionMatrix()
90
+ @renderer.render(@scene, @camera)
91
+
92
+ this
@@ -0,0 +1,1519 @@
1
+ "use strict";
2
+ var Markdown;
3
+
4
+ if (typeof exports === "object" && typeof require === "function") // we're in a CommonJS (e.g. Node.js) module
5
+ Markdown = exports;
6
+ else
7
+ Markdown = {};
8
+
9
+ // The following text is included for historical reasons, but should
10
+ // be taken with a pinch of salt; it's not all true anymore.
11
+
12
+ //
13
+ // Wherever possible, Showdown is a straight, line-by-line port
14
+ // of the Perl version of Markdown.
15
+ //
16
+ // This is not a normal parser design; it's basically just a
17
+ // series of string substitutions. It's hard to read and
18
+ // maintain this way, but keeping Showdown close to the original
19
+ // design makes it easier to port new features.
20
+ //
21
+ // More importantly, Showdown behaves like markdown.pl in most
22
+ // edge cases. So web applications can do client-side preview
23
+ // in Javascript, and then build identical HTML on the server.
24
+ //
25
+ // This port needs the new RegExp functionality of ECMA 262,
26
+ // 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
27
+ // should do fine. Even with the new regular expression features,
28
+ // We do a lot of work to emulate Perl's regex functionality.
29
+ // The tricky changes in this file mostly have the "attacklab:"
30
+ // label. Major or self-explanatory changes don't.
31
+ //
32
+ // Smart diff tools like Araxis Merge will be able to match up
33
+ // this file with markdown.pl in a useful way. A little tweaking
34
+ // helps: in a copy of markdown.pl, replace "#" with "//" and
35
+ // replace "$text" with "text". Be sure to ignore whitespace
36
+ // and line endings.
37
+ //
38
+
39
+
40
+ //
41
+ // Usage:
42
+ //
43
+ // var text = "Markdown *rocks*.";
44
+ //
45
+ // var converter = new Markdown.Converter();
46
+ // var html = converter.makeHtml(text);
47
+ //
48
+ // alert(html);
49
+ //
50
+ // Note: move the sample code to the bottom of this
51
+ // file before uncommenting it.
52
+ //
53
+
54
+ (function () {
55
+
56
+ function identity(x) { return x; }
57
+ function returnFalse(x) { return false; }
58
+
59
+ function HookCollection() { }
60
+
61
+ HookCollection.prototype = {
62
+
63
+ chain: function (hookname, func) {
64
+ var original = this[hookname];
65
+ if (!original)
66
+ throw new Error("unknown hook " + hookname);
67
+
68
+ if (original === identity)
69
+ this[hookname] = func;
70
+ else
71
+ this[hookname] = function (text) {
72
+ var args = Array.prototype.slice.call(arguments, 0);
73
+ args[0] = original.apply(null, args);
74
+ return func.apply(null, args);
75
+ };
76
+ },
77
+ set: function (hookname, func) {
78
+ if (!this[hookname])
79
+ throw new Error("unknown hook " + hookname);
80
+ this[hookname] = func;
81
+ },
82
+ addNoop: function (hookname) {
83
+ this[hookname] = identity;
84
+ },
85
+ addFalse: function (hookname) {
86
+ this[hookname] = returnFalse;
87
+ }
88
+ };
89
+
90
+ Markdown.HookCollection = HookCollection;
91
+
92
+ // g_urls and g_titles allow arbitrary user-entered strings as keys. This
93
+ // caused an exception (and hence stopped the rendering) when the user entered
94
+ // e.g. [push] or [__proto__]. Adding a prefix to the actual key prevents this
95
+ // (since no builtin property starts with "s_"). See
96
+ // http://meta.stackexchange.com/questions/64655/strange-wmd-bug
97
+ // (granted, switching from Array() to Object() alone would have left only __proto__
98
+ // to be a problem)
99
+ function SaveHash() { }
100
+ SaveHash.prototype = {
101
+ set: function (key, value) {
102
+ this["s_" + key] = value;
103
+ },
104
+ get: function (key) {
105
+ return this["s_" + key];
106
+ }
107
+ };
108
+
109
+ Markdown.Converter = function (OPTIONS) {
110
+ var pluginHooks = this.hooks = new HookCollection();
111
+
112
+ // given a URL that was encountered by itself (without markup), should return the link text that's to be given to this link
113
+ pluginHooks.addNoop("plainLinkText");
114
+
115
+ // called with the orignal text as given to makeHtml. The result of this plugin hook is the actual markdown source that will be cooked
116
+ pluginHooks.addNoop("preConversion");
117
+
118
+ // called with the text once all normalizations have been completed (tabs to spaces, line endings, etc.), but before any conversions have
119
+ pluginHooks.addNoop("postNormalization");
120
+
121
+ // Called with the text before / after creating block elements like code blocks and lists. Note that this is called recursively
122
+ // with inner content, e.g. it's called with the full text, and then only with the content of a blockquote. The inner
123
+ // call will receive outdented text.
124
+ pluginHooks.addNoop("preBlockGamut");
125
+ pluginHooks.addNoop("postBlockGamut");
126
+
127
+ // called with the text of a single block element before / after the span-level conversions (bold, code spans, etc.) have been made
128
+ pluginHooks.addNoop("preSpanGamut");
129
+ pluginHooks.addNoop("postSpanGamut");
130
+
131
+ // called with the final cooked HTML code. The result of this plugin hook is the actual output of makeHtml
132
+ pluginHooks.addNoop("postConversion");
133
+
134
+ //
135
+ // Private state of the converter instance:
136
+ //
137
+
138
+ // Global hashes, used by various utility routines
139
+ var g_urls;
140
+ var g_titles;
141
+ var g_html_blocks;
142
+
143
+ // Used to track when we're inside an ordered or unordered list
144
+ // (see _ProcessListItems() for details):
145
+ var g_list_level;
146
+
147
+ OPTIONS = OPTIONS || {};
148
+ var asciify = identity, deasciify = identity;
149
+ if (OPTIONS.nonAsciiLetters) {
150
+
151
+ /* In JavaScript regular expressions, \w only denotes [a-zA-Z0-9_].
152
+ * That's why there's inconsistent handling e.g. with intra-word bolding
153
+ * of Japanese words. That's why we do the following if OPTIONS.nonAsciiLetters
154
+ * is true:
155
+ *
156
+ * Before doing bold and italics, we find every instance
157
+ * of a unicode word character in the Markdown source that is not
158
+ * matched by \w, and the letter "Q". We take the character's code point
159
+ * and encode it in base 51, using the "digits"
160
+ *
161
+ * A, B, ..., P, R, ..., Y, Z, a, b, ..., y, z
162
+ *
163
+ * delimiting it with "Q" on both sides. For example, the source
164
+ *
165
+ * > In Chinese, the smurfs are called 藍精靈, meaning "blue spirits".
166
+ *
167
+ * turns into
168
+ *
169
+ * > In Chinese, the smurfs are called QNIhQQMOIQQOuUQ, meaning "blue spirits".
170
+ *
171
+ * Since everything that is a letter in Unicode is now a letter (or
172
+ * several letters) in ASCII, \w and \b should always do the right thing.
173
+ *
174
+ * After the bold/italic conversion, we decode again; since "Q" was encoded
175
+ * alongside all non-ascii characters (as "QBfQ"), and the conversion
176
+ * will not generate "Q", the only instances of that letter should be our
177
+ * encoded characters. And since the conversion will not break words, the
178
+ * "Q...Q" should all still be in one piece.
179
+ *
180
+ * We're using "Q" as the delimiter because it's probably one of the
181
+ * rarest characters, and also because I can't think of any special behavior
182
+ * that would ever be triggered by this letter (to use a silly example, if we
183
+ * delimited with "H" on the left and "P" on the right, then "Ψ" would be
184
+ * encoded as "HTTP", which may cause special behavior). The latter would not
185
+ * actually be a huge issue for bold/italic, but may be if we later use it
186
+ * in other places as well.
187
+ * */
188
+ (function () {
189
+ var lettersThatJavaScriptDoesNotKnowAndQ = /[Q\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376-\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0523\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0621-\u064a\u0660-\u0669\u066e-\u066f\u0671-\u06d3\u06d5\u06e5-\u06e6\u06ee-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07c0-\u07ea\u07f4-\u07f5\u07fa\u0904-\u0939\u093d\u0950\u0958-\u0961\u0966-\u096f\u0971-\u0972\u097b-\u097f\u0985-\u098c\u098f-\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc-\u09dd\u09df-\u09e1\u09e6-\u09f1\u0a05-\u0a0a\u0a0f-\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32-\u0a33\u0a35-\u0a36\u0a38-\u0a39\u0a59-\u0a5c\u0a5e\u0a66-\u0a6f\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2-\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0-\u0ae1\u0ae6-\u0aef\u0b05-\u0b0c\u0b0f-\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32-\u0b33\u0b35-\u0b39\u0b3d\u0b5c-\u0b5d\u0b5f-\u0b61\u0b66-\u0b6f\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99-\u0b9a\u0b9c\u0b9e-\u0b9f\u0ba3-\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0be6-\u0bef\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58-\u0c59\u0c60-\u0c61\u0c66-\u0c6f\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0-\u0ce1\u0ce6-\u0cef\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d28\u0d2a-\u0d39\u0d3d\u0d60-\u0d61\u0d66-\u0d6f\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32-\u0e33\u0e40-\u0e46\u0e50-\u0e59\u0e81-\u0e82\u0e84\u0e87-\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa-\u0eab\u0ead-\u0eb0\u0eb2-\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0ed0-\u0ed9\u0edc-\u0edd\u0f00\u0f20-\u0f29\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8b\u1000-\u102a\u103f-\u1049\u1050-\u1055\u105a-\u105d\u1061\u1065-\u1066\u106e-\u1070\u1075-\u1081\u108e\u1090-\u1099\u10a0-\u10c5\u10d0-\u10fa\u10fc\u1100-\u1159\u115f-\u11a2\u11a8-\u11f9\u1200-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u1676\u1681-\u169a\u16a0-\u16ea\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u17e0-\u17e9\u1810-\u1819\u1820-\u1877\u1880-\u18a8\u18aa\u1900-\u191c\u1946-\u196d\u1970-\u1974\u1980-\u19a9\u19c1-\u19c7\u19d0-\u19d9\u1a00-\u1a16\u1b05-\u1b33\u1b45-\u1b4b\u1b50-\u1b59\u1b83-\u1ba0\u1bae-\u1bb9\u1c00-\u1c23\u1c40-\u1c49\u1c4d-\u1c7d\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u203f-\u2040\u2054\u2071\u207f\u2090-\u2094\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2183-\u2184\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2c6f\u2c71-\u2c7d\u2c80-\u2ce4\u2d00-\u2d25\u2d30-\u2d65\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3006\u3031-\u3035\u303b-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31b7\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fc3\ua000-\ua48c\ua500-\ua60c\ua610-\ua62b\ua640-\ua65f\ua662-\ua66e\ua67f-\ua697\ua717-\ua71f\ua722-\ua788\ua78b-\ua78c\ua7fb-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8d0-\ua8d9\ua900-\ua925\ua930-\ua946\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa50-\uaa59\uac00-\ud7a3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe33-\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]/g;
190
+ var cp_Q = "Q".charCodeAt(0);
191
+ var cp_A = "A".charCodeAt(0);
192
+ var cp_Z = "Z".charCodeAt(0);
193
+ var dist_Za = "a".charCodeAt(0) - cp_Z - 1;
194
+
195
+ asciify = function(text) {
196
+ return text.replace(lettersThatJavaScriptDoesNotKnowAndQ, function (m) {
197
+ var c = m.charCodeAt(0);
198
+ var s = "";
199
+ var v;
200
+ while (c > 0) {
201
+ v = (c % 51) + cp_A;
202
+ if (v >= cp_Q)
203
+ v++;
204
+ if (v > cp_Z)
205
+ v += dist_Za;
206
+ s = String.fromCharCode(v) + s;
207
+ c = c / 51 | 0;
208
+ }
209
+ return "Q" + s + "Q";
210
+ })
211
+ };
212
+
213
+ deasciify = function(text) {
214
+ return text.replace(/Q([A-PR-Za-z]{1,3})Q/g, function (m, s) {
215
+ var c = 0;
216
+ var v;
217
+ for (var i = 0; i < s.length; i++) {
218
+ v = s.charCodeAt(i);
219
+ if (v > cp_Z)
220
+ v -= dist_Za;
221
+ if (v > cp_Q)
222
+ v--;
223
+ v -= cp_A;
224
+ c = (c * 51) + v;
225
+ }
226
+ return String.fromCharCode(c);
227
+ })
228
+ }
229
+ })();
230
+ }
231
+
232
+ this.makeHtml = function (text) {
233
+
234
+ //
235
+ // Main function. The order in which other subs are called here is
236
+ // essential. Link and image substitutions need to happen before
237
+ // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
238
+ // and <img> tags get encoded.
239
+ //
240
+
241
+ // This will only happen if makeHtml on the same converter instance is called from a plugin hook.
242
+ // Don't do that.
243
+ if (g_urls)
244
+ throw new Error("Recursive call to converter.makeHtml");
245
+
246
+ // Create the private state objects.
247
+ g_urls = new SaveHash();
248
+ g_titles = new SaveHash();
249
+ g_html_blocks = [];
250
+ g_list_level = 0;
251
+
252
+ text = pluginHooks.preConversion(text);
253
+
254
+ // attacklab: Replace ~ with ~T
255
+ // This lets us use tilde as an escape char to avoid md5 hashes
256
+ // The choice of character is arbitray; anything that isn't
257
+ // magic in Markdown will work.
258
+ text = text.replace(/~/g, "~T");
259
+
260
+ // attacklab: Replace $ with ~D
261
+ // RegExp interprets $ as a special character
262
+ // when it's in a replacement string
263
+ text = text.replace(/\$/g, "~D");
264
+
265
+ // Standardize line endings
266
+ text = text.replace(/\r\n/g, "\n"); // DOS to Unix
267
+ text = text.replace(/\r/g, "\n"); // Mac to Unix
268
+
269
+ // Make sure text begins and ends with a couple of newlines:
270
+ text = "\n\n" + text + "\n\n";
271
+
272
+ // Convert all tabs to spaces.
273
+ text = _Detab(text);
274
+
275
+ // Strip any lines consisting only of spaces and tabs.
276
+ // This makes subsequent regexen easier to write, because we can
277
+ // match consecutive blank lines with /\n+/ instead of something
278
+ // contorted like /[ \t]*\n+/ .
279
+ text = text.replace(/^[ \t]+$/mg, "");
280
+
281
+ text = pluginHooks.postNormalization(text);
282
+
283
+ // Turn block-level HTML blocks into hash entries
284
+ text = _HashHTMLBlocks(text);
285
+
286
+ // Strip link definitions, store in hashes.
287
+ text = _StripLinkDefinitions(text);
288
+
289
+ text = _RunBlockGamut(text);
290
+
291
+ text = _UnescapeSpecialChars(text);
292
+
293
+ // attacklab: Restore dollar signs
294
+ text = text.replace(/~D/g, "$$");
295
+
296
+ // attacklab: Restore tildes
297
+ text = text.replace(/~T/g, "~");
298
+
299
+ text = pluginHooks.postConversion(text);
300
+
301
+ g_html_blocks = g_titles = g_urls = null;
302
+
303
+ return text;
304
+ };
305
+
306
+ function _StripLinkDefinitions(text) {
307
+ //
308
+ // Strips link definitions from text, stores the URLs and titles in
309
+ // hash references.
310
+ //
311
+
312
+ // Link defs are in the form: ^[id]: url "optional title"
313
+
314
+ /*
315
+ text = text.replace(/
316
+ ^[ ]{0,3}\[([^\[\]]+)\]: // id = $1 attacklab: g_tab_width - 1
317
+ [ \t]*
318
+ \n? // maybe *one* newline
319
+ [ \t]*
320
+ <?(\S+?)>? // url = $2
321
+ (?=\s|$) // lookahead for whitespace instead of the lookbehind removed below
322
+ [ \t]*
323
+ \n? // maybe one newline
324
+ [ \t]*
325
+ ( // (potential) title = $3
326
+ (\n*) // any lines skipped = $4 attacklab: lookbehind removed
327
+ [ \t]+
328
+ ["(]
329
+ (.+?) // title = $5
330
+ [")]
331
+ [ \t]*
332
+ )? // title is optional
333
+ (?:\n+|$)
334
+ /gm, function(){...});
335
+ */
336
+
337
+ text = text.replace(/^[ ]{0,3}\[([^\[\]]+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,
338
+ function (wholeMatch, m1, m2, m3, m4, m5) {
339
+ m1 = m1.toLowerCase();
340
+ g_urls.set(m1, _EncodeAmpsAndAngles(m2)); // Link IDs are case-insensitive
341
+ if (m4) {
342
+ // Oops, found blank lines, so it's not a title.
343
+ // Put back the parenthetical statement we stole.
344
+ return m3;
345
+ } else if (m5) {
346
+ g_titles.set(m1, m5.replace(/"/g, "&quot;"));
347
+ }
348
+
349
+ // Completely remove the definition from the text
350
+ return "";
351
+ }
352
+ );
353
+
354
+ return text;
355
+ }
356
+
357
+ function _HashHTMLBlocks(text) {
358
+
359
+ // Hashify HTML blocks:
360
+ // We only want to do this for block-level HTML tags, such as headers,
361
+ // lists, and tables. That's because we still want to wrap <p>s around
362
+ // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
363
+ // phrase emphasis, and spans. The list of tags we're looking for is
364
+ // hard-coded:
365
+ var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
366
+ var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
367
+
368
+ // First, look for nested blocks, e.g.:
369
+ // <div>
370
+ // <div>
371
+ // tags for inner block must be indented.
372
+ // </div>
373
+ // </div>
374
+ //
375
+ // The outermost tags must start at the left margin for this to match, and
376
+ // the inner nested divs must be indented.
377
+ // We need to do this before the next, more liberal match, because the next
378
+ // match will start at the first `<div>` and stop at the first `</div>`.
379
+
380
+ // attacklab: This regex can be expensive when it fails.
381
+
382
+ /*
383
+ text = text.replace(/
384
+ ( // save in $1
385
+ ^ // start of line (with /m)
386
+ <($block_tags_a) // start tag = $2
387
+ \b // word break
388
+ // attacklab: hack around khtml/pcre bug...
389
+ [^\r]*?\n // any number of lines, minimally matching
390
+ </\2> // the matching end tag
391
+ [ \t]* // trailing spaces/tabs
392
+ (?=\n+) // followed by a newline
393
+ ) // attacklab: there are sentinel newlines at end of document
394
+ /gm,function(){...}};
395
+ */
396
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm, hashMatch);
397
+
398
+ //
399
+ // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
400
+ //
401
+
402
+ /*
403
+ text = text.replace(/
404
+ ( // save in $1
405
+ ^ // start of line (with /m)
406
+ <($block_tags_b) // start tag = $2
407
+ \b // word break
408
+ // attacklab: hack around khtml/pcre bug...
409
+ [^\r]*? // any number of lines, minimally matching
410
+ .*</\2> // the matching end tag
411
+ [ \t]* // trailing spaces/tabs
412
+ (?=\n+) // followed by a newline
413
+ ) // attacklab: there are sentinel newlines at end of document
414
+ /gm,function(){...}};
415
+ */
416
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm, hashMatch);
417
+
418
+ // Special case just for <hr />. It was easier to make a special case than
419
+ // to make the other regex more complicated.
420
+
421
+ /*
422
+ text = text.replace(/
423
+ \n // Starting after a blank line
424
+ [ ]{0,3}
425
+ ( // save in $1
426
+ (<(hr) // start tag = $2
427
+ \b // word break
428
+ ([^<>])*?
429
+ \/?>) // the matching end tag
430
+ [ \t]*
431
+ (?=\n{2,}) // followed by a blank line
432
+ )
433
+ /g,hashMatch);
434
+ */
435
+ text = text.replace(/\n[ ]{0,3}((<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, hashMatch);
436
+
437
+ // Special case for standalone HTML comments:
438
+
439
+ /*
440
+ text = text.replace(/
441
+ \n\n // Starting after a blank line
442
+ [ ]{0,3} // attacklab: g_tab_width - 1
443
+ ( // save in $1
444
+ <!
445
+ (--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--) // see http://www.w3.org/TR/html-markup/syntax.html#comments and http://meta.stackexchange.com/q/95256
446
+ >
447
+ [ \t]*
448
+ (?=\n{2,}) // followed by a blank line
449
+ )
450
+ /g,hashMatch);
451
+ */
452
+ text = text.replace(/\n\n[ ]{0,3}(<!(--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>[ \t]*(?=\n{2,}))/g, hashMatch);
453
+
454
+ // PHP and ASP-style processor instructions (<?...?> and <%...%>)
455
+
456
+ /*
457
+ text = text.replace(/
458
+ (?:
459
+ \n\n // Starting after a blank line
460
+ )
461
+ ( // save in $1
462
+ [ ]{0,3} // attacklab: g_tab_width - 1
463
+ (?:
464
+ <([?%]) // $2
465
+ [^\r]*?
466
+ \2>
467
+ )
468
+ [ \t]*
469
+ (?=\n{2,}) // followed by a blank line
470
+ )
471
+ /g,hashMatch);
472
+ */
473
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, hashMatch);
474
+
475
+ return text;
476
+ }
477
+
478
+ function hashBlock(text) {
479
+ text = text.replace(/(^\n+|\n+$)/g, "");
480
+ // Replace the element text with a marker ("~KxK" where x is its key)
481
+ return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n";
482
+ }
483
+
484
+ function hashMatch(wholeMatch, m1) {
485
+ return hashBlock(m1);
486
+ }
487
+
488
+ var blockGamutHookCallback = function (t) { return _RunBlockGamut(t); }
489
+
490
+ function _RunBlockGamut(text, doNotUnhash) {
491
+ //
492
+ // These are all the transformations that form block-level
493
+ // tags like paragraphs, headers, and list items.
494
+ //
495
+
496
+ text = pluginHooks.preBlockGamut(text, blockGamutHookCallback);
497
+
498
+ text = _DoHeaders(text);
499
+
500
+ // Do Horizontal Rules:
501
+ var replacement = "<hr />\n";
502
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, replacement);
503
+ text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$/gm, replacement);
504
+ text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, replacement);
505
+
506
+ text = _DoLists(text);
507
+ text = _DoCodeBlocks(text);
508
+ text = _DoBlockQuotes(text);
509
+
510
+ text = pluginHooks.postBlockGamut(text, blockGamutHookCallback);
511
+
512
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that
513
+ // was to escape raw HTML in the original Markdown source. This time,
514
+ // we're escaping the markup we've just created, so that we don't wrap
515
+ // <p> tags around block-level tags.
516
+ text = _HashHTMLBlocks(text);
517
+ text = _FormParagraphs(text, doNotUnhash);
518
+
519
+ return text;
520
+ }
521
+
522
+ function _RunSpanGamut(text) {
523
+ //
524
+ // These are all the transformations that occur *within* block-level
525
+ // tags like paragraphs, headers, and list items.
526
+ //
527
+
528
+ text = pluginHooks.preSpanGamut(text);
529
+
530
+ text = _DoCodeSpans(text);
531
+ text = _EscapeSpecialCharsWithinTagAttributes(text);
532
+ text = _EncodeBackslashEscapes(text);
533
+
534
+ // Process anchor and image tags. Images must come first,
535
+ // because ![foo][f] looks like an anchor.
536
+ text = _DoImages(text);
537
+ text = _DoAnchors(text);
538
+
539
+ // Make links out of things like `<http://example.com/>`
540
+ // Must come after _DoAnchors(), because you can use < and >
541
+ // delimiters in inline links like [this](<url>).
542
+ text = _DoAutoLinks(text);
543
+
544
+ text = text.replace(/~P/g, "://"); // put in place to prevent autolinking; reset now
545
+
546
+ text = _EncodeAmpsAndAngles(text);
547
+ text = _DoItalicsAndBold(text);
548
+
549
+ // Do hard breaks:
550
+ text = text.replace(/ +\n/g, " <br>\n");
551
+
552
+ text = pluginHooks.postSpanGamut(text);
553
+
554
+ return text;
555
+ }
556
+
557
+ function _EscapeSpecialCharsWithinTagAttributes(text) {
558
+ //
559
+ // Within tags -- meaning between < and > -- encode [\ ` * _] so they
560
+ // don't conflict with their use in Markdown for code, italics and strong.
561
+ //
562
+
563
+ // Build a regex to find HTML tags and comments. See Friedl's
564
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
565
+
566
+ // SE: changed the comment part of the regex
567
+
568
+ var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi;
569
+
570
+ text = text.replace(regex, function (wholeMatch) {
571
+ var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`");
572
+ tag = escapeCharacters(tag, wholeMatch.charAt(1) == "!" ? "\\`*_/" : "\\`*_"); // also escape slashes in comments to prevent autolinking there -- http://meta.stackexchange.com/questions/95987
573
+ return tag;
574
+ });
575
+
576
+ return text;
577
+ }
578
+
579
+ function _DoAnchors(text) {
580
+ //
581
+ // Turn Markdown link shortcuts into XHTML <a> tags.
582
+ //
583
+ //
584
+ // First, handle reference-style links: [link text] [id]
585
+ //
586
+
587
+ /*
588
+ text = text.replace(/
589
+ ( // wrap whole match in $1
590
+ \[
591
+ (
592
+ (?:
593
+ \[[^\]]*\] // allow brackets nested one level
594
+ |
595
+ [^\[] // or anything else
596
+ )*
597
+ )
598
+ \]
599
+
600
+ [ ]? // one optional space
601
+ (?:\n[ ]*)? // one optional newline followed by spaces
602
+
603
+ \[
604
+ (.*?) // id = $3
605
+ \]
606
+ )
607
+ ()()()() // pad remaining backreferences
608
+ /g, writeAnchorTag);
609
+ */
610
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag);
611
+
612
+ //
613
+ // Next, inline-style links: [link text](url "optional title")
614
+ //
615
+
616
+ /*
617
+ text = text.replace(/
618
+ ( // wrap whole match in $1
619
+ \[
620
+ (
621
+ (?:
622
+ \[[^\]]*\] // allow brackets nested one level
623
+ |
624
+ [^\[\]] // or anything else
625
+ )*
626
+ )
627
+ \]
628
+ \( // literal paren
629
+ [ \t]*
630
+ () // no id, so leave $3 empty
631
+ <?( // href = $4
632
+ (?:
633
+ \([^)]*\) // allow one level of (correctly nested) parens (think MSDN)
634
+ |
635
+ [^()\s]
636
+ )*?
637
+ )>?
638
+ [ \t]*
639
+ ( // $5
640
+ (['"]) // quote char = $6
641
+ (.*?) // Title = $7
642
+ \6 // matching quote
643
+ [ \t]* // ignore any spaces/tabs between closing quote and )
644
+ )? // title is optional
645
+ \)
646
+ )
647
+ /g, writeAnchorTag);
648
+ */
649
+
650
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?((?:\([^)]*\)|[^()\s])*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag);
651
+
652
+ //
653
+ // Last, handle reference-style shortcuts: [link text]
654
+ // These must come last in case you've also got [link test][1]
655
+ // or [link test](/foo)
656
+ //
657
+
658
+ /*
659
+ text = text.replace(/
660
+ ( // wrap whole match in $1
661
+ \[
662
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']'
663
+ \]
664
+ )
665
+ ()()()()() // pad rest of backreferences
666
+ /g, writeAnchorTag);
667
+ */
668
+ text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
669
+
670
+ return text;
671
+ }
672
+
673
+ function writeAnchorTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
674
+ if (m7 == undefined) m7 = "";
675
+ var whole_match = m1;
676
+ var link_text = m2.replace(/:\/\//g, "~P"); // to prevent auto-linking withing the link. will be converted back after the auto-linker runs
677
+ var link_id = m3.toLowerCase();
678
+ var url = m4;
679
+ var title = m7;
680
+
681
+ if (url == "") {
682
+ if (link_id == "") {
683
+ // lower-case and turn embedded newlines into spaces
684
+ link_id = link_text.toLowerCase().replace(/ ?\n/g, " ");
685
+ }
686
+ url = "#" + link_id;
687
+
688
+ if (g_urls.get(link_id) != undefined) {
689
+ url = g_urls.get(link_id);
690
+ if (g_titles.get(link_id) != undefined) {
691
+ title = g_titles.get(link_id);
692
+ }
693
+ }
694
+ else {
695
+ if (whole_match.search(/\(\s*\)$/m) > -1) {
696
+ // Special case for explicit empty url
697
+ url = "";
698
+ } else {
699
+ return whole_match;
700
+ }
701
+ }
702
+ }
703
+ url = encodeProblemUrlChars(url);
704
+ url = escapeCharacters(url, "*_");
705
+ var result = "<a href=\"" + url + "\"";
706
+
707
+ if (title != "") {
708
+ title = attributeEncode(title);
709
+ title = escapeCharacters(title, "*_");
710
+ result += " title=\"" + title + "\"";
711
+ }
712
+
713
+ result += ">" + link_text + "</a>";
714
+
715
+ return result;
716
+ }
717
+
718
+ function _DoImages(text) {
719
+ //
720
+ // Turn Markdown image shortcuts into <img> tags.
721
+ //
722
+
723
+ //
724
+ // First, handle reference-style labeled images: ![alt text][id]
725
+ //
726
+
727
+ /*
728
+ text = text.replace(/
729
+ ( // wrap whole match in $1
730
+ !\[
731
+ (.*?) // alt text = $2
732
+ \]
733
+
734
+ [ ]? // one optional space
735
+ (?:\n[ ]*)? // one optional newline followed by spaces
736
+
737
+ \[
738
+ (.*?) // id = $3
739
+ \]
740
+ )
741
+ ()()()() // pad rest of backreferences
742
+ /g, writeImageTag);
743
+ */
744
+ text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag);
745
+
746
+ //
747
+ // Next, handle inline images: ![alt text](url "optional title")
748
+ // Don't forget: encode * and _
749
+
750
+ /*
751
+ text = text.replace(/
752
+ ( // wrap whole match in $1
753
+ !\[
754
+ (.*?) // alt text = $2
755
+ \]
756
+ \s? // One optional whitespace character
757
+ \( // literal paren
758
+ [ \t]*
759
+ () // no id, so leave $3 empty
760
+ <?(\S+?)>? // src url = $4
761
+ [ \t]*
762
+ ( // $5
763
+ (['"]) // quote char = $6
764
+ (.*?) // title = $7
765
+ \6 // matching quote
766
+ [ \t]*
767
+ )? // title is optional
768
+ \)
769
+ )
770
+ /g, writeImageTag);
771
+ */
772
+ text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag);
773
+
774
+ return text;
775
+ }
776
+
777
+ function attributeEncode(text) {
778
+ // unconditionally replace angle brackets here -- what ends up in an attribute (e.g. alt or title)
779
+ // never makes sense to have verbatim HTML in it (and the sanitizer would totally break it)
780
+ return text.replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
781
+ }
782
+
783
+ function writeImageTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
784
+ var whole_match = m1;
785
+ var alt_text = m2;
786
+ var link_id = m3.toLowerCase();
787
+ var url = m4;
788
+ var title = m7;
789
+
790
+ if (!title) title = "";
791
+
792
+ if (url == "") {
793
+ if (link_id == "") {
794
+ // lower-case and turn embedded newlines into spaces
795
+ link_id = alt_text.toLowerCase().replace(/ ?\n/g, " ");
796
+ }
797
+ url = "#" + link_id;
798
+
799
+ if (g_urls.get(link_id) != undefined) {
800
+ url = g_urls.get(link_id);
801
+ if (g_titles.get(link_id) != undefined) {
802
+ title = g_titles.get(link_id);
803
+ }
804
+ }
805
+ else {
806
+ return whole_match;
807
+ }
808
+ }
809
+
810
+ alt_text = escapeCharacters(attributeEncode(alt_text), "*_[]()");
811
+ url = escapeCharacters(url, "*_");
812
+ var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
813
+
814
+ // attacklab: Markdown.pl adds empty title attributes to images.
815
+ // Replicate this bug.
816
+
817
+ //if (title != "") {
818
+ title = attributeEncode(title);
819
+ title = escapeCharacters(title, "*_");
820
+ result += " title=\"" + title + "\"";
821
+ //}
822
+
823
+ result += " />";
824
+
825
+ return result;
826
+ }
827
+
828
+ function _DoHeaders(text) {
829
+
830
+ // Setext-style headers:
831
+ // Header 1
832
+ // ========
833
+ //
834
+ // Header 2
835
+ // --------
836
+ //
837
+ text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
838
+ function (wholeMatch, m1) { return "<h1>" + _RunSpanGamut(m1) + "</h1>\n\n"; }
839
+ );
840
+
841
+ text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
842
+ function (matchFound, m1) { return "<h2>" + _RunSpanGamut(m1) + "</h2>\n\n"; }
843
+ );
844
+
845
+ // atx-style headers:
846
+ // # Header 1
847
+ // ## Header 2
848
+ // ## Header 2 with closing hashes ##
849
+ // ...
850
+ // ###### Header 6
851
+ //
852
+
853
+ /*
854
+ text = text.replace(/
855
+ ^(\#{1,6}) // $1 = string of #'s
856
+ [ \t]*
857
+ (.+?) // $2 = Header text
858
+ [ \t]*
859
+ \#* // optional closing #'s (not counted)
860
+ \n+
861
+ /gm, function() {...});
862
+ */
863
+
864
+ text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
865
+ function (wholeMatch, m1, m2) {
866
+ var h_level = m1.length;
867
+ return "<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">\n\n";
868
+ }
869
+ );
870
+
871
+ return text;
872
+ }
873
+
874
+ function _DoLists(text, isInsideParagraphlessListItem) {
875
+ //
876
+ // Form HTML ordered (numbered) and unordered (bulleted) lists.
877
+ //
878
+
879
+ // attacklab: add sentinel to hack around khtml/safari bug:
880
+ // http://bugs.webkit.org/show_bug.cgi?id=11231
881
+ text += "~0";
882
+
883
+ // Re-usable pattern to match any entirel ul or ol list:
884
+
885
+ /*
886
+ var whole_list = /
887
+ ( // $1 = whole list
888
+ ( // $2
889
+ [ ]{0,3} // attacklab: g_tab_width - 1
890
+ ([*+-]|\d+[.]) // $3 = first list item marker
891
+ [ \t]+
892
+ )
893
+ [^\r]+?
894
+ ( // $4
895
+ ~0 // sentinel for workaround; should be $
896
+ |
897
+ \n{2,}
898
+ (?=\S)
899
+ (?! // Negative lookahead for another list item marker
900
+ [ \t]*
901
+ (?:[*+-]|\d+[.])[ \t]+
902
+ )
903
+ )
904
+ )
905
+ /g
906
+ */
907
+ var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
908
+
909
+ if (g_list_level) {
910
+ text = text.replace(whole_list, function (wholeMatch, m1, m2) {
911
+ var list = m1;
912
+ var list_type = (m2.search(/[*+-]/g) > -1) ? "ul" : "ol";
913
+
914
+ var result = _ProcessListItems(list, list_type, isInsideParagraphlessListItem);
915
+
916
+ // Trim any trailing whitespace, to put the closing `</$list_type>`
917
+ // up on the preceding line, to get it past the current stupid
918
+ // HTML block parser. This is a hack to work around the terrible
919
+ // hack that is the HTML block parser.
920
+ result = result.replace(/\s+$/, "");
921
+ result = "<" + list_type + ">" + result + "</" + list_type + ">\n";
922
+ return result;
923
+ });
924
+ } else {
925
+ whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
926
+ text = text.replace(whole_list, function (wholeMatch, m1, m2, m3) {
927
+ var runup = m1;
928
+ var list = m2;
929
+
930
+ var list_type = (m3.search(/[*+-]/g) > -1) ? "ul" : "ol";
931
+ var result = _ProcessListItems(list, list_type);
932
+ result = runup + "<" + list_type + ">\n" + result + "</" + list_type + ">\n";
933
+ return result;
934
+ });
935
+ }
936
+
937
+ // attacklab: strip sentinel
938
+ text = text.replace(/~0/, "");
939
+
940
+ return text;
941
+ }
942
+
943
+ var _listItemMarkers = { ol: "\\d+[.]", ul: "[*+-]" };
944
+
945
+ function _ProcessListItems(list_str, list_type, isInsideParagraphlessListItem) {
946
+ //
947
+ // Process the contents of a single ordered or unordered list, splitting it
948
+ // into individual list items.
949
+ //
950
+ // list_type is either "ul" or "ol".
951
+
952
+ // The $g_list_level global keeps track of when we're inside a list.
953
+ // Each time we enter a list, we increment it; when we leave a list,
954
+ // we decrement. If it's zero, we're not in a list anymore.
955
+ //
956
+ // We do this because when we're not inside a list, we want to treat
957
+ // something like this:
958
+ //
959
+ // I recommend upgrading to version
960
+ // 8. Oops, now this line is treated
961
+ // as a sub-list.
962
+ //
963
+ // As a single paragraph, despite the fact that the second line starts
964
+ // with a digit-period-space sequence.
965
+ //
966
+ // Whereas when we're inside a list (or sub-list), that line will be
967
+ // treated as the start of a sub-list. What a kludge, huh? This is
968
+ // an aspect of Markdown's syntax that's hard to parse perfectly
969
+ // without resorting to mind-reading. Perhaps the solution is to
970
+ // change the syntax rules such that sub-lists must start with a
971
+ // starting cardinal number; e.g. "1." or "a.".
972
+
973
+ g_list_level++;
974
+
975
+ // trim trailing blank lines:
976
+ list_str = list_str.replace(/\n{2,}$/, "\n");
977
+
978
+ // attacklab: add sentinel to emulate \z
979
+ list_str += "~0";
980
+
981
+ // In the original attacklab showdown, list_type was not given to this function, and anything
982
+ // that matched /[*+-]|\d+[.]/ would just create the next <li>, causing this mismatch:
983
+ //
984
+ // Markdown rendered by WMD rendered by MarkdownSharp
985
+ // ------------------------------------------------------------------
986
+ // 1. first 1. first 1. first
987
+ // 2. second 2. second 2. second
988
+ // - third 3. third * third
989
+ //
990
+ // We changed this to behave identical to MarkdownSharp. This is the constructed RegEx,
991
+ // with {MARKER} being one of \d+[.] or [*+-], depending on list_type:
992
+
993
+ /*
994
+ list_str = list_str.replace(/
995
+ (^[ \t]*) // leading whitespace = $1
996
+ ({MARKER}) [ \t]+ // list marker = $2
997
+ ([^\r]+? // list item text = $3
998
+ (\n+)
999
+ )
1000
+ (?=
1001
+ (~0 | \2 ({MARKER}) [ \t]+)
1002
+ )
1003
+ /gm, function(){...});
1004
+ */
1005
+
1006
+ var marker = _listItemMarkers[list_type];
1007
+ var re = new RegExp("(^[ \\t]*)(" + marker + ")[ \\t]+([^\\r]+?(\\n+))(?=(~0|\\1(" + marker + ")[ \\t]+))", "gm");
1008
+ var last_item_had_a_double_newline = false;
1009
+ list_str = list_str.replace(re,
1010
+ function (wholeMatch, m1, m2, m3) {
1011
+ var item = m3;
1012
+ var leading_space = m1;
1013
+ var ends_with_double_newline = /\n\n$/.test(item);
1014
+ var contains_double_newline = ends_with_double_newline || item.search(/\n{2,}/) > -1;
1015
+
1016
+ if (contains_double_newline || last_item_had_a_double_newline) {
1017
+ item = _RunBlockGamut(_Outdent(item), /* doNotUnhash = */true);
1018
+ }
1019
+ else {
1020
+ // Recursion for sub-lists:
1021
+ item = _DoLists(_Outdent(item), /* isInsideParagraphlessListItem= */ true);
1022
+ item = item.replace(/\n$/, ""); // chomp(item)
1023
+ if (!isInsideParagraphlessListItem) // only the outer-most item should run this, otherwise it's run multiple times for the inner ones
1024
+ item = _RunSpanGamut(item);
1025
+ }
1026
+ last_item_had_a_double_newline = ends_with_double_newline;
1027
+ return "<li>" + item + "</li>\n";
1028
+ }
1029
+ );
1030
+
1031
+ // attacklab: strip sentinel
1032
+ list_str = list_str.replace(/~0/g, "");
1033
+
1034
+ g_list_level--;
1035
+ return list_str;
1036
+ }
1037
+
1038
+ function _DoCodeBlocks(text) {
1039
+ //
1040
+ // Process Markdown `<pre><code>` blocks.
1041
+ //
1042
+
1043
+ /*
1044
+ text = text.replace(/
1045
+ (?:\n\n|^)
1046
+ ( // $1 = the code block -- one or more lines, starting with a space/tab
1047
+ (?:
1048
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
1049
+ .*\n+
1050
+ )+
1051
+ )
1052
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
1053
+ /g ,function(){...});
1054
+ */
1055
+
1056
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
1057
+ text += "~0";
1058
+
1059
+ text = text.replace(/(?:\n\n|^\n?)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
1060
+ function (wholeMatch, m1, m2) {
1061
+ var codeblock = m1;
1062
+ var nextChar = m2;
1063
+
1064
+ codeblock = _EncodeCode(_Outdent(codeblock));
1065
+ codeblock = _Detab(codeblock);
1066
+ codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
1067
+ codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
1068
+
1069
+ codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
1070
+
1071
+ return "\n\n" + codeblock + "\n\n" + nextChar;
1072
+ }
1073
+ );
1074
+
1075
+ // attacklab: strip sentinel
1076
+ text = text.replace(/~0/, "");
1077
+
1078
+ return text;
1079
+ }
1080
+
1081
+ function _DoCodeSpans(text) {
1082
+ //
1083
+ // * Backtick quotes are used for <code></code> spans.
1084
+ //
1085
+ // * You can use multiple backticks as the delimiters if you want to
1086
+ // include literal backticks in the code span. So, this input:
1087
+ //
1088
+ // Just type ``foo `bar` baz`` at the prompt.
1089
+ //
1090
+ // Will translate to:
1091
+ //
1092
+ // <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
1093
+ //
1094
+ // There's no arbitrary limit to the number of backticks you
1095
+ // can use as delimters. If you need three consecutive backticks
1096
+ // in your code, use four for delimiters, etc.
1097
+ //
1098
+ // * You can use spaces to get literal backticks at the edges:
1099
+ //
1100
+ // ... type `` `bar` `` ...
1101
+ //
1102
+ // Turns to:
1103
+ //
1104
+ // ... type <code>`bar`</code> ...
1105
+ //
1106
+
1107
+ /*
1108
+ text = text.replace(/
1109
+ (^|[^\\`]) // Character before opening ` can't be a backslash or backtick
1110
+ (`+) // $2 = Opening run of `
1111
+ (?!`) // and no more backticks -- match the full run
1112
+ ( // $3 = The code block
1113
+ [^\r]*?
1114
+ [^`] // attacklab: work around lack of lookbehind
1115
+ )
1116
+ \2 // Matching closer
1117
+ (?!`)
1118
+ /gm, function(){...});
1119
+ */
1120
+
1121
+ text = text.replace(/(^|[^\\`])(`+)(?!`)([^\r]*?[^`])\2(?!`)/gm,
1122
+ function (wholeMatch, m1, m2, m3, m4) {
1123
+ var c = m3;
1124
+ c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
1125
+ c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
1126
+ c = _EncodeCode(c);
1127
+ c = c.replace(/:\/\//g, "~P"); // to prevent auto-linking. Not necessary in code *blocks*, but in code spans. Will be converted back after the auto-linker runs.
1128
+ return m1 + "<code>" + c + "</code>";
1129
+ }
1130
+ );
1131
+
1132
+ return text;
1133
+ }
1134
+
1135
+ function _EncodeCode(text) {
1136
+ //
1137
+ // Encode/escape certain characters inside Markdown code runs.
1138
+ // The point is that in code, these characters are literals,
1139
+ // and lose their special Markdown meanings.
1140
+ //
1141
+ // Encode all ampersands; HTML entities are not
1142
+ // entities within a Markdown code span.
1143
+ text = text.replace(/&/g, "&amp;");
1144
+
1145
+ // Do the angle bracket song and dance:
1146
+ text = text.replace(/</g, "&lt;");
1147
+ text = text.replace(/>/g, "&gt;");
1148
+
1149
+ // Now, escape characters that are magic in Markdown:
1150
+ text = escapeCharacters(text, "\*_{}[]\\", false);
1151
+
1152
+ // jj the line above breaks this:
1153
+ //---
1154
+
1155
+ //* Item
1156
+
1157
+ // 1. Subitem
1158
+
1159
+ // special char: *
1160
+ //---
1161
+
1162
+ return text;
1163
+ }
1164
+
1165
+ function _DoItalicsAndBold(text) {
1166
+
1167
+ text = asciify(text);
1168
+
1169
+ // <strong> must go first:
1170
+
1171
+ // (^|[\W_]) Start with a non-letter or beginning of string. Store in \1.
1172
+ // (?:(?!\1)|(?=^)) Either the next character is *not* the same as the previous,
1173
+ // or we started at the end of the string (in which case the previous
1174
+ // group had zero width, so we're still there). Because the next
1175
+ // character is the marker, this means that if there are e.g. multiple
1176
+ // underscores in a row, we can only match the left-most ones (which
1177
+ // prevents foo___bar__ from getting bolded)
1178
+ // (\*|_) The marker character itself, asterisk or underscore. Store in \2.
1179
+ // \2 The marker again, since bold needs two.
1180
+ // (?=\S) The first bolded character cannot be a space.
1181
+ // ([^\r]*?\S) The actual bolded string. At least one character, and it cannot *end*
1182
+ // with a space either. Note that like in many other places, [^\r] is
1183
+ // just a workaround for JS' lack of single-line regexes; it's equivalent
1184
+ // to a . in an /s regex, because the string cannot contain any \r (they
1185
+ // are removed in the normalizing step).
1186
+ // \2\2 The marker character, twice -- end of bold.
1187
+ // (?!\2) Not followed by another marker character (ensuring that we match the
1188
+ // rightmost two in a longer row)...
1189
+ // (?=[\W_]|$) ...but by any other non-word character or the end of string.
1190
+ text = text.replace(/(^|[\W_])(?:(?!\1)|(?=^))(\*|_)\2(?=\S)([^\r]*?\S)\2\2(?!\2)(?=[\W_]|$)/g,
1191
+ "$1<strong>$3</strong>");
1192
+
1193
+ // This is almost identical to the <strong> regex, except 1) there's obviously just one marker
1194
+ // character, and 2) the italicized string cannot contain the marker character.
1195
+ text = text.replace(/(^|[\W_])(?:(?!\1)|(?=^))(\*|_)(?=\S)((?:(?!\2)[^\r])*?\S)\2(?!\2)(?=[\W_]|$)/g,
1196
+ "$1<em>$3</em>");
1197
+
1198
+ return deasciify(text);
1199
+ }
1200
+
1201
+ function _DoBlockQuotes(text) {
1202
+
1203
+ /*
1204
+ text = text.replace(/
1205
+ ( // Wrap whole match in $1
1206
+ (
1207
+ ^[ \t]*>[ \t]? // '>' at the start of a line
1208
+ .+\n // rest of the first line
1209
+ (.+\n)* // subsequent consecutive lines
1210
+ \n* // blanks
1211
+ )+
1212
+ )
1213
+ /gm, function(){...});
1214
+ */
1215
+
1216
+ text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
1217
+ function (wholeMatch, m1) {
1218
+ var bq = m1;
1219
+
1220
+ // attacklab: hack around Konqueror 3.5.4 bug:
1221
+ // "----------bug".replace(/^-/g,"") == "bug"
1222
+
1223
+ bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); // trim one level of quoting
1224
+
1225
+ // attacklab: clean up hack
1226
+ bq = bq.replace(/~0/g, "");
1227
+
1228
+ bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines
1229
+ bq = _RunBlockGamut(bq); // recurse
1230
+
1231
+ bq = bq.replace(/(^|\n)/g, "$1 ");
1232
+ // These leading spaces screw with <pre> content, so we need to fix that:
1233
+ bq = bq.replace(
1234
+ /(\s*<pre>[^\r]+?<\/pre>)/gm,
1235
+ function (wholeMatch, m1) {
1236
+ var pre = m1;
1237
+ // attacklab: hack around Konqueror 3.5.4 bug:
1238
+ pre = pre.replace(/^ /mg, "~0");
1239
+ pre = pre.replace(/~0/g, "");
1240
+ return pre;
1241
+ });
1242
+
1243
+ return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
1244
+ }
1245
+ );
1246
+ return text;
1247
+ }
1248
+
1249
+ function _FormParagraphs(text, doNotUnhash) {
1250
+ //
1251
+ // Params:
1252
+ // $text - string to process with html <p> tags
1253
+ //
1254
+
1255
+ // Strip leading and trailing lines:
1256
+ text = text.replace(/^\n+/g, "");
1257
+ text = text.replace(/\n+$/g, "");
1258
+
1259
+ var grafs = text.split(/\n{2,}/g);
1260
+ var grafsOut = [];
1261
+
1262
+ var markerRe = /~K(\d+)K/;
1263
+
1264
+ //
1265
+ // Wrap <p> tags.
1266
+ //
1267
+ var end = grafs.length;
1268
+ for (var i = 0; i < end; i++) {
1269
+ var str = grafs[i];
1270
+
1271
+ // if this is an HTML marker, copy it
1272
+ if (markerRe.test(str)) {
1273
+ grafsOut.push(str);
1274
+ }
1275
+ else if (/\S/.test(str)) {
1276
+ str = _RunSpanGamut(str);
1277
+ str = str.replace(/^([ \t]*)/g, "<p>");
1278
+ str += "</p>"
1279
+ grafsOut.push(str);
1280
+ }
1281
+
1282
+ }
1283
+ //
1284
+ // Unhashify HTML blocks
1285
+ //
1286
+ if (!doNotUnhash) {
1287
+ end = grafsOut.length;
1288
+ for (var i = 0; i < end; i++) {
1289
+ var foundAny = true;
1290
+ while (foundAny) { // we may need several runs, since the data may be nested
1291
+ foundAny = false;
1292
+ grafsOut[i] = grafsOut[i].replace(/~K(\d+)K/g, function (wholeMatch, id) {
1293
+ foundAny = true;
1294
+ return g_html_blocks[id];
1295
+ });
1296
+ }
1297
+ }
1298
+ }
1299
+ return grafsOut.join("\n\n");
1300
+ }
1301
+
1302
+ function _EncodeAmpsAndAngles(text) {
1303
+ // Smart processing for ampersands and angle brackets that need to be encoded.
1304
+
1305
+ // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1306
+ // http://bumppo.net/projects/amputator/
1307
+ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, "&amp;");
1308
+
1309
+ // Encode naked <'s
1310
+ text = text.replace(/<(?![a-z\/?!]|~D)/gi, "&lt;");
1311
+
1312
+ return text;
1313
+ }
1314
+
1315
+ function _EncodeBackslashEscapes(text) {
1316
+ //
1317
+ // Parameter: String.
1318
+ // Returns: The string, with after processing the following backslash
1319
+ // escape sequences.
1320
+ //
1321
+
1322
+ // attacklab: The polite way to do this is with the new
1323
+ // escapeCharacters() function:
1324
+ //
1325
+ // text = escapeCharacters(text,"\\",true);
1326
+ // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
1327
+ //
1328
+ // ...but we're sidestepping its use of the (slow) RegExp constructor
1329
+ // as an optimization for Firefox. This function gets called a LOT.
1330
+
1331
+ text = text.replace(/\\(\\)/g, escapeCharacters_callback);
1332
+ text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, escapeCharacters_callback);
1333
+ return text;
1334
+ }
1335
+
1336
+ var charInsideUrl = "[-A-Z0-9+&@#/%?=~_|[\\]()!:,.;]",
1337
+ charEndingUrl = "[-A-Z0-9+&@#/%=~_|[\\])]",
1338
+ autoLinkRegex = new RegExp("(=\"|<)?\\b(https?|ftp)(://" + charInsideUrl + "*" + charEndingUrl + ")(?=$|\\W)", "gi"),
1339
+ endCharRegex = new RegExp(charEndingUrl, "i");
1340
+
1341
+ function handleTrailingParens(wholeMatch, lookbehind, protocol, link) {
1342
+ if (lookbehind)
1343
+ return wholeMatch;
1344
+ if (link.charAt(link.length - 1) !== ")")
1345
+ return "<" + protocol + link + ">";
1346
+ var parens = link.match(/[()]/g);
1347
+ var level = 0;
1348
+ for (var i = 0; i < parens.length; i++) {
1349
+ if (parens[i] === "(") {
1350
+ if (level <= 0)
1351
+ level = 1;
1352
+ else
1353
+ level++;
1354
+ }
1355
+ else {
1356
+ level--;
1357
+ }
1358
+ }
1359
+ var tail = "";
1360
+ if (level < 0) {
1361
+ var re = new RegExp("\\){1," + (-level) + "}$");
1362
+ link = link.replace(re, function (trailingParens) {
1363
+ tail = trailingParens;
1364
+ return "";
1365
+ });
1366
+ }
1367
+ if (tail) {
1368
+ var lastChar = link.charAt(link.length - 1);
1369
+ if (!endCharRegex.test(lastChar)) {
1370
+ tail = lastChar + tail;
1371
+ link = link.substr(0, link.length - 1);
1372
+ }
1373
+ }
1374
+ return "<" + protocol + link + ">" + tail;
1375
+ }
1376
+
1377
+ function _DoAutoLinks(text) {
1378
+
1379
+ // note that at this point, all other URL in the text are already hyperlinked as <a href=""></a>
1380
+ // *except* for the <http://www.foo.com> case
1381
+
1382
+ // automatically add < and > around unadorned raw hyperlinks
1383
+ // must be preceded by a non-word character (and not by =" or <) and followed by non-word/EOF character
1384
+ // simulating the lookbehind in a consuming way is okay here, since a URL can neither and with a " nor
1385
+ // with a <, so there is no risk of overlapping matches.
1386
+ text = text.replace(autoLinkRegex, handleTrailingParens);
1387
+
1388
+ // autolink anything like <http://example.com>
1389
+
1390
+
1391
+ var replacer = function (wholematch, m1) {
1392
+ var url = encodeProblemUrlChars(m1);
1393
+ url = escapeCharacters(url, "*_");
1394
+
1395
+ return "<a href=\"" + url + "\">" + pluginHooks.plainLinkText(m1) + "</a>";
1396
+ };
1397
+ text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, replacer);
1398
+
1399
+ // Email addresses: <address@domain.foo>
1400
+ /*
1401
+ text = text.replace(/
1402
+ <
1403
+ (?:mailto:)?
1404
+ (
1405
+ [-.\w]+
1406
+ \@
1407
+ [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
1408
+ )
1409
+ >
1410
+ /gi, _DoAutoLinks_callback());
1411
+ */
1412
+
1413
+ /* disabling email autolinking, since we don't do that on the server, either
1414
+ text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
1415
+ function(wholeMatch,m1) {
1416
+ return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
1417
+ }
1418
+ );
1419
+ */
1420
+ return text;
1421
+ }
1422
+
1423
+ function _UnescapeSpecialChars(text) {
1424
+ //
1425
+ // Swap back in all the special characters we've hidden.
1426
+ //
1427
+ text = text.replace(/~E(\d+)E/g,
1428
+ function (wholeMatch, m1) {
1429
+ var charCodeToReplace = parseInt(m1);
1430
+ return String.fromCharCode(charCodeToReplace);
1431
+ }
1432
+ );
1433
+ return text;
1434
+ }
1435
+
1436
+ function _Outdent(text) {
1437
+ //
1438
+ // Remove one level of line-leading tabs or spaces
1439
+ //
1440
+
1441
+ // attacklab: hack around Konqueror 3.5.4 bug:
1442
+ // "----------bug".replace(/^-/g,"") == "bug"
1443
+
1444
+ text = text.replace(/^(\t|[ ]{1,4})/gm, "~0"); // attacklab: g_tab_width
1445
+
1446
+ // attacklab: clean up hack
1447
+ text = text.replace(/~0/g, "")
1448
+
1449
+ return text;
1450
+ }
1451
+
1452
+ function _Detab(text) {
1453
+ if (!/\t/.test(text))
1454
+ return text;
1455
+
1456
+ var spaces = [" ", " ", " ", " "],
1457
+ skew = 0,
1458
+ v;
1459
+
1460
+ return text.replace(/[\n\t]/g, function (match, offset) {
1461
+ if (match === "\n") {
1462
+ skew = offset + 1;
1463
+ return match;
1464
+ }
1465
+ v = (offset - skew) % 4;
1466
+ skew = offset + 1;
1467
+ return spaces[v];
1468
+ });
1469
+ }
1470
+
1471
+ //
1472
+ // attacklab: Utility functions
1473
+ //
1474
+
1475
+ var _problemUrlChars = /(?:["'*()[\]:]|~D)/g;
1476
+
1477
+ // hex-encodes some unusual "problem" chars in URLs to avoid URL detection problems
1478
+ function encodeProblemUrlChars(url) {
1479
+ if (!url)
1480
+ return "";
1481
+
1482
+ var len = url.length;
1483
+
1484
+ return url.replace(_problemUrlChars, function (match, offset) {
1485
+ if (match == "~D") // escape for dollar
1486
+ return "%24";
1487
+ if (match == ":") {
1488
+ if (offset == len - 1 || /[0-9\/]/.test(url.charAt(offset + 1)))
1489
+ return ":"
1490
+ }
1491
+ return "%" + match.charCodeAt(0).toString(16);
1492
+ });
1493
+ }
1494
+
1495
+
1496
+ function escapeCharacters(text, charsToEscape, afterBackslash) {
1497
+ // First we have to escape the escape characters so that
1498
+ // we can build a character class out of them
1499
+ var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g, "\\$1") + "])";
1500
+
1501
+ if (afterBackslash) {
1502
+ regexString = "\\\\" + regexString;
1503
+ }
1504
+
1505
+ var regex = new RegExp(regexString, "g");
1506
+ text = text.replace(regex, escapeCharacters_callback);
1507
+
1508
+ return text;
1509
+ }
1510
+
1511
+
1512
+ function escapeCharacters_callback(wholeMatch, m1) {
1513
+ var charCodeToEscape = m1.charCodeAt(0);
1514
+ return "~E" + charCodeToEscape + "E";
1515
+ }
1516
+
1517
+ }; // end of the Markdown.Converter constructor
1518
+
1519
+ })();