dependabot-linguist 0.0.1 → 0.212.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +25 -3
  3. data/Gemfile +0 -9
  4. data/Gemfile.lock +162 -5
  5. data/LICENSE +674 -1
  6. data/{LICENSE.Nonstandard → LICENSE.dependabot-core} +0 -0
  7. data/Makefile +8 -1
  8. data/README.md +39 -5
  9. data/demo_script.rb +50 -0
  10. data/dependabot-linguist.gemspec +16 -5
  11. data/devlog.md +186 -0
  12. data/exe/dependabot-linguist +145 -0
  13. data/lib/dependabot/linguist/dependabot_file_validator.rb +190 -0
  14. data/lib/dependabot/linguist/dependabot_patch.rb +8 -0
  15. data/lib/dependabot/linguist/file_fetchers/base.rb +48 -0
  16. data/lib/dependabot/linguist/file_fetchers/git_submodules.rb +63 -0
  17. data/lib/dependabot/linguist/file_fetchers/go_modules.rb +41 -0
  18. data/lib/dependabot/linguist/language.rb +62 -0
  19. data/lib/dependabot/linguist/languages_to_ecosystems/contexts.rb +234 -0
  20. data/lib/dependabot/linguist/languages_to_ecosystems/contexts_applied.rb +36 -0
  21. data/lib/dependabot/linguist/languages_to_ecosystems/languages.yaml +7950 -0
  22. data/lib/dependabot/linguist/languages_to_ecosystems/main.rb +55 -0
  23. data/lib/dependabot/linguist/languages_to_ecosystems/manager_ecosystem_maps.rb +154 -0
  24. data/lib/dependabot/linguist/languages_to_patch.txt +37 -0
  25. data/lib/dependabot/linguist/linguist_patch.rb +6 -0
  26. data/lib/dependabot/linguist/repository.rb +232 -0
  27. data/lib/dependabot/linguist/version.rb +1 -1
  28. data/lib/dependabot/linguist.rb +5 -2
  29. data/smoke-test/README.md +58 -0
  30. data/smoke-test/bundler/Gemfile +9 -0
  31. data/smoke-test/bundler/Gemfile.lock +47 -0
  32. data/smoke-test/bundler/dependabot-all-updates-test-staging.gemspec +10 -0
  33. data/smoke-test/cargo/Cargo.lock +90 -0
  34. data/smoke-test/cargo/Cargo.toml +8 -0
  35. data/smoke-test/composer/composer.json +5 -0
  36. data/smoke-test/composer/composer.lock +72 -0
  37. data/smoke-test/composer/vendor/autoload.php +7 -0
  38. data/smoke-test/composer/vendor/composer/ClassLoader.php +445 -0
  39. data/smoke-test/composer/vendor/composer/LICENSE +21 -0
  40. data/smoke-test/composer/vendor/composer/autoload_classmap.php +13 -0
  41. data/smoke-test/composer/vendor/composer/autoload_namespaces.php +9 -0
  42. data/smoke-test/composer/vendor/composer/autoload_psr4.php +9 -0
  43. data/smoke-test/composer/vendor/composer/autoload_real.php +55 -0
  44. data/smoke-test/composer/vendor/composer/autoload_static.php +23 -0
  45. data/smoke-test/composer/vendor/composer/installed.json +57 -0
  46. data/smoke-test/composer/vendor/phpmailer/phpmailer/.gitignore +3 -0
  47. data/smoke-test/composer/vendor/phpmailer/phpmailer/LICENSE +504 -0
  48. data/smoke-test/composer/vendor/phpmailer/phpmailer/README.md +112 -0
  49. data/smoke-test/composer/vendor/phpmailer/phpmailer/changelog.md +530 -0
  50. data/smoke-test/composer/vendor/phpmailer/phpmailer/class.phpmailer.php +2758 -0
  51. data/smoke-test/composer/vendor/phpmailer/phpmailer/class.pop3.php +417 -0
  52. data/smoke-test/composer/vendor/phpmailer/phpmailer/class.smtp.php +1075 -0
  53. data/smoke-test/composer/vendor/phpmailer/phpmailer/composer.json +32 -0
  54. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/Callback_function_notes.txt +17 -0
  55. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/DomainKeys_notes.txt +55 -0
  56. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/Note_for_SMTP_debugging.txt +23 -0
  57. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/extending.html +148 -0
  58. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/faq.html +67 -0
  59. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/generatedocs.sh +4 -0
  60. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/pop3_article.txt +39 -0
  61. data/smoke-test/composer/vendor/phpmailer/phpmailer/docs/use_gmail.txt +44 -0
  62. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/contents.html +20 -0
  63. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/images/phpmailer.gif +0 -0
  64. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/images/phpmailer_mini.gif +0 -0
  65. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/index.html +50 -0
  66. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_db_smtp_basic.php +58 -0
  67. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_mail_advanced.php +30 -0
  68. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_mail_basic.php +41 -0
  69. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_pop_before_smtp_advanced.php +39 -0
  70. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_pop_before_smtp_basic.php +49 -0
  71. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_sendmail_advanced.php +33 -0
  72. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_sendmail_basic.php +43 -0
  73. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_advanced.php +42 -0
  74. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_advanced_no_auth.php +36 -0
  75. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_basic.php +58 -0
  76. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_basic_no_auth.php +53 -0
  77. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_gmail_advanced.php +42 -0
  78. data/smoke-test/composer/vendor/phpmailer/phpmailer/examples/test_smtp_gmail_basic.php +59 -0
  79. data/smoke-test/composer/vendor/phpmailer/phpmailer/extras/class.html2text.inc +489 -0
  80. data/smoke-test/composer/vendor/phpmailer/phpmailer/extras/htmlfilter.php +861 -0
  81. data/smoke-test/composer/vendor/phpmailer/phpmailer/extras/ntlm_sasl_client.php +185 -0
  82. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ar.php +26 -0
  83. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-br.php +25 -0
  84. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php +25 -0
  85. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ch.php +25 -0
  86. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-cz.php +24 -0
  87. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php +24 -0
  88. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-dk.php +25 -0
  89. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-es.php +25 -0
  90. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php +25 -0
  91. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php +26 -0
  92. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-fo.php +26 -0
  93. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php +24 -0
  94. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php +24 -0
  95. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php +26 -0
  96. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php +25 -0
  97. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-nl.php +24 -0
  98. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-no.php +24 -0
  99. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php +24 -0
  100. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php +26 -0
  101. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-ru.php +24 -0
  102. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-se.php +25 -0
  103. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php +25 -0
  104. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php +26 -0
  105. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php +25 -0
  106. data/smoke-test/composer/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php +25 -0
  107. data/smoke-test/composer/vendor/phpmailer/phpmailer/test/contents.html +10 -0
  108. data/smoke-test/composer/vendor/phpmailer/phpmailer/test/phpmailerTest.php +1084 -0
  109. data/smoke-test/composer/vendor/phpmailer/phpmailer/test/test.png +0 -0
  110. data/smoke-test/composer/vendor/phpmailer/phpmailer/test/test_callback.php +84 -0
  111. data/smoke-test/composer/vendor/phpmailer/phpmailer/test/testemail.php +48 -0
  112. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/LGPLv3.txt +165 -0
  113. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/contents.html +14 -0
  114. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/images/aikido.gif +0 -0
  115. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/images/bkgrnd.gif +0 -0
  116. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/images/phpmailer.gif +0 -0
  117. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/index.php +427 -0
  118. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/clipboard.swf +0 -0
  119. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushBash.js +59 -0
  120. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushCSharp.js +64 -0
  121. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushCpp.js +99 -0
  122. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushCss.js +93 -0
  123. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushDelphi.js +57 -0
  124. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushDiff.js +43 -0
  125. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushGroovy.js +69 -0
  126. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushJScript.js +51 -0
  127. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushJava.js +55 -0
  128. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushPerl.js +74 -0
  129. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushPhp.js +91 -0
  130. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushPlain.js +35 -0
  131. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushPython.js +56 -0
  132. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushRuby.js +57 -0
  133. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushScala.js +53 -0
  134. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushSql.js +68 -0
  135. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushVb.js +58 -0
  136. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shBrushXml.js +71 -0
  137. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shCore.js +30 -0
  138. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/scripts/shLegacy.js +30 -0
  139. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/src/shCore.js +1949 -0
  140. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/src/shLegacy.js +172 -0
  141. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/help.png +0 -0
  142. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/magnifier.png +0 -0
  143. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/page_white_code.png +0 -0
  144. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/page_white_copy.png +0 -0
  145. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/printer.png +0 -0
  146. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shCore.css +321 -0
  147. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeDefault.css +191 -0
  148. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeDjango.css +193 -0
  149. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeEmacs.css +192 -0
  150. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeFadeToGrey.css +193 -0
  151. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeMidnight.css +192 -0
  152. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/shThemeRDark.css +192 -0
  153. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/styles/wrapping.png +0 -0
  154. data/smoke-test/composer/vendor/phpmailer/phpmailer/test_script/test.html +46 -0
  155. data/smoke-test/dependabot-file/no-config/.github/TARGET.yaml +14 -0
  156. data/smoke-test/dependabot-file/no-config/bundler/Gemfile +9 -0
  157. data/smoke-test/dependabot-file/no-config/bundler/Gemfile.lock +47 -0
  158. data/smoke-test/dependabot-file/no-config/bundler/dependabot-all-updates-test-staging.gemspec +10 -0
  159. data/smoke-test/dependabot-file/no-config/cargo/Cargo.lock +90 -0
  160. data/smoke-test/dependabot-file/no-config/cargo/Cargo.toml +8 -0
  161. data/smoke-test/dependabot-file/no-config/composer/composer.json +5 -0
  162. data/smoke-test/dependabot-file/no-config/composer/composer.lock +72 -0
  163. data/smoke-test/dependabot-file/over-config/.github/TARGET.yaml +17 -0
  164. data/smoke-test/dependabot-file/over-config/.github/dependabot.yaml +12 -0
  165. data/smoke-test/dependabot-file/over-config/bundler/Gemfile +9 -0
  166. data/smoke-test/dependabot-file/over-config/bundler/Gemfile.lock +47 -0
  167. data/smoke-test/dependabot-file/over-config/bundler/dependabot-all-updates-test-staging.gemspec +10 -0
  168. data/smoke-test/dependabot-file/over-config/cargo/Cargo.lock +90 -0
  169. data/smoke-test/dependabot-file/over-config/cargo/Cargo.toml +8 -0
  170. data/smoke-test/dependabot-file/over-config/composer/composer.json +5 -0
  171. data/smoke-test/dependabot-file/over-config/composer/composer.lock +72 -0
  172. data/smoke-test/dependabot-file/overer-config/.github/TARGET.yaml +19 -0
  173. data/smoke-test/dependabot-file/overer-config/.github/dependabot.yaml +12 -0
  174. data/smoke-test/dependabot-file/overer-config/bundler/Gemfile +9 -0
  175. data/smoke-test/dependabot-file/overer-config/bundler/Gemfile.lock +47 -0
  176. data/smoke-test/dependabot-file/overer-config/bundler/dependabot-all-updates-test-staging.gemspec +10 -0
  177. data/smoke-test/dependabot-file/overer-config/cargo/Cargo.lock +90 -0
  178. data/smoke-test/dependabot-file/overer-config/cargo/Cargo.toml +8 -0
  179. data/smoke-test/dependabot-file/overer-config/composer/composer.json +5 -0
  180. data/smoke-test/dependabot-file/overer-config/composer/composer.lock +72 -0
  181. data/smoke-test/dependabot-file/partial-config/.github/TARGET.yaml +17 -0
  182. data/smoke-test/dependabot-file/partial-config/.github/dependabot.yaml +7 -0
  183. data/smoke-test/dependabot-file/partial-config/bundler/Gemfile +9 -0
  184. data/smoke-test/dependabot-file/partial-config/bundler/Gemfile.lock +47 -0
  185. data/smoke-test/dependabot-file/partial-config/bundler/dependabot-all-updates-test-staging.gemspec +10 -0
  186. data/smoke-test/dependabot-file/partial-config/cargo/Cargo.lock +90 -0
  187. data/smoke-test/dependabot-file/partial-config/cargo/Cargo.toml +8 -0
  188. data/smoke-test/dependabot-file/partial-config/composer/composer.json +5 -0
  189. data/smoke-test/dependabot-file/partial-config/composer/composer.lock +72 -0
  190. data/smoke-test/docker/Dockerfile +19 -0
  191. data/smoke-test/elm/elm-package.json +15 -0
  192. data/smoke-test/elm/elm.json +31 -0
  193. data/smoke-test/github-actions/both/.github/workflows/this.yaml +11 -0
  194. data/smoke-test/github-actions/both/yaml/action.yml +13 -0
  195. data/smoke-test/github-actions/invalid/invalid_file.yaml +0 -0
  196. data/smoke-test/github-actions/workflow/.github/workflows/this.yaml +11 -0
  197. data/smoke-test/github-actions/yaml/action.yml +13 -0
  198. data/smoke-test/gitsubmodule/.gitmodules +4 -0
  199. data/smoke-test/gomod/go.mod +16 -0
  200. data/smoke-test/gomod/go.sum +18 -0
  201. data/smoke-test/gomod/gomain.go +14 -0
  202. data/smoke-test/gradle/.gitignore +1 -0
  203. data/smoke-test/gradle/build.gradle +65 -0
  204. data/smoke-test/maven/pom.xml +65 -0
  205. data/smoke-test/mix/mix.exs +24 -0
  206. data/smoke-test/mix/mix.lock +5 -0
  207. data/smoke-test/npm/package-lock.json +166 -0
  208. data/smoke-test/npm/package.json +22 -0
  209. data/smoke-test/npm/removed/package-lock.json +44 -0
  210. data/smoke-test/npm/removed/package.json +15 -0
  211. data/smoke-test/nuget/project.csproj +14 -0
  212. data/smoke-test/pip/pip/requirements.txt +5 -0
  213. data/smoke-test/pip/pip-compile/requirements.in +2 -0
  214. data/smoke-test/pip/pip-compile/requirements.txt +16 -0
  215. data/smoke-test/pip/pipenv/Pipfile +13 -0
  216. data/smoke-test/pip/pipenv/Pipfile.lock +86 -0
  217. data/smoke-test/pip/poetry/poetry.lock +33 -0
  218. data/smoke-test/pip/poetry/pyproject.toml +18 -0
  219. data/smoke-test/pub/pubspec.lock +40 -0
  220. data/smoke-test/pub/pubspec.yaml +10 -0
  221. data/smoke-test/terraform/main.tf +143 -0
  222. metadata +314 -6
  223. data/LICENSE.GPL-3.0-only +0 -674
@@ -0,0 +1,1949 @@
1
+ /**
2
+ * SyntaxHighlighter
3
+ * http://alexgorbatchev.com/
4
+ *
5
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
6
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
7
+ *
8
+ * @version
9
+ * 2.0.296 (March 01 2009)
10
+ *
11
+ * @copyright
12
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
13
+ *
14
+ * @license
15
+ * This file is part of SyntaxHighlighter.
16
+ *
17
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
18
+ * it under the terms of the GNU General Public License as published by
19
+ * the Free Software Foundation, either version 3 of the License, or
20
+ * (at your option) any later version.
21
+ *
22
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
23
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
+ * GNU General Public License for more details.
26
+ *
27
+ * You should have received a copy of the GNU General Public License
28
+ * along with SyntaxHighlighter. If not, see <http://www.gnu.org/licenses/>.
29
+ */
30
+ //
31
+ // Begin anonymous function. This is used to contain local scope variables without polutting global scope.
32
+ //
33
+ if (!window.SyntaxHighlighter) var SyntaxHighlighter = function() {
34
+
35
+ // Shortcut object which will be assigned to the SyntaxHighlighter variable.
36
+ // This is a shorthand for local reference in order to avoid long namespace
37
+ // references to SyntaxHighlighter.whatever...
38
+ var sh = {
39
+ defaults : {
40
+ /** Additional CSS class names to be added to highlighter elements. */
41
+ 'class-name' : '',
42
+
43
+ /** First line number. */
44
+ 'first-line' : 1,
45
+
46
+ /** Font size of the SyntaxHighlighter block. */
47
+ 'font-size' : null,
48
+
49
+ /** Lines to highlight. */
50
+ 'highlight' : null,
51
+
52
+ /** Enables or disables smart tabs. */
53
+ 'smart-tabs' : true,
54
+
55
+ /** Gets or sets tab size. */
56
+ 'tab-size' : 4,
57
+
58
+ /** Enables or disables ruler. */
59
+ 'ruler' : false,
60
+
61
+ /** Enables or disables gutter. */
62
+ 'gutter' : true,
63
+
64
+ /** Enables or disables toolbar. */
65
+ 'toolbar' : true,
66
+
67
+ /** Forces code view to be collapsed. */
68
+ 'collapse' : false,
69
+
70
+ /** Enables or disables automatic links. */
71
+ 'auto-links' : true,
72
+
73
+ /** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
74
+ 'light' : false
75
+ },
76
+
77
+ config : {
78
+ /** Path to the copy to clipboard SWF file. */
79
+ clipboardSwf : null,
80
+
81
+ /** Width of an item in the toolbar. */
82
+ toolbarItemWidth : 16,
83
+
84
+ /** Height of an item in the toolbar. */
85
+ toolbarItemHeight : 16,
86
+
87
+ /** Blogger mode flag. */
88
+ bloggerMode : false,
89
+
90
+ /** Name of the tag that SyntaxHighlighter will automatically look for. */
91
+ tagName : 'pre',
92
+
93
+ strings : {
94
+ expandSource : 'expand source',
95
+ viewSource : 'view source',
96
+ copyToClipboard : 'copy to clipboard',
97
+ copyToClipboardConfirmation : 'The code is in your clipboard now',
98
+ print : 'print',
99
+ help : '?',
100
+ alert: 'SyntaxHighlighter\n\n',
101
+ noBrush : 'Can\'t find brush for: ',
102
+ brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
103
+
104
+ // this is populated by the build script
105
+ aboutDialog : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>About SyntaxHighlighter</title></head><body style="font-family:Georgia,\'Times New Roman\',Times,serif;background-color:#fff;color:#000;font-size:1em;text-align:center;"><div style="text-align:center;margin-top:3em;"><div style="font-family:Geneva,Arial,Helvetica,sans-serif;font-size:xx-large;">SyntaxHighlighter</div><div style="font-size:.75em;margin-bottom:4em;"><div>version 2.0.296 (March 01 2009)</div><div><a href="http://alexgorbatchev.com" target="_blank" style="color:#0099FF;text-decoration:none;">http://alexgorbatchev.com</a></div></div><div>JavaScript code syntax highlighter.</div><div>Copyright 2004-2009 Alex Gorbatchev.</div></div></body></html>'
106
+ },
107
+
108
+ /** If true, output will show HTML produces instead. */
109
+ debug : false
110
+ },
111
+
112
+ /** Internal 'global' variables. */
113
+ vars : {
114
+ discoveredBrushes : null,
115
+ spaceWidth : null,
116
+ printFrame : null,
117
+ highlighters : {}
118
+ },
119
+
120
+ /** This object is populated by user included external brush files. */
121
+ brushes : {},
122
+
123
+ /** Common regular expressions. */
124
+ regexLib : {
125
+ multiLineCComments : /\/\*[\s\S]*?\*\//gm,
126
+ singleLineCComments : /\/\/.*$/gm,
127
+ singleLinePerlComments : /#.*$/gm,
128
+ doubleQuotedString : /"(?:\.|(\\\")|[^\""\n])*"/g,
129
+ singleQuotedString : /'(?:\.|(\\\')|[^\''\n])*'/g,
130
+ multiLineDoubleQuotedString : /"(?:\.|(\\\")|[^\""])*"/g,
131
+ multiLineSingleQuotedString : /'(?:\.|(\\\')|[^\''])*'/g,
132
+ url : /\w+:\/\/[\w-.\/?%&=]*/g,
133
+
134
+ /** <?= ?> tags. */
135
+ phpScriptTags : { left: /(&lt;|<)\?=?/g, right: /\?(&gt;|>)/g },
136
+
137
+ /** <%= %> tags. */
138
+ aspScriptTags : { left: /(&lt;|<)%=?/g, right: /%(&gt;|>)/g },
139
+
140
+ /** <script></script> tags. */
141
+ scriptScriptTags : { left: /(&lt;|<)\s*script.*?(&gt;|>)/gi, right: /(&lt;|<)\/\s*script\s*(&gt;|>)/gi }
142
+ },
143
+
144
+ toolbar : {
145
+ /**
146
+ * Creates new toolbar for a highlighter.
147
+ * @param {Highlighter} highlighter Target highlighter.
148
+ */
149
+ create : function(highlighter)
150
+ {
151
+ var div = document.createElement('DIV'),
152
+ items = sh.toolbar.items
153
+ ;
154
+
155
+ div.className = 'toolbar';
156
+
157
+ for (var name in items)
158
+ {
159
+ var constructor = items[name],
160
+ command = new constructor(highlighter),
161
+ element = command.create()
162
+ ;
163
+
164
+ highlighter.toolbarCommands[name] = command;
165
+
166
+ if (element == null)
167
+ continue;
168
+
169
+ if (typeof(element) == 'string')
170
+ element = sh.toolbar.createButton(element, highlighter.id, name);
171
+
172
+ element.className += 'item ' + name;
173
+ div.appendChild(element);
174
+ }
175
+
176
+ return div;
177
+ },
178
+
179
+ /**
180
+ * Create a standard anchor button for the toolbar.
181
+ * @param {String} label Label text to display.
182
+ * @param {String} highlighterId Highlighter ID that this button would belong to.
183
+ * @param {String} commandName Command name that would be executed.
184
+ * @return {Element} Returns an 'A' element.
185
+ */
186
+ createButton : function(label, highlighterId, commandName)
187
+ {
188
+ var a = document.createElement('a'),
189
+ style = a.style,
190
+ config = sh.config,
191
+ width = config.toolbarItemWidth,
192
+ height = config.toolbarItemHeight
193
+ ;
194
+
195
+ a.href = '#' + commandName;
196
+ a.title = label;
197
+ a.highlighterId = highlighterId;
198
+ a.commandName = commandName;
199
+ a.innerHTML = label;
200
+
201
+ if (isNaN(width) == false)
202
+ style.width = width + 'px';
203
+
204
+ if (isNaN(height) == false)
205
+ style.height = height + 'px';
206
+
207
+ a.onclick = function(e)
208
+ {
209
+ try
210
+ {
211
+ sh.toolbar.executeCommand(
212
+ this,
213
+ e || window.event,
214
+ this.highlighterId,
215
+ this.commandName
216
+ );
217
+ }
218
+ catch(e)
219
+ {
220
+ sh.utils.alert(e.message);
221
+ }
222
+
223
+ return false;
224
+ };
225
+
226
+ return a;
227
+ },
228
+
229
+ /**
230
+ * Executes a toolbar command.
231
+ * @param {Element} sender Sender element.
232
+ * @param {MouseEvent} event Original mouse event object.
233
+ * @param {String} highlighterId Highlighter DIV element ID.
234
+ * @param {String} commandName Name of the command to execute.
235
+ * @return {Object} Passes out return value from command execution.
236
+ */
237
+ executeCommand : function(sender, event, highlighterId, commandName, args)
238
+ {
239
+ var highlighter = sh.vars.highlighters[highlighterId],
240
+ command
241
+ ;
242
+
243
+ if (highlighter == null || (command = highlighter.toolbarCommands[commandName]) == null)
244
+ return null;
245
+
246
+ return command.execute(sender, event, args);
247
+ },
248
+
249
+ /** Collection of toolbar items. */
250
+ items : {
251
+ expandSource : function(highlighter)
252
+ {
253
+ this.create = function()
254
+ {
255
+ if (highlighter.getParam('collapse') != true)
256
+ return;
257
+
258
+ return sh.config.strings.expandSource;
259
+ };
260
+
261
+ this.execute = function(sender, event, args)
262
+ {
263
+ var div = highlighter.div;
264
+
265
+ sender.parentNode.removeChild(sender);
266
+ div.className = div.className.replace('collapsed', '');
267
+ };
268
+ },
269
+
270
+ /**
271
+ * Command to open a new window and display the original unformatted source code inside.
272
+ */
273
+ viewSource : function(highlighter)
274
+ {
275
+ this.create = function()
276
+ {
277
+ return sh.config.strings.viewSource;
278
+ };
279
+
280
+ this.execute = function(sender, event, args)
281
+ {
282
+ var code = sh.utils.fixForBlogger(highlighter.originalCode).replace(/</g, '&lt;'),
283
+ wnd = sh.utils.popup('', '_blank', 750, 400, 'location=0, resizable=1, menubar=0, scrollbars=1')
284
+ ;
285
+
286
+ code = sh.utils.unindent(code);
287
+
288
+ wnd.document.write('<pre>' + code + '</pre>');
289
+ wnd.document.close();
290
+ };
291
+ },
292
+
293
+ /**
294
+ * Command to copy the original source code in to the clipboard.
295
+ * Uses Flash method if <code>clipboardSwf</code> is configured.
296
+ */
297
+ copyToClipboard : function(highlighter)
298
+ {
299
+ var flashDiv, flashSwf,
300
+ highlighterId = highlighter.id
301
+ ;
302
+
303
+ this.create = function()
304
+ {
305
+ var config = sh.config;
306
+
307
+ // disable functionality if running locally
308
+ if (config.clipboardSwf == null)
309
+ return null;
310
+
311
+ function params(list)
312
+ {
313
+ var result = '';
314
+
315
+ for (var name in list)
316
+ result += "<param name='" + name + "' value='" + list[name] + "'/>";
317
+
318
+ return result;
319
+ };
320
+
321
+ function attributes(list)
322
+ {
323
+ var result = '';
324
+
325
+ for (var name in list)
326
+ result += " " + name + "='" + list[name] + "'";
327
+
328
+ return result;
329
+ };
330
+
331
+ var args1 = {
332
+ width : config.toolbarItemWidth,
333
+ height : config.toolbarItemHeight,
334
+ id : highlighterId + '_clipboard',
335
+ type : 'application/x-shockwave-flash',
336
+ title : sh.config.strings.copyToClipboard
337
+ },
338
+
339
+ // these arguments are used in IE's <param /> collection
340
+ args2 = {
341
+ allowScriptAccess : 'always',
342
+ wmode : 'transparent',
343
+ flashVars : 'highlighterId=' + highlighterId,
344
+ menu : 'false'
345
+ },
346
+ swf = config.clipboardSwf,
347
+ html
348
+ ;
349
+
350
+ if (/msie/i.test(navigator.userAgent))
351
+ {
352
+ html = '<object'
353
+ + attributes({
354
+ classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
355
+ codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
356
+ })
357
+ + attributes(args1)
358
+ + '>'
359
+ + params(args2)
360
+ + params({ movie : swf })
361
+ + '</object>'
362
+ ;
363
+ }
364
+ else
365
+ {
366
+ html = '<embed'
367
+ + attributes(args1)
368
+ + attributes(args2)
369
+ + attributes({ src : swf })
370
+ + '/>'
371
+ ;
372
+ }
373
+
374
+ flashDiv = document.createElement('div');
375
+ flashDiv.innerHTML = html;
376
+
377
+ return flashDiv;
378
+ };
379
+
380
+ this.execute = function(sender, event, args)
381
+ {
382
+ var command = args.command;
383
+
384
+ switch (command)
385
+ {
386
+ case 'get':
387
+ var code = sh.utils.unindent(
388
+ sh.utils.fixForBlogger(highlighter.originalCode)
389
+ .replace(/&lt;/g, '<')
390
+ .replace(/&gt;/g, '>')
391
+ .replace(/&amp;/g, '&')
392
+ );
393
+
394
+ if(window.clipboardData)
395
+ // will fall through to the confirmation because there isn't a break
396
+ window.clipboardData.setData('text', code);
397
+ else
398
+ return sh.utils.unindent(code);
399
+
400
+ case 'ok':
401
+ sh.utils.alert(sh.config.strings.copyToClipboardConfirmation);
402
+ break;
403
+
404
+ case 'error':
405
+ sh.utils.alert(args.message);
406
+ break;
407
+ }
408
+ };
409
+ },
410
+
411
+ /** Command to print the colored source code. */
412
+ printSource : function(highlighter)
413
+ {
414
+ this.create = function()
415
+ {
416
+ return sh.config.strings.print;
417
+ };
418
+
419
+ this.execute = function(sender, event, args)
420
+ {
421
+ var iframe = document.createElement('IFRAME'),
422
+ doc = null
423
+ ;
424
+
425
+ // make sure there is never more than one hidden iframe created by SH
426
+ if (sh.vars.printFrame != null)
427
+ document.body.removeChild(sh.vars.printFrame);
428
+
429
+ sh.vars.printFrame = iframe;
430
+
431
+ // this hides the iframe
432
+ iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;';
433
+
434
+ document.body.appendChild(iframe);
435
+ doc = iframe.contentWindow.document;
436
+
437
+ copyStyles(doc, window.document);
438
+ doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>');
439
+ doc.close();
440
+
441
+ iframe.contentWindow.focus();
442
+ iframe.contentWindow.print();
443
+
444
+ function copyStyles(destDoc, sourceDoc)
445
+ {
446
+ var links = sourceDoc.getElementsByTagName('link');
447
+
448
+ for(var i = 0; i < links.length; i++)
449
+ if(links[i].rel.toLowerCase() == 'stylesheet' && /shCore\.css$/.test(links[i].href))
450
+ destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
451
+ };
452
+ };
453
+ },
454
+
455
+ /** Command to display the about dialog window. */
456
+ about : function(highlighter)
457
+ {
458
+ this.create = function()
459
+ {
460
+ return sh.config.strings.help;
461
+ };
462
+
463
+ this.execute = function(sender, event)
464
+ {
465
+ var wnd = sh.utils.popup('', '_blank', 500, 250, 'scrollbars=0'),
466
+ doc = wnd.document
467
+ ;
468
+
469
+ doc.write(sh.config.strings.aboutDialog);
470
+ doc.close();
471
+ wnd.focus();
472
+ };
473
+ }
474
+ }
475
+ },
476
+
477
+ utils : {
478
+ guid : function(prefix)
479
+ {
480
+ return prefix + Math.round(Math.random() * 1000000).toString();
481
+ },
482
+
483
+ /**
484
+ * Merges two objects. Values from obj2 override values in obj1.
485
+ * Function is NOT recursive and works only for one dimensional objects.
486
+ * @param {Object} obj1 First object.
487
+ * @param {Object} obj2 Second object.
488
+ * @return {Object} Returns combination of both objects.
489
+ */
490
+ merge: function(obj1, obj2)
491
+ {
492
+ var result = {}, name;
493
+
494
+ for (name in obj1)
495
+ result[name] = obj1[name];
496
+
497
+ for (name in obj2)
498
+ result[name] = obj2[name];
499
+
500
+ return result;
501
+ },
502
+
503
+ /**
504
+ * Attempts to convert string to boolean.
505
+ * @param {String} value Input string.
506
+ * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
507
+ */
508
+ toBoolean: function(value)
509
+ {
510
+ switch (value)
511
+ {
512
+ case "true":
513
+ return true;
514
+
515
+ case "false":
516
+ return false;
517
+ }
518
+
519
+ return value;
520
+ },
521
+
522
+ /**
523
+ * Opens up a centered popup window.
524
+ * @param {String} url URL to open in the window.
525
+ * @param {String} name Popup name.
526
+ * @param {int} width Popup width.
527
+ * @param {int} height Popup height.
528
+ * @param {String} options window.open() options.
529
+ * @return {Window} Returns window instance.
530
+ */
531
+ popup: function(url, name, width, height, options)
532
+ {
533
+ var x = (screen.width - width) / 2,
534
+ y = (screen.height - height) / 2
535
+ ;
536
+
537
+ options += ', left=' + x +
538
+ ', top=' + y +
539
+ ', width=' + width +
540
+ ', height=' + height
541
+ ;
542
+ options = options.replace(/^,/, '');
543
+
544
+ var win = window.open(url, name, options);
545
+ win.focus();
546
+ return win;
547
+ },
548
+
549
+ /**
550
+ * Adds event handler to the target object.
551
+ * @param {Object} obj Target object.
552
+ * @param {String} type Name of the event.
553
+ * @param {Function} func Handling function.
554
+ */
555
+ addEvent: function(obj, type, func)
556
+ {
557
+ if (obj.attachEvent)
558
+ {
559
+ obj['e' + type + func] = func;
560
+ obj[type + func] = function()
561
+ {
562
+ obj['e' + type + func](window.event);
563
+ }
564
+ obj.attachEvent('on' + type, obj[type + func]);
565
+ }
566
+ else
567
+ {
568
+ obj.addEventListener(type, func, false);
569
+ }
570
+ },
571
+
572
+ /**
573
+ * Displays an alert.
574
+ * @param {String} str String to display.
575
+ */
576
+ alert: function(str)
577
+ {
578
+ alert(sh.config.strings.alert + str)
579
+ },
580
+
581
+ /**
582
+ * Finds a brush by its alias.
583
+ *
584
+ * @param {String} alias Brush alias.
585
+ * @param {Boolean} alert Suppresses the alert if false.
586
+ * @return {Brush} Returns bursh constructor if found, null otherwise.
587
+ */
588
+ findBrush: function(alias, alert)
589
+ {
590
+ var brushes = sh.vars.discoveredBrushes,
591
+ result = null
592
+ ;
593
+
594
+ if (brushes == null)
595
+ {
596
+ brushes = {};
597
+
598
+ // Find all brushes
599
+ for (var brush in sh.brushes)
600
+ {
601
+ var aliases = sh.brushes[brush].aliases;
602
+
603
+ if (aliases == null)
604
+ continue;
605
+
606
+ for (var i = 0; i < aliases.length; i++)
607
+ brushes[aliases[i]] = brush;
608
+ }
609
+
610
+ sh.vars.discoveredBrushes = brushes;
611
+ }
612
+
613
+ result = sh.brushes[brushes[alias]];
614
+
615
+ if (result == null && alert != false)
616
+ sh.utils.alert(sh.config.strings.noBrush + alias);
617
+
618
+ return result;
619
+ },
620
+
621
+ /**
622
+ * Executes a callback on each line and replaces each line with result from the callback.
623
+ * @param {Object} str Input string.
624
+ * @param {Object} callback Callback function taking one string argument and returning a string.
625
+ */
626
+ eachLine: function(str, callback)
627
+ {
628
+ var lines = str.split('\n');
629
+
630
+ for (var i = 0; i < lines.length; i++)
631
+ lines[i] = callback(lines[i]);
632
+
633
+ return lines.join('\n');
634
+ },
635
+
636
+ /**
637
+ * Creates rules looking div.
638
+ */
639
+ createRuler: function()
640
+ {
641
+ var div = document.createElement('div'),
642
+ ruler = document.createElement('div'),
643
+ showEvery = 10,
644
+ i = 1
645
+ ;
646
+
647
+ while (i <= 150)
648
+ {
649
+ if (i % showEvery === 0)
650
+ {
651
+ div.innerHTML += i;
652
+ i += (i + '').length;
653
+ }
654
+ else
655
+ {
656
+ div.innerHTML += '&middot;';
657
+ i++;
658
+ }
659
+ }
660
+
661
+ ruler.className = 'ruler line';
662
+ ruler.appendChild(div);
663
+
664
+ return ruler;
665
+ },
666
+
667
+ /**
668
+ * This is a special trim which only removes first and last empty lines
669
+ * and doesn't affect valid leading space on the first line.
670
+ *
671
+ * @param {String} str Input string
672
+ * @return {String} Returns string without empty first and last lines.
673
+ */
674
+ trimFirstAndLastLines: function(str)
675
+ {
676
+ return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
677
+ },
678
+
679
+ /**
680
+ * Parses key/value pairs into hash object.
681
+ *
682
+ * Understands the following formats:
683
+ * - name: word;
684
+ * - name: [word, word];
685
+ * - name: "string";
686
+ * - name: 'string';
687
+ *
688
+ * For example:
689
+ * name1: value; name2: [value, value]; name3: 'value'
690
+ *
691
+ * @param {String} str Input string.
692
+ * @return {Object} Returns deserialized object.
693
+ */
694
+ parseParams: function(str)
695
+ {
696
+ var match,
697
+ result = {},
698
+ arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
699
+ regex = new XRegExp(
700
+ "(?<name>[\\w-]+)" +
701
+ "\\s*:\\s*" +
702
+ "(?<value>" +
703
+ "[\\w-%#]+|" + // word
704
+ "\\[.*?\\]|" + // [] array
705
+ '".*?"|' + // "" string
706
+ "'.*?'" + // '' string
707
+ ")\\s*;?",
708
+ "g"
709
+ )
710
+ ;
711
+
712
+ while ((match = regex.exec(str)) != null)
713
+ {
714
+ var value = match.value
715
+ .replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
716
+ ;
717
+
718
+ // try to parse array value
719
+ if (value != null && arrayRegex.test(value))
720
+ {
721
+ var m = arrayRegex.exec(value);
722
+ value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
723
+ }
724
+
725
+ result[match.name] = value;
726
+ }
727
+
728
+ return result;
729
+ },
730
+
731
+ /**
732
+ * Wraps each line of the string into <code/> tag with given style applied to it.
733
+ *
734
+ * @param {String} str Input string.
735
+ * @param {String} css Style name to apply to the string.
736
+ * @return {String} Returns input string with each line surrounded by <span/> tag.
737
+ */
738
+ decorate: function(str, css)
739
+ {
740
+ if (str == null || str.length == 0 || str == '\n')
741
+ return str;
742
+
743
+ str = str.replace(/</g, '&lt;');
744
+
745
+ // Replace two or more sequential spaces with &nbsp; leaving last space untouched.
746
+ str = str.replace(/ {2,}/g, function(m)
747
+ {
748
+ var spaces = '';
749
+
750
+ for (var i = 0; i < m.length - 1; i++)
751
+ spaces += '&nbsp;';
752
+
753
+ return spaces + ' ';
754
+ });
755
+
756
+ // Split each line and apply <span class="...">...</span> to them so that
757
+ // leading spaces aren't included.
758
+ if (css != null)
759
+ str = sh.utils.eachLine(str, function(line)
760
+ {
761
+ if (line.length == 0)
762
+ return '';
763
+
764
+ var spaces = '';
765
+
766
+ line = line.replace(/^(&nbsp;| )+/, function(s)
767
+ {
768
+ spaces = s;
769
+ return '';
770
+ });
771
+
772
+ if (line.length == 0)
773
+ return spaces;
774
+
775
+ return spaces + '<code class="' + css + '">' + line + '</code>';
776
+ });
777
+
778
+ return str;
779
+ },
780
+
781
+ /**
782
+ * Pads number with zeros until it's length is the same as given length.
783
+ *
784
+ * @param {Number} number Number to pad.
785
+ * @param {Number} length Max string length with.
786
+ * @return {String} Returns a string padded with proper amount of '0'.
787
+ */
788
+ padNumber : function(number, length)
789
+ {
790
+ var result = number.toString();
791
+
792
+ while (result.length < length)
793
+ result = '0' + result;
794
+
795
+ return result;
796
+ },
797
+
798
+ /**
799
+ * Measures width of a single space character.
800
+ * @return {Number} Returns width of a single space character.
801
+ */
802
+ measureSpace : function()
803
+ {
804
+ var container = document.createElement('div'),
805
+ span,
806
+ result = 0,
807
+ body = document.body,
808
+ id = sh.utils.guid('measureSpace'),
809
+
810
+ // variable names will be compressed, so it's better than a plain string
811
+ divOpen = '<div class="',
812
+ closeDiv = '</div>',
813
+ closeSpan = '</span>'
814
+ ;
815
+
816
+ // we have to duplicate highlighter nested structure in order to get an acurate space measurment
817
+ container.innerHTML =
818
+ divOpen + 'syntaxhighlighter">'
819
+ + divOpen + 'lines">'
820
+ + divOpen + 'line">'
821
+ + divOpen + 'content'
822
+ + '"><span class="block"><span id="' + id + '">&nbsp;' + closeSpan + closeSpan
823
+ + closeDiv
824
+ + closeDiv
825
+ + closeDiv
826
+ + closeDiv
827
+ ;
828
+
829
+ body.appendChild(container);
830
+ span = document.getElementById(id);
831
+
832
+ if (/opera/i.test(navigator.userAgent))
833
+ {
834
+ var style = window.getComputedStyle(span, null);
835
+ result = parseInt(style.getPropertyValue("width"));
836
+ }
837
+ else
838
+ {
839
+ result = span.offsetWidth;
840
+ }
841
+
842
+ body.removeChild(container);
843
+
844
+ return result;
845
+ },
846
+
847
+ /**
848
+ * Replaces tabs with spaces.
849
+ *
850
+ * @param {String} code Source code.
851
+ * @param {Number} tabSize Size of the tab.
852
+ * @return {String} Returns code with all tabs replaces by spaces.
853
+ */
854
+ processTabs : function(code, tabSize)
855
+ {
856
+ var tab = '';
857
+
858
+ for (var i = 0; i < tabSize; i++)
859
+ tab += ' ';
860
+
861
+ return code.replace(/\t/g, tab);
862
+ },
863
+
864
+ /**
865
+ * Replaces tabs with smart spaces.
866
+ *
867
+ * @param {String} code Code to fix the tabs in.
868
+ * @param {Number} tabSize Number of spaces in a column.
869
+ * @return {String} Returns code with all tabs replaces with roper amount of spaces.
870
+ */
871
+ processSmartTabs : function(code, tabSize)
872
+ {
873
+ var lines = code.split('\n'),
874
+ tab = '\t',
875
+ spaces = ''
876
+ ;
877
+
878
+ // Create a string with 1000 spaces to copy spaces from...
879
+ // It's assumed that there would be no indentation longer than that.
880
+ for (var i = 0; i < 50; i++)
881
+ spaces += ' '; // 20 spaces * 50
882
+
883
+ // This function inserts specified amount of spaces in the string
884
+ // where a tab is while removing that given tab.
885
+ function insertSpaces(line, pos, count)
886
+ {
887
+ return line.substr(0, pos)
888
+ + spaces.substr(0, count)
889
+ + line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
890
+ ;
891
+ };
892
+
893
+ // Go through all the lines and do the 'smart tabs' magic.
894
+ code = sh.utils.eachLine(code, function(line)
895
+ {
896
+ if (line.indexOf(tab) == -1)
897
+ return line;
898
+
899
+ var pos = 0;
900
+
901
+ while ((pos = line.indexOf(tab)) != -1)
902
+ {
903
+ // This is pretty much all there is to the 'smart tabs' logic.
904
+ // Based on the position within the line and size of a tab,
905
+ // calculate the amount of spaces we need to insert.
906
+ var spaces = tabSize - pos % tabSize;
907
+ line = insertSpaces(line, pos, spaces);
908
+ }
909
+
910
+ return line;
911
+ });
912
+
913
+ return code;
914
+ },
915
+
916
+ fixForBlogger : function(str)
917
+ {
918
+ return (sh.config.bloggerMode == true) ? str.replace(/<br\s*\/?>|&lt;br\s*\/?&gt;/gi, '\n') : str;
919
+ },
920
+
921
+ /**
922
+ * Removes all white space at the begining and end of a string.
923
+ *
924
+ * @param {String} str String to trim.
925
+ * @return {String} Returns string without leading and following white space characters.
926
+ */
927
+ trim: function(str)
928
+ {
929
+ return str.replace(/\s*$/g, '').replace(/^\s*/, '');
930
+ },
931
+
932
+ /**
933
+ * Unindents a block of text by the lowest common indent amount.
934
+ * @param {String} str Text to unindent.
935
+ * @return {String} Returns unindented text block.
936
+ */
937
+ unindent: function(str)
938
+ {
939
+ var lines = sh.utils.fixForBlogger(str).split('\n'),
940
+ indents = new Array(),
941
+ regex = /^\s*/,
942
+ min = 1000
943
+ ;
944
+
945
+ // go through every line and check for common number of indents
946
+ for (var i = 0; i < lines.length && min > 0; i++)
947
+ {
948
+ var line = lines[i];
949
+
950
+ if (sh.utils.trim(line).length == 0)
951
+ continue;
952
+
953
+ var matches = regex.exec(line);
954
+
955
+ // In the event that just one line doesn't have leading white space
956
+ // we can't unindent anything, so bail completely.
957
+ if (matches == null)
958
+ return str;
959
+
960
+ min = Math.min(matches[0].length, min);
961
+ }
962
+
963
+ // trim minimum common number of white space from the begining of every line
964
+ if (min > 0)
965
+ for (var i = 0; i < lines.length; i++)
966
+ lines[i] = lines[i].substr(min);
967
+
968
+ return lines.join('\n');
969
+ },
970
+
971
+ /**
972
+ * Callback method for Array.sort() which sorts matches by
973
+ * index position and then by length.
974
+ *
975
+ * @param {Match} m1 Left object.
976
+ * @param {Match} m2 Right object.
977
+ * @return {Number} Returns -1, 0 or -1 as a comparison result.
978
+ */
979
+ matchesSortCallback: function(m1, m2)
980
+ {
981
+ // sort matches by index first
982
+ if(m1.index < m2.index)
983
+ return -1;
984
+ else if(m1.index > m2.index)
985
+ return 1;
986
+ else
987
+ {
988
+ // if index is the same, sort by length
989
+ if(m1.length < m2.length)
990
+ return -1;
991
+ else if(m1.length > m2.length)
992
+ return 1;
993
+ }
994
+
995
+ return 0;
996
+ },
997
+
998
+ /**
999
+ * Executes given regular expression on provided code and returns all
1000
+ * matches that are found.
1001
+ *
1002
+ * @param {String} code Code to execute regular expression on.
1003
+ * @param {Object} regex Regular expression item info from <code>regexList</code> collection.
1004
+ * @return {Array} Returns a list of Match objects.
1005
+ */
1006
+ getMatches: function(code, regexInfo)
1007
+ {
1008
+ function defaultAdd(match, regexInfo)
1009
+ {
1010
+ return [new sh.Match(match[0], match.index, regexInfo.css)];
1011
+ };
1012
+
1013
+ var index = 0,
1014
+ match = null,
1015
+ result = [],
1016
+ func = regexInfo.func ? regexInfo.func : defaultAdd
1017
+ ;
1018
+
1019
+ while((match = regexInfo.regex.exec(code)) != null)
1020
+ result = result.concat(func(match, regexInfo));
1021
+
1022
+ return result;
1023
+ },
1024
+
1025
+ processUrls: function(code)
1026
+ {
1027
+ return code.replace(sh.regexLib.url, function(m)
1028
+ {
1029
+ return '<a href="' + m + '">' + m + '</a>';
1030
+ });
1031
+ }
1032
+ }, // end of utils
1033
+
1034
+ /**
1035
+ * Shorthand to highlight all elements on the page that are marked as
1036
+ * SyntaxHighlighter source code.
1037
+ *
1038
+ * @param {Object} globalParams Optional parameters which override element's
1039
+ * parameters. Only used if element is specified.
1040
+ *
1041
+ * @param {Object} element Optional element to highlight. If none is
1042
+ * provided, all elements in the current document
1043
+ * are highlighted.
1044
+ */
1045
+ highlight : function(globalParams, element)
1046
+ {
1047
+ function toArray(source)
1048
+ {
1049
+ var result = [];
1050
+
1051
+ for (var i = 0; i < source.length; i++)
1052
+ result.push(source[i]);
1053
+
1054
+ return result;
1055
+ };
1056
+
1057
+ var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)),
1058
+ propertyName = 'innerHTML',
1059
+ highlighter = null
1060
+ ;
1061
+
1062
+ if (elements.length === 0)
1063
+ return;
1064
+
1065
+ for (var i = 0; i < elements.length; i++)
1066
+ {
1067
+ var target = elements[i],
1068
+ params = sh.utils.parseParams(target.className),
1069
+ brushName
1070
+ ;
1071
+
1072
+ // local params take precedence over globals
1073
+ params = sh.utils.merge(globalParams, params);
1074
+ brushName = params['brush'];
1075
+
1076
+ if (brushName == null)
1077
+ continue;
1078
+
1079
+ // Instantiate a brush
1080
+ if (params['html-script'] == 'true')
1081
+ {
1082
+ highlighter = new sh.HtmlScript(brushName);
1083
+ }
1084
+ else
1085
+ {
1086
+ var brush = sh.utils.findBrush(brushName);
1087
+
1088
+ if (brush)
1089
+ highlighter = new brush();
1090
+ else
1091
+ continue;
1092
+ }
1093
+
1094
+ highlighter.highlight(target[propertyName], params);
1095
+
1096
+ var result = highlighter.div;
1097
+
1098
+ if (sh.config.debug)
1099
+ {
1100
+ result = document.createElement('textarea');
1101
+ result.value = highlighter.div.innerHTML;
1102
+ result.style.width = '70em';
1103
+ result.style.height = '30em';
1104
+ }
1105
+
1106
+ target.parentNode.replaceChild(result, target);
1107
+ }
1108
+ },
1109
+
1110
+ /**
1111
+ * Main entry point for the SyntaxHighlighter.
1112
+ * @param {Object} params Optional params to apply to all highlighted elements.
1113
+ */
1114
+ all : function(params)
1115
+ {
1116
+ sh.utils.addEvent(
1117
+ window,
1118
+ 'load',
1119
+ function() { sh.highlight(params); }
1120
+ );
1121
+ }
1122
+ }; // end of sh
1123
+
1124
+ /** Match object */
1125
+ sh.Match = function(value, index, css)
1126
+ {
1127
+ this.value = value;
1128
+ this.index = index;
1129
+ this.length = value.length;
1130
+ this.css = css;
1131
+ };
1132
+
1133
+ sh.Match.prototype.toString = function()
1134
+ {
1135
+ return this.value;
1136
+ };
1137
+
1138
+ /**
1139
+ * Simulates HTML code with a scripting language embedded.
1140
+ *
1141
+ * @param {String} scriptBrushName Brush name of the scripting language.
1142
+ */
1143
+ sh.HtmlScript = function(scriptBrushName)
1144
+ {
1145
+ var scriptBrush = sh.utils.findBrush(scriptBrushName),
1146
+ xmlBrush = new sh.brushes.Xml(),
1147
+ bracketsRegex = null
1148
+ ;
1149
+
1150
+ if (scriptBrush == null)
1151
+ return;
1152
+
1153
+ scriptBrush = new scriptBrush();
1154
+ this.xmlBrush = xmlBrush;
1155
+
1156
+ if (scriptBrush.htmlScript == null)
1157
+ {
1158
+ sh.utils.alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
1159
+ return;
1160
+ }
1161
+
1162
+ xmlBrush.regexList.push(
1163
+ { regex: scriptBrush.htmlScript.code, func: process }
1164
+ );
1165
+
1166
+ function offsetMatches(matches, offset)
1167
+ {
1168
+ for (var j = 0; j < matches.length; j++)
1169
+ matches[j].index += offset;
1170
+ }
1171
+
1172
+ function process(match, info)
1173
+ {
1174
+ var code = match.code,
1175
+ matches = [],
1176
+ regexList = scriptBrush.regexList,
1177
+ offset = match.index + match.left.length,
1178
+ htmlScript = scriptBrush.htmlScript,
1179
+ result
1180
+ ;
1181
+
1182
+ for (var i = 0; i < regexList.length; i++)
1183
+ {
1184
+ result = sh.utils.getMatches(code, regexList[i]);
1185
+ offsetMatches(result, offset);
1186
+ matches = matches.concat(result);
1187
+ }
1188
+
1189
+ if (htmlScript.left != null && match.left != null)
1190
+ {
1191
+ result = sh.utils.getMatches(match.left, htmlScript.left);
1192
+ offsetMatches(result, match.index);
1193
+ matches = matches.concat(result);
1194
+ }
1195
+
1196
+ if (htmlScript.right != null && match.right != null)
1197
+ {
1198
+ result = sh.utils.getMatches(match.right, htmlScript.right);
1199
+ offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
1200
+ matches = matches.concat(result);
1201
+ }
1202
+
1203
+ return matches;
1204
+ }
1205
+ };
1206
+
1207
+ sh.HtmlScript.prototype.highlight = function(code, params)
1208
+ {
1209
+ this.xmlBrush.highlight(code, params);
1210
+ this.div = this.xmlBrush.div;
1211
+ }
1212
+
1213
+ /**
1214
+ * Main Highlither class.
1215
+ * @constructor
1216
+ */
1217
+ sh.Highlighter = function()
1218
+ {
1219
+ };
1220
+
1221
+ sh.Highlighter.prototype = {
1222
+ /**
1223
+ * Returns value of the parameter passed to the highlighter.
1224
+ * @param {String} name Name of the parameter.
1225
+ * @param {Object} defaultValue Default value.
1226
+ * @return {Object} Returns found value or default value otherwise.
1227
+ */
1228
+ getParam : function(name, defaultValue)
1229
+ {
1230
+ var result = this.params[name];
1231
+ return sh.utils.toBoolean(result == null ? defaultValue : result);
1232
+ },
1233
+
1234
+ /**
1235
+ * Shortcut to document.createElement().
1236
+ * @param {String} name Name of the element to create (DIV, A, etc).
1237
+ * @return {HTMLElement} Returns new HTML element.
1238
+ */
1239
+ create: function(name)
1240
+ {
1241
+ return document.createElement(name);
1242
+ },
1243
+
1244
+ /**
1245
+ * Checks if one match is inside another.
1246
+ * @param {Match} match Match object to check.
1247
+ * @return {Boolean} Returns true if given match was inside another, false otherwise.
1248
+ */
1249
+ isMatchNested: function(match)
1250
+ {
1251
+ for (var i = 0; i < this.matches.length; i++)
1252
+ {
1253
+ var item = this.matches[i];
1254
+
1255
+ if (item === null)
1256
+ continue;
1257
+
1258
+ if ((match.index > item.index) && (match.index < item.index + item.length))
1259
+ return true;
1260
+ }
1261
+
1262
+ return false;
1263
+ },
1264
+
1265
+ /**
1266
+ * Applies all regular expression to the code and stores all found
1267
+ * matches in the `this.matches` array.
1268
+ * @param {Array} regexList List of regular expressions.
1269
+ * @param {String} code Source code.
1270
+ * @return {Array} Returns list of matches.
1271
+ */
1272
+ findMatches: function(regexList, code)
1273
+ {
1274
+ var result = [];
1275
+
1276
+ if (regexList != null)
1277
+ for (var i = 0; i < regexList.length; i++)
1278
+ result = result.concat(sh.utils.getMatches(code, regexList[i]));
1279
+
1280
+ // sort the matches
1281
+ result = result.sort(sh.utils.matchesSortCallback);
1282
+
1283
+ return result;
1284
+ },
1285
+
1286
+ /**
1287
+ * Checks to see if any of the matches are inside of other matches.
1288
+ * This process would get rid of highligted strings inside comments,
1289
+ * keywords inside strings and so on.
1290
+ */
1291
+ removeNestedMatches: function()
1292
+ {
1293
+ for (var i = 0; i < this.matches.length; i++)
1294
+ if (this.isMatchNested(this.matches[i]))
1295
+ this.matches[i] = null;
1296
+ },
1297
+
1298
+ /**
1299
+ * Splits block of text into individual DIV lines.
1300
+ * @param {String} code Code to highlight.
1301
+ * @return {String} Returns highlighted code in HTML form.
1302
+ */
1303
+ createDisplayLines : function(code)
1304
+ {
1305
+ var lines = code.split(/\n/g),
1306
+ firstLine = parseInt(this.getParam('first-line')),
1307
+ padLength = (firstLine + lines.length).toString().length,
1308
+ highlightedLines = this.getParam('highlight', [])
1309
+ ;
1310
+
1311
+ code = '';
1312
+
1313
+ for (var i = 0; i < lines.length; i++)
1314
+ {
1315
+ var line = lines[i],
1316
+ indent = /^(&nbsp;|\s)+/.exec(line),
1317
+ lineClass = 'line alt' + (i % 2 == 0 ? 1 : 2),
1318
+ lineNumber = sh.utils.padNumber(firstLine + i, padLength),
1319
+ highlighted = highlightedLines.indexOf((firstLine + i).toString()) != -1,
1320
+ spaces = null
1321
+ ;
1322
+
1323
+ if (indent != null)
1324
+ {
1325
+ spaces = indent[0].toString();
1326
+ line = line.substr(spaces.length);
1327
+ spaces = spaces.replace(/&nbsp;/g, ' ');
1328
+ indent = sh.vars.spaceWidth * spaces.length;
1329
+ }
1330
+ else
1331
+ {
1332
+ indent = 0;
1333
+ }
1334
+
1335
+ line = sh.utils.trim(line);
1336
+
1337
+ if (line.length == 0)
1338
+ line = '&nbsp;';
1339
+
1340
+ if (highlighted)
1341
+ lineClass += ' highlighted';
1342
+
1343
+ code +=
1344
+ '<div class="' + lineClass + '">'
1345
+ + '<code class="number">' + lineNumber + '.</code>'
1346
+ + '<span class="content">'
1347
+ + (spaces != null ? '<code class="spaces">' + spaces.replace(/\s/g, '&nbsp;') + '</code>' : '')
1348
+ + '<span class="block" style="margin-left: ' + indent + 'px !important;">' + line + '</span>'
1349
+ + '</span>'
1350
+ + '</div>'
1351
+ ;
1352
+ }
1353
+
1354
+ return code;
1355
+ },
1356
+
1357
+ /**
1358
+ * Finds all matches in the source code.
1359
+ * @param {String} code Source code to process matches in.
1360
+ * @param {Array} matches Discovered regex matches.
1361
+ * @return {String} Returns formatted HTML with processed mathes.
1362
+ */
1363
+ processMatches: function(code, matches)
1364
+ {
1365
+ var pos = 0,
1366
+ result = '',
1367
+ decorate = sh.utils.decorate // make an alias to save some bytes
1368
+ ;
1369
+
1370
+ // Finally, go through the final list of matches and pull the all
1371
+ // together adding everything in between that isn't a match.
1372
+ for (var i = 0; i < matches.length; i++)
1373
+ {
1374
+ var match = matches[i];
1375
+
1376
+ if (match === null || match.length === 0)
1377
+ continue;
1378
+
1379
+ result += decorate(code.substr(pos, match.index - pos), 'plain')
1380
+ + decorate(match.value, match.css)
1381
+ ;
1382
+
1383
+ pos = match.index + match.length;
1384
+ }
1385
+
1386
+ // don't forget to add whatever's remaining in the string
1387
+ result += decorate(code.substr(pos), 'plain');
1388
+
1389
+ return result;
1390
+ },
1391
+
1392
+ /**
1393
+ * Highlights the code and returns complete HTML.
1394
+ * @param {String} code Code to highlight.
1395
+ * @param {Object} params Parameters object.
1396
+ */
1397
+ highlight: function(code, params)
1398
+ {
1399
+ var conf = sh.config,
1400
+ vars = sh.vars,
1401
+ div,
1402
+ tabSize
1403
+ ;
1404
+
1405
+ this.params = {};
1406
+ this.div = null;
1407
+ this.lines = null;
1408
+ this.code = null;
1409
+ this.bar = null;
1410
+ this.toolbarCommands = {};
1411
+ this.id = sh.utils.guid('highlighter_');
1412
+
1413
+ // register this instance in the highlighters list
1414
+ vars.highlighters[this.id] = this;
1415
+
1416
+ if (code === null)
1417
+ code = '';
1418
+
1419
+ // Measure width of a single space.
1420
+ if (vars.spaceWidth === null)
1421
+ vars.spaceWidth = sh.utils.measureSpace();
1422
+
1423
+ // local params take precedence over defaults
1424
+ this.params = sh.utils.merge(sh.defaults, params || {});
1425
+
1426
+ // process light mode
1427
+ if (this.getParam('light') == true)
1428
+ this.params.toolbar = this.params.gutter = false;
1429
+
1430
+ this.div = div = this.create('DIV');
1431
+ this.lines = this.create('DIV');
1432
+ this.lines.className = 'lines';
1433
+
1434
+ div.className = 'syntaxhighlighter';
1435
+ div.id = this.id;
1436
+
1437
+ if (this.getParam('collapse'))
1438
+ div.className += ' collapsed';
1439
+
1440
+ if (this.getParam('gutter') == false)
1441
+ div.className += ' nogutter';
1442
+
1443
+ div.className += ' ' + this.getParam('class-name');
1444
+ div.style.fontSize = this.getParam('font-size', ''); // IE7 can't take null
1445
+
1446
+ this.originalCode = code;
1447
+ this.code = sh.utils.trimFirstAndLastLines(code)
1448
+ .replace(/\r/g, ' ') // IE lets these buggers through
1449
+ ;
1450
+
1451
+ tabSize = this.getParam('tab-size');
1452
+
1453
+ // replace tabs with spaces
1454
+ this.code = this.getParam('smart-tabs') == true
1455
+ ? sh.utils.processSmartTabs(this.code, tabSize)
1456
+ : sh.utils.processTabs(this.code, tabSize)
1457
+ ;
1458
+
1459
+ this.code = sh.utils.unindent(this.code);
1460
+
1461
+ // add controls toolbar
1462
+ if (this.getParam('toolbar'))
1463
+ {
1464
+ this.bar = this.create('DIV');
1465
+ this.bar.className = 'bar';
1466
+ this.bar.appendChild(sh.toolbar.create(this));
1467
+ div.appendChild(this.bar);
1468
+ }
1469
+
1470
+ // add columns ruler
1471
+ if (this.getParam('ruler'))
1472
+ div.appendChild(sh.utils.createRuler());
1473
+
1474
+ div.appendChild(this.lines);
1475
+
1476
+ this.matches = this.findMatches(this.regexList, this.code);
1477
+ this.removeNestedMatches();
1478
+
1479
+ code = this.processMatches(this.code, this.matches);
1480
+
1481
+ // finally, split all lines so that they wrap well
1482
+ code = this.createDisplayLines(sh.utils.trim(code));
1483
+
1484
+ // finally, process the links
1485
+ if (this.getParam('auto-links'))
1486
+ code = sh.utils.processUrls(code);
1487
+
1488
+ this.lines.innerHTML = code;
1489
+ },
1490
+
1491
+ /**
1492
+ * Converts space separated list of keywords into a regular expression string.
1493
+ * @param {String} str Space separated keywords.
1494
+ * @return {String} Returns regular expression string.
1495
+ */
1496
+ getKeywords: function(str)
1497
+ {
1498
+ str = str
1499
+ .replace(/^\s+|\s+$/g, '')
1500
+ .replace(/\s+/g, '\\b|\\b')
1501
+ ;
1502
+
1503
+ return '\\b' + str + '\\b';
1504
+ },
1505
+
1506
+ /**
1507
+ * Makes a brush compatible with the `html-script` functionality.
1508
+ * @param {Object} regexGroup Object containing `left` and `right` regular expressions.
1509
+ */
1510
+ forHtmlScript: function(regexGroup)
1511
+ {
1512
+ this.htmlScript = {
1513
+ left : { regex: regexGroup.left, css: 'script' },
1514
+ right : { regex: regexGroup.right, css: 'script' },
1515
+ code : new XRegExp(
1516
+ "(?<left>" + regexGroup.left.source + ")" +
1517
+ "(?<code>.*?)" +
1518
+ "(?<right>" + regexGroup.right.source + ")",
1519
+ "sgi"
1520
+ )
1521
+ };
1522
+ }
1523
+ }; // end of Highlighter
1524
+
1525
+ return sh;
1526
+ }(); // end of anonymous function
1527
+
1528
+ if (!Array.indexOf)
1529
+ /**
1530
+ * Finds an index of element in the array.
1531
+ * @ignore
1532
+ * @param {Object} searchElement
1533
+ * @param {Number} fromIndex
1534
+ * @return {Number} Returns index of element if found; -1 otherwise.
1535
+ */
1536
+ Array.prototype.indexOf = function (searchElement, fromIndex)
1537
+ {
1538
+ fromIndex = Math.max(fromIndex || 0, 0);
1539
+
1540
+ for (var i = fromIndex; i < this.length; i++)
1541
+ if(this[i] == searchElement)
1542
+ return i;
1543
+
1544
+ return -1;
1545
+ };
1546
+
1547
+ /**
1548
+ * XRegExp 0.6.1
1549
+ * (c) 2007-2008 Steven Levithan
1550
+ * <http://stevenlevithan.com/regex/xregexp/>
1551
+ * MIT License
1552
+ *
1553
+ * provides an augmented, cross-browser implementation of regular expressions
1554
+ * including support for additional modifiers and syntax. several convenience
1555
+ * methods and a recursive-construct parser are also included.
1556
+ */
1557
+
1558
+ // prevent running twice, which would break references to native globals
1559
+ if (!window.XRegExp) {
1560
+ // anonymous function to avoid global variables
1561
+ (function () {
1562
+ // copy various native globals for reference. can't use the name ``native``
1563
+ // because it's a reserved JavaScript keyword.
1564
+ var real = {
1565
+ exec: RegExp.prototype.exec,
1566
+ match: String.prototype.match,
1567
+ replace: String.prototype.replace,
1568
+ split: String.prototype.split
1569
+ },
1570
+ /* regex syntax parsing with support for all the necessary cross-
1571
+ browser and context issues (escapings, character classes, etc.) */
1572
+ lib = {
1573
+ part: /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g,
1574
+ replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g,
1575
+ extended: /^(?:\s+|#.*)+/,
1576
+ quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/,
1577
+ classLeft: /&&\[\^?/g,
1578
+ classRight: /]/g
1579
+ },
1580
+ indexOf = function (array, item, from) {
1581
+ for (var i = from || 0; i < array.length; i++)
1582
+ if (array[i] === item) return i;
1583
+ return -1;
1584
+ },
1585
+ brokenExecUndef = /()??/.exec("")[1] !== undefined,
1586
+ plugins = {};
1587
+
1588
+ /**
1589
+ * Accepts a pattern and flags, returns a new, extended RegExp object.
1590
+ * differs from a native regex in that additional flags and syntax are
1591
+ * supported and browser inconsistencies are ameliorated.
1592
+ * @ignore
1593
+ */
1594
+ XRegExp = function (pattern, flags) {
1595
+ if (pattern instanceof RegExp) {
1596
+ if (flags !== undefined)
1597
+ throw TypeError("can't supply flags when constructing one RegExp from another");
1598
+ return pattern.addFlags(); // new copy
1599
+ }
1600
+
1601
+ var flags = flags || "",
1602
+ singleline = flags.indexOf("s") > -1,
1603
+ extended = flags.indexOf("x") > -1,
1604
+ hasNamedCapture = false,
1605
+ captureNames = [],
1606
+ output = [],
1607
+ part = lib.part,
1608
+ match, cc, len, index, regex;
1609
+
1610
+ part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class)
1611
+
1612
+ while (match = real.exec.call(part, pattern)) {
1613
+ // comment pattern. this check must come before the capturing group check,
1614
+ // because both match[1] and match[2] will be non-empty.
1615
+ if (match[2]) {
1616
+ // keep tokens separated unless the following token is a quantifier
1617
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex)))
1618
+ output.push("(?:)");
1619
+ // capturing group
1620
+ } else if (match[1]) {
1621
+ captureNames.push(match[3] || null);
1622
+ if (match[3])
1623
+ hasNamedCapture = true;
1624
+ output.push("(");
1625
+ // named backreference
1626
+ } else if (match[4]) {
1627
+ index = indexOf(captureNames, match[4]);
1628
+ // keep backreferences separate from subsequent literal numbers
1629
+ // preserve backreferences to named groups that are undefined at this point as literal strings
1630
+ output.push(index > -1 ?
1631
+ "\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") :
1632
+ match[0]
1633
+ );
1634
+ // unicode element (requires plugin)
1635
+ } else if (match[5]) {
1636
+ output.push(plugins.unicode ?
1637
+ plugins.unicode.get(match[5], match[0].charAt(1) === "P") :
1638
+ match[0]
1639
+ );
1640
+ // character class opening delimiter ("[" or "[^")
1641
+ // (non-native unicode elements are not supported within character classes)
1642
+ } else if (match[6]) {
1643
+ if (pattern.charAt(part.lastIndex) === "]") {
1644
+ // for cross-browser compatibility with ECMA-262 v3 behavior,
1645
+ // convert [] to (?!) and [^] to [\S\s].
1646
+ output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]");
1647
+ part.lastIndex++;
1648
+ } else {
1649
+ // parse the character class with support for inner escapes and
1650
+ // ES4's infinitely nesting intersection syntax ([&&[^&&[]]]).
1651
+ cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0];
1652
+ output.push(match[6] + cc + "]");
1653
+ part.lastIndex += cc.length + 1;
1654
+ }
1655
+ // dot ("."), pound sign ("#"), or whitespace character
1656
+ } else if (match[7]) {
1657
+ if (singleline && match[7] === ".") {
1658
+ output.push("[\\S\\s]");
1659
+ } else if (extended && lib.extended.test(match[7])) {
1660
+ len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length;
1661
+ // keep tokens separated unless the following token is a quantifier
1662
+ if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len)))
1663
+ output.push("(?:)");
1664
+ part.lastIndex += len - 1;
1665
+ } else {
1666
+ output.push(match[7]);
1667
+ }
1668
+ } else {
1669
+ output.push(match[0]);
1670
+ }
1671
+ }
1672
+
1673
+ regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, ""));
1674
+ regex._x = {
1675
+ source: pattern,
1676
+ captureNames: hasNamedCapture ? captureNames : null
1677
+ };
1678
+ return regex;
1679
+ };
1680
+
1681
+ /**
1682
+ * Barebones plugin support for now (intentionally undocumented)
1683
+ * @ignore
1684
+ * @param {Object} name
1685
+ * @param {Object} o
1686
+ */
1687
+ XRegExp.addPlugin = function (name, o) {
1688
+ plugins[name] = o;
1689
+ };
1690
+
1691
+ /**
1692
+ * Adds named capture support, with values returned as ``result.name``.
1693
+ *
1694
+ * Also fixes two cross-browser issues, following the ECMA-262 v3 spec:
1695
+ * - captured values for non-participating capturing groups should be returned
1696
+ * as ``undefined``, rather than the empty string.
1697
+ * - the regex's ``lastIndex`` should not be incremented after zero-length
1698
+ * matches.
1699
+ * @ignore
1700
+ */
1701
+ RegExp.prototype.exec = function (str) {
1702
+ var match = real.exec.call(this, str),
1703
+ name, i, r2;
1704
+ if (match) {
1705
+ // fix browsers whose exec methods don't consistently return
1706
+ // undefined for non-participating capturing groups
1707
+ if (brokenExecUndef && match.length > 1) {
1708
+ // r2 doesn't need /g or /y, but they shouldn't hurt
1709
+ r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags());
1710
+ real.replace.call(match[0], r2, function () {
1711
+ for (i = 1; i < arguments.length - 2; i++) {
1712
+ if (arguments[i] === undefined) match[i] = undefined;
1713
+ }
1714
+ });
1715
+ }
1716
+ // attach named capture properties
1717
+ if (this._x && this._x.captureNames) {
1718
+ for (i = 1; i < match.length; i++) {
1719
+ name = this._x.captureNames[i - 1];
1720
+ if (name) match[name] = match[i];
1721
+ }
1722
+ }
1723
+ // fix browsers that increment lastIndex after zero-length matches
1724
+ if (this.global && this.lastIndex > (match.index + match[0].length))
1725
+ this.lastIndex--;
1726
+ }
1727
+ return match;
1728
+ };
1729
+ })(); // end anonymous function
1730
+ } // end if(!window.XRegExp)
1731
+
1732
+ /**
1733
+ * intentionally undocumented
1734
+ * @ignore
1735
+ */
1736
+ RegExp.prototype.getNativeFlags = function () {
1737
+ return (this.global ? "g" : "") +
1738
+ (this.ignoreCase ? "i" : "") +
1739
+ (this.multiline ? "m" : "") +
1740
+ (this.extended ? "x" : "") +
1741
+ (this.sticky ? "y" : "");
1742
+ };
1743
+
1744
+ /**
1745
+ * Accepts flags; returns a new XRegExp object generated by recompiling
1746
+ * the regex with the additional flags (may include non-native flags).
1747
+ * The original regex object is not altered.
1748
+ * @ignore
1749
+ */
1750
+ RegExp.prototype.addFlags = function (flags) {
1751
+ var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags());
1752
+ if (this._x) {
1753
+ regex._x = {
1754
+ source: this._x.source,
1755
+ captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null
1756
+ };
1757
+ }
1758
+ return regex;
1759
+ };
1760
+
1761
+ /**
1762
+ * Accepts a context object and string; returns the result of calling
1763
+ * ``exec`` with the provided string. the context is ignored but is
1764
+ * accepted for congruity with ``Function.prototype.call``.
1765
+ * @ignore
1766
+ */
1767
+ RegExp.prototype.call = function (context, str) {
1768
+ return this.exec(str);
1769
+ };
1770
+
1771
+ /**
1772
+ * Accepts a context object and arguments array; returns the result of
1773
+ * calling ``exec`` with the first value in the arguments array. the context
1774
+ * is ignored but is accepted for congruity with ``Function.prototype.apply``.
1775
+ * @ignore
1776
+ */
1777
+ RegExp.prototype.apply = function (context, args) {
1778
+ return this.exec(args[0]);
1779
+ };
1780
+
1781
+ /**
1782
+ * Accepts a pattern and flags; returns an XRegExp object. if the pattern
1783
+ * and flag combination has previously been cached, the cached copy is
1784
+ * returned, otherwise the new object is cached.
1785
+ * @ignore
1786
+ */
1787
+ XRegExp.cache = function (pattern, flags) {
1788
+ var key = "/" + pattern + "/" + (flags || "");
1789
+ return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags));
1790
+ };
1791
+
1792
+ /**
1793
+ * Accepts a string; returns the string with regex metacharacters escaped.
1794
+ * the returned string can safely be used within a regex to match a literal
1795
+ * string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
1796
+ * |, #, [comma], and whitespace.
1797
+ * @ignore
1798
+ */
1799
+ XRegExp.escape = function (str) {
1800
+ return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
1801
+ };
1802
+
1803
+ /**
1804
+ * Accepts a string to search, left and right delimiters as regex pattern
1805
+ * strings, optional regex flags (may include non-native s, x, and y flags),
1806
+ * and an options object which allows setting an escape character and changing
1807
+ * the return format from an array of matches to a two-dimensional array of
1808
+ * string parts with extended position data. returns an array of matches
1809
+ * (optionally with extended data), allowing nested instances of left and right
1810
+ * delimiters. use the g flag to return all matches, otherwise only the first
1811
+ * is returned. if delimiters are unbalanced within the subject data, an error
1812
+ * is thrown.
1813
+ *
1814
+ * This function admittedly pushes the boundaries of what can be accomplished
1815
+ * sensibly without a "real" parser. however, by doing so it provides flexible
1816
+ * and powerful recursive parsing capabilities with minimal code weight.
1817
+ *
1818
+ * Warning: the ``escapeChar`` option is considered experimental and might be
1819
+ * changed or removed in future versions of XRegExp.
1820
+ *
1821
+ * unsupported features:
1822
+ * - backreferences within delimiter patterns when using ``escapeChar``.
1823
+ * - although providing delimiters as regex objects adds the minor feature of
1824
+ * independent delimiter flags, it introduces other limitations and is only
1825
+ * intended to be done by the ``XRegExp`` constructor (which can't call
1826
+ * itself while building a regex).
1827
+ *
1828
+ * @ignore
1829
+ */
1830
+ XRegExp.matchRecursive = function (str, left, right, flags, options) {
1831
+ var options = options || {},
1832
+ escapeChar = options.escapeChar,
1833
+ vN = options.valueNames,
1834
+ flags = flags || "",
1835
+ global = flags.indexOf("g") > -1,
1836
+ ignoreCase = flags.indexOf("i") > -1,
1837
+ multiline = flags.indexOf("m") > -1,
1838
+ sticky = flags.indexOf("y") > -1,
1839
+ /* sticky mode has its own handling in this function, which means you
1840
+ can use flag "y" even in browsers which don't support it natively */
1841
+ flags = flags.replace(/y/g, ""),
1842
+ left = left instanceof RegExp ? (left.global ? left : left.addFlags("g")) : new XRegExp(left, "g" + flags),
1843
+ right = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags),
1844
+ output = [],
1845
+ openTokens = 0,
1846
+ delimStart = 0,
1847
+ delimEnd = 0,
1848
+ lastOuterEnd = 0,
1849
+ outerStart, innerStart, leftMatch, rightMatch, escaped, esc;
1850
+
1851
+ if (escapeChar) {
1852
+ if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character");
1853
+ if (multiline) throw TypeError("can't supply escape character when using the multiline flag");
1854
+ escaped = XRegExp.escape(escapeChar);
1855
+ /* Escape pattern modifiers:
1856
+ /g - not needed here
1857
+ /i - included
1858
+ /m - **unsupported**, throws error
1859
+ /s - handled by XRegExp when delimiters are provided as strings
1860
+ /x - handled by XRegExp when delimiters are provided as strings
1861
+ /y - not needed here; supported by other handling in this function
1862
+ */
1863
+ esc = new RegExp(
1864
+ "^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+",
1865
+ ignoreCase ? "i" : ""
1866
+ );
1867
+ }
1868
+
1869
+ while (true) {
1870
+ /* advance the starting search position to the end of the last delimiter match.
1871
+ a couple special cases are also covered:
1872
+ - if using an escape character, advance to the next delimiter's starting position,
1873
+ skipping any escaped characters
1874
+ - first time through, reset lastIndex in case delimiters were provided as regexes
1875
+ */
1876
+ left.lastIndex = right.lastIndex = delimEnd +
1877
+ (escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0);
1878
+
1879
+ leftMatch = left.exec(str);
1880
+ rightMatch = right.exec(str);
1881
+
1882
+ // only keep the result which matched earlier in the string
1883
+ if (leftMatch && rightMatch) {
1884
+ if (leftMatch.index <= rightMatch.index)
1885
+ rightMatch = null;
1886
+ else leftMatch = null;
1887
+ }
1888
+
1889
+ /* paths*:
1890
+ leftMatch | rightMatch | openTokens | result
1891
+ 1 | 0 | 1 | ...
1892
+ 1 | 0 | 0 | ...
1893
+ 0 | 1 | 1 | ...
1894
+ 0 | 1 | 0 | throw
1895
+ 0 | 0 | 1 | throw
1896
+ 0 | 0 | 0 | break
1897
+ * - does not include the sticky mode special case
1898
+ - the loop ends after the first completed match if not in global mode
1899
+ */
1900
+
1901
+ if (leftMatch || rightMatch) {
1902
+ delimStart = (leftMatch || rightMatch).index;
1903
+ delimEnd = (leftMatch ? left : right).lastIndex;
1904
+ } else if (!openTokens) {
1905
+ break;
1906
+ }
1907
+
1908
+ if (sticky && !openTokens && delimStart > lastOuterEnd)
1909
+ break;
1910
+
1911
+ if (leftMatch) {
1912
+ if (!openTokens++) {
1913
+ outerStart = delimStart;
1914
+ innerStart = delimEnd;
1915
+ }
1916
+ } else if (rightMatch && openTokens) {
1917
+ if (!--openTokens) {
1918
+ if (vN) {
1919
+ if (vN[0] && outerStart > lastOuterEnd)
1920
+ output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]);
1921
+ if (vN[1]) output.push([vN[1], str.slice(outerStart, innerStart), outerStart, innerStart]);
1922
+ if (vN[2]) output.push([vN[2], str.slice(innerStart, delimStart), innerStart, delimStart]);
1923
+ if (vN[3]) output.push([vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd]);
1924
+ } else {
1925
+ output.push(str.slice(innerStart, delimStart));
1926
+ }
1927
+ lastOuterEnd = delimEnd;
1928
+ if (!global)
1929
+ break;
1930
+ }
1931
+ } else {
1932
+ // reset lastIndex in case delimiters were provided as regexes
1933
+ left.lastIndex = right.lastIndex = 0;
1934
+ throw Error("subject data contains unbalanced delimiters");
1935
+ }
1936
+
1937
+ // if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop
1938
+ if (delimStart === delimEnd)
1939
+ delimEnd++;
1940
+ }
1941
+
1942
+ if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd)
1943
+ output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]);
1944
+
1945
+ // reset lastIndex in case delimiters were provided as regexes
1946
+ left.lastIndex = right.lastIndex = 0;
1947
+
1948
+ return output;
1949
+ };