String locator - Version 2.0.3

Version Description

  • Added support for HHVM
  • Improved inline documentation
Download this release

Release Info

Developer Clorith
Plugin Icon 128x128 String locator
Version 2.0.3
Comparing to
See all releases

Version 2.0.3

Files changed (116) hide show
  1. LICENSE +339 -0
  2. changelog.txt +75 -0
  3. editor.php +197 -0
  4. languages/string-locator-de_DE.mo +0 -0
  5. languages/string-locator-de_DE.po +198 -0
  6. languages/string-locator-es.ES.mo +0 -0
  7. languages/string-locator-es.ES.po +182 -0
  8. languages/string-locator-nb_NO.mo +0 -0
  9. languages/string-locator-nb_NO.po +188 -0
  10. languages/string-locator-sr_RS.mo +0 -0
  11. languages/string-locator-sr_RS.po +182 -0
  12. languages/string-locator.pot +158 -0
  13. options.php +69 -0
  14. readme.txt +75 -0
  15. resources/css/codemirror.css +272 -0
  16. resources/css/codemirror/3024-day.css +34 -0
  17. resources/css/codemirror/3024-night.css +34 -0
  18. resources/css/codemirror/ambiance-mobile.css +5 -0
  19. resources/css/codemirror/ambiance.css +74 -0
  20. resources/css/codemirror/base16-dark.css +34 -0
  21. resources/css/codemirror/base16-light.css +34 -0
  22. resources/css/codemirror/blackboard.css +28 -0
  23. resources/css/codemirror/cobalt.css +21 -0
  24. resources/css/codemirror/eclipse.css +23 -0
  25. resources/css/codemirror/elegant.css +13 -0
  26. resources/css/codemirror/erlang-dark.css +30 -0
  27. resources/css/codemirror/lesser-dark.css +43 -0
  28. resources/css/codemirror/mbo.css +37 -0
  29. resources/css/codemirror/mdn-like.css +44 -0
  30. resources/css/codemirror/midnight.css +43 -0
  31. resources/css/codemirror/monokai.css +29 -0
  32. resources/css/codemirror/neat.css +12 -0
  33. resources/css/codemirror/neo.css +40 -0
  34. resources/css/codemirror/night.css +24 -0
  35. resources/css/codemirror/paraiso-dark.css +34 -0
  36. resources/css/codemirror/paraiso-light.css +34 -0
  37. resources/css/codemirror/pastel-on-dark.css +48 -0
  38. resources/css/codemirror/rubyblue.css +21 -0
  39. resources/css/codemirror/solarized.css +167 -0
  40. resources/css/codemirror/the-matrix.css +26 -0
  41. resources/css/codemirror/tomorrow-night-eighties.css +34 -0
  42. resources/css/codemirror/twilight.css +28 -0
  43. resources/css/codemirror/vibrant-ink.css +30 -0
  44. resources/css/codemirror/xq-dark.css +49 -0
  45. resources/css/codemirror/xq-light.css +43 -0
  46. resources/css/string-locator.css +87 -0
  47. resources/js/codemirror/addon/comment/comment.js +172 -0
  48. resources/js/codemirror/addon/comment/continuecomment.js +85 -0
  49. resources/js/codemirror/addon/dialog/dialog.css +32 -0
  50. resources/js/codemirror/addon/dialog/dialog.js +133 -0
  51. resources/js/codemirror/addon/display/fullscreen.css +6 -0
  52. resources/js/codemirror/addon/display/fullscreen.js +41 -0
  53. resources/js/codemirror/addon/display/placeholder.js +58 -0
  54. resources/js/codemirror/addon/display/rulers.js +64 -0
  55. resources/js/codemirror/addon/edit/closebrackets.js +143 -0
  56. resources/js/codemirror/addon/edit/closetag.js +141 -0
  57. resources/js/codemirror/addon/edit/continuelist.js +38 -0
  58. resources/js/codemirror/addon/edit/matchbrackets.js +120 -0
  59. resources/js/codemirror/addon/edit/matchtags.js +66 -0
  60. resources/js/codemirror/addon/edit/trailingspace.js +27 -0
  61. resources/js/codemirror/addon/fold/brace-fold.js +105 -0
  62. resources/js/codemirror/addon/fold/comment-fold.js +57 -0
  63. resources/js/codemirror/addon/fold/foldcode.js +145 -0
  64. resources/js/codemirror/addon/fold/foldgutter.css +21 -0
  65. resources/js/codemirror/addon/fold/foldgutter.js +134 -0
  66. resources/js/codemirror/addon/fold/indent-fold.js +44 -0
  67. resources/js/codemirror/addon/fold/markdown-fold.js +49 -0
  68. resources/js/codemirror/addon/fold/xml-fold.js +181 -0
  69. resources/js/codemirror/addon/hint/anyword-hint.js +42 -0
  70. resources/js/codemirror/addon/hint/css-hint.js +56 -0
  71. resources/js/codemirror/addon/hint/html-hint.js +348 -0
  72. resources/js/codemirror/addon/hint/javascript-hint.js +141 -0
  73. resources/js/codemirror/addon/hint/python-hint.js +102 -0
  74. resources/js/codemirror/addon/hint/show-hint.css +38 -0
  75. resources/js/codemirror/addon/hint/show-hint.js +389 -0
  76. resources/js/codemirror/addon/hint/sql-hint.js +164 -0
  77. resources/js/codemirror/addon/hint/xml-hint.js +96 -0
  78. resources/js/codemirror/addon/lint/coffeescript-lint.js +41 -0
  79. resources/js/codemirror/addon/lint/css-lint.js +35 -0
  80. resources/js/codemirror/addon/lint/javascript-lint.js +136 -0
  81. resources/js/codemirror/addon/lint/json-lint.js +31 -0
  82. resources/js/codemirror/addon/lint/lint.css +73 -0
  83. resources/js/codemirror/addon/lint/lint.js +210 -0
  84. resources/js/codemirror/addon/lint/yaml-lint.js +28 -0
  85. resources/js/codemirror/addon/merge/merge.css +92 -0
  86. resources/js/codemirror/addon/merge/merge.js +513 -0
  87. resources/js/codemirror/addon/mode/loadmode.js +61 -0
  88. resources/js/codemirror/addon/mode/multiplex.js +118 -0
  89. resources/js/codemirror/addon/mode/multiplex_test.js +33 -0
  90. resources/js/codemirror/addon/mode/overlay.js +85 -0
  91. resources/js/codemirror/addon/runmode/colorize.js +40 -0
  92. resources/js/codemirror/addon/runmode/runmode-standalone.js +153 -0
  93. resources/js/codemirror/addon/runmode/runmode.js +72 -0
  94. resources/js/codemirror/addon/runmode/runmode.node.js +122 -0
  95. resources/js/codemirror/addon/scroll/scrollpastend.js +46 -0
  96. resources/js/codemirror/addon/search/match-highlighter.js +104 -0
  97. resources/js/codemirror/addon/search/search.js +158 -0
  98. resources/js/codemirror/addon/search/searchcursor.js +189 -0
  99. resources/js/codemirror/addon/selection/active-line.js +69 -0
  100. resources/js/codemirror/addon/selection/mark-selection.js +118 -0
  101. resources/js/codemirror/addon/tern/tern.css +86 -0
  102. resources/js/codemirror/addon/tern/tern.js +667 -0
  103. resources/js/codemirror/addon/tern/worker.js +44 -0
  104. resources/js/codemirror/addon/wrap/hardwrap.js +139 -0
  105. resources/js/codemirror/lib/codemirror.js +7601 -0
  106. resources/js/codemirror/mode/clike/clike.js +439 -0
  107. resources/js/codemirror/mode/css/css.js +717 -0
  108. resources/js/codemirror/mode/htmlembedded/htmlembedded.js +86 -0
  109. resources/js/codemirror/mode/htmlmixed/htmlmixed.js +120 -0
  110. resources/js/codemirror/mode/javascript/javascript.js +663 -0
  111. resources/js/codemirror/mode/php/php.js +233 -0
  112. resources/js/codemirror/mode/xml/xml.js +384 -0
  113. resources/js/string-locator-search.js +137 -0
  114. resources/js/string-locator.js +34 -0
  115. string-locator.php +1363 -0
  116. uninstall.php +6 -0
LICENSE ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+
294
+ Copyright (C) 2013 Marius
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ {signature of Ty Coon}, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
changelog.txt ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ = 1.9.1 =
2
+ * Fixes a regression relating to support for older versions of PHP introduced in 1.9.0
3
+
4
+ = 1.9.0 =
5
+ * Perform batch searches on the server for as long as possible until we get close to the max execution time.
6
+ * Fix previous searches not clearing if you don't navigate away.
7
+
8
+ = 1.8.2 =
9
+ * Compatibility fix for certain versions of PHP that would throw notices
10
+ * Reset the search results when you start a new search
11
+
12
+ = 1.8.1 =
13
+ * Make sure we don't add extra linefeeds to the end of files to prevent sending early headers where files end with the `?>` PHP closing tag
14
+
15
+ = 1.8.0 =
16
+ * Search everything in $home/wp-content and ignore core files
17
+ * Fix searches containing quotes
18
+ * Search is now AJAX based to prevent max execution time errors for some users
19
+ * Restore previous search also restores the search term and search locations
20
+ * Removed the WordPress list tables, they didn't work too well for our purpose
21
+ * Also search in file names
22
+
23
+ = 1.7.0 =
24
+ * Tested with WordPress 4.3
25
+ * Made it uses WordPress list tables (because they look nice and I felt adventurous)
26
+ * If the preview text is really long, an excerpt is pulled instead of making a massive text blob
27
+ * Fixed a typo in a query argument
28
+ * Reordered the search result list based on priority
29
+
30
+ = 1.6.0 =
31
+ * Revert edits if site health degrades as a direct cause of said edit
32
+
33
+ = 1.5.0 =
34
+ * Return to your search results from the editor, or restore the previous search if you closed the page
35
+ * Multisite support
36
+ * Made marked text more prominent in the editor for readability
37
+ * Fixed rare notice outputs when searching within all plugins/all themes
38
+ * Moved older changelog entries to changelog.txt
39
+ * Updated translation files to use the correct text domain
40
+
41
+ = 1.4.0 =
42
+ * Added code references for WordPress function calls
43
+ * Added the ability to search recursively from the WordPress root
44
+ * Updated textdomain (translations) to use the actual plugin slug
45
+
46
+ = 1.3.0 =
47
+ * Added search all for themes and plugins
48
+ * Refactored code
49
+ * Added german translations
50
+
51
+ = 1.2.1 =
52
+ * Added missing i18n text strings
53
+ * Added capability checks for edit screens
54
+
55
+ = 1.2.0 =
56
+ * Added custom code editor
57
+ * Syntax highlighting
58
+ * Code validation using Smart-Scan
59
+ * Quick jump links to areas with errors detected
60
+ * Replaced unused admin notice
61
+ * Removed previously used WP Editor checks
62
+
63
+ = 1.1.1 =
64
+ * Added Spanish translation files added
65
+ * Added Serbian translation files added
66
+
67
+ = 1.1.0 =
68
+ * Added link to the online editor for themes/plugins from search results
69
+ * Added extra notification text on editor page when referenced by the plugin, makes it easier to find your search string
70
+ * Screenshots and more plugin details added
71
+ * Fixed column width for line number being way too large
72
+ * Add missing inline comments/function references
73
+
74
+ = 1.0.0 =
75
+ * Initial release
editor.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ global $string_locator;
3
+ $editor_content = "";
4
+ $file = $_GET['string-locator-path'];
5
+ $details = array();
6
+ $this_url = admin_url( ( is_multisite() ? 'network/admin.php' : 'tools.php' ) . '?page=string-locator' );
7
+
8
+ if ( 'core' == $_GET['file-type'] ) {
9
+ $details = array(
10
+ 'name' => 'WordPress',
11
+ 'version' => get_bloginfo( 'version' ),
12
+ 'author' => array(
13
+ 'uri' => 'https://wordpress.org/',
14
+ 'name' => 'WordPress'
15
+ ),
16
+ 'description' => 'WordPress is web software you can use to create a beautiful website or blog. We like to say that WordPress is both free and priceless at the same time.'
17
+ );
18
+ }
19
+ elseif ( 'theme' == $_GET['file-type'] ) {
20
+ $themedata = wp_get_theme( $_GET['file-reference'] );
21
+
22
+ $details = array(
23
+ 'name' => $themedata->get( 'Name' ),
24
+ 'version' => $themedata->get( 'Version' ),
25
+ 'author' => array(
26
+ 'uri' => $themedata->get( 'AuthorURI' ),
27
+ 'name' => $themedata->get( 'Author' )
28
+ ),
29
+ 'description' => $themedata->get( 'Description' ),
30
+ 'parent' => $themedata->get( 'parent' )
31
+ );
32
+ }
33
+ else {
34
+ $plugins = get_plugins();
35
+
36
+ foreach( $plugins AS $pluginname => $plugindata ) {
37
+ $pluginref = explode( '/', $pluginname );
38
+
39
+ if ( $pluginref[0] == $_GET['file-reference'] ) {
40
+ $details = array(
41
+ 'name' => $plugindata['Name'],
42
+ 'version' => $plugindata['Version'],
43
+ 'author' => array(
44
+ 'uri' => $plugindata['AuthorURI'],
45
+ 'name' => $plugindata['Author']
46
+ ),
47
+ 'description' => $plugindata['Description']
48
+ );
49
+ }
50
+ }
51
+ }
52
+
53
+ if ( ! $string_locator->failed_edit ) {
54
+ $readfile = fopen( $file, "r" );
55
+ if ( $readfile )
56
+ {
57
+ while ( ( $readline = fgets( $readfile ) ) !== false )
58
+ {
59
+ $editor_content .= $readline;
60
+ }
61
+ }
62
+ }
63
+ else {
64
+ $editor_content = stripslashes( $_POST['string-locator-editor-content'] );
65
+ }
66
+ ?>
67
+ <div class="wrap">
68
+ <h2>
69
+ <?php _e( 'String Locator - Code Editor', 'string-locator' ); ?>
70
+ <a href="<?php echo esc_url( $this_url . '&restore=true' ); ?>" class="button button-primary"><?php _e( 'Return to search results', 'string-locator' ); ?></a>
71
+ </h2>
72
+
73
+ <form action="<?php echo ( is_ssl() ? 'http://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>" id="string-locator-edit-form" method="post">
74
+ <div class="string-locator-edit-wrap">
75
+ <textarea name="string-locator-editor-content" class="string-locator-editor" id="code-editor" data-editor-goto-line="<?php echo $_GET['string-locator-line']; ?>" data-editor-language="<?php echo $string_locator->string_locator_language; ?>" autofocus="autofocus"><?php echo esc_html( $editor_content ); ?></textarea>
76
+ </div>
77
+
78
+ <div class="string-locator-sidebar-wrap">
79
+ <div class="string-locator-details">
80
+ <div class="string-locator-theme-details">
81
+ <h2><?php echo $details['name']; ?> <small>v. <?php echo $details['version']; ?></small></h2>
82
+ <p>
83
+ <?php _e( 'By', 'string-locator' ); ?> <a href="<?php echo $details['author']['uri']; ?>" target="_blank"><?php echo $details['author']['name']; ?></a>
84
+ </p>
85
+ <p>
86
+ <?php echo $details['description'] ?>
87
+ </p>
88
+ </div>
89
+
90
+ <div class="string-locator-actions">
91
+ <?php wp_nonce_field( 'string-locator-edit_' . $_GET['edit-file'] ); ?>
92
+ <p>
93
+ <label>
94
+ <input type="checkbox" name="string-locator-smart-edit" checked="checked">
95
+ <?php _e( 'Enable a smart-scan of your code to help detect bracket mismatches before saving.', 'string-locator' ); ?>
96
+ </label>
97
+ </p>
98
+
99
+ <?php if ( isset( $details['parent'] ) && ! $details['parent'] ) { ?>
100
+ <!--
101
+ <div class="notice notice-warning inline below-h2">
102
+ <p>
103
+ <?php _e( 'It seems you are making direct edits to a theme.', 'string-locator' ); ?>
104
+ </p>
105
+
106
+ <p>
107
+ <?php _e( 'When making changes to a theme, it is recommended you make a <a href="https://codex.wordpress.org/Child_Themes">Child Theme</a>.', 'string-locator' ); ?>
108
+ </p>
109
+
110
+ <p>
111
+ <label>
112
+ <input type="checkbox" name="string-locator-make-child-theme" checked="checked">
113
+ <?php _e( 'Automatically create a new child theme for these edits', 'string-locator' ); ?>
114
+ </label>
115
+ </p>
116
+ </div>
117
+
118
+ <p>
119
+
120
+ </p>
121
+ -->
122
+ <?php } ?>
123
+
124
+ <?php if ( ! stristr( $file, 'wp-content' ) ) { ?>
125
+ <div class="notice notice-warning inline below-h2">
126
+ <p>
127
+ <strong>Warning:</strong> You appear to be editing a Core file.
128
+ </p>
129
+ <p>
130
+ Keep in mind that edits to core files will be lost when WordPress is updated.
131
+ </p>
132
+ </div>
133
+ <?php } ?>
134
+
135
+ <p class="submit">
136
+ <input type="submit" name="submit" class="button button-primary" value="<?php _e( 'Save changes', 'string-locator' ); ?>">
137
+ </p>
138
+ </div>
139
+ </div>
140
+
141
+ <?php
142
+ $function_info = get_defined_functions();
143
+ $function_help = '';
144
+
145
+ foreach( $function_info['user'] AS $user_func ) {
146
+ if ( strstr( $editor_content, $user_func . '(' ) ) {
147
+ $function_object = new ReflectionFunction( $user_func );
148
+ $attrs = $function_object->getParameters();
149
+
150
+ $attr_strings = array();
151
+
152
+ foreach( $attrs AS $attr ) {
153
+ $arg = '';
154
+
155
+ if ( $attr->isPassedByReference() ) {
156
+ $arg .= '&';
157
+ }
158
+
159
+ if ( $attr->isOptional() ) {
160
+ $arg = sprintf(
161
+ '[ %s$%s ]',
162
+ $arg,
163
+ $attr->getName()
164
+ );
165
+ } else {
166
+ $arg = sprintf(
167
+ '%s$%s',
168
+ $arg,
169
+ $attr->getName()
170
+ );
171
+ }
172
+
173
+ $attr_strings[] = $arg;
174
+ }
175
+
176
+ $function_help .= sprintf(
177
+ '<p><a href="%s" target="_blank">%s</a></p>',
178
+ esc_url( sprintf( 'https://developer.wordpress.org/reference/functions/%s/', $user_func ) ),
179
+ $user_func . '( ' . implode( ', ', $attr_strings ) . ' )'
180
+ );
181
+ }
182
+ }
183
+ ?>
184
+
185
+ <?php if ( ! empty( $function_help ) ) { ?>
186
+ <div class="string-locator-details">
187
+
188
+ <div class="string-locator-theme-details">
189
+ <h2><?php _e( 'WordPress Functions', 'string-locator' ); ?></h2>
190
+
191
+ <?php echo $function_help; ?>
192
+ </div>
193
+ </div>
194
+ <?php }?>
195
+ </div>
196
+ </form>
197
+ </div>
languages/string-locator-de_DE.mo ADDED
Binary file
languages/string-locator-de_DE.po ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: String Locator\n"
4
+ "POT-Creation-Date: 2015-08-23 19:38+0200\n"
5
+ "PO-Revision-Date: 2015-08-23 19:38+0200\n"
6
+ "Last-Translator: pixolin <pixolin@gmx.com>\n"
7
+ "Language-Team: pixolin <pixolin@gmx.com>\n"
8
+ "Language: de_DE\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8.4\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "X-Poedit-WPHeader: string-locator.php\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
17
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
18
+ "_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+ "X-Poedit-SearchPath-0: .\n"
21
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
22
+
23
+ #: editor.php:68
24
+ msgid "String Locator - Code Editor"
25
+ msgstr "String-Locator - Code-Editor"
26
+
27
+ #: editor.php:69
28
+ msgid "Return to search results"
29
+ msgstr "Zu Suchergebnissen zurückkehren"
30
+
31
+ #: editor.php:82
32
+ msgid "By"
33
+ msgstr "Von"
34
+
35
+ #: editor.php:94
36
+ msgid ""
37
+ "Enable a smart-scan of your code to help detect bracket mismatches before "
38
+ "saving."
39
+ msgstr ""
40
+ "Aktiviere eine intelligente Code-Suche, um fehlenden Klammern vor dem "
41
+ "Speichern aufzuspüren."
42
+
43
+ #: editor.php:110
44
+ msgid "Save changes"
45
+ msgstr "Änderungen speichern"
46
+
47
+ #: editor.php:163
48
+ msgid "WordPress Functions"
49
+ msgstr "WordPress-Funktionen"
50
+
51
+ #. Plugin Name of the plugin/theme
52
+ #: options.php:12 string-locator.php:200 string-locator.php:201
53
+ #: string-locator.php:212 string-locator.php:213
54
+ msgid "String Locator"
55
+ msgstr "String Locator"
56
+
57
+ #: options.php:16
58
+ msgid "Search through"
59
+ msgstr "Durchsuche"
60
+
61
+ #: options.php:18
62
+ msgid "Core"
63
+ msgstr "Core"
64
+
65
+ #: options.php:19
66
+ msgid "The whole WordPress directory"
67
+ msgstr "das gesamte WordPress-Verzeichnis"
68
+
69
+ #: options.php:21
70
+ msgid "Themes"
71
+ msgstr "Themes"
72
+
73
+ #: options.php:22
74
+ msgid "All themes"
75
+ msgstr "Alle Themes"
76
+
77
+ #: options.php:37
78
+ msgid "Plugins"
79
+ msgstr "Plugins"
80
+
81
+ #: options.php:38
82
+ msgid "All plugins"
83
+ msgstr "Alle Plugins"
84
+
85
+ #: options.php:54
86
+ msgid "Search string"
87
+ msgstr "Zeichenkette suchen"
88
+
89
+ #: options.php:58
90
+ msgid "Search"
91
+ msgstr "Suche"
92
+
93
+ #: options.php:59
94
+ msgid "Restore last search"
95
+ msgstr "Wiederherstellen der letzten Suche"
96
+
97
+ #: string-locator.php:286
98
+ msgid ""
99
+ "The file could not be written to, please check file permissions or edit it "
100
+ "manually."
101
+ msgstr ""
102
+ "An der Datei konnten keine Änderungen vorgenommen werden. Bitte prüfe die "
103
+ "Datei-Berechtigungen oder ändere die Datei von Hand."
104
+
105
+ #: string-locator.php:307
106
+ #, php-format
107
+ msgid ""
108
+ "There is an inconsistency in the opening and closing braces, { and }, of "
109
+ "your file on line %s"
110
+ msgstr ""
111
+ "Beim Öffnen und Schließen geschwungener Klammern { und } gibt es "
112
+ "Unstimmigkeiten in Zeile %s deiner Datei."
113
+
114
+ #: string-locator.php:325
115
+ #, php-format
116
+ msgid ""
117
+ "There is an inconsistency in the opening and closing braces, [ and ], of "
118
+ "your file on line %s"
119
+ msgstr ""
120
+ "Beim Öffnen und Schließen eckiger Klammern [ und ] gibt es Unstimmigkeiten "
121
+ "in Zeile %s deiner Datei."
122
+
123
+ #: string-locator.php:343
124
+ #, php-format
125
+ msgid ""
126
+ "There is an inconsistency in the opening and closing braces, ( and ), of "
127
+ "your file on line %s"
128
+ msgstr ""
129
+ "Beim Öffnen und Schließen von runden Klammern ( und ) gibt es "
130
+ "Unstimmigkeiten in Zeile %s deiner Datei."
131
+
132
+ #: string-locator.php:374
133
+ msgid ""
134
+ "A 500 server error was detected on your site after updating your file. We "
135
+ "have restored the previous version of the file for you."
136
+ msgstr ""
137
+ "Auf deiner Website ist nach dem Aktualisieren der Datei ein Serverfehler 500 "
138
+ "aufgetreten. Die vorherige Version der Datei wurde wiederhergestellt."
139
+
140
+ #: string-locator.php:380
141
+ msgid "The file has been saved"
142
+ msgstr "Die Datei wurde gespeichert"
143
+
144
+ #: string-locator.php:526
145
+ msgid "Could not read file: "
146
+ msgstr "Datei konnte nicht gelesen werden:"
147
+
148
+ #: table-controller.php:13
149
+ msgid "String"
150
+ msgstr "Zeichenkette"
151
+
152
+ #: table-controller.php:14
153
+ msgid "File"
154
+ msgstr "Datei"
155
+
156
+ #: table-controller.php:15
157
+ msgid "Line number"
158
+ msgstr ""
159
+
160
+ #: table-controller.php:30
161
+ msgid "Your string was not present in any of the available files."
162
+ msgstr "Deine Zeichenkette war in keiner der vorhandenen Datei enthalten. "
163
+
164
+ #: table-controller.php:74
165
+ msgid "Edit"
166
+ msgstr ""
167
+
168
+ #. Plugin URI of the plugin/theme
169
+ msgid "http://www.clorith.net/wordpress-string-locator/"
170
+ msgstr ""
171
+
172
+ #. Description of the plugin/theme
173
+ msgid "Scan through theme and plugin files looking for text strings"
174
+ msgstr "Durchsuche Theme- und Plugin-Dateien nach Zeichenketten"
175
+
176
+ #. Author of the plugin/theme
177
+ msgid "Clorith"
178
+ msgstr ""
179
+
180
+ #. Author URI of the plugin/theme
181
+ msgid "http://www.clorith.net"
182
+ msgstr ""
183
+
184
+ #~ msgid "<strong>Warning:</strong> You appear to be editing a Core file."
185
+ #~ msgstr "<strong>Warnung:</strong> Du scheinst eine Core-Datei zu ändern."
186
+
187
+ #~ msgid ""
188
+ #~ "Keep in mind that edits to core files will be lost when WordPress is "
189
+ #~ "updated."
190
+ #~ msgstr ""
191
+ #~ "Bitte denke daran, dass Änderungen an Core-Dateien bei einer "
192
+ #~ "Aktualisierung von WordPress verloren gehen."
193
+
194
+ #~ msgid "the whole WordPress directory"
195
+ #~ msgstr "das gesamte WordPress-Verzeichnis"
196
+
197
+ #~ msgid "Line"
198
+ #~ msgstr "Zeile"
languages/string-locator-es.ES.mo ADDED
Binary file
languages/string-locator-es.ES.po ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2014 String Locator
2
+ # This file is distributed under the same license as the String Locator package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: String Locator 1.1.0\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/string-locator\n"
7
+ "POT-Creation-Date: 2015-08-23 19:37+0200\n"
8
+ "PO-Revision-Date: 2015-08-23 19:37+0200\n"
9
+ "Last-Translator: jelena kovacevic <jecajeca260@gmail.com>\n"
10
+ "Language-Team: \n"
11
+ "Language: es\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Generator: Poedit 1.8.4\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e\n"
18
+ "X-Poedit-Basepath: ..\n"
19
+ "X-Poedit-SearchPath-0: .\n"
20
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
21
+
22
+ #: editor.php:68
23
+ msgid "String Locator - Code Editor"
24
+ msgstr ""
25
+
26
+ #: editor.php:69
27
+ msgid "Return to search results"
28
+ msgstr ""
29
+
30
+ #: editor.php:82
31
+ msgid "By"
32
+ msgstr ""
33
+
34
+ #: editor.php:94
35
+ msgid ""
36
+ "Enable a smart-scan of your code to help detect bracket mismatches before "
37
+ "saving."
38
+ msgstr ""
39
+
40
+ #: editor.php:110
41
+ msgid "Save changes"
42
+ msgstr ""
43
+
44
+ #: editor.php:163
45
+ msgid "WordPress Functions"
46
+ msgstr ""
47
+
48
+ #: options.php:12 string-locator.php:200 string-locator.php:201
49
+ #: string-locator.php:212 string-locator.php:213
50
+ msgid "String Locator"
51
+ msgstr "Localizador de Cadena"
52
+
53
+ #: options.php:16
54
+ msgid "Search through"
55
+ msgstr "Buscar a través de "
56
+
57
+ #: options.php:18
58
+ msgid "Core"
59
+ msgstr ""
60
+
61
+ #: options.php:19
62
+ msgid "The whole WordPress directory"
63
+ msgstr ""
64
+
65
+ #: options.php:21
66
+ msgid "Themes"
67
+ msgstr "Temas"
68
+
69
+ #: options.php:22
70
+ msgid "All themes"
71
+ msgstr ""
72
+
73
+ #: options.php:37
74
+ msgid "Plugins"
75
+ msgstr "Plugins"
76
+
77
+ #: options.php:38
78
+ msgid "All plugins"
79
+ msgstr ""
80
+
81
+ #: options.php:54
82
+ msgid "Search string"
83
+ msgstr "Cadena de búsqueda"
84
+
85
+ #: options.php:58
86
+ msgid "Search"
87
+ msgstr "Buscar"
88
+
89
+ #: options.php:59
90
+ msgid "Restore last search"
91
+ msgstr ""
92
+
93
+ #: string-locator.php:286
94
+ msgid ""
95
+ "The file could not be written to, please check file permissions or edit it "
96
+ "manually."
97
+ msgstr ""
98
+
99
+ #: string-locator.php:307
100
+ #, php-format
101
+ msgid ""
102
+ "There is an inconsistency in the opening and closing braces, { and }, of your "
103
+ "file on line %s"
104
+ msgstr ""
105
+
106
+ #: string-locator.php:325
107
+ #, php-format
108
+ msgid ""
109
+ "There is an inconsistency in the opening and closing braces, [ and ], of your "
110
+ "file on line %s"
111
+ msgstr ""
112
+
113
+ #: string-locator.php:343
114
+ #, php-format
115
+ msgid ""
116
+ "There is an inconsistency in the opening and closing braces, ( and ), of your "
117
+ "file on line %s"
118
+ msgstr ""
119
+
120
+ #: string-locator.php:374
121
+ msgid ""
122
+ "A 500 server error was detected on your site after updating your file. We "
123
+ "have restored the previous version of the file for you."
124
+ msgstr ""
125
+
126
+ #: string-locator.php:380
127
+ msgid "The file has been saved"
128
+ msgstr ""
129
+
130
+ #: string-locator.php:526
131
+ msgid "Could not read file: "
132
+ msgstr "No se puede leer el archivo:"
133
+
134
+ #: table-controller.php:13
135
+ msgid "String"
136
+ msgstr "Cadena"
137
+
138
+ #: table-controller.php:14
139
+ msgid "File"
140
+ msgstr "Archivo"
141
+
142
+ #: table-controller.php:15
143
+ msgid "Line number"
144
+ msgstr ""
145
+
146
+ #: table-controller.php:30
147
+ msgid "Your string was not present in any of the available files."
148
+ msgstr "Su cadena no estuvo presente en ninguno de los archivos disponibles."
149
+
150
+ #: table-controller.php:74
151
+ msgid "Edit"
152
+ msgstr ""
153
+
154
+ #~ msgid "Line"
155
+ #~ msgstr "Línea"
156
+
157
+ #~ msgid "Scan through theme and plugin files looking for text strings"
158
+ #~ msgstr ""
159
+ #~ "Escanear por los archivos de temas y plugins buscando cadenas de texto"
160
+
161
+ #~ msgid "Clorith"
162
+ #~ msgstr "Clorith"
163
+
164
+ #~ msgid ""
165
+ #~ "You recently searched for <strong>%s</strong> which was located on line "
166
+ #~ "<strong>%d</strong>."
167
+ #~ msgstr ""
168
+ #~ "Usted buscó recientemente <strong>%s</strong> que estuvo localizado en la "
169
+ #~ "línea <strong>%d</strong>."
170
+
171
+ #~ msgid ""
172
+ #~ "You can easily locate the line in the text editor by using your browsers "
173
+ #~ "search function (CTRL+F / CMD+F)."
174
+ #~ msgstr ""
175
+ #~ "Usted puede localizar fácilmente la línea en el editor de texto usando su "
176
+ #~ "función de búsqueda de los navegadores (CTRL+F/CMD+F)"
177
+
178
+ #~ msgid "http://www.mrstk.net/wordpress-string-locator/"
179
+ #~ msgstr "http://www.mrstk.net/wordpress-string-locator/"
180
+
181
+ #~ msgid "http://www.mrstk.net"
182
+ #~ msgstr "http://www.mrstk.net"
languages/string-locator-nb_NO.mo ADDED
Binary file
languages/string-locator-nb_NO.po ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: String Locator\n"
4
+ "POT-Creation-Date: 2015-08-23 19:36+0200\n"
5
+ "PO-Revision-Date: 2015-08-23 19:36+0200\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: \n"
8
+ "Language: nb_NO\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8.4\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "X-Poedit-WPHeader: string-locator.php\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
17
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;"
18
+ "_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
19
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
+ "X-Poedit-SearchPath-0: .\n"
21
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
22
+
23
+ #: editor.php:68
24
+ msgid "String Locator - Code Editor"
25
+ msgstr "String Locator - Redigerings verktøy"
26
+
27
+ #: editor.php:69
28
+ msgid "Return to search results"
29
+ msgstr "Tilbake til søkeresultatene"
30
+
31
+ #: editor.php:82
32
+ msgid "By"
33
+ msgstr "Av"
34
+
35
+ #: editor.php:94
36
+ msgid ""
37
+ "Enable a smart-scan of your code to help detect bracket mismatches before "
38
+ "saving."
39
+ msgstr ""
40
+ "Aktiver en smart-skanning av koden for å oppdage feil med klammer, "
41
+ "paranteser eller lignende før filen lagres."
42
+
43
+ #: editor.php:110
44
+ msgid "Save changes"
45
+ msgstr "Lagre endringer"
46
+
47
+ #: editor.php:163
48
+ msgid "WordPress Functions"
49
+ msgstr "WordPress funksjoner"
50
+
51
+ #. Plugin Name of the plugin/theme
52
+ #: options.php:12 string-locator.php:200 string-locator.php:201
53
+ #: string-locator.php:212 string-locator.php:213
54
+ msgid "String Locator"
55
+ msgstr ""
56
+
57
+ #: options.php:16
58
+ msgid "Search through"
59
+ msgstr "Søk igjennom"
60
+
61
+ #: options.php:18
62
+ msgid "Core"
63
+ msgstr "Kjernjen"
64
+
65
+ #: options.php:19
66
+ msgid "The whole WordPress directory"
67
+ msgstr "Hele WordPress mappen"
68
+
69
+ #: options.php:21
70
+ msgid "Themes"
71
+ msgstr "Temaer"
72
+
73
+ #: options.php:22
74
+ msgid "All themes"
75
+ msgstr "Alle temaer"
76
+
77
+ #: options.php:37
78
+ msgid "Plugins"
79
+ msgstr "Innstikk"
80
+
81
+ #: options.php:38
82
+ msgid "All plugins"
83
+ msgstr "Alle innstikk"
84
+
85
+ #: options.php:54
86
+ msgid "Search string"
87
+ msgstr "Søkeord"
88
+
89
+ #: options.php:58
90
+ msgid "Search"
91
+ msgstr "Søk"
92
+
93
+ #: options.php:59
94
+ msgid "Restore last search"
95
+ msgstr "Gjenopprett forrige søk"
96
+
97
+ #: string-locator.php:286
98
+ msgid ""
99
+ "The file could not be written to, please check file permissions or edit it "
100
+ "manually."
101
+ msgstr ""
102
+ "Filen er ikke skrivbar, vennligst sjekk filrettighetene eller endre filen "
103
+ "manuelt."
104
+
105
+ #: string-locator.php:307
106
+ #, php-format
107
+ msgid ""
108
+ "There is an inconsistency in the opening and closing braces, { and }, of "
109
+ "your file on line %s"
110
+ msgstr ""
111
+ "Det er ett ujevnt antall åpnende og lukkende klamme-parenteser, { og }, i "
112
+ "filen på linje %s"
113
+
114
+ #: string-locator.php:325
115
+ #, php-format
116
+ msgid ""
117
+ "There is an inconsistency in the opening and closing braces, [ and ], of "
118
+ "your file on line %s"
119
+ msgstr ""
120
+ "Det er ett ujevnt antall åpnende og lukkende klammer, [ og ], i filen på "
121
+ "linje %s"
122
+
123
+ #: string-locator.php:343
124
+ #, php-format
125
+ msgid ""
126
+ "There is an inconsistency in the opening and closing braces, ( and ), of "
127
+ "your file on line %s"
128
+ msgstr ""
129
+ "Det er ett ujevnt antall åpnende og lukkende parenteser, ( og ), i filen på "
130
+ "linje %s"
131
+
132
+ #: string-locator.php:374
133
+ msgid ""
134
+ "A 500 server error was detected on your site after updating your file. We "
135
+ "have restored the previous version of the file for you."
136
+ msgstr ""
137
+ "Det ble oppdaget en 500 feilmelding på siden etter denne endringen. Vi har "
138
+ "gjenopprettet forrige utgave av filen for deg."
139
+
140
+ #: string-locator.php:380
141
+ msgid "The file has been saved"
142
+ msgstr "Filen er lagret"
143
+
144
+ #: string-locator.php:526
145
+ msgid "Could not read file: "
146
+ msgstr "Kunne ikke lese filen: "
147
+
148
+ #: table-controller.php:13
149
+ msgid "String"
150
+ msgstr "Søkeord"
151
+
152
+ #: table-controller.php:14
153
+ msgid "File"
154
+ msgstr "Fil"
155
+
156
+ #: table-controller.php:15
157
+ msgid "Line number"
158
+ msgstr "Linje"
159
+
160
+ #: table-controller.php:30
161
+ msgid "Your string was not present in any of the available files."
162
+ msgstr "Begrepet du søkte etter fantes ikke i noen av de tilgjengelige filene"
163
+
164
+ #: table-controller.php:74
165
+ msgid "Edit"
166
+ msgstr ""
167
+
168
+ #. Plugin URI of the plugin/theme
169
+ msgid "http://www.clorith.net/wordpress-string-locator/"
170
+ msgstr ""
171
+
172
+ #. Description of the plugin/theme
173
+ msgid "Scan through theme and plugin files looking for text strings"
174
+ msgstr "Søk etter tekster i tema og innstikk koder"
175
+
176
+ #. Author of the plugin/theme
177
+ msgid "Clorith"
178
+ msgstr ""
179
+
180
+ #. Author URI of the plugin/theme
181
+ msgid "http://www.clorith.net"
182
+ msgstr ""
183
+
184
+ #~ msgid "Line"
185
+ #~ msgstr "Linje"
186
+
187
+ #~ msgid "WordPress Core"
188
+ #~ msgstr "Hele WordPress installasjonen"
languages/string-locator-sr_RS.mo ADDED
Binary file
languages/string-locator-sr_RS.po ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2014 String Locator
2
+ # This file is distributed under the same license as the String Locator package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: String Locator 1.1.0\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/string-locator\n"
7
+ "POT-Creation-Date: 2015-08-23 19:37+0200\n"
8
+ "PO-Revision-Date: 2015-08-23 19:37+0200\n"
9
+ "Last-Translator: Borisa Djuraskovic <borisad@webhostinghub.com>\n"
10
+ "Language-Team: \n"
11
+ "Language: sr_RS\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Generator: Poedit 1.8.4\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-Basepath: ..\n"
18
+ "X-Poedit-KeywordsList: __;_e\n"
19
+ "X-Poedit-SearchPath-0: .\n"
20
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
21
+
22
+ #: editor.php:68
23
+ msgid "String Locator - Code Editor"
24
+ msgstr ""
25
+
26
+ #: editor.php:69
27
+ msgid "Return to search results"
28
+ msgstr ""
29
+
30
+ #: editor.php:82
31
+ msgid "By"
32
+ msgstr ""
33
+
34
+ #: editor.php:94
35
+ msgid ""
36
+ "Enable a smart-scan of your code to help detect bracket mismatches before "
37
+ "saving."
38
+ msgstr ""
39
+
40
+ #: editor.php:110
41
+ msgid "Save changes"
42
+ msgstr ""
43
+
44
+ #: editor.php:163
45
+ msgid "WordPress Functions"
46
+ msgstr ""
47
+
48
+ #: options.php:12 string-locator.php:200 string-locator.php:201
49
+ #: string-locator.php:212 string-locator.php:213
50
+ msgid "String Locator"
51
+ msgstr "String Locator"
52
+
53
+ #: options.php:16
54
+ msgid "Search through"
55
+ msgstr "Pretraga kroz"
56
+
57
+ #: options.php:18
58
+ msgid "Core"
59
+ msgstr ""
60
+
61
+ #: options.php:19
62
+ msgid "The whole WordPress directory"
63
+ msgstr ""
64
+
65
+ #: options.php:21
66
+ msgid "Themes"
67
+ msgstr "Teme"
68
+
69
+ #: options.php:22
70
+ msgid "All themes"
71
+ msgstr ""
72
+
73
+ #: options.php:37
74
+ msgid "Plugins"
75
+ msgstr "Pluginovi"
76
+
77
+ #: options.php:38
78
+ msgid "All plugins"
79
+ msgstr ""
80
+
81
+ #: options.php:54
82
+ msgid "Search string"
83
+ msgstr "String pretrage"
84
+
85
+ #: options.php:58
86
+ msgid "Search"
87
+ msgstr "Pretraga"
88
+
89
+ #: options.php:59
90
+ msgid "Restore last search"
91
+ msgstr ""
92
+
93
+ #: string-locator.php:286
94
+ msgid ""
95
+ "The file could not be written to, please check file permissions or edit it "
96
+ "manually."
97
+ msgstr ""
98
+
99
+ #: string-locator.php:307
100
+ #, php-format
101
+ msgid ""
102
+ "There is an inconsistency in the opening and closing braces, { and }, of your "
103
+ "file on line %s"
104
+ msgstr ""
105
+
106
+ #: string-locator.php:325
107
+ #, php-format
108
+ msgid ""
109
+ "There is an inconsistency in the opening and closing braces, [ and ], of your "
110
+ "file on line %s"
111
+ msgstr ""
112
+
113
+ #: string-locator.php:343
114
+ #, php-format
115
+ msgid ""
116
+ "There is an inconsistency in the opening and closing braces, ( and ), of your "
117
+ "file on line %s"
118
+ msgstr ""
119
+
120
+ #: string-locator.php:374
121
+ msgid ""
122
+ "A 500 server error was detected on your site after updating your file. We "
123
+ "have restored the previous version of the file for you."
124
+ msgstr ""
125
+
126
+ #: string-locator.php:380
127
+ msgid "The file has been saved"
128
+ msgstr ""
129
+
130
+ #: string-locator.php:526
131
+ msgid "Could not read file: "
132
+ msgstr "Ne može da se učita fajl:"
133
+
134
+ #: table-controller.php:13
135
+ msgid "String"
136
+ msgstr "String"
137
+
138
+ #: table-controller.php:14
139
+ msgid "File"
140
+ msgstr "Fajl"
141
+
142
+ #: table-controller.php:15
143
+ msgid "Line number"
144
+ msgstr ""
145
+
146
+ #: table-controller.php:30
147
+ msgid "Your string was not present in any of the available files."
148
+ msgstr "Vaš string nije prisutan ni u jednom od fajlova."
149
+
150
+ #: table-controller.php:74
151
+ msgid "Edit"
152
+ msgstr ""
153
+
154
+ #~ msgid "Line"
155
+ #~ msgstr "Rečenica"
156
+
157
+ #~ msgid "Scan through theme and plugin files looking for text strings"
158
+ #~ msgstr ""
159
+ #~ "Skeniranje kroz teme i plugin fajlove u potrazi za stringovima teksta."
160
+
161
+ #~ msgid "Clorith"
162
+ #~ msgstr "Clorith"
163
+
164
+ #~ msgid ""
165
+ #~ "You recently searched for <strong>%s</strong> which was located on line "
166
+ #~ "<strong>%d</strong>."
167
+ #~ msgstr ""
168
+ #~ "Vaša nedavna pretraga za <strong>%s</strong> koja je locirana an <strong>"
169
+ #~ "%d</strong>."
170
+
171
+ #~ msgid ""
172
+ #~ "You can easily locate the line in the text editor by using your browsers "
173
+ #~ "search function (CTRL+F / CMD+F)."
174
+ #~ msgstr ""
175
+ #~ "Možete lako da locirate rečenicu u tekst editoru korišćenjem funkcija za "
176
+ #~ "pretragu na pretraživačima (CTRL+F / CMD+F)."
177
+
178
+ #~ msgid "http://www.mrstk.net/wordpress-string-locator/"
179
+ #~ msgstr "http://www.mrstk.net/wordpress-string-locator/"
180
+
181
+ #~ msgid "http://www.mrstk.net"
182
+ #~ msgstr "http://www.mrstk.net"
languages/string-locator.pot ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #, fuzzy
2
+ msgid ""
3
+ msgstr ""
4
+ "Project-Id-Version: String Locator\n"
5
+ "POT-Creation-Date: 2015-05-25 18:05+0100\n"
6
+ "PO-Revision-Date: 2015-05-25 18:04+0100\n"
7
+ "Last-Translator: \n"
8
+ "Language-Team: \n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "X-Poedit-WPHeader: string-locator.php\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
17
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
18
+ "_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
19
+ "X-Poedit-SearchPath-0: .\n"
20
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
21
+
22
+ #: editor.php:67
23
+ msgid "String Locator - Code Editor"
24
+ msgstr ""
25
+
26
+ #: editor.php:68
27
+ msgid "Return to search results"
28
+ msgstr ""
29
+
30
+ #: editor.php:81
31
+ msgid "By"
32
+ msgstr ""
33
+
34
+ #: editor.php:93
35
+ msgid ""
36
+ "Enable a smart-scan of your code to help detect bracket mismatches before "
37
+ "saving."
38
+ msgstr ""
39
+
40
+ #: editor.php:109
41
+ msgid "Save changes"
42
+ msgstr ""
43
+
44
+ #: editor.php:162
45
+ msgid "WordPress Functions"
46
+ msgstr ""
47
+
48
+ #. Plugin Name of the plugin/theme
49
+ #: options.php:10 string-locator.php:181 string-locator.php:182
50
+ msgid "String Locator"
51
+ msgstr ""
52
+
53
+ #: options.php:14
54
+ msgid "Search through"
55
+ msgstr ""
56
+
57
+ #: options.php:16
58
+ msgid "Core"
59
+ msgstr ""
60
+
61
+ #: options.php:17
62
+ msgid "WordPress Core"
63
+ msgstr ""
64
+
65
+ #: options.php:19
66
+ msgid "Themes"
67
+ msgstr ""
68
+
69
+ #: options.php:20
70
+ msgid "All themes"
71
+ msgstr ""
72
+
73
+ #: options.php:35
74
+ msgid "Plugins"
75
+ msgstr ""
76
+
77
+ #: options.php:36
78
+ msgid "All plugins"
79
+ msgstr ""
80
+
81
+ #: options.php:52
82
+ msgid "Search string"
83
+ msgstr ""
84
+
85
+ #: options.php:56
86
+ msgid "Search"
87
+ msgstr ""
88
+
89
+ #: options.php:57
90
+ msgid "Restore last search"
91
+ msgstr ""
92
+
93
+ #: options.php:70 options.php:78
94
+ msgid "Line"
95
+ msgstr ""
96
+
97
+ #: options.php:71 options.php:79
98
+ msgid "File"
99
+ msgstr ""
100
+
101
+ #: options.php:72 options.php:80
102
+ msgid "String"
103
+ msgstr ""
104
+
105
+ #: options.php:187
106
+ msgid "Your string was not present in any of the available files."
107
+ msgstr ""
108
+
109
+ #: string-locator.php:256
110
+ msgid ""
111
+ "The file could not be written to, please check file permissions or edit it "
112
+ "manually."
113
+ msgstr ""
114
+
115
+ #: string-locator.php:276
116
+ #, php-format
117
+ msgid ""
118
+ "There is an inconsistency in the opening and closing braces, { and }, of "
119
+ "your file on line %s"
120
+ msgstr ""
121
+
122
+ #: string-locator.php:291
123
+ #, php-format
124
+ msgid ""
125
+ "There is an inconsistency in the opening and closing braces, [ and ], of "
126
+ "your file on line %s"
127
+ msgstr ""
128
+
129
+ #: string-locator.php:306
130
+ #, php-format
131
+ msgid ""
132
+ "There is an inconsistency in the opening and closing braces, ( and ), of "
133
+ "your file on line %s"
134
+ msgstr ""
135
+
136
+ #: string-locator.php:324
137
+ msgid "The file has been saved"
138
+ msgstr ""
139
+
140
+ #: string-locator.php:412
141
+ msgid "Could not read file: "
142
+ msgstr ""
143
+
144
+ #. Plugin URI of the plugin/theme
145
+ msgid "http://www.clorith.net/wordpress-string-locator/"
146
+ msgstr ""
147
+
148
+ #. Description of the plugin/theme
149
+ msgid "Scan through theme and plugin files looking for text strings"
150
+ msgstr ""
151
+
152
+ #. Author of the plugin/theme
153
+ msgid "Clorith"
154
+ msgstr ""
155
+
156
+ #. Author URI of the plugin/theme
157
+ msgid "http://www.clorith.net"
158
+ msgstr ""
options.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this_url = admin_url( ( is_multisite() ? 'network/admin.php' : 'tools.php' ) . '?page=string-locator' );
3
+
4
+ $search_string = '';
5
+ $search_location = '';
6
+
7
+ if ( isset( $_POST['string-locator-string'] ) ) {
8
+ $search_string = $_POST['string-locator-string'];
9
+ }
10
+ if ( isset( $_POST['string-locator-search'] ) ) {
11
+ $search_location = $_POST['string-locator-search'];
12
+ }
13
+
14
+ if ( isset( $_GET['restore'] ) ) {
15
+ $restore = unserialize( get_option( 'string-locator-search-overview' ) );
16
+
17
+ $search_string = $restore->search;
18
+ $search_location = $restore->directory;
19
+ }
20
+ ?>
21
+ <div class="wrap">
22
+ <h2>
23
+ <?php _e( 'String Locator', 'string-locator' ); ?>
24
+ </h2>
25
+
26
+ <form action="<?php echo esc_url( $this_url ); ?>" method="post" id="string-locator-search-form">
27
+ <label for="string-locator-search"><?php _e( 'Search through', 'string-locator' ); ?></label>
28
+ <select name="string-locator-search" id="string-locator-search">
29
+ <optgroup label="<?php _e( 'Core', 'string-locator' ); ?>">
30
+ <option value="core"><?php _e( 'The whole WordPress directory', 'string-locator' ); ?></option>
31
+ <option value="wp-content"><?php _e( 'Everything under wp-content', 'string-locator' ); ?></option>
32
+ </optgroup>
33
+ <optgroup label="<?php _e( 'Themes', 'string-locator' ); ?>">
34
+ <?php echo String_Locator::get_themes_options( $search_location ); ?>
35
+ </optgroup>
36
+ <optgroup label="<?php _e( 'Plugins', 'string-locator' ); ?>">
37
+ <?php echo String_Locator::get_plugins_options( $search_location ); ?>
38
+ </optgroup>
39
+ </select>
40
+
41
+ <label for="string-locator-string"><?php _e( 'Search string', 'string-locator' ); ?></label>
42
+ <input type="text" name="string-locator-string" id="string-locator-string" value="<?php echo esc_attr( $search_string ); ?>" />
43
+
44
+ <p>
45
+ <input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Search', 'string-locator' ); ?>">
46
+ <a href="<?php echo esc_url( $this_url . '&restore=true' ); ?>" class="button button-primary"><?php _e( 'Restore last search', 'string-locator' ); ?></a>
47
+ </p>
48
+ </form>
49
+
50
+ <div class="notices"></div>
51
+
52
+ <div class="string-locator-feedback hide">
53
+ <progress id="string-locator-search-progress" max="100"></progress>
54
+ <span id="string-locator-feedback-text"><?php esc_html_e( 'Preparing search&hellip;', 'string-locator' ); ?></span>
55
+ </div>
56
+
57
+ <div class="table-wrapper">
58
+ <?php
59
+ if ( isset( $_GET['restore'] ) ) {
60
+ $items = maybe_unserialize( get_option( 'string-locator-search-history', array() ) );
61
+
62
+ echo String_Locator::prepare_full_table( $items, array( 'restore' ) );
63
+ }
64
+ else {
65
+ echo String_Locator::prepare_full_table( array() );
66
+ }
67
+ ?>
68
+ </div>
69
+ </div>
readme.txt ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === String locator ===
2
+ Contributors: Clorith
3
+ Author URI: http://www.clorith.net
4
+ Plugin URI: http://wordpress.org/plugins/string-locator/
5
+ Donate link: https://www.paypal.me/clorith
6
+ Tags: theme, plugin, text, search, find, editor, syntax, highlight
7
+ Requires at least: 3.6
8
+ Tested up to: 4.7
9
+ Stable tag: 2.0.3
10
+ License: GPLv2 or later
11
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
+
13
+ Find and edit code in your themes and plugins
14
+
15
+ == Description ==
16
+
17
+ When working on themes and plugins you often notice a piece of text that appears hardcoded into the files, you need to modify it, but you don't know where it's located in the theme files.
18
+
19
+ Easily search through your themes, plugins or the WordPress core and be presented with a list of files, the matched text and what line of the file matched your search.
20
+ You can then quickly make edits directly in your browser by clicking the link from the search results.
21
+
22
+ By default a Smart-Scan is enabled when making edits, this will look for inconsistencies with braces, brackets and parenthesis that are often accidentally left.
23
+ This drastically reduces the risk of breaking your site when making edits, but is not an absolute guarantee.
24
+
25
+ ** Translations**
26
+
27
+ српски (Serbian) - Ognjen Djuraskovic
28
+
29
+ Español (Spanish) - Ognjen Djuraskovic
30
+
31
+ Deutsch (German) - [pixolin](http://profiles.wordpress.org/pixolin/)
32
+
33
+ == Installation ==
34
+
35
+ 1. Upload the `string-locator` folder to the `/wp-content/plugins/` directory
36
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
37
+ 3. You will find the String Locator option under then `Tools` menu
38
+
39
+ == Frequently asked questions ==
40
+
41
+ = Will Smart-Scan guarantee my site is safe when making edits? =
42
+ Although it will do it's best at detecting incorrect usage of the commonly used symbols (parenthesis, brackets and braces), there is no guarantee every possible error is detected. The best safe guard is to keep consistent backups of your site (even when not making edits).
43
+
44
+ As of version 1.6, the plugin will check your site health after performing an edit. If the site is returning a site breaking error code, we'll revert to the previous version of the file.
45
+
46
+
47
+ == Screenshots ==
48
+
49
+ 1. Searching through the Twenty Fourteen theme for the string 'not found'
50
+ 2. Having clicked the link for one of the results and being taken to the editor in the browser
51
+ 3. Smart-Scan has detected an inconsistency in the use of braces
52
+
53
+ == Changelog ==
54
+ = 2.0.3 =
55
+ * Added support for HHVM
56
+ * Improved inline documentation
57
+
58
+ = 2.0.2 =
59
+ * Fixed max memory indicators on hosts that do not use shorthands
60
+
61
+ = 2.0.1 =
62
+ * Fixed a bug where heavy sites would not run searches due to incorrect memory consumption calculations
63
+ * Fixed a visual bug when warnings are displayed
64
+ * Added error feedback if high execution times or memory consumption is detected before a search is started
65
+
66
+ = 2.0.0 =
67
+ * Performance enhancement, now also detects memory consumption to avoid exceeding memory limits
68
+ * Fixed a warning incorrectly being shown saying files cannot be read
69
+ * Better feedback during the search process
70
+ * Fixed a longstanding bug with searching single file plugins
71
+
72
+
73
+ == Upgrade notice ==
74
+
75
+ Add support for HHVM setups
resources/css/codemirror.css ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* BASICS */
2
+
3
+ .CodeMirror {
4
+ /* Set height, width, borders, and global font properties here */
5
+ font-family: monospace;
6
+ height: 300px;
7
+ }
8
+ .CodeMirror-scroll {
9
+ /* Set scrolling behaviour here */
10
+ overflow: auto;
11
+ }
12
+
13
+ /* PADDING */
14
+
15
+ .CodeMirror-lines {
16
+ padding: 4px 0; /* Vertical padding around content */
17
+ }
18
+ .CodeMirror pre {
19
+ padding: 0 4px; /* Horizontal padding of content */
20
+ }
21
+
22
+ .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
23
+ background-color: white; /* The little square between H and V scrollbars */
24
+ }
25
+
26
+ /* GUTTER */
27
+
28
+ .CodeMirror-gutters {
29
+ border-right: 1px solid #ddd;
30
+ background-color: #f7f7f7;
31
+ white-space: nowrap;
32
+ }
33
+ .CodeMirror-linenumbers {}
34
+ .CodeMirror-linenumber {
35
+ padding: 0 3px 0 5px;
36
+ min-width: 20px;
37
+ text-align: right;
38
+ color: #999;
39
+ -moz-box-sizing: content-box;
40
+ box-sizing: content-box;
41
+ }
42
+
43
+ /* CURSOR */
44
+
45
+ .CodeMirror div.CodeMirror-cursor {
46
+ border-left: 1px solid black;
47
+ }
48
+ /* Shown when moving in bi-directional text */
49
+ .CodeMirror div.CodeMirror-secondarycursor {
50
+ border-left: 1px solid silver;
51
+ }
52
+ .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
53
+ width: auto;
54
+ border: 0;
55
+ background: #7e7;
56
+ }
57
+ /* Can style cursor different in overwrite (non-insert) mode */
58
+ div.CodeMirror-overwrite div.CodeMirror-cursor {}
59
+
60
+ .cm-tab { display: inline-block; }
61
+
62
+ .CodeMirror-ruler {
63
+ border-left: 1px solid #ccc;
64
+ position: absolute;
65
+ }
66
+
67
+ /* DEFAULT THEME */
68
+
69
+ .cm-s-default .cm-keyword {color: #708;}
70
+ .cm-s-default .cm-atom {color: #219;}
71
+ .cm-s-default .cm-number {color: #164;}
72
+ .cm-s-default .cm-def {color: #00f;}
73
+ .cm-s-default .cm-variable,
74
+ .cm-s-default .cm-punctuation,
75
+ .cm-s-default .cm-property,
76
+ .cm-s-default .cm-operator {}
77
+ .cm-s-default .cm-variable-2 {color: #05a;}
78
+ .cm-s-default .cm-variable-3 {color: #085;}
79
+ .cm-s-default .cm-comment {color: #a50;}
80
+ .cm-s-default .cm-string {color: #a11;}
81
+ .cm-s-default .cm-string-2 {color: #f50;}
82
+ .cm-s-default .cm-meta {color: #555;}
83
+ .cm-s-default .cm-qualifier {color: #555;}
84
+ .cm-s-default .cm-builtin {color: #30a;}
85
+ .cm-s-default .cm-bracket {color: #997;}
86
+ .cm-s-default .cm-tag {color: #170;}
87
+ .cm-s-default .cm-attribute {color: #00c;}
88
+ .cm-s-default .cm-header {color: blue;}
89
+ .cm-s-default .cm-quote {color: #090;}
90
+ .cm-s-default .cm-hr {color: #999;}
91
+ .cm-s-default .cm-link {color: #00c;}
92
+
93
+ .cm-negative {color: #d44;}
94
+ .cm-positive {color: #292;}
95
+ .cm-header, .cm-strong {font-weight: bold;}
96
+ .cm-em {font-style: italic;}
97
+ .cm-link {text-decoration: underline;}
98
+
99
+ .cm-s-default .cm-error {color: #f00;}
100
+ .cm-invalidchar {color: #f00;}
101
+
102
+ div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
103
+ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
104
+ .CodeMirror-activeline-background {background: #e8f2ff;}
105
+
106
+ /* STOP */
107
+
108
+ /* The rest of this file contains styles related to the mechanics of
109
+ the editor. You probably shouldn't touch them. */
110
+
111
+ .CodeMirror {
112
+ line-height: 1;
113
+ position: relative;
114
+ overflow: hidden;
115
+ background: white;
116
+ color: black;
117
+ }
118
+
119
+ .CodeMirror-scroll {
120
+ /* 30px is the magic margin used to hide the element's real scrollbars */
121
+ /* See overflow: hidden in .CodeMirror */
122
+ margin-bottom: -30px; margin-right: -30px;
123
+ padding-bottom: 30px;
124
+ height: 100%;
125
+ outline: none; /* Prevent dragging from highlighting the element */
126
+ position: relative;
127
+ -moz-box-sizing: content-box;
128
+ box-sizing: content-box;
129
+ }
130
+ .CodeMirror-sizer {
131
+ position: relative;
132
+ border-right: 30px solid transparent;
133
+ -moz-box-sizing: content-box;
134
+ box-sizing: content-box;
135
+ }
136
+
137
+ /* The fake, visible scrollbars. Used to force redraw during scrolling
138
+ before actuall scrolling happens, thus preventing shaking and
139
+ flickering artifacts. */
140
+ .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
141
+ position: absolute;
142
+ z-index: 6;
143
+ display: none;
144
+ }
145
+ .CodeMirror-vscrollbar {
146
+ right: 0; top: 0;
147
+ overflow-x: hidden;
148
+ overflow-y: scroll;
149
+ }
150
+ .CodeMirror-hscrollbar {
151
+ bottom: 0; left: 0;
152
+ overflow-y: hidden;
153
+ overflow-x: scroll;
154
+ }
155
+ .CodeMirror-scrollbar-filler {
156
+ right: 0; bottom: 0;
157
+ }
158
+ .CodeMirror-gutter-filler {
159
+ left: 0; bottom: 0;
160
+ }
161
+
162
+ .CodeMirror-gutters {
163
+ position: absolute; left: 0; top: 0;
164
+ padding-bottom: 30px;
165
+ z-index: 3;
166
+ }
167
+ .CodeMirror-gutter {
168
+ white-space: normal;
169
+ height: 100%;
170
+ -moz-box-sizing: content-box;
171
+ box-sizing: content-box;
172
+ padding-bottom: 30px;
173
+ margin-bottom: -32px;
174
+ display: inline-block;
175
+ /* Hack to make IE7 behave */
176
+ *zoom:1;
177
+ *display:inline;
178
+ }
179
+ .CodeMirror-gutter-elt {
180
+ position: absolute;
181
+ cursor: default;
182
+ z-index: 4;
183
+ }
184
+
185
+ .CodeMirror-lines {
186
+ cursor: text;
187
+ }
188
+ .CodeMirror pre {
189
+ /* Reset some styles that the rest of the page might have set */
190
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
191
+ border-width: 0;
192
+ background: transparent;
193
+ font-family: inherit;
194
+ font-size: inherit;
195
+ margin: 0;
196
+ white-space: pre;
197
+ word-wrap: normal;
198
+ line-height: inherit;
199
+ color: inherit;
200
+ z-index: 2;
201
+ position: relative;
202
+ overflow: visible;
203
+ }
204
+ .CodeMirror-wrap pre {
205
+ word-wrap: break-word;
206
+ white-space: pre-wrap;
207
+ word-break: normal;
208
+ }
209
+
210
+ .CodeMirror-linebackground {
211
+ position: absolute;
212
+ left: 0; right: 0; top: 0; bottom: 0;
213
+ z-index: 0;
214
+ }
215
+
216
+ .CodeMirror-linewidget {
217
+ position: relative;
218
+ z-index: 2;
219
+ overflow: auto;
220
+ }
221
+
222
+ .CodeMirror-widget {}
223
+
224
+ .CodeMirror-wrap .CodeMirror-scroll {
225
+ overflow-x: hidden;
226
+ }
227
+
228
+ .CodeMirror-measure {
229
+ position: absolute;
230
+ width: 100%;
231
+ height: 0;
232
+ overflow: hidden;
233
+ visibility: hidden;
234
+ }
235
+ .CodeMirror-measure pre { position: static; }
236
+
237
+ .CodeMirror div.CodeMirror-cursor {
238
+ position: absolute;
239
+ border-right: none;
240
+ width: 0;
241
+ }
242
+
243
+ div.CodeMirror-cursors {
244
+ visibility: hidden;
245
+ position: relative;
246
+ z-index: 1;
247
+ }
248
+ .CodeMirror-focused div.CodeMirror-cursors {
249
+ visibility: visible;
250
+ }
251
+
252
+ .CodeMirror-selected { background: #d9d9d9; }
253
+ .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
254
+ .CodeMirror-crosshair { cursor: crosshair; }
255
+
256
+ .cm-searching {
257
+ background: #ffa;
258
+ background: rgba(255, 255, 0, .4);
259
+ }
260
+
261
+ /* IE7 hack to prevent it from returning funny offsetTops on the spans */
262
+ .CodeMirror span { *vertical-align: text-bottom; }
263
+
264
+ /* Used to force a border model for a node */
265
+ .cm-force-border { padding-right: .1px; }
266
+
267
+ @media print {
268
+ /* Hide the cursor when printing */
269
+ .CodeMirror div.CodeMirror-cursors {
270
+ visibility: hidden;
271
+ }
272
+ }
resources/css/codemirror/3024-day.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: 3024 day
4
+ Author: Jan T. Sott (http://github.com/idleberg)
5
+
6
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
7
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
8
+
9
+ */
10
+
11
+ .cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;}
12
+ .cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;}
13
+ .cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;}
14
+ .cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;}
15
+ .cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;}
16
+
17
+ .cm-s-3024-day span.cm-comment {color: #cdab53;}
18
+ .cm-s-3024-day span.cm-atom {color: #a16a94;}
19
+ .cm-s-3024-day span.cm-number {color: #a16a94;}
20
+
21
+ .cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;}
22
+ .cm-s-3024-day span.cm-keyword {color: #db2d20;}
23
+ .cm-s-3024-day span.cm-string {color: #fded02;}
24
+
25
+ .cm-s-3024-day span.cm-variable {color: #01a252;}
26
+ .cm-s-3024-day span.cm-variable-2 {color: #01a0e4;}
27
+ .cm-s-3024-day span.cm-def {color: #e8bbd0;}
28
+ .cm-s-3024-day span.cm-bracket {color: #3a3432;}
29
+ .cm-s-3024-day span.cm-tag {color: #db2d20;}
30
+ .cm-s-3024-day span.cm-link {color: #a16a94;}
31
+ .cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;}
32
+
33
+ .cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;}
34
+ .cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/3024-night.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: 3024 night
4
+ Author: Jan T. Sott (http://github.com/idleberg)
5
+
6
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
7
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
8
+
9
+ */
10
+
11
+ .cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;}
12
+ .cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;}
13
+ .cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;}
14
+ .cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;}
15
+ .cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;}
16
+
17
+ .cm-s-3024-night span.cm-comment {color: #cdab53;}
18
+ .cm-s-3024-night span.cm-atom {color: #a16a94;}
19
+ .cm-s-3024-night span.cm-number {color: #a16a94;}
20
+
21
+ .cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;}
22
+ .cm-s-3024-night span.cm-keyword {color: #db2d20;}
23
+ .cm-s-3024-night span.cm-string {color: #fded02;}
24
+
25
+ .cm-s-3024-night span.cm-variable {color: #01a252;}
26
+ .cm-s-3024-night span.cm-variable-2 {color: #01a0e4;}
27
+ .cm-s-3024-night span.cm-def {color: #e8bbd0;}
28
+ .cm-s-3024-night span.cm-bracket {color: #d6d5d4;}
29
+ .cm-s-3024-night span.cm-tag {color: #db2d20;}
30
+ .cm-s-3024-night span.cm-link {color: #a16a94;}
31
+ .cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;}
32
+
33
+ .cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;}
34
+ .cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/ambiance-mobile.css ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ .cm-s-ambiance.CodeMirror {
2
+ -webkit-box-shadow: none;
3
+ -moz-box-shadow: none;
4
+ box-shadow: none;
5
+ }
resources/css/codemirror/ambiance.css ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ambiance theme for codemirror */
2
+
3
+ /* Color scheme */
4
+
5
+ .cm-s-ambiance .cm-keyword { color: #cda869; }
6
+ .cm-s-ambiance .cm-atom { color: #CF7EA9; }
7
+ .cm-s-ambiance .cm-number { color: #78CF8A; }
8
+ .cm-s-ambiance .cm-def { color: #aac6e3; }
9
+ .cm-s-ambiance .cm-variable { color: #ffb795; }
10
+ .cm-s-ambiance .cm-variable-2 { color: #eed1b3; }
11
+ .cm-s-ambiance .cm-variable-3 { color: #faded3; }
12
+ .cm-s-ambiance .cm-property { color: #eed1b3; }
13
+ .cm-s-ambiance .cm-operator {color: #fa8d6a;}
14
+ .cm-s-ambiance .cm-comment { color: #555; font-style:italic; }
15
+ .cm-s-ambiance .cm-string { color: #8f9d6a; }
16
+ .cm-s-ambiance .cm-string-2 { color: #9d937c; }
17
+ .cm-s-ambiance .cm-meta { color: #D2A8A1; }
18
+ .cm-s-ambiance .cm-qualifier { color: yellow; }
19
+ .cm-s-ambiance .cm-builtin { color: #9999cc; }
20
+ .cm-s-ambiance .cm-bracket { color: #24C2C7; }
21
+ .cm-s-ambiance .cm-tag { color: #fee4ff }
22
+ .cm-s-ambiance .cm-attribute { color: #9B859D; }
23
+ .cm-s-ambiance .cm-header {color: blue;}
24
+ .cm-s-ambiance .cm-quote { color: #24C2C7; }
25
+ .cm-s-ambiance .cm-hr { color: pink; }
26
+ .cm-s-ambiance .cm-link { color: #F4C20B; }
27
+ .cm-s-ambiance .cm-special { color: #FF9D00; }
28
+ .cm-s-ambiance .cm-error { color: #AF2018; }
29
+
30
+ .cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }
31
+ .cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }
32
+
33
+ .cm-s-ambiance .CodeMirror-selected {
34
+ background: rgba(255, 255, 255, 0.15);
35
+ }
36
+ .cm-s-ambiance.CodeMirror-focused .CodeMirror-selected {
37
+ background: rgba(255, 255, 255, 0.10);
38
+ }
39
+
40
+ /* Editor styling */
41
+
42
+ .cm-s-ambiance.CodeMirror {
43
+ line-height: 1.40em;
44
+ color: #E6E1DC;
45
+ background-color: #202020;
46
+ -webkit-box-shadow: inset 0 0 10px black;
47
+ -moz-box-shadow: inset 0 0 10px black;
48
+ box-shadow: inset 0 0 10px black;
49
+ }
50
+
51
+ .cm-s-ambiance .CodeMirror-gutters {
52
+ background: #3D3D3D;
53
+ border-right: 1px solid #4D4D4D;
54
+ box-shadow: 0 10px 20px black;
55
+ }
56
+
57
+ .cm-s-ambiance .CodeMirror-linenumber {
58
+ text-shadow: 0px 1px 1px #4d4d4d;
59
+ color: #222;
60
+ padding: 0 5px;
61
+ }
62
+
63
+ .cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor {
64
+ border-left: 1px solid #7991E8;
65
+ }
66
+
67
+ .cm-s-ambiance .CodeMirror-activeline-background {
68
+ background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);
69
+ }
70
+
71
+ .cm-s-ambiance.CodeMirror,
72
+ .cm-s-ambiance .CodeMirror-gutters {
73
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC");
74
+ }
resources/css/codemirror/base16-dark.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: Base16 Default Dark
4
+ Author: Chris Kempson (http://chriskempson.com)
5
+
6
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
7
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
8
+
9
+ */
10
+
11
+ .cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;}
12
+ .cm-s-base16-dark div.CodeMirror-selected {background: #202020 !important;}
13
+ .cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;}
14
+ .cm-s-base16-dark .CodeMirror-linenumber {color: #505050;}
15
+ .cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;}
16
+
17
+ .cm-s-base16-dark span.cm-comment {color: #8f5536;}
18
+ .cm-s-base16-dark span.cm-atom {color: #aa759f;}
19
+ .cm-s-base16-dark span.cm-number {color: #aa759f;}
20
+
21
+ .cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;}
22
+ .cm-s-base16-dark span.cm-keyword {color: #ac4142;}
23
+ .cm-s-base16-dark span.cm-string {color: #f4bf75;}
24
+
25
+ .cm-s-base16-dark span.cm-variable {color: #90a959;}
26
+ .cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;}
27
+ .cm-s-base16-dark span.cm-def {color: #d28445;}
28
+ .cm-s-base16-dark span.cm-bracket {color: #e0e0e0;}
29
+ .cm-s-base16-dark span.cm-tag {color: #ac4142;}
30
+ .cm-s-base16-dark span.cm-link {color: #aa759f;}
31
+ .cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;}
32
+
33
+ .cm-s-base16-dark .CodeMirror-activeline-background {background: #2F2F2F !important;}
34
+ .cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/base16-light.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: Base16 Default Light
4
+ Author: Chris Kempson (http://chriskempson.com)
5
+
6
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
7
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
8
+
9
+ */
10
+
11
+ .cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;}
12
+ .cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;}
13
+ .cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;}
14
+ .cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;}
15
+ .cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;}
16
+
17
+ .cm-s-base16-light span.cm-comment {color: #8f5536;}
18
+ .cm-s-base16-light span.cm-atom {color: #aa759f;}
19
+ .cm-s-base16-light span.cm-number {color: #aa759f;}
20
+
21
+ .cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;}
22
+ .cm-s-base16-light span.cm-keyword {color: #ac4142;}
23
+ .cm-s-base16-light span.cm-string {color: #f4bf75;}
24
+
25
+ .cm-s-base16-light span.cm-variable {color: #90a959;}
26
+ .cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;}
27
+ .cm-s-base16-light span.cm-def {color: #d28445;}
28
+ .cm-s-base16-light span.cm-bracket {color: #202020;}
29
+ .cm-s-base16-light span.cm-tag {color: #ac4142;}
30
+ .cm-s-base16-light span.cm-link {color: #aa759f;}
31
+ .cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;}
32
+
33
+ .cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;}
34
+ .cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/blackboard.css ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Port of TextMate's Blackboard theme */
2
+
3
+ .cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }
4
+ .cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; }
5
+ .cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }
6
+ .cm-s-blackboard .CodeMirror-linenumber { color: #888; }
7
+ .cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
8
+
9
+ .cm-s-blackboard .cm-keyword { color: #FBDE2D; }
10
+ .cm-s-blackboard .cm-atom { color: #D8FA3C; }
11
+ .cm-s-blackboard .cm-number { color: #D8FA3C; }
12
+ .cm-s-blackboard .cm-def { color: #8DA6CE; }
13
+ .cm-s-blackboard .cm-variable { color: #FF6400; }
14
+ .cm-s-blackboard .cm-operator { color: #FBDE2D;}
15
+ .cm-s-blackboard .cm-comment { color: #AEAEAE; }
16
+ .cm-s-blackboard .cm-string { color: #61CE3C; }
17
+ .cm-s-blackboard .cm-string-2 { color: #61CE3C; }
18
+ .cm-s-blackboard .cm-meta { color: #D8FA3C; }
19
+ .cm-s-blackboard .cm-builtin { color: #8DA6CE; }
20
+ .cm-s-blackboard .cm-tag { color: #8DA6CE; }
21
+ .cm-s-blackboard .cm-attribute { color: #8DA6CE; }
22
+ .cm-s-blackboard .cm-header { color: #FF6400; }
23
+ .cm-s-blackboard .cm-hr { color: #AEAEAE; }
24
+ .cm-s-blackboard .cm-link { color: #8DA6CE; }
25
+ .cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
26
+
27
+ .cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;}
28
+ .cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
resources/css/codemirror/cobalt.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-cobalt.CodeMirror { background: #002240; color: white; }
2
+ .cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; }
3
+ .cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
4
+ .cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }
5
+ .cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; }
6
+
7
+ .cm-s-cobalt span.cm-comment { color: #08f; }
8
+ .cm-s-cobalt span.cm-atom { color: #845dc4; }
9
+ .cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }
10
+ .cm-s-cobalt span.cm-keyword { color: #ffee80; }
11
+ .cm-s-cobalt span.cm-string { color: #3ad900; }
12
+ .cm-s-cobalt span.cm-meta { color: #ff9d00; }
13
+ .cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
14
+ .cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
15
+ .cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
16
+ .cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
17
+ .cm-s-cobalt span.cm-link { color: #845dc4; }
18
+ .cm-s-cobalt span.cm-error { color: #9d1e15; }
19
+
20
+ .cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;}
21
+ .cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
resources/css/codemirror/eclipse.css ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-eclipse span.cm-meta {color: #FF1717;}
2
+ .cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
3
+ .cm-s-eclipse span.cm-atom {color: #219;}
4
+ .cm-s-eclipse span.cm-number {color: #164;}
5
+ .cm-s-eclipse span.cm-def {color: #00f;}
6
+ .cm-s-eclipse span.cm-variable {color: black;}
7
+ .cm-s-eclipse span.cm-variable-2 {color: #0000C0;}
8
+ .cm-s-eclipse span.cm-variable-3 {color: #0000C0;}
9
+ .cm-s-eclipse span.cm-property {color: black;}
10
+ .cm-s-eclipse span.cm-operator {color: black;}
11
+ .cm-s-eclipse span.cm-comment {color: #3F7F5F;}
12
+ .cm-s-eclipse span.cm-string {color: #2A00FF;}
13
+ .cm-s-eclipse span.cm-string-2 {color: #f50;}
14
+ .cm-s-eclipse span.cm-qualifier {color: #555;}
15
+ .cm-s-eclipse span.cm-builtin {color: #30a;}
16
+ .cm-s-eclipse span.cm-bracket {color: #cc7;}
17
+ .cm-s-eclipse span.cm-tag {color: #170;}
18
+ .cm-s-eclipse span.cm-attribute {color: #00c;}
19
+ .cm-s-eclipse span.cm-link {color: #219;}
20
+ .cm-s-eclipse span.cm-error {color: #f00;}
21
+
22
+ .cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}
23
+ .cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
resources/css/codemirror/elegant.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
2
+ .cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}
3
+ .cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}
4
+ .cm-s-elegant span.cm-variable {color: black;}
5
+ .cm-s-elegant span.cm-variable-2 {color: #b11;}
6
+ .cm-s-elegant span.cm-qualifier {color: #555;}
7
+ .cm-s-elegant span.cm-keyword {color: #730;}
8
+ .cm-s-elegant span.cm-builtin {color: #30a;}
9
+ .cm-s-elegant span.cm-link {color: #762;}
10
+ .cm-s-elegant span.cm-error {background-color: #fdd;}
11
+
12
+ .cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;}
13
+ .cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
resources/css/codemirror/erlang-dark.css ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-erlang-dark.CodeMirror { background: #002240; color: white; }
2
+ .cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; }
3
+ .cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
4
+ .cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }
5
+ .cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
6
+
7
+ .cm-s-erlang-dark span.cm-atom { color: #f133f1; }
8
+ .cm-s-erlang-dark span.cm-attribute { color: #ff80e1; }
9
+ .cm-s-erlang-dark span.cm-bracket { color: #ff9d00; }
10
+ .cm-s-erlang-dark span.cm-builtin { color: #eaa; }
11
+ .cm-s-erlang-dark span.cm-comment { color: #77f; }
12
+ .cm-s-erlang-dark span.cm-def { color: #e7a; }
13
+ .cm-s-erlang-dark span.cm-keyword { color: #ffee80; }
14
+ .cm-s-erlang-dark span.cm-meta { color: #50fefe; }
15
+ .cm-s-erlang-dark span.cm-number { color: #ffd0d0; }
16
+ .cm-s-erlang-dark span.cm-operator { color: #d55; }
17
+ .cm-s-erlang-dark span.cm-property { color: #ccc; }
18
+ .cm-s-erlang-dark span.cm-qualifier { color: #ccc; }
19
+ .cm-s-erlang-dark span.cm-quote { color: #ccc; }
20
+ .cm-s-erlang-dark span.cm-special { color: #ffbbbb; }
21
+ .cm-s-erlang-dark span.cm-string { color: #3ad900; }
22
+ .cm-s-erlang-dark span.cm-string-2 { color: #ccc; }
23
+ .cm-s-erlang-dark span.cm-tag { color: #9effff; }
24
+ .cm-s-erlang-dark span.cm-variable { color: #50fe50; }
25
+ .cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }
26
+ .cm-s-erlang-dark span.cm-variable-3 { color: #ccc; }
27
+ .cm-s-erlang-dark span.cm-error { color: #9d1e15; }
28
+
29
+ .cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;}
30
+ .cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/lesser-dark.css ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ http://lesscss.org/ dark theme
3
+ Ported to CodeMirror by Peter Kroon
4
+ */
5
+ .cm-s-lesser-dark {
6
+ line-height: 1.3em;
7
+ }
8
+ .cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
9
+ .cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/
10
+ .cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
11
+ .cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/
12
+
13
+ .cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
14
+
15
+ .cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }
16
+ .cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }
17
+
18
+ .cm-s-lesser-dark span.cm-keyword { color: #599eff; }
19
+ .cm-s-lesser-dark span.cm-atom { color: #C2B470; }
20
+ .cm-s-lesser-dark span.cm-number { color: #B35E4D; }
21
+ .cm-s-lesser-dark span.cm-def {color: white;}
22
+ .cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }
23
+ .cm-s-lesser-dark span.cm-variable-2 { color: #669199; }
24
+ .cm-s-lesser-dark span.cm-variable-3 { color: white; }
25
+ .cm-s-lesser-dark span.cm-property {color: #92A75C;}
26
+ .cm-s-lesser-dark span.cm-operator {color: #92A75C;}
27
+ .cm-s-lesser-dark span.cm-comment { color: #666; }
28
+ .cm-s-lesser-dark span.cm-string { color: #BCD279; }
29
+ .cm-s-lesser-dark span.cm-string-2 {color: #f50;}
30
+ .cm-s-lesser-dark span.cm-meta { color: #738C73; }
31
+ .cm-s-lesser-dark span.cm-qualifier {color: #555;}
32
+ .cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }
33
+ .cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }
34
+ .cm-s-lesser-dark span.cm-tag { color: #669199; }
35
+ .cm-s-lesser-dark span.cm-attribute {color: #00c;}
36
+ .cm-s-lesser-dark span.cm-header {color: #a0a;}
37
+ .cm-s-lesser-dark span.cm-quote {color: #090;}
38
+ .cm-s-lesser-dark span.cm-hr {color: #999;}
39
+ .cm-s-lesser-dark span.cm-link {color: #00c;}
40
+ .cm-s-lesser-dark span.cm-error { color: #9d1e15; }
41
+
42
+ .cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;}
43
+ .cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/mbo.css ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Based on mbonaci's Brackets mbo theme */
2
+
3
+ .cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;}
4
+ .cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;}
5
+ .cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;}
6
+ .cm-s-mbo .CodeMirror-linenumber {color: #dadada;}
7
+ .cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;}
8
+
9
+ .cm-s-mbo span.cm-comment {color: #95958a;}
10
+ .cm-s-mbo span.cm-atom {color: #00a8c6;}
11
+ .cm-s-mbo span.cm-number {color: #00a8c6;}
12
+
13
+ .cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;}
14
+ .cm-s-mbo span.cm-keyword {color: #ffb928;}
15
+ .cm-s-mbo span.cm-string {color: #ffcf6c;}
16
+
17
+ .cm-s-mbo span.cm-variable {color: #ffffec;}
18
+ .cm-s-mbo span.cm-variable-2 {color: #00a8c6;}
19
+ .cm-s-mbo span.cm-def {color: #ffffec;}
20
+ .cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;}
21
+ .cm-s-mbo span.cm-tag {color: #9ddfe9;}
22
+ .cm-s-mbo span.cm-link {color: #f54b07;}
23
+ .cm-s-mbo span.cm-error {background: #636363; color: #ffffec;}
24
+
25
+ .cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}
26
+ .cm-s-mbo .CodeMirror-matchingbracket {
27
+ text-decoration: underline;
28
+ color: #f5e107 !important;
29
+ }
30
+
31
+ .cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;}
32
+
33
+ .cm-s-mbo span.cm-searching {
34
+ background-color: none;
35
+ background: none;
36
+ box-shadow: 0 0 0 1px #ffffec;
37
+ }
resources/css/codemirror/mdn-like.css ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ MDN-LIKE Theme - Mozilla
3
+ Ported to CodeMirror by Peter Kroon <plakroon@gmail.com>
4
+ Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues
5
+ GitHub: @peterkroon
6
+
7
+ The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation
8
+
9
+ */
10
+ .cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }
11
+ .cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; }
12
+
13
+ .cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }
14
+ .cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; margin-left: 3px; }
15
+ div.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; }
16
+
17
+ .cm-s-mdn-like .cm-keyword { color: #6262FF; }
18
+ .cm-s-mdn-like .cm-atom { color: #F90; }
19
+ .cm-s-mdn-like .cm-number { color: #ca7841; }
20
+ .cm-s-mdn-like .cm-def { color: #8DA6CE; }
21
+ .cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; }
22
+ .cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; }
23
+
24
+ .cm-s-mdn-like .cm-variable { color: #07a; }
25
+ .cm-s-mdn-like .cm-property { color: #905; }
26
+ .cm-s-mdn-like .cm-qualifier { color: #690; }
27
+
28
+ .cm-s-mdn-like .cm-operator { color: #cda869; }
29
+ .cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; }
30
+ .cm-s-mdn-like .cm-string { color:#07a; font-style:italic; }
31
+ .cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/
32
+ .cm-s-mdn-like .cm-meta { color: #000; } /*?*/
33
+ .cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/
34
+ .cm-s-mdn-like .cm-tag { color: #997643; }
35
+ .cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/
36
+ .cm-s-mdn-like .cm-header { color: #FF6400; }
37
+ .cm-s-mdn-like .cm-hr { color: #AEAEAE; }
38
+ .cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; }
39
+ .cm-s-mdn-like .cm-error { border-bottom: 1px solid red; }
40
+
41
+ div.cm-s-mdn-like .CodeMirror-activeline-background {background: #efefff;}
42
+ div.cm-s-mdn-like span.CodeMirror-matchingbracket {outline:1px solid grey; color: inherit;}
43
+
44
+ .cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); }
resources/css/codemirror/midnight.css ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */
2
+
3
+ /*<!--match-->*/
4
+ .cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }
5
+ .cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }
6
+
7
+ /*<!--activeline-->*/
8
+ .cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;}
9
+
10
+ .cm-s-midnight.CodeMirror {
11
+ background: #0F192A;
12
+ color: #D1EDFF;
13
+ }
14
+
15
+ .cm-s-midnight.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
16
+
17
+ .cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;}
18
+ .cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;}
19
+ .cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;}
20
+ .cm-s-midnight .CodeMirror-cursor {
21
+ border-left: 1px solid #F8F8F0 !important;
22
+ }
23
+
24
+ .cm-s-midnight span.cm-comment {color: #428BDD;}
25
+ .cm-s-midnight span.cm-atom {color: #AE81FF;}
26
+ .cm-s-midnight span.cm-number {color: #D1EDFF;}
27
+
28
+ .cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute {color: #A6E22E;}
29
+ .cm-s-midnight span.cm-keyword {color: #E83737;}
30
+ .cm-s-midnight span.cm-string {color: #1DC116;}
31
+
32
+ .cm-s-midnight span.cm-variable {color: #FFAA3E;}
33
+ .cm-s-midnight span.cm-variable-2 {color: #FFAA3E;}
34
+ .cm-s-midnight span.cm-def {color: #4DD;}
35
+ .cm-s-midnight span.cm-bracket {color: #D1EDFF;}
36
+ .cm-s-midnight span.cm-tag {color: #449;}
37
+ .cm-s-midnight span.cm-link {color: #AE81FF;}
38
+ .cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;}
39
+
40
+ .cm-s-midnight .CodeMirror-matchingbracket {
41
+ text-decoration: underline;
42
+ color: white !important;
43
+ }
resources/css/codemirror/monokai.css ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Based on Sublime Text's Monokai theme */
2
+
3
+ .cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;}
4
+ .cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
5
+ .cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;}
6
+ .cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;}
7
+ .cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
8
+
9
+ .cm-s-monokai span.cm-comment {color: #75715e;}
10
+ .cm-s-monokai span.cm-atom {color: #ae81ff;}
11
+ .cm-s-monokai span.cm-number {color: #ae81ff;}
12
+
13
+ .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
14
+ .cm-s-monokai span.cm-keyword {color: #f92672;}
15
+ .cm-s-monokai span.cm-string {color: #e6db74;}
16
+
17
+ .cm-s-monokai span.cm-variable {color: #a6e22e;}
18
+ .cm-s-monokai span.cm-variable-2 {color: #9effff;}
19
+ .cm-s-monokai span.cm-def {color: #fd971f;}
20
+ .cm-s-monokai span.cm-bracket {color: #f8f8f2;}
21
+ .cm-s-monokai span.cm-tag {color: #f92672;}
22
+ .cm-s-monokai span.cm-link {color: #ae81ff;}
23
+ .cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
24
+
25
+ .cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}
26
+ .cm-s-monokai .CodeMirror-matchingbracket {
27
+ text-decoration: underline;
28
+ color: white !important;
29
+ }
resources/css/codemirror/neat.css ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-neat span.cm-comment { color: #a86; }
2
+ .cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
3
+ .cm-s-neat span.cm-string { color: #a22; }
4
+ .cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
5
+ .cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
6
+ .cm-s-neat span.cm-variable { color: black; }
7
+ .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
8
+ .cm-s-neat span.cm-meta {color: #555;}
9
+ .cm-s-neat span.cm-link { color: #3a3; }
10
+
11
+ .cm-s-neat .CodeMirror-activeline-background {background: #e8f2ff !important;}
12
+ .cm-s-neat .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
resources/css/codemirror/neo.css ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* neo theme for codemirror */
2
+
3
+ /* Color scheme */
4
+
5
+ .cm-s-neo.CodeMirror {
6
+ background-color:#ffffff;
7
+ color:#2e383c;
8
+ line-height:1.4375;
9
+ }
10
+ .cm-s-neo .cm-comment {color:#75787b}
11
+ .cm-s-neo .cm-keyword, .cm-s-neo .cm-property {color:#1d75b3}
12
+ .cm-s-neo .cm-atom,.cm-s-neo .cm-number {color:#75438a}
13
+ .cm-s-neo .cm-node,.cm-s-neo .cm-tag {color:#9c3328}
14
+ .cm-s-neo .cm-string {color:#b35e14}
15
+ .cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier {color:#047d65}
16
+
17
+
18
+ /* Editor styling */
19
+
20
+ .cm-s-neo pre {
21
+ padding:0;
22
+ }
23
+
24
+ .cm-s-neo .CodeMirror-gutters {
25
+ border:none;
26
+ border-right:10px solid transparent;
27
+ background-color:transparent;
28
+ }
29
+
30
+ .cm-s-neo .CodeMirror-linenumber {
31
+ padding:0;
32
+ color:#e0e2e5;
33
+ }
34
+
35
+ .cm-s-neo div.CodeMirror-cursor {
36
+ width: auto;
37
+ border: 0;
38
+ background: rgba(155,157,162,0.37);
39
+ z-index: 1;
40
+ }
resources/css/codemirror/night.css ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Loosely based on the Midnight Textmate theme */
2
+
3
+ .cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; }
4
+ .cm-s-night div.CodeMirror-selected { background: #447 !important; }
5
+ .cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
6
+ .cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }
7
+ .cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
8
+
9
+ .cm-s-night span.cm-comment { color: #6900a1; }
10
+ .cm-s-night span.cm-atom { color: #845dc4; }
11
+ .cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
12
+ .cm-s-night span.cm-keyword { color: #599eff; }
13
+ .cm-s-night span.cm-string { color: #37f14a; }
14
+ .cm-s-night span.cm-meta { color: #7678e2; }
15
+ .cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
16
+ .cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
17
+ .cm-s-night span.cm-bracket { color: #8da6ce; }
18
+ .cm-s-night span.cm-comment { color: #6900a1; }
19
+ .cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
20
+ .cm-s-night span.cm-link { color: #845dc4; }
21
+ .cm-s-night span.cm-error { color: #9d1e15; }
22
+
23
+ .cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;}
24
+ .cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/paraiso-dark.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: Paraíso (Dark)
4
+ Author: Jan T. Sott
5
+
6
+ Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
7
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
8
+
9
+ */
10
+
11
+ .cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;}
12
+ .cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;}
13
+ .cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;}
14
+ .cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;}
15
+ .cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;}
16
+
17
+ .cm-s-paraiso-dark span.cm-comment {color: #e96ba8;}
18
+ .cm-s-paraiso-dark span.cm-atom {color: #815ba4;}
19
+ .cm-s-paraiso-dark span.cm-number {color: #815ba4;}
20
+
21
+ .cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;}
22
+ .cm-s-paraiso-dark span.cm-keyword {color: #ef6155;}
23
+ .cm-s-paraiso-dark span.cm-string {color: #fec418;}
24
+
25
+ .cm-s-paraiso-dark span.cm-variable {color: #48b685;}
26
+ .cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;}
27
+ .cm-s-paraiso-dark span.cm-def {color: #f99b15;}
28
+ .cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;}
29
+ .cm-s-paraiso-dark span.cm-tag {color: #ef6155;}
30
+ .cm-s-paraiso-dark span.cm-link {color: #815ba4;}
31
+ .cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;}
32
+
33
+ .cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;}
34
+ .cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/paraiso-light.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: Paraíso (Light)
4
+ Author: Jan T. Sott
5
+
6
+ Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
7
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
8
+
9
+ */
10
+
11
+ .cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;}
12
+ .cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;}
13
+ .cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;}
14
+ .cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;}
15
+ .cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;}
16
+
17
+ .cm-s-paraiso-light span.cm-comment {color: #e96ba8;}
18
+ .cm-s-paraiso-light span.cm-atom {color: #815ba4;}
19
+ .cm-s-paraiso-light span.cm-number {color: #815ba4;}
20
+
21
+ .cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;}
22
+ .cm-s-paraiso-light span.cm-keyword {color: #ef6155;}
23
+ .cm-s-paraiso-light span.cm-string {color: #fec418;}
24
+
25
+ .cm-s-paraiso-light span.cm-variable {color: #48b685;}
26
+ .cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;}
27
+ .cm-s-paraiso-light span.cm-def {color: #f99b15;}
28
+ .cm-s-paraiso-light span.cm-bracket {color: #41323f;}
29
+ .cm-s-paraiso-light span.cm-tag {color: #ef6155;}
30
+ .cm-s-paraiso-light span.cm-link {color: #815ba4;}
31
+ .cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;}
32
+
33
+ .cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;}
34
+ .cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/pastel-on-dark.css ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Pastel On Dark theme ported from ACE editor
3
+ * @license MIT
4
+ * @copyright AtomicPages LLC 2014
5
+ * @author Dennis Thompson, AtomicPages LLC
6
+ * @version 1.1
7
+ * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme
8
+ */
9
+
10
+ .cm-s-pastel-on-dark.CodeMirror {
11
+ background: #2c2827;
12
+ color: #8F938F;
13
+ line-height: 1.5;
14
+ font-size: 14px;
15
+ }
16
+ .cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
17
+ .cm-s-pastel-on-dark .CodeMirror-gutters {
18
+ background: #34302f;
19
+ border-right: 0px;
20
+ padding: 0 3px;
21
+ }
22
+ .cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }
23
+ .cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
24
+ .cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }
25
+ .cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }
26
+ .cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }
27
+ .cm-s-pastel-on-dark span.cm-property { color: #8F938F; }
28
+ .cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }
29
+ .cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }
30
+ .cm-s-pastel-on-dark span.cm-string { color: #66A968; }
31
+ .cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
32
+ .cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
33
+ .cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }
34
+ .cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
35
+ .cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
36
+ .cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }
37
+ .cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }
38
+ .cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }
39
+ .cm-s-pastel-on-dark span.cm-error {
40
+ background: #757aD8;
41
+ color: #f8f8f0;
42
+ }
43
+ .cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; }
44
+ .cm-s-pastel-on-dark .CodeMirror-matchingbracket {
45
+ border: 1px solid rgba(255,255,255,0.25);
46
+ color: #8F938F !important;
47
+ margin: -1px -1px 0 -1px;
48
+ }
resources/css/codemirror/rubyblue.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-rubyblue.CodeMirror { background: #112435; color: white; }
2
+ .cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
3
+ .cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }
4
+ .cm-s-rubyblue .CodeMirror-linenumber { color: white; }
5
+ .cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; }
6
+
7
+ .cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }
8
+ .cm-s-rubyblue span.cm-atom { color: #F4C20B; }
9
+ .cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }
10
+ .cm-s-rubyblue span.cm-keyword { color: #F0F; }
11
+ .cm-s-rubyblue span.cm-string { color: #F08047; }
12
+ .cm-s-rubyblue span.cm-meta { color: #F0F; }
13
+ .cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
14
+ .cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
15
+ .cm-s-rubyblue span.cm-bracket { color: #F0F; }
16
+ .cm-s-rubyblue span.cm-link { color: #F4C20B; }
17
+ .cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
18
+ .cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
19
+ .cm-s-rubyblue span.cm-error { color: #AF2018; }
20
+
21
+ .cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;}
resources/css/codemirror/solarized.css ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Solarized theme for code-mirror
3
+ http://ethanschoonover.com/solarized
4
+ */
5
+
6
+ /*
7
+ Solarized color pallet
8
+ http://ethanschoonover.com/solarized/img/solarized-palette.png
9
+ */
10
+
11
+ .solarized.base03 { color: #002b36; }
12
+ .solarized.base02 { color: #073642; }
13
+ .solarized.base01 { color: #586e75; }
14
+ .solarized.base00 { color: #657b83; }
15
+ .solarized.base0 { color: #839496; }
16
+ .solarized.base1 { color: #93a1a1; }
17
+ .solarized.base2 { color: #eee8d5; }
18
+ .solarized.base3 { color: #fdf6e3; }
19
+ .solarized.solar-yellow { color: #b58900; }
20
+ .solarized.solar-orange { color: #cb4b16; }
21
+ .solarized.solar-red { color: #dc322f; }
22
+ .solarized.solar-magenta { color: #d33682; }
23
+ .solarized.solar-violet { color: #6c71c4; }
24
+ .solarized.solar-blue { color: #268bd2; }
25
+ .solarized.solar-cyan { color: #2aa198; }
26
+ .solarized.solar-green { color: #859900; }
27
+
28
+ /* Color scheme for code-mirror */
29
+
30
+ .cm-s-solarized {
31
+ line-height: 1.45em;
32
+ color-profile: sRGB;
33
+ rendering-intent: auto;
34
+ }
35
+ .cm-s-solarized.cm-s-dark {
36
+ color: #839496;
37
+ background-color: #002b36;
38
+ text-shadow: #002b36 0 1px;
39
+ }
40
+ .cm-s-solarized.cm-s-light {
41
+ background-color: #fdf6e3;
42
+ color: #657b83;
43
+ text-shadow: #eee8d5 0 1px;
44
+ }
45
+
46
+ .cm-s-solarized .CodeMirror-widget {
47
+ text-shadow: none;
48
+ }
49
+
50
+
51
+ .cm-s-solarized .cm-keyword { color: #cb4b16 }
52
+ .cm-s-solarized .cm-atom { color: #d33682; }
53
+ .cm-s-solarized .cm-number { color: #d33682; }
54
+ .cm-s-solarized .cm-def { color: #2aa198; }
55
+
56
+ .cm-s-solarized .cm-variable { color: #268bd2; }
57
+ .cm-s-solarized .cm-variable-2 { color: #b58900; }
58
+ .cm-s-solarized .cm-variable-3 { color: #6c71c4; }
59
+
60
+ .cm-s-solarized .cm-property { color: #2aa198; }
61
+ .cm-s-solarized .cm-operator {color: #6c71c4;}
62
+
63
+ .cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }
64
+
65
+ .cm-s-solarized .cm-string { color: #859900; }
66
+ .cm-s-solarized .cm-string-2 { color: #b58900; }
67
+
68
+ .cm-s-solarized .cm-meta { color: #859900; }
69
+ .cm-s-solarized .cm-qualifier { color: #b58900; }
70
+ .cm-s-solarized .cm-builtin { color: #d33682; }
71
+ .cm-s-solarized .cm-bracket { color: #cb4b16; }
72
+ .cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }
73
+ .cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }
74
+ .cm-s-solarized .cm-tag { color: #93a1a1 }
75
+ .cm-s-solarized .cm-attribute { color: #2aa198; }
76
+ .cm-s-solarized .cm-header { color: #586e75; }
77
+ .cm-s-solarized .cm-quote { color: #93a1a1; }
78
+ .cm-s-solarized .cm-hr {
79
+ color: transparent;
80
+ border-top: 1px solid #586e75;
81
+ display: block;
82
+ }
83
+ .cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }
84
+ .cm-s-solarized .cm-special { color: #6c71c4; }
85
+ .cm-s-solarized .cm-em {
86
+ color: #999;
87
+ text-decoration: underline;
88
+ text-decoration-style: dotted;
89
+ }
90
+ .cm-s-solarized .cm-strong { color: #eee; }
91
+ .cm-s-solarized .cm-tab:before {
92
+ content: "➤"; /*visualize tab character*/
93
+ color: #586e75;
94
+ position:absolute;
95
+ }
96
+ .cm-s-solarized .cm-error,
97
+ .cm-s-solarized .cm-invalidchar {
98
+ color: #586e75;
99
+ border-bottom: 1px dotted #dc322f;
100
+ }
101
+
102
+ .cm-s-solarized.cm-s-dark .CodeMirror-selected {
103
+ background: #073642;
104
+ }
105
+
106
+ .cm-s-solarized.cm-s-light .CodeMirror-selected {
107
+ background: #eee8d5;
108
+ }
109
+
110
+ /* Editor styling */
111
+
112
+
113
+
114
+ /* Little shadow on the view-port of the buffer view */
115
+ .cm-s-solarized.CodeMirror {
116
+ -moz-box-shadow: inset 7px 0 12px -6px #000;
117
+ -webkit-box-shadow: inset 7px 0 12px -6px #000;
118
+ box-shadow: inset 7px 0 12px -6px #000;
119
+ }
120
+
121
+ /* Gutter border and some shadow from it */
122
+ .cm-s-solarized .CodeMirror-gutters {
123
+ border-right: 1px solid;
124
+ }
125
+
126
+ /* Gutter colors and line number styling based of color scheme (dark / light) */
127
+
128
+ /* Dark */
129
+ .cm-s-solarized.cm-s-dark .CodeMirror-gutters {
130
+ background-color: #002b36;
131
+ border-color: #00232c;
132
+ }
133
+
134
+ .cm-s-solarized.cm-s-dark .CodeMirror-linenumber {
135
+ text-shadow: #021014 0 -1px;
136
+ }
137
+
138
+ /* Light */
139
+ .cm-s-solarized.cm-s-light .CodeMirror-gutters {
140
+ background-color: #fdf6e3;
141
+ border-color: #eee8d5;
142
+ }
143
+
144
+ /* Common */
145
+ .cm-s-solarized .CodeMirror-linenumber {
146
+ color: #586e75;
147
+ padding: 0 5px;
148
+ }
149
+
150
+ .cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {
151
+ color: #586e75;
152
+ }
153
+
154
+ .cm-s-solarized .CodeMirror-lines .CodeMirror-cursor {
155
+ border-left: 1px solid #819090;
156
+ }
157
+
158
+ /*
159
+ Active line. Negative margin compensates left padding of the text in the
160
+ view-port
161
+ */
162
+ .cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
163
+ background: rgba(255, 255, 255, 0.10);
164
+ }
165
+ .cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
166
+ background: rgba(0, 0, 0, 0.10);
167
+ }
resources/css/codemirror/the-matrix.css ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
2
+ .cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; }
3
+ .cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }
4
+ .cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }
5
+ .cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; }
6
+
7
+ .cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;}
8
+ .cm-s-the-matrix span.cm-atom {color: #3FF;}
9
+ .cm-s-the-matrix span.cm-number {color: #FFB94F;}
10
+ .cm-s-the-matrix span.cm-def {color: #99C;}
11
+ .cm-s-the-matrix span.cm-variable {color: #F6C;}
12
+ .cm-s-the-matrix span.cm-variable-2 {color: #C6F;}
13
+ .cm-s-the-matrix span.cm-variable-3 {color: #96F;}
14
+ .cm-s-the-matrix span.cm-property {color: #62FFA0;}
15
+ .cm-s-the-matrix span.cm-operator {color: #999}
16
+ .cm-s-the-matrix span.cm-comment {color: #CCCCCC;}
17
+ .cm-s-the-matrix span.cm-string {color: #39C;}
18
+ .cm-s-the-matrix span.cm-meta {color: #C9F;}
19
+ .cm-s-the-matrix span.cm-qualifier {color: #FFF700;}
20
+ .cm-s-the-matrix span.cm-builtin {color: #30a;}
21
+ .cm-s-the-matrix span.cm-bracket {color: #cc7;}
22
+ .cm-s-the-matrix span.cm-tag {color: #FFBD40;}
23
+ .cm-s-the-matrix span.cm-attribute {color: #FFF700;}
24
+ .cm-s-the-matrix span.cm-error {color: #FF0000;}
25
+
26
+ .cm-s-the-matrix .CodeMirror-activeline-background {background: #040;}
resources/css/codemirror/tomorrow-night-eighties.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Name: Tomorrow Night - Eighties
4
+ Author: Chris Kempson
5
+
6
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
7
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
8
+
9
+ */
10
+
11
+ .cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;}
12
+ .cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;}
13
+ .cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;}
14
+ .cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;}
15
+ .cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;}
16
+
17
+ .cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;}
18
+ .cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;}
19
+ .cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;}
20
+
21
+ .cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;}
22
+ .cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;}
23
+ .cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;}
24
+
25
+ .cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;}
26
+ .cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;}
27
+ .cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;}
28
+ .cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;}
29
+ .cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;}
30
+ .cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;}
31
+ .cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;}
32
+
33
+ .cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;}
34
+ .cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
resources/css/codemirror/twilight.css ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/
2
+ .cm-s-twilight .CodeMirror-selected { background: #fff !important; color: #000; } /**/
3
+
4
+ .cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; }
5
+ .cm-s-twilight .CodeMirror-linenumber { color: #aaa; }
6
+ .cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white !important; }
7
+
8
+ .cm-s-twilight .cm-keyword { color: #f9ee98; } /**/
9
+ .cm-s-twilight .cm-atom { color: #FC0; }
10
+ .cm-s-twilight .cm-number { color: #ca7841; } /**/
11
+ .cm-s-twilight .cm-def { color: #8DA6CE; }
12
+ .cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/
13
+ .cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/
14
+ .cm-s-twilight .cm-operator { color: #cda869; } /**/
15
+ .cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/
16
+ .cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/
17
+ .cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/
18
+ .cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/
19
+ .cm-s-twilight .cm-builtin { color: #cda869; } /*?*/
20
+ .cm-s-twilight .cm-tag { color: #997643; } /**/
21
+ .cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/
22
+ .cm-s-twilight .cm-header { color: #FF6400; }
23
+ .cm-s-twilight .cm-hr { color: #AEAEAE; }
24
+ .cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/
25
+ .cm-s-twilight .cm-error { border-bottom: 1px solid red; }
26
+
27
+ .cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;}
28
+ .cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/vibrant-ink.css ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Taken from the popular Visual Studio Vibrant Ink Schema */
2
+
3
+ .cm-s-vibrant-ink.CodeMirror { background: black; color: white; }
4
+ .cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; }
5
+
6
+ .cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
7
+ .cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; }
8
+ .cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; }
9
+
10
+ .cm-s-vibrant-ink .cm-keyword { color: #CC7832; }
11
+ .cm-s-vibrant-ink .cm-atom { color: #FC0; }
12
+ .cm-s-vibrant-ink .cm-number { color: #FFEE98; }
13
+ .cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
14
+ .cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D }
15
+ .cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D }
16
+ .cm-s-vibrant-ink .cm-operator { color: #888; }
17
+ .cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
18
+ .cm-s-vibrant-ink .cm-string { color: #A5C25C }
19
+ .cm-s-vibrant-ink .cm-string-2 { color: red }
20
+ .cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
21
+ .cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
22
+ .cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
23
+ .cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
24
+ .cm-s-vibrant-ink .cm-header { color: #FF6400; }
25
+ .cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
26
+ .cm-s-vibrant-ink .cm-link { color: blue; }
27
+ .cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
28
+
29
+ .cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;}
30
+ .cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/xq-dark.css ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (C) 2011 by MarkLogic Corporation
3
+ Author: Mike Brevoort <mike@brevoort.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ */
23
+ .cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }
24
+ .cm-s-xq-dark .CodeMirror-selected { background: #27007A !important; }
25
+ .cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
26
+ .cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }
27
+ .cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
28
+
29
+ .cm-s-xq-dark span.cm-keyword {color: #FFBD40;}
30
+ .cm-s-xq-dark span.cm-atom {color: #6C8CD5;}
31
+ .cm-s-xq-dark span.cm-number {color: #164;}
32
+ .cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;}
33
+ .cm-s-xq-dark span.cm-variable {color: #FFF;}
34
+ .cm-s-xq-dark span.cm-variable-2 {color: #EEE;}
35
+ .cm-s-xq-dark span.cm-variable-3 {color: #DDD;}
36
+ .cm-s-xq-dark span.cm-property {}
37
+ .cm-s-xq-dark span.cm-operator {}
38
+ .cm-s-xq-dark span.cm-comment {color: gray;}
39
+ .cm-s-xq-dark span.cm-string {color: #9FEE00;}
40
+ .cm-s-xq-dark span.cm-meta {color: yellow;}
41
+ .cm-s-xq-dark span.cm-qualifier {color: #FFF700;}
42
+ .cm-s-xq-dark span.cm-builtin {color: #30a;}
43
+ .cm-s-xq-dark span.cm-bracket {color: #cc7;}
44
+ .cm-s-xq-dark span.cm-tag {color: #FFBD40;}
45
+ .cm-s-xq-dark span.cm-attribute {color: #FFF700;}
46
+ .cm-s-xq-dark span.cm-error {color: #f00;}
47
+
48
+ .cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;}
49
+ .cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
resources/css/codemirror/xq-light.css ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (C) 2011 by MarkLogic Corporation
3
+ Author: Mike Brevoort <mike@brevoort.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ */
23
+ .cm-s-xq-light span.cm-keyword {line-height: 1em; font-weight: bold; color: #5A5CAD; }
24
+ .cm-s-xq-light span.cm-atom {color: #6C8CD5;}
25
+ .cm-s-xq-light span.cm-number {color: #164;}
26
+ .cm-s-xq-light span.cm-def {text-decoration:underline;}
27
+ .cm-s-xq-light span.cm-variable {color: black; }
28
+ .cm-s-xq-light span.cm-variable-2 {color:black;}
29
+ .cm-s-xq-light span.cm-variable-3 {color: black; }
30
+ .cm-s-xq-light span.cm-property {}
31
+ .cm-s-xq-light span.cm-operator {}
32
+ .cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;}
33
+ .cm-s-xq-light span.cm-string {color: red;}
34
+ .cm-s-xq-light span.cm-meta {color: yellow;}
35
+ .cm-s-xq-light span.cm-qualifier {color: grey}
36
+ .cm-s-xq-light span.cm-builtin {color: #7EA656;}
37
+ .cm-s-xq-light span.cm-bracket {color: #cc7;}
38
+ .cm-s-xq-light span.cm-tag {color: #3F7F7F;}
39
+ .cm-s-xq-light span.cm-attribute {color: #7F007F;}
40
+ .cm-s-xq-light span.cm-error {color: #f00;}
41
+
42
+ .cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;}
43
+ .cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;}
resources/css/string-locator.css ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Basic styling */
2
+ .wrap > h2 {
3
+ margin-bottom: 15px;
4
+ }
5
+
6
+ .string-locator-feedback {
7
+ background: #fff;
8
+ display: inline-block;
9
+ width: 100%;
10
+ text-align: center;
11
+ }
12
+ .string-locator-feedback progress {
13
+ width: 100%;
14
+ height: 1.5em;
15
+ }
16
+ .string-locator-feedback #string-locator-feedback-text {
17
+ display: inline-block;
18
+ text-align: center;
19
+ width: 100%;
20
+ }
21
+ .string-locator-feedback.hide {
22
+ display: none;
23
+ }
24
+ table.tools_page_string-locator {
25
+ display: none;
26
+ }
27
+ table.tools_page_string-locator.restore {
28
+ display: block;
29
+ }
30
+
31
+ .string-locator-edit-wrap {
32
+ box-sizing: border-box;
33
+ display: inline-block;
34
+ margin-right: 3%;
35
+ vertical-align: top;
36
+ width: 70%;
37
+ }
38
+
39
+ .string-locator-sidebar-wrap {
40
+ display: inline-block;
41
+ vertical-align: top;
42
+ width: 25%;
43
+ }
44
+ .string-locator-details {
45
+ background: #fff;
46
+ border: 1px solid #e5e5e5;
47
+ box-shadow: 0 1px 1px rgba( 0, 0, 0, 0.04 );
48
+ box-sizing: border-box;
49
+ display: block;
50
+ margin-top: 2em;
51
+ }
52
+ .string-locator-sidebar-wrap > div:first-of-type {
53
+ margin-top: 0;
54
+ }
55
+ .string-locator-theme-details {
56
+ box-sizing: border-box;
57
+ height: auto;
58
+ padding: 10px;
59
+ width: 100%;
60
+ }
61
+ .string-locator-theme-details h2 small {
62
+ font-size: 50%;
63
+ }
64
+
65
+ .string-locator-actions {
66
+ background: #f5f5f5;
67
+ border-top: 1px solid #ddd;
68
+ box-sizing: border-box;
69
+ display: inline-block;
70
+ padding: 10px;
71
+ width: 100%;
72
+ }
73
+
74
+ /* Media Queries for responsive behavior */
75
+ @media (max-width: 1065px) {
76
+ .string-locator-edit-wrap {
77
+ display: block;
78
+ margin-bottom: 20px;
79
+ width: 99%;
80
+ }
81
+
82
+ .string-locator-sidebar-wrap {
83
+ display: block;
84
+ margin-bottom: 20px;
85
+ width: 99%;
86
+ }
87
+ }
resources/js/codemirror/addon/comment/comment.js ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var noOptions = {};
15
+ var nonWS = /[^\s\u00a0]/;
16
+ var Pos = CodeMirror.Pos;
17
+
18
+ function firstNonWS(str) {
19
+ var found = str.search(nonWS);
20
+ return found == -1 ? 0 : found;
21
+ }
22
+
23
+ CodeMirror.commands.toggleComment = function(cm) {
24
+ var minLine = Infinity, ranges = cm.listSelections(), mode = null;
25
+ for (var i = ranges.length - 1; i >= 0; i--) {
26
+ var from = ranges[i].from(), to = ranges[i].to();
27
+ if (from.line >= minLine) continue;
28
+ if (to.line >= minLine) to = Pos(minLine, 0);
29
+ minLine = from.line;
30
+ if (mode == null) {
31
+ if (cm.uncomment(from, to)) mode = "un";
32
+ else { cm.lineComment(from, to); mode = "line"; }
33
+ } else if (mode == "un") {
34
+ cm.uncomment(from, to);
35
+ } else {
36
+ cm.lineComment(from, to);
37
+ }
38
+ }
39
+ };
40
+
41
+ CodeMirror.defineExtension("lineComment", function(from, to, options) {
42
+ if (!options) options = noOptions;
43
+ var self = this, mode = self.getModeAt(from);
44
+ var commentString = options.lineComment || mode.lineComment;
45
+ if (!commentString) {
46
+ if (options.blockCommentStart || mode.blockCommentStart) {
47
+ options.fullLines = true;
48
+ self.blockComment(from, to, options);
49
+ }
50
+ return;
51
+ }
52
+ var firstLine = self.getLine(from.line);
53
+ if (firstLine == null) return;
54
+ var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
55
+ var pad = options.padding == null ? " " : options.padding;
56
+ var blankLines = options.commentBlankLines || from.line == to.line;
57
+
58
+ self.operation(function() {
59
+ if (options.indent) {
60
+ var baseString = firstLine.slice(0, firstNonWS(firstLine));
61
+ for (var i = from.line; i < end; ++i) {
62
+ var line = self.getLine(i), cut = baseString.length;
63
+ if (!blankLines && !nonWS.test(line)) continue;
64
+ if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
65
+ self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
66
+ }
67
+ } else {
68
+ for (var i = from.line; i < end; ++i) {
69
+ if (blankLines || nonWS.test(self.getLine(i)))
70
+ self.replaceRange(commentString + pad, Pos(i, 0));
71
+ }
72
+ }
73
+ });
74
+ });
75
+
76
+ CodeMirror.defineExtension("blockComment", function(from, to, options) {
77
+ if (!options) options = noOptions;
78
+ var self = this, mode = self.getModeAt(from);
79
+ var startString = options.blockCommentStart || mode.blockCommentStart;
80
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
81
+ if (!startString || !endString) {
82
+ if ((options.lineComment || mode.lineComment) && options.fullLines != false)
83
+ self.lineComment(from, to, options);
84
+ return;
85
+ }
86
+
87
+ var end = Math.min(to.line, self.lastLine());
88
+ if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
89
+
90
+ var pad = options.padding == null ? " " : options.padding;
91
+ if (from.line > end) return;
92
+
93
+ self.operation(function() {
94
+ if (options.fullLines != false) {
95
+ var lastLineHasText = nonWS.test(self.getLine(end));
96
+ self.replaceRange(pad + endString, Pos(end));
97
+ self.replaceRange(startString + pad, Pos(from.line, 0));
98
+ var lead = options.blockCommentLead || mode.blockCommentLead;
99
+ if (lead != null) for (var i = from.line + 1; i <= end; ++i)
100
+ if (i != end || lastLineHasText)
101
+ self.replaceRange(lead + pad, Pos(i, 0));
102
+ } else {
103
+ self.replaceRange(endString, to);
104
+ self.replaceRange(startString, from);
105
+ }
106
+ });
107
+ });
108
+
109
+ CodeMirror.defineExtension("uncomment", function(from, to, options) {
110
+ if (!options) options = noOptions;
111
+ var self = this, mode = self.getModeAt(from);
112
+ var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);
113
+
114
+ // Try finding line comments
115
+ var lineString = options.lineComment || mode.lineComment, lines = [];
116
+ var pad = options.padding == null ? " " : options.padding, didSomething;
117
+ lineComment: {
118
+ if (!lineString) break lineComment;
119
+ for (var i = start; i <= end; ++i) {
120
+ var line = self.getLine(i);
121
+ var found = line.indexOf(lineString);
122
+ if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
123
+ if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
124
+ if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
125
+ lines.push(line);
126
+ }
127
+ self.operation(function() {
128
+ for (var i = start; i <= end; ++i) {
129
+ var line = lines[i - start];
130
+ var pos = line.indexOf(lineString), endPos = pos + lineString.length;
131
+ if (pos < 0) continue;
132
+ if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
133
+ didSomething = true;
134
+ self.replaceRange("", Pos(i, pos), Pos(i, endPos));
135
+ }
136
+ });
137
+ if (didSomething) return true;
138
+ }
139
+
140
+ // Try block comments
141
+ var startString = options.blockCommentStart || mode.blockCommentStart;
142
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
143
+ if (!startString || !endString) return false;
144
+ var lead = options.blockCommentLead || mode.blockCommentLead;
145
+ var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
146
+ var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
147
+ if (close == -1 && start != end) {
148
+ endLine = self.getLine(--end);
149
+ close = endLine.lastIndexOf(endString);
150
+ }
151
+ if (open == -1 || close == -1 ||
152
+ !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
153
+ !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
154
+ return false;
155
+
156
+ self.operation(function() {
157
+ self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
158
+ Pos(end, close + endString.length));
159
+ var openEnd = open + startString.length;
160
+ if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
161
+ self.replaceRange("", Pos(start, open), Pos(start, openEnd));
162
+ if (lead) for (var i = start + 1; i <= end; ++i) {
163
+ var line = self.getLine(i), found = line.indexOf(lead);
164
+ if (found == -1 || nonWS.test(line.slice(0, found))) continue;
165
+ var foundEnd = found + lead.length;
166
+ if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
167
+ self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
168
+ }
169
+ });
170
+ return true;
171
+ });
172
+ });
resources/js/codemirror/addon/comment/continuecomment.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var modes = ["clike", "css", "javascript"];
13
+
14
+ for (var i = 0; i < modes.length; ++i)
15
+ CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
16
+
17
+ function continueComment(cm) {
18
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
19
+ var ranges = cm.listSelections(), mode, inserts = [];
20
+ for (var i = 0; i < ranges.length; i++) {
21
+ var pos = ranges[i].head, token = cm.getTokenAt(pos);
22
+ if (token.type != "comment") return CodeMirror.Pass;
23
+ var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
24
+ if (!mode) mode = modeHere;
25
+ else if (mode != modeHere) return CodeMirror.Pass;
26
+
27
+ var insert = null;
28
+ if (mode.blockCommentStart && mode.blockCommentContinue) {
29
+ var end = token.string.indexOf(mode.blockCommentEnd);
30
+ var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
31
+ if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
32
+ // Comment ended, don't continue it
33
+ } else if (token.string.indexOf(mode.blockCommentStart) == 0) {
34
+ insert = full.slice(0, token.start);
35
+ if (!/^\s*$/.test(insert)) {
36
+ insert = "";
37
+ for (var j = 0; j < token.start; ++j) insert += " ";
38
+ }
39
+ } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
40
+ found + mode.blockCommentContinue.length > token.start &&
41
+ /^\s*$/.test(full.slice(0, found))) {
42
+ insert = full.slice(0, found);
43
+ }
44
+ if (insert != null) insert += mode.blockCommentContinue;
45
+ }
46
+ if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
47
+ var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
48
+ if (found > -1) {
49
+ insert = line.slice(0, found);
50
+ if (/\S/.test(insert)) insert = null;
51
+ else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
52
+ }
53
+ }
54
+ if (insert == null) return CodeMirror.Pass;
55
+ inserts[i] = "\n" + insert;
56
+ }
57
+
58
+ cm.operation(function() {
59
+ for (var i = ranges.length - 1; i >= 0; i--)
60
+ cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
61
+ });
62
+ }
63
+
64
+ function continueLineCommentEnabled(cm) {
65
+ var opt = cm.getOption("continueComments");
66
+ if (opt && typeof opt == "object")
67
+ return opt.continueLineComment !== false;
68
+ return true;
69
+ }
70
+
71
+ CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
72
+ if (prev && prev != CodeMirror.Init)
73
+ cm.removeKeyMap("continueComment");
74
+ if (val) {
75
+ var key = "Enter";
76
+ if (typeof val == "string")
77
+ key = val;
78
+ else if (typeof val == "object" && val.key)
79
+ key = val.key;
80
+ var map = {name: "continueComment"};
81
+ map[key] = continueComment;
82
+ cm.addKeyMap(map);
83
+ }
84
+ });
85
+ });
resources/js/codemirror/addon/dialog/dialog.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-dialog {
2
+ position: absolute;
3
+ left: 0; right: 0;
4
+ background: white;
5
+ z-index: 15;
6
+ padding: .1em .8em;
7
+ overflow: hidden;
8
+ color: #333;
9
+ }
10
+
11
+ .CodeMirror-dialog-top {
12
+ border-bottom: 1px solid #eee;
13
+ top: 0;
14
+ }
15
+
16
+ .CodeMirror-dialog-bottom {
17
+ border-top: 1px solid #eee;
18
+ bottom: 0;
19
+ }
20
+
21
+ .CodeMirror-dialog input {
22
+ border: none;
23
+ outline: none;
24
+ background: transparent;
25
+ width: 20em;
26
+ color: inherit;
27
+ font-family: monospace;
28
+ }
29
+
30
+ .CodeMirror-dialog button {
31
+ font-size: 70%;
32
+ }
resources/js/codemirror/addon/dialog/dialog.js ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Open simple dialogs on top of an editor. Relies on dialog.css.
5
+
6
+ (function(mod) {
7
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
8
+ mod(require("../../lib/codemirror"));
9
+ else if (typeof define == "function" && define.amd) // AMD
10
+ define(["../../lib/codemirror"], mod);
11
+ else // Plain browser env
12
+ mod(CodeMirror);
13
+ })(function(CodeMirror) {
14
+ function dialogDiv(cm, template, bottom) {
15
+ var wrap = cm.getWrapperElement();
16
+ var dialog;
17
+ dialog = wrap.appendChild(document.createElement("div"));
18
+ if (bottom) {
19
+ dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
20
+ } else {
21
+ dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
22
+ }
23
+ if (typeof template == "string") {
24
+ dialog.innerHTML = template;
25
+ } else { // Assuming it's a detached DOM element.
26
+ dialog.appendChild(template);
27
+ }
28
+ return dialog;
29
+ }
30
+
31
+ function closeNotification(cm, newVal) {
32
+ if (cm.state.currentNotificationClose)
33
+ cm.state.currentNotificationClose();
34
+ cm.state.currentNotificationClose = newVal;
35
+ }
36
+
37
+ CodeMirror.defineExtension("openDialog", function(template, callback, options) {
38
+ closeNotification(this, null);
39
+ var dialog = dialogDiv(this, template, options && options.bottom);
40
+ var closed = false, me = this;
41
+ function close() {
42
+ if (closed) return;
43
+ closed = true;
44
+ dialog.parentNode.removeChild(dialog);
45
+ }
46
+ var inp = dialog.getElementsByTagName("input")[0], button;
47
+ if (inp) {
48
+ if (options && options.value) inp.value = options.value;
49
+ CodeMirror.on(inp, "keydown", function(e) {
50
+ if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
51
+ if (e.keyCode == 13 || e.keyCode == 27) {
52
+ inp.blur();
53
+ CodeMirror.e_stop(e);
54
+ close();
55
+ me.focus();
56
+ if (e.keyCode == 13) callback(inp.value);
57
+ }
58
+ });
59
+ if (options && options.onKeyUp) {
60
+ CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
61
+ }
62
+ if (options && options.value) inp.value = options.value;
63
+ inp.focus();
64
+ CodeMirror.on(inp, "blur", close);
65
+ } else if (button = dialog.getElementsByTagName("button")[0]) {
66
+ CodeMirror.on(button, "click", function() {
67
+ close();
68
+ me.focus();
69
+ });
70
+ button.focus();
71
+ CodeMirror.on(button, "blur", close);
72
+ }
73
+ return close;
74
+ });
75
+
76
+ CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
77
+ closeNotification(this, null);
78
+ var dialog = dialogDiv(this, template, options && options.bottom);
79
+ var buttons = dialog.getElementsByTagName("button");
80
+ var closed = false, me = this, blurring = 1;
81
+ function close() {
82
+ if (closed) return;
83
+ closed = true;
84
+ dialog.parentNode.removeChild(dialog);
85
+ me.focus();
86
+ }
87
+ buttons[0].focus();
88
+ for (var i = 0; i < buttons.length; ++i) {
89
+ var b = buttons[i];
90
+ (function(callback) {
91
+ CodeMirror.on(b, "click", function(e) {
92
+ CodeMirror.e_preventDefault(e);
93
+ close();
94
+ if (callback) callback(me);
95
+ });
96
+ })(callbacks[i]);
97
+ CodeMirror.on(b, "blur", function() {
98
+ --blurring;
99
+ setTimeout(function() { if (blurring <= 0) close(); }, 200);
100
+ });
101
+ CodeMirror.on(b, "focus", function() { ++blurring; });
102
+ }
103
+ });
104
+
105
+ /*
106
+ * openNotification
107
+ * Opens a notification, that can be closed with an optional timer
108
+ * (default 5000ms timer) and always closes on click.
109
+ *
110
+ * If a notification is opened while another is opened, it will close the
111
+ * currently opened one and open the new one immediately.
112
+ */
113
+ CodeMirror.defineExtension("openNotification", function(template, options) {
114
+ closeNotification(this, close);
115
+ var dialog = dialogDiv(this, template, options && options.bottom);
116
+ var duration = options && (options.duration === undefined ? 5000 : options.duration);
117
+ var closed = false, doneTimer;
118
+
119
+ function close() {
120
+ if (closed) return;
121
+ closed = true;
122
+ clearTimeout(doneTimer);
123
+ dialog.parentNode.removeChild(dialog);
124
+ }
125
+
126
+ CodeMirror.on(dialog, 'click', function(e) {
127
+ CodeMirror.e_preventDefault(e);
128
+ close();
129
+ });
130
+ if (duration)
131
+ doneTimer = setTimeout(close, options.duration);
132
+ });
133
+ });
resources/js/codemirror/addon/display/fullscreen.css ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ .CodeMirror-fullscreen {
2
+ position: fixed;
3
+ top: 0; left: 0; right: 0; bottom: 0;
4
+ height: auto;
5
+ z-index: 9;
6
+ }
resources/js/codemirror/addon/display/fullscreen.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
15
+ if (old == CodeMirror.Init) old = false;
16
+ if (!old == !val) return;
17
+ if (val) setFullscreen(cm);
18
+ else setNormal(cm);
19
+ });
20
+
21
+ function setFullscreen(cm) {
22
+ var wrap = cm.getWrapperElement();
23
+ cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
24
+ width: wrap.style.width, height: wrap.style.height};
25
+ wrap.style.width = "";
26
+ wrap.style.height = "auto";
27
+ wrap.className += " CodeMirror-fullscreen";
28
+ document.documentElement.style.overflow = "hidden";
29
+ cm.refresh();
30
+ }
31
+
32
+ function setNormal(cm) {
33
+ var wrap = cm.getWrapperElement();
34
+ wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
35
+ document.documentElement.style.overflow = "";
36
+ var info = cm.state.fullScreenRestore;
37
+ wrap.style.width = info.width; wrap.style.height = info.height;
38
+ window.scrollTo(info.scrollLeft, info.scrollTop);
39
+ cm.refresh();
40
+ }
41
+ });
resources/js/codemirror/addon/display/placeholder.js ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
13
+ var prev = old && old != CodeMirror.Init;
14
+ if (val && !prev) {
15
+ cm.on("blur", onBlur);
16
+ cm.on("change", onChange);
17
+ onChange(cm);
18
+ } else if (!val && prev) {
19
+ cm.off("blur", onBlur);
20
+ cm.off("change", onChange);
21
+ clearPlaceholder(cm);
22
+ var wrapper = cm.getWrapperElement();
23
+ wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
24
+ }
25
+
26
+ if (val && !cm.hasFocus()) onBlur(cm);
27
+ });
28
+
29
+ function clearPlaceholder(cm) {
30
+ if (cm.state.placeholder) {
31
+ cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
32
+ cm.state.placeholder = null;
33
+ }
34
+ }
35
+ function setPlaceholder(cm) {
36
+ clearPlaceholder(cm);
37
+ var elt = cm.state.placeholder = document.createElement("pre");
38
+ elt.style.cssText = "height: 0; overflow: visible";
39
+ elt.className = "CodeMirror-placeholder";
40
+ elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
41
+ cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
42
+ }
43
+
44
+ function onBlur(cm) {
45
+ if (isEmpty(cm)) setPlaceholder(cm);
46
+ }
47
+ function onChange(cm) {
48
+ var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
49
+ wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
50
+
51
+ if (empty) setPlaceholder(cm);
52
+ else clearPlaceholder(cm);
53
+ }
54
+
55
+ function isEmpty(cm) {
56
+ return (cm.lineCount() === 1) && (cm.getLine(0) === "");
57
+ }
58
+ });
resources/js/codemirror/addon/display/rulers.js ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineOption("rulers", false, function(cm, val, old) {
15
+ if (old && old != CodeMirror.Init) {
16
+ clearRulers(cm);
17
+ cm.off("refresh", refreshRulers);
18
+ }
19
+ if (val && val.length) {
20
+ setRulers(cm);
21
+ cm.on("refresh", refreshRulers);
22
+ }
23
+ });
24
+
25
+ function clearRulers(cm) {
26
+ for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {
27
+ var node = cm.display.lineSpace.childNodes[i];
28
+ if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
29
+ node.parentNode.removeChild(node);
30
+ }
31
+ }
32
+
33
+ function setRulers(cm) {
34
+ var val = cm.getOption("rulers");
35
+ var cw = cm.defaultCharWidth();
36
+ var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
37
+ var minH = cm.display.scroller.offsetHeight + 30;
38
+ for (var i = 0; i < val.length; i++) {
39
+ var elt = document.createElement("div");
40
+ elt.className = "CodeMirror-ruler";
41
+ var col, cls = null, conf = val[i];
42
+ if (typeof conf == "number") {
43
+ col = conf;
44
+ } else {
45
+ col = conf.column;
46
+ if (conf.className) elt.className = " " + conf.className;
47
+ if (conf.color) elt.style.borderColor = conf.color;
48
+ if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;
49
+ if (conf.width) elt.style.borderLeftWidth = conf.width;
50
+ cls = val[i].className;
51
+ }
52
+ elt.style.left = (left + col * cw) + "px";
53
+ elt.style.top = "-50px";
54
+ elt.style.bottom = "-20px";
55
+ elt.style.minHeight = minH + "px";
56
+ cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
57
+ }
58
+ }
59
+
60
+ function refreshRulers(cm) {
61
+ clearRulers(cm);
62
+ setRulers(cm);
63
+ }
64
+ });
resources/js/codemirror/addon/edit/closebrackets.js ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var DEFAULT_BRACKETS = "()[]{}''\"\"";
13
+ var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
14
+ var SPACE_CHAR_REGEX = /\s/;
15
+
16
+ var Pos = CodeMirror.Pos;
17
+
18
+ CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
19
+ if (old != CodeMirror.Init && old)
20
+ cm.removeKeyMap("autoCloseBrackets");
21
+ if (!val) return;
22
+ var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
23
+ if (typeof val == "string") pairs = val;
24
+ else if (typeof val == "object") {
25
+ if (val.pairs != null) pairs = val.pairs;
26
+ if (val.explode != null) explode = val.explode;
27
+ }
28
+ var map = buildKeymap(pairs);
29
+ if (explode) map.Enter = buildExplodeHandler(explode);
30
+ cm.addKeyMap(map);
31
+ });
32
+
33
+ function charsAround(cm, pos) {
34
+ var str = cm.getRange(Pos(pos.line, pos.ch - 1),
35
+ Pos(pos.line, pos.ch + 1));
36
+ return str.length == 2 ? str : null;
37
+ }
38
+
39
+ function buildKeymap(pairs) {
40
+ var map = {
41
+ name : "autoCloseBrackets",
42
+ Backspace: function(cm) {
43
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
44
+ var ranges = cm.listSelections();
45
+ for (var i = 0; i < ranges.length; i++) {
46
+ if (!ranges[i].empty()) return CodeMirror.Pass;
47
+ var around = charsAround(cm, ranges[i].head);
48
+ if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
49
+ }
50
+ for (var i = ranges.length - 1; i >= 0; i--) {
51
+ var cur = ranges[i].head;
52
+ cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
53
+ }
54
+ }
55
+ };
56
+ var closingBrackets = "";
57
+ for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
58
+ if (left != right) closingBrackets += right;
59
+ map["'" + left + "'"] = function(cm) {
60
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
61
+ var ranges = cm.listSelections(), type, next;
62
+ for (var i = 0; i < ranges.length; i++) {
63
+ var range = ranges[i], cur = range.head, curType;
64
+ if (left == "'" && cm.getTokenTypeAt(cur) == "comment")
65
+ return CodeMirror.Pass;
66
+ var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
67
+ if (!range.empty())
68
+ curType = "surround";
69
+ else if (left == right && next == right) {
70
+ if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left)
71
+ curType = "skipThree";
72
+ else
73
+ curType = "skip";
74
+ } else if (left == right && cur.ch > 1 &&
75
+ cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &&
76
+ (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left))
77
+ curType = "addFour";
78
+ else if (left == right && CodeMirror.isWordChar(next))
79
+ return CodeMirror.Pass;
80
+ else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next))
81
+ curType = "both";
82
+ else
83
+ return CodeMirror.Pass;
84
+ if (!type) type = curType;
85
+ else if (type != curType) return CodeMirror.Pass;
86
+ }
87
+
88
+ cm.operation(function() {
89
+ if (type == "skip") {
90
+ cm.execCommand("goCharRight");
91
+ } else if (type == "skipThree") {
92
+ for (var i = 0; i < 3; i++)
93
+ cm.execCommand("goCharRight");
94
+ } else if (type == "surround") {
95
+ var sels = cm.getSelections();
96
+ for (var i = 0; i < sels.length; i++)
97
+ sels[i] = left + sels[i] + right;
98
+ cm.replaceSelections(sels, "around");
99
+ } else if (type == "both") {
100
+ cm.replaceSelection(left + right, null);
101
+ cm.execCommand("goCharLeft");
102
+ } else if (type == "addFour") {
103
+ cm.replaceSelection(left + left + left + left, "before");
104
+ cm.execCommand("goCharRight");
105
+ }
106
+ });
107
+ };
108
+ if (left != right) map["'" + right + "'"] = function(cm) {
109
+ var ranges = cm.listSelections();
110
+ for (var i = 0; i < ranges.length; i++) {
111
+ var range = ranges[i];
112
+ if (!range.empty() ||
113
+ cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right)
114
+ return CodeMirror.Pass;
115
+ }
116
+ cm.execCommand("goCharRight");
117
+ };
118
+ })(pairs.charAt(i), pairs.charAt(i + 1));
119
+ return map;
120
+ }
121
+
122
+ function buildExplodeHandler(pairs) {
123
+ return function(cm) {
124
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
125
+ var ranges = cm.listSelections();
126
+ for (var i = 0; i < ranges.length; i++) {
127
+ if (!ranges[i].empty()) return CodeMirror.Pass;
128
+ var around = charsAround(cm, ranges[i].head);
129
+ if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
130
+ }
131
+ cm.operation(function() {
132
+ cm.replaceSelection("\n\n", null);
133
+ cm.execCommand("goCharLeft");
134
+ ranges = cm.listSelections();
135
+ for (var i = 0; i < ranges.length; i++) {
136
+ var line = ranges[i].head.line;
137
+ cm.indentLine(line, null, true);
138
+ cm.indentLine(line + 1, null, true);
139
+ }
140
+ });
141
+ };
142
+ }
143
+ });
resources/js/codemirror/addon/edit/closetag.js ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ /**
5
+ * Tag-closer extension for CodeMirror.
6
+ *
7
+ * This extension adds an "autoCloseTags" option that can be set to
8
+ * either true to get the default behavior, or an object to further
9
+ * configure its behavior.
10
+ *
11
+ * These are supported options:
12
+ *
13
+ * `whenClosing` (default true)
14
+ * Whether to autoclose when the '/' of a closing tag is typed.
15
+ * `whenOpening` (default true)
16
+ * Whether to autoclose the tag when the final '>' of an opening
17
+ * tag is typed.
18
+ * `dontCloseTags` (default is empty tags for HTML, none for XML)
19
+ * An array of tag names that should not be autoclosed.
20
+ * `indentTags` (default is block tags for HTML, none for XML)
21
+ * An array of tag names that should, when opened, cause a
22
+ * blank line to be added inside the tag, and the blank line and
23
+ * closing line to be indented.
24
+ *
25
+ * See demos/closetag.html for a usage example.
26
+ */
27
+
28
+ (function(mod) {
29
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
30
+ mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
31
+ else if (typeof define == "function" && define.amd) // AMD
32
+ define(["../../lib/codemirror", "../fold/xml-fold"], mod);
33
+ else // Plain browser env
34
+ mod(CodeMirror);
35
+ })(function(CodeMirror) {
36
+ CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
37
+ if (old != CodeMirror.Init && old)
38
+ cm.removeKeyMap("autoCloseTags");
39
+ if (!val) return;
40
+ var map = {name: "autoCloseTags"};
41
+ if (typeof val != "object" || val.whenClosing)
42
+ map["'/'"] = function(cm) { return autoCloseSlash(cm); };
43
+ if (typeof val != "object" || val.whenOpening)
44
+ map["'>'"] = function(cm) { return autoCloseGT(cm); };
45
+ cm.addKeyMap(map);
46
+ });
47
+
48
+ var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
49
+ "source", "track", "wbr"];
50
+ var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
51
+ "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
52
+
53
+ function autoCloseGT(cm) {
54
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
55
+ var ranges = cm.listSelections(), replacements = [];
56
+ for (var i = 0; i < ranges.length; i++) {
57
+ if (!ranges[i].empty()) return CodeMirror.Pass;
58
+ var pos = ranges[i].head, tok = cm.getTokenAt(pos);
59
+ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
60
+ if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
61
+
62
+ var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
63
+ var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
64
+ var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
65
+
66
+ var tagName = state.tagName;
67
+ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
68
+ var lowerTagName = tagName.toLowerCase();
69
+ // Don't process the '>' at the end of an end-tag or self-closing tag
70
+ if (!tagName ||
71
+ tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
72
+ tok.type == "tag" && state.type == "closeTag" ||
73
+ tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
74
+ dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
75
+ closingTagExists(cm, tagName, pos, state, true))
76
+ return CodeMirror.Pass;
77
+
78
+ var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
79
+ replacements[i] = {indent: indent,
80
+ text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
81
+ newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
82
+ }
83
+
84
+ for (var i = ranges.length - 1; i >= 0; i--) {
85
+ var info = replacements[i];
86
+ cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
87
+ var sel = cm.listSelections().slice(0);
88
+ sel[i] = {head: info.newPos, anchor: info.newPos};
89
+ cm.setSelections(sel);
90
+ if (info.indent) {
91
+ cm.indentLine(info.newPos.line, null, true);
92
+ cm.indentLine(info.newPos.line + 1, null, true);
93
+ }
94
+ }
95
+ }
96
+
97
+ function autoCloseSlash(cm) {
98
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
99
+ var ranges = cm.listSelections(), replacements = [];
100
+ for (var i = 0; i < ranges.length; i++) {
101
+ if (!ranges[i].empty()) return CodeMirror.Pass;
102
+ var pos = ranges[i].head, tok = cm.getTokenAt(pos);
103
+ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
104
+ if (tok.type == "string" || tok.string.charAt(0) != "<" ||
105
+ tok.start != pos.ch - 1 || inner.mode.name != "xml" ||
106
+ !state.context || !state.context.tagName ||
107
+ closingTagExists(cm, state.context.tagName, pos, state))
108
+ return CodeMirror.Pass;
109
+ replacements[i] = "/" + state.context.tagName + ">";
110
+ }
111
+ cm.replaceSelections(replacements);
112
+ }
113
+
114
+ function indexOf(collection, elt) {
115
+ if (collection.indexOf) return collection.indexOf(elt);
116
+ for (var i = 0, e = collection.length; i < e; ++i)
117
+ if (collection[i] == elt) return i;
118
+ return -1;
119
+ }
120
+
121
+ // If xml-fold is loaded, we use its functionality to try and verify
122
+ // whether a given tag is actually unclosed.
123
+ function closingTagExists(cm, tagName, pos, state, newTag) {
124
+ if (!CodeMirror.scanForClosingTag) return false;
125
+ var end = Math.min(cm.lastLine() + 1, pos.line + 500);
126
+ var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
127
+ if (!nextClose || nextClose.tag != tagName) return false;
128
+ var cx = state.context;
129
+ // If the immediate wrapping context contains onCx instances of
130
+ // the same tag, a closing tag only exists if there are at least
131
+ // that many closing tags of that type following.
132
+ for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
133
+ pos = nextClose.to;
134
+ for (var i = 1; i < onCx; i++) {
135
+ var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
136
+ if (!next || next.tag != tagName) return false;
137
+ pos = next.to;
138
+ }
139
+ return true;
140
+ }
141
+ });
resources/js/codemirror/addon/edit/continuelist.js ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var listRE = /^(\s*)([*+-]|(\d+)\.)(\s*)/,
15
+ unorderedBullets = "*+-";
16
+
17
+ CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
18
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
19
+ var ranges = cm.listSelections(), replacements = [];
20
+ for (var i = 0; i < ranges.length; i++) {
21
+ var pos = ranges[i].head, match;
22
+ var inList = cm.getStateAfter(pos.line).list !== false;
23
+
24
+ if (!ranges[i].empty() || !inList || !(match = cm.getLine(pos.line).match(listRE))) {
25
+ cm.execCommand("newlineAndIndent");
26
+ return;
27
+ }
28
+ var indent = match[1], after = match[4];
29
+ var bullet = unorderedBullets.indexOf(match[2]) >= 0
30
+ ? match[2]
31
+ : (parseInt(match[3], 10) + 1) + ".";
32
+
33
+ replacements[i] = "\n" + indent + bullet + after;
34
+ }
35
+
36
+ cm.replaceSelections(replacements);
37
+ };
38
+ });
resources/js/codemirror/addon/edit/matchbrackets.js ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
13
+ (document.documentMode == null || document.documentMode < 8);
14
+
15
+ var Pos = CodeMirror.Pos;
16
+
17
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
18
+
19
+ function findMatchingBracket(cm, where, strict, config) {
20
+ var line = cm.getLineHandle(where.line), pos = where.ch - 1;
21
+ var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
22
+ if (!match) return null;
23
+ var dir = match.charAt(1) == ">" ? 1 : -1;
24
+ if (strict && (dir > 0) != (pos == where.ch)) return null;
25
+ var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
26
+
27
+ var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
28
+ if (found == null) return null;
29
+ return {from: Pos(where.line, pos), to: found && found.pos,
30
+ match: found && found.ch == match.charAt(0), forward: dir > 0};
31
+ }
32
+
33
+ // bracketRegex is used to specify which type of bracket to scan
34
+ // should be a regexp, e.g. /[[\]]/
35
+ //
36
+ // Note: If "where" is on an open bracket, then this bracket is ignored.
37
+ //
38
+ // Returns false when no bracket was found, null when it reached
39
+ // maxScanLines and gave up
40
+ function scanForBracket(cm, where, dir, style, config) {
41
+ var maxScanLen = (config && config.maxScanLineLength) || 10000;
42
+ var maxScanLines = (config && config.maxScanLines) || 1000;
43
+
44
+ var stack = [];
45
+ var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
46
+ var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
47
+ : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
48
+ for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
49
+ var line = cm.getLine(lineNo);
50
+ if (!line) continue;
51
+ var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
52
+ if (line.length > maxScanLen) continue;
53
+ if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
54
+ for (; pos != end; pos += dir) {
55
+ var ch = line.charAt(pos);
56
+ if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
57
+ var match = matching[ch];
58
+ if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
59
+ else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
60
+ else stack.pop();
61
+ }
62
+ }
63
+ }
64
+ return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
65
+ }
66
+
67
+ function matchBrackets(cm, autoclear, config) {
68
+ // Disable brace matching in long lines, since it'll cause hugely slow updates
69
+ var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
70
+ var marks = [], ranges = cm.listSelections();
71
+ for (var i = 0; i < ranges.length; i++) {
72
+ var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
73
+ if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
74
+ var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
75
+ marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
76
+ if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
77
+ marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
78
+ }
79
+ }
80
+
81
+ if (marks.length) {
82
+ // Kludge to work around the IE bug from issue #1193, where text
83
+ // input stops going to the textare whever this fires.
84
+ if (ie_lt8 && cm.state.focused) cm.display.input.focus();
85
+
86
+ var clear = function() {
87
+ cm.operation(function() {
88
+ for (var i = 0; i < marks.length; i++) marks[i].clear();
89
+ });
90
+ };
91
+ if (autoclear) setTimeout(clear, 800);
92
+ else return clear;
93
+ }
94
+ }
95
+
96
+ var currentlyHighlighted = null;
97
+ function doMatchBrackets(cm) {
98
+ cm.operation(function() {
99
+ if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
100
+ currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
101
+ });
102
+ }
103
+
104
+ CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
105
+ if (old && old != CodeMirror.Init)
106
+ cm.off("cursorActivity", doMatchBrackets);
107
+ if (val) {
108
+ cm.state.matchBrackets = typeof val == "object" ? val : {};
109
+ cm.on("cursorActivity", doMatchBrackets);
110
+ }
111
+ });
112
+
113
+ CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
114
+ CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
115
+ return findMatchingBracket(this, pos, strict, config);
116
+ });
117
+ CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
118
+ return scanForBracket(this, pos, dir, style, config);
119
+ });
120
+ });
resources/js/codemirror/addon/edit/matchtags.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../fold/xml-fold"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
15
+ if (old && old != CodeMirror.Init) {
16
+ cm.off("cursorActivity", doMatchTags);
17
+ cm.off("viewportChange", maybeUpdateMatch);
18
+ clear(cm);
19
+ }
20
+ if (val) {
21
+ cm.state.matchBothTags = typeof val == "object" && val.bothTags;
22
+ cm.on("cursorActivity", doMatchTags);
23
+ cm.on("viewportChange", maybeUpdateMatch);
24
+ doMatchTags(cm);
25
+ }
26
+ });
27
+
28
+ function clear(cm) {
29
+ if (cm.state.tagHit) cm.state.tagHit.clear();
30
+ if (cm.state.tagOther) cm.state.tagOther.clear();
31
+ cm.state.tagHit = cm.state.tagOther = null;
32
+ }
33
+
34
+ function doMatchTags(cm) {
35
+ cm.state.failedTagMatch = false;
36
+ cm.operation(function() {
37
+ clear(cm);
38
+ if (cm.somethingSelected()) return;
39
+ var cur = cm.getCursor(), range = cm.getViewport();
40
+ range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
41
+ var match = CodeMirror.findMatchingTag(cm, cur, range);
42
+ if (!match) return;
43
+ if (cm.state.matchBothTags) {
44
+ var hit = match.at == "open" ? match.open : match.close;
45
+ if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
46
+ }
47
+ var other = match.at == "close" ? match.open : match.close;
48
+ if (other)
49
+ cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
50
+ else
51
+ cm.state.failedTagMatch = true;
52
+ });
53
+ }
54
+
55
+ function maybeUpdateMatch(cm) {
56
+ if (cm.state.failedTagMatch) doMatchTags(cm);
57
+ }
58
+
59
+ CodeMirror.commands.toMatchingTag = function(cm) {
60
+ var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
61
+ if (found) {
62
+ var other = found.at == "close" ? found.open : found.close;
63
+ if (other) cm.extendSelection(other.to, other.from);
64
+ }
65
+ };
66
+ });
resources/js/codemirror/addon/edit/trailingspace.js ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
13
+ if (prev == CodeMirror.Init) prev = false;
14
+ if (prev && !val)
15
+ cm.removeOverlay("trailingspace");
16
+ else if (!prev && val)
17
+ cm.addOverlay({
18
+ token: function(stream) {
19
+ for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
20
+ if (i > stream.pos) { stream.pos = i; return null; }
21
+ stream.pos = l;
22
+ return "trailingspace";
23
+ },
24
+ name: "trailingspace"
25
+ });
26
+ });
27
+ });
resources/js/codemirror/addon/fold/brace-fold.js ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.registerHelper("fold", "brace", function(cm, start) {
15
+ var line = start.line, lineText = cm.getLine(line);
16
+ var startCh, tokenType;
17
+
18
+ function findOpening(openCh) {
19
+ for (var at = start.ch, pass = 0;;) {
20
+ var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
21
+ if (found == -1) {
22
+ if (pass == 1) break;
23
+ pass = 1;
24
+ at = lineText.length;
25
+ continue;
26
+ }
27
+ if (pass == 1 && found < start.ch) break;
28
+ tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
29
+ if (!/^(comment|string)/.test(tokenType)) return found + 1;
30
+ at = found - 1;
31
+ }
32
+ }
33
+
34
+ var startToken = "{", endToken = "}", startCh = findOpening("{");
35
+ if (startCh == null) {
36
+ startToken = "[", endToken = "]";
37
+ startCh = findOpening("[");
38
+ }
39
+
40
+ if (startCh == null) return;
41
+ var count = 1, lastLine = cm.lastLine(), end, endCh;
42
+ outer: for (var i = line; i <= lastLine; ++i) {
43
+ var text = cm.getLine(i), pos = i == line ? startCh : 0;
44
+ for (;;) {
45
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
46
+ if (nextOpen < 0) nextOpen = text.length;
47
+ if (nextClose < 0) nextClose = text.length;
48
+ pos = Math.min(nextOpen, nextClose);
49
+ if (pos == text.length) break;
50
+ if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
51
+ if (pos == nextOpen) ++count;
52
+ else if (!--count) { end = i; endCh = pos; break outer; }
53
+ }
54
+ ++pos;
55
+ }
56
+ }
57
+ if (end == null || line == end && endCh == startCh) return;
58
+ return {from: CodeMirror.Pos(line, startCh),
59
+ to: CodeMirror.Pos(end, endCh)};
60
+ });
61
+
62
+ CodeMirror.registerHelper("fold", "import", function(cm, start) {
63
+ function hasImport(line) {
64
+ if (line < cm.firstLine() || line > cm.lastLine()) return null;
65
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
66
+ if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
67
+ if (start.type != "keyword" || start.string != "import") return null;
68
+ // Now find closing semicolon, return its position
69
+ for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
70
+ var text = cm.getLine(i), semi = text.indexOf(";");
71
+ if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
72
+ }
73
+ }
74
+
75
+ var start = start.line, has = hasImport(start), prev;
76
+ if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
77
+ return null;
78
+ for (var end = has.end;;) {
79
+ var next = hasImport(end.line + 1);
80
+ if (next == null) break;
81
+ end = next.end;
82
+ }
83
+ return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
84
+ });
85
+
86
+ CodeMirror.registerHelper("fold", "include", function(cm, start) {
87
+ function hasInclude(line) {
88
+ if (line < cm.firstLine() || line > cm.lastLine()) return null;
89
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
90
+ if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
91
+ if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
92
+ }
93
+
94
+ var start = start.line, has = hasInclude(start);
95
+ if (has == null || hasInclude(start - 1) != null) return null;
96
+ for (var end = start;;) {
97
+ var next = hasInclude(end + 1);
98
+ if (next == null) break;
99
+ ++end;
100
+ }
101
+ return {from: CodeMirror.Pos(start, has + 1),
102
+ to: cm.clipPos(CodeMirror.Pos(end))};
103
+ });
104
+
105
+ });
resources/js/codemirror/addon/fold/comment-fold.js ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
15
+ return mode.blockCommentStart && mode.blockCommentEnd;
16
+ }, function(cm, start) {
17
+ var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
18
+ if (!startToken || !endToken) return;
19
+ var line = start.line, lineText = cm.getLine(line);
20
+
21
+ var startCh;
22
+ for (var at = start.ch, pass = 0;;) {
23
+ var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
24
+ if (found == -1) {
25
+ if (pass == 1) return;
26
+ pass = 1;
27
+ at = lineText.length;
28
+ continue;
29
+ }
30
+ if (pass == 1 && found < start.ch) return;
31
+ if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
32
+ startCh = found + startToken.length;
33
+ break;
34
+ }
35
+ at = found - 1;
36
+ }
37
+
38
+ var depth = 1, lastLine = cm.lastLine(), end, endCh;
39
+ outer: for (var i = line; i <= lastLine; ++i) {
40
+ var text = cm.getLine(i), pos = i == line ? startCh : 0;
41
+ for (;;) {
42
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
43
+ if (nextOpen < 0) nextOpen = text.length;
44
+ if (nextClose < 0) nextClose = text.length;
45
+ pos = Math.min(nextOpen, nextClose);
46
+ if (pos == text.length) break;
47
+ if (pos == nextOpen) ++depth;
48
+ else if (!--depth) { end = i; endCh = pos; break outer; }
49
+ ++pos;
50
+ }
51
+ }
52
+ if (end == null || line == end && endCh == startCh) return;
53
+ return {from: CodeMirror.Pos(line, startCh),
54
+ to: CodeMirror.Pos(end, endCh)};
55
+ });
56
+
57
+ });
resources/js/codemirror/addon/fold/foldcode.js ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ function doFold(cm, pos, options, force) {
15
+ if (options && options.call) {
16
+ var finder = options;
17
+ options = null;
18
+ } else {
19
+ var finder = getOption(cm, options, "rangeFinder");
20
+ }
21
+ if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
22
+ var minSize = getOption(cm, options, "minFoldSize");
23
+
24
+ function getRange(allowFolded) {
25
+ var range = finder(cm, pos);
26
+ if (!range || range.to.line - range.from.line < minSize) return null;
27
+ var marks = cm.findMarksAt(range.from);
28
+ for (var i = 0; i < marks.length; ++i) {
29
+ if (marks[i].__isFold && force !== "fold") {
30
+ if (!allowFolded) return null;
31
+ range.cleared = true;
32
+ marks[i].clear();
33
+ }
34
+ }
35
+ return range;
36
+ }
37
+
38
+ var range = getRange(true);
39
+ if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
40
+ pos = CodeMirror.Pos(pos.line - 1, 0);
41
+ range = getRange(false);
42
+ }
43
+ if (!range || range.cleared || force === "unfold") return;
44
+
45
+ var myWidget = makeWidget(cm, options);
46
+ CodeMirror.on(myWidget, "mousedown", function(e) {
47
+ myRange.clear();
48
+ CodeMirror.e_preventDefault(e);
49
+ });
50
+ var myRange = cm.markText(range.from, range.to, {
51
+ replacedWith: myWidget,
52
+ clearOnEnter: true,
53
+ __isFold: true
54
+ });
55
+ myRange.on("clear", function(from, to) {
56
+ CodeMirror.signal(cm, "unfold", cm, from, to);
57
+ });
58
+ CodeMirror.signal(cm, "fold", cm, range.from, range.to);
59
+ }
60
+
61
+ function makeWidget(cm, options) {
62
+ var widget = getOption(cm, options, "widget");
63
+ if (typeof widget == "string") {
64
+ var text = document.createTextNode(widget);
65
+ widget = document.createElement("span");
66
+ widget.appendChild(text);
67
+ widget.className = "CodeMirror-foldmarker";
68
+ }
69
+ return widget;
70
+ }
71
+
72
+ // Clumsy backwards-compatible interface
73
+ CodeMirror.newFoldFunction = function(rangeFinder, widget) {
74
+ return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
75
+ };
76
+
77
+ // New-style interface
78
+ CodeMirror.defineExtension("foldCode", function(pos, options, force) {
79
+ doFold(this, pos, options, force);
80
+ });
81
+
82
+ CodeMirror.defineExtension("isFolded", function(pos) {
83
+ var marks = this.findMarksAt(pos);
84
+ for (var i = 0; i < marks.length; ++i)
85
+ if (marks[i].__isFold) return true;
86
+ });
87
+
88
+ CodeMirror.commands.toggleFold = function(cm) {
89
+ cm.foldCode(cm.getCursor());
90
+ };
91
+ CodeMirror.commands.fold = function(cm) {
92
+ cm.foldCode(cm.getCursor(), null, "fold");
93
+ };
94
+ CodeMirror.commands.unfold = function(cm) {
95
+ cm.foldCode(cm.getCursor(), null, "unfold");
96
+ };
97
+ CodeMirror.commands.foldAll = function(cm) {
98
+ cm.operation(function() {
99
+ for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
100
+ cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
101
+ });
102
+ };
103
+ CodeMirror.commands.unfoldAll = function(cm) {
104
+ cm.operation(function() {
105
+ for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
106
+ cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
107
+ });
108
+ };
109
+
110
+ CodeMirror.registerHelper("fold", "combine", function() {
111
+ var funcs = Array.prototype.slice.call(arguments, 0);
112
+ return function(cm, start) {
113
+ for (var i = 0; i < funcs.length; ++i) {
114
+ var found = funcs[i](cm, start);
115
+ if (found) return found;
116
+ }
117
+ };
118
+ });
119
+
120
+ CodeMirror.registerHelper("fold", "auto", function(cm, start) {
121
+ var helpers = cm.getHelpers(start, "fold");
122
+ for (var i = 0; i < helpers.length; i++) {
123
+ var cur = helpers[i](cm, start);
124
+ if (cur) return cur;
125
+ }
126
+ });
127
+
128
+ var defaultOptions = {
129
+ rangeFinder: CodeMirror.fold.auto,
130
+ widget: "\u2194",
131
+ minFoldSize: 0,
132
+ scanUp: false
133
+ };
134
+
135
+ CodeMirror.defineOption("foldOptions", null);
136
+
137
+ function getOption(cm, options, name) {
138
+ if (options && options[name] !== undefined)
139
+ return options[name];
140
+ var editorOptions = cm.options.foldOptions;
141
+ if (editorOptions && editorOptions[name] !== undefined)
142
+ return editorOptions[name];
143
+ return defaultOptions[name];
144
+ }
145
+ });
resources/js/codemirror/addon/fold/foldgutter.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-foldmarker {
2
+ color: blue;
3
+ text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
4
+ font-family: arial;
5
+ line-height: .3;
6
+ cursor: pointer;
7
+ }
8
+ .CodeMirror-foldgutter {
9
+ width: .7em;
10
+ }
11
+ .CodeMirror-foldgutter-open,
12
+ .CodeMirror-foldgutter-folded {
13
+ color: #555;
14
+ cursor: pointer;
15
+ }
16
+ .CodeMirror-foldgutter-open:after {
17
+ content: "\25BE";
18
+ }
19
+ .CodeMirror-foldgutter-folded:after {
20
+ content: "\25B8";
21
+ }
resources/js/codemirror/addon/fold/foldgutter.js ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("./foldcode"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "./foldcode"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
15
+ if (old && old != CodeMirror.Init) {
16
+ cm.clearGutter(cm.state.foldGutter.options.gutter);
17
+ cm.state.foldGutter = null;
18
+ cm.off("gutterClick", onGutterClick);
19
+ cm.off("change", onChange);
20
+ cm.off("viewportChange", onViewportChange);
21
+ cm.off("fold", onFold);
22
+ cm.off("unfold", onFold);
23
+ cm.off("swapDoc", updateInViewport);
24
+ }
25
+ if (val) {
26
+ cm.state.foldGutter = new State(parseOptions(val));
27
+ updateInViewport(cm);
28
+ cm.on("gutterClick", onGutterClick);
29
+ cm.on("change", onChange);
30
+ cm.on("viewportChange", onViewportChange);
31
+ cm.on("fold", onFold);
32
+ cm.on("unfold", onFold);
33
+ cm.on("swapDoc", updateInViewport);
34
+ }
35
+ });
36
+
37
+ var Pos = CodeMirror.Pos;
38
+
39
+ function State(options) {
40
+ this.options = options;
41
+ this.from = this.to = 0;
42
+ }
43
+
44
+ function parseOptions(opts) {
45
+ if (opts === true) opts = {};
46
+ if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
47
+ if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
48
+ if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
49
+ return opts;
50
+ }
51
+
52
+ function isFolded(cm, line) {
53
+ var marks = cm.findMarksAt(Pos(line));
54
+ for (var i = 0; i < marks.length; ++i)
55
+ if (marks[i].__isFold && marks[i].find().from.line == line) return true;
56
+ }
57
+
58
+ function marker(spec) {
59
+ if (typeof spec == "string") {
60
+ var elt = document.createElement("div");
61
+ elt.className = spec;
62
+ return elt;
63
+ } else {
64
+ return spec.cloneNode(true);
65
+ }
66
+ }
67
+
68
+ function updateFoldInfo(cm, from, to) {
69
+ var opts = cm.state.foldGutter.options, cur = from;
70
+ cm.eachLine(from, to, function(line) {
71
+ var mark = null;
72
+ if (isFolded(cm, cur)) {
73
+ mark = marker(opts.indicatorFolded);
74
+ } else {
75
+ var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto;
76
+ var range = func && func(cm, pos);
77
+ if (range && range.from.line + 1 < range.to.line)
78
+ mark = marker(opts.indicatorOpen);
79
+ }
80
+ cm.setGutterMarker(line, opts.gutter, mark);
81
+ ++cur;
82
+ });
83
+ }
84
+
85
+ function updateInViewport(cm) {
86
+ var vp = cm.getViewport(), state = cm.state.foldGutter;
87
+ if (!state) return;
88
+ cm.operation(function() {
89
+ updateFoldInfo(cm, vp.from, vp.to);
90
+ });
91
+ state.from = vp.from; state.to = vp.to;
92
+ }
93
+
94
+ function onGutterClick(cm, line, gutter) {
95
+ var opts = cm.state.foldGutter.options;
96
+ if (gutter != opts.gutter) return;
97
+ cm.foldCode(Pos(line, 0), opts.rangeFinder);
98
+ }
99
+
100
+ function onChange(cm) {
101
+ var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
102
+ state.from = state.to = 0;
103
+ clearTimeout(state.changeUpdate);
104
+ state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
105
+ }
106
+
107
+ function onViewportChange(cm) {
108
+ var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
109
+ clearTimeout(state.changeUpdate);
110
+ state.changeUpdate = setTimeout(function() {
111
+ var vp = cm.getViewport();
112
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
113
+ updateInViewport(cm);
114
+ } else {
115
+ cm.operation(function() {
116
+ if (vp.from < state.from) {
117
+ updateFoldInfo(cm, vp.from, state.from);
118
+ state.from = vp.from;
119
+ }
120
+ if (vp.to > state.to) {
121
+ updateFoldInfo(cm, state.to, vp.to);
122
+ state.to = vp.to;
123
+ }
124
+ });
125
+ }
126
+ }, opts.updateViewportTimeSpan || 400);
127
+ }
128
+
129
+ function onFold(cm, from) {
130
+ var state = cm.state.foldGutter, line = from.line;
131
+ if (line >= state.from && line < state.to)
132
+ updateFoldInfo(cm, line, line + 1);
133
+ }
134
+ });
resources/js/codemirror/addon/fold/indent-fold.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.registerHelper("fold", "indent", function(cm, start) {
15
+ var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
16
+ if (!/\S/.test(firstLine)) return;
17
+ var getIndent = function(line) {
18
+ return CodeMirror.countColumn(line, null, tabSize);
19
+ };
20
+ var myIndent = getIndent(firstLine);
21
+ var lastLineInFold = null;
22
+ // Go through lines until we find a line that definitely doesn't belong in
23
+ // the block we're folding, or to the end.
24
+ for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
25
+ var curLine = cm.getLine(i);
26
+ var curIndent = getIndent(curLine);
27
+ if (curIndent > myIndent) {
28
+ // Lines with a greater indent are considered part of the block.
29
+ lastLineInFold = i;
30
+ } else if (!/\S/.test(curLine)) {
31
+ // Empty lines might be breaks within the block we're trying to fold.
32
+ } else {
33
+ // A non-empty line at an indent equal to or less than ours marks the
34
+ // start of another block.
35
+ break;
36
+ }
37
+ }
38
+ if (lastLineInFold) return {
39
+ from: CodeMirror.Pos(start.line, firstLine.length),
40
+ to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
41
+ };
42
+ });
43
+
44
+ });
resources/js/codemirror/addon/fold/markdown-fold.js ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
15
+ var maxDepth = 100;
16
+
17
+ function isHeader(lineNo) {
18
+ var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
19
+ return tokentype && /\bheader\b/.test(tokentype);
20
+ }
21
+
22
+ function headerLevel(lineNo, line, nextLine) {
23
+ var match = line && line.match(/^#+/);
24
+ if (match && isHeader(lineNo)) return match[0].length;
25
+ match = nextLine && nextLine.match(/^[=\-]+\s*$/);
26
+ if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
27
+ return maxDepth;
28
+ }
29
+
30
+ var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
31
+ var level = headerLevel(start.line, firstLine, nextLine);
32
+ if (level === maxDepth) return undefined;
33
+
34
+ var lastLineNo = cm.lastLine();
35
+ var end = start.line, nextNextLine = cm.getLine(end + 2);
36
+ while (end < lastLineNo) {
37
+ if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
38
+ ++end;
39
+ nextLine = nextNextLine;
40
+ nextNextLine = cm.getLine(end + 2);
41
+ }
42
+
43
+ return {
44
+ from: CodeMirror.Pos(start.line, firstLine.length),
45
+ to: CodeMirror.Pos(end, cm.getLine(end).length)
46
+ };
47
+ });
48
+
49
+ });
resources/js/codemirror/addon/fold/xml-fold.js ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var Pos = CodeMirror.Pos;
15
+ function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
16
+
17
+ var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
18
+ var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
19
+ var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
20
+
21
+ function Iter(cm, line, ch, range) {
22
+ this.line = line; this.ch = ch;
23
+ this.cm = cm; this.text = cm.getLine(line);
24
+ this.min = range ? range.from : cm.firstLine();
25
+ this.max = range ? range.to - 1 : cm.lastLine();
26
+ }
27
+
28
+ function tagAt(iter, ch) {
29
+ var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
30
+ return type && /\btag\b/.test(type);
31
+ }
32
+
33
+ function nextLine(iter) {
34
+ if (iter.line >= iter.max) return;
35
+ iter.ch = 0;
36
+ iter.text = iter.cm.getLine(++iter.line);
37
+ return true;
38
+ }
39
+ function prevLine(iter) {
40
+ if (iter.line <= iter.min) return;
41
+ iter.text = iter.cm.getLine(--iter.line);
42
+ iter.ch = iter.text.length;
43
+ return true;
44
+ }
45
+
46
+ function toTagEnd(iter) {
47
+ for (;;) {
48
+ var gt = iter.text.indexOf(">", iter.ch);
49
+ if (gt == -1) { if (nextLine(iter)) continue; else return; }
50
+ if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
51
+ var lastSlash = iter.text.lastIndexOf("/", gt);
52
+ var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
53
+ iter.ch = gt + 1;
54
+ return selfClose ? "selfClose" : "regular";
55
+ }
56
+ }
57
+ function toTagStart(iter) {
58
+ for (;;) {
59
+ var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
60
+ if (lt == -1) { if (prevLine(iter)) continue; else return; }
61
+ if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
62
+ xmlTagStart.lastIndex = lt;
63
+ iter.ch = lt;
64
+ var match = xmlTagStart.exec(iter.text);
65
+ if (match && match.index == lt) return match;
66
+ }
67
+ }
68
+
69
+ function toNextTag(iter) {
70
+ for (;;) {
71
+ xmlTagStart.lastIndex = iter.ch;
72
+ var found = xmlTagStart.exec(iter.text);
73
+ if (!found) { if (nextLine(iter)) continue; else return; }
74
+ if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
75
+ iter.ch = found.index + found[0].length;
76
+ return found;
77
+ }
78
+ }
79
+ function toPrevTag(iter) {
80
+ for (;;) {
81
+ var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
82
+ if (gt == -1) { if (prevLine(iter)) continue; else return; }
83
+ if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
84
+ var lastSlash = iter.text.lastIndexOf("/", gt);
85
+ var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
86
+ iter.ch = gt + 1;
87
+ return selfClose ? "selfClose" : "regular";
88
+ }
89
+ }
90
+
91
+ function findMatchingClose(iter, tag) {
92
+ var stack = [];
93
+ for (;;) {
94
+ var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
95
+ if (!next || !(end = toTagEnd(iter))) return;
96
+ if (end == "selfClose") continue;
97
+ if (next[1]) { // closing tag
98
+ for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
99
+ stack.length = i;
100
+ break;
101
+ }
102
+ if (i < 0 && (!tag || tag == next[2])) return {
103
+ tag: next[2],
104
+ from: Pos(startLine, startCh),
105
+ to: Pos(iter.line, iter.ch)
106
+ };
107
+ } else { // opening tag
108
+ stack.push(next[2]);
109
+ }
110
+ }
111
+ }
112
+ function findMatchingOpen(iter, tag) {
113
+ var stack = [];
114
+ for (;;) {
115
+ var prev = toPrevTag(iter);
116
+ if (!prev) return;
117
+ if (prev == "selfClose") { toTagStart(iter); continue; }
118
+ var endLine = iter.line, endCh = iter.ch;
119
+ var start = toTagStart(iter);
120
+ if (!start) return;
121
+ if (start[1]) { // closing tag
122
+ stack.push(start[2]);
123
+ } else { // opening tag
124
+ for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
125
+ stack.length = i;
126
+ break;
127
+ }
128
+ if (i < 0 && (!tag || tag == start[2])) return {
129
+ tag: start[2],
130
+ from: Pos(iter.line, iter.ch),
131
+ to: Pos(endLine, endCh)
132
+ };
133
+ }
134
+ }
135
+ }
136
+
137
+ CodeMirror.registerHelper("fold", "xml", function(cm, start) {
138
+ var iter = new Iter(cm, start.line, 0);
139
+ for (;;) {
140
+ var openTag = toNextTag(iter), end;
141
+ if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
142
+ if (!openTag[1] && end != "selfClose") {
143
+ var start = Pos(iter.line, iter.ch);
144
+ var close = findMatchingClose(iter, openTag[2]);
145
+ return close && {from: start, to: close.from};
146
+ }
147
+ }
148
+ });
149
+ CodeMirror.findMatchingTag = function(cm, pos, range) {
150
+ var iter = new Iter(cm, pos.line, pos.ch, range);
151
+ if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
152
+ var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
153
+ var start = end && toTagStart(iter);
154
+ if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return;
155
+ var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
156
+
157
+ if (start[1]) { // closing tag
158
+ return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
159
+ } else { // opening tag
160
+ iter = new Iter(cm, to.line, to.ch, range);
161
+ return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
162
+ }
163
+ };
164
+
165
+ CodeMirror.findEnclosingTag = function(cm, pos, range) {
166
+ var iter = new Iter(cm, pos.line, pos.ch, range);
167
+ for (;;) {
168
+ var open = findMatchingOpen(iter);
169
+ if (!open) break;
170
+ var forward = new Iter(cm, pos.line, pos.ch, range);
171
+ var close = findMatchingClose(forward, open.tag);
172
+ if (close) return {open: open, close: close};
173
+ }
174
+ };
175
+
176
+ // Used by addon/edit/closetag.js
177
+ CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
178
+ var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
179
+ return findMatchingClose(iter, name);
180
+ };
181
+ });
resources/js/codemirror/addon/hint/anyword-hint.js ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var WORD = /[\w$]+/, RANGE = 500;
15
+
16
+ CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
17
+ var word = options && options.word || WORD;
18
+ var range = options && options.range || RANGE;
19
+ var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
20
+ var start = cur.ch, end = start;
21
+ while (end < curLine.length && word.test(curLine.charAt(end))) ++end;
22
+ while (start && word.test(curLine.charAt(start - 1))) --start;
23
+ var curWord = start != end && curLine.slice(start, end);
24
+
25
+ var list = [], seen = {};
26
+ var re = new RegExp(word.source, "g");
27
+ for (var dir = -1; dir <= 1; dir += 2) {
28
+ var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
29
+ for (; line != endLine; line += dir) {
30
+ var text = editor.getLine(line), m;
31
+ while (m = re.exec(text)) {
32
+ if (line == cur.line && m[0] === curWord) continue;
33
+ if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
34
+ seen[m[0]] = true;
35
+ list.push(m[0]);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
41
+ });
42
+ });
resources/js/codemirror/addon/hint/css-hint.js ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../../mode/css/css"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../../mode/css/css"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
15
+ "first-letter": 1, "first-line": 1, "first-child": 1,
16
+ before: 1, after: 1, lang: 1};
17
+
18
+ CodeMirror.registerHelper("hint", "css", function(cm) {
19
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
20
+ var inner = CodeMirror.innerMode(cm.getMode(), token.state);
21
+ if (inner.mode.name != "css") return;
22
+
23
+ var word = token.string, start = token.start, end = token.end;
24
+ if (/[^\w$_-]/.test(word)) {
25
+ word = ""; start = end = cur.ch;
26
+ }
27
+
28
+ var spec = CodeMirror.resolveMode("text/css");
29
+
30
+ var result = [];
31
+ function add(keywords) {
32
+ for (var name in keywords)
33
+ if (!word || name.lastIndexOf(word, 0) == 0)
34
+ result.push(name);
35
+ }
36
+
37
+ var st = inner.state.state;
38
+ if (st == "pseudo" || token.type == "variable-3") {
39
+ add(pseudoClasses);
40
+ } else if (st == "block" || st == "maybeprop") {
41
+ add(spec.propertyKeywords);
42
+ } else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
43
+ add(spec.valueKeywords);
44
+ add(spec.colorKeywords);
45
+ } else if (st == "media" || st == "media_parens") {
46
+ add(spec.mediaTypes);
47
+ add(spec.mediaFeatures);
48
+ }
49
+
50
+ if (result.length) return {
51
+ list: result,
52
+ from: CodeMirror.Pos(cur.line, start),
53
+ to: CodeMirror.Pos(cur.line, end)
54
+ };
55
+ });
56
+ });
resources/js/codemirror/addon/hint/html-hint.js ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" ");
15
+ var targets = ["_blank", "_self", "_top", "_parent"];
16
+ var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"];
17
+ var methods = ["get", "post", "put", "delete"];
18
+ var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"];
19
+ var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech",
20
+ "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait",
21
+ "orientation:landscape", "device-height: [X]", "device-width: [X]"];
22
+ var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags
23
+
24
+ var data = {
25
+ a: {
26
+ attrs: {
27
+ href: null, ping: null, type: null,
28
+ media: media,
29
+ target: targets,
30
+ hreflang: langs
31
+ }
32
+ },
33
+ abbr: s,
34
+ acronym: s,
35
+ address: s,
36
+ applet: s,
37
+ area: {
38
+ attrs: {
39
+ alt: null, coords: null, href: null, target: null, ping: null,
40
+ media: media, hreflang: langs, type: null,
41
+ shape: ["default", "rect", "circle", "poly"]
42
+ }
43
+ },
44
+ article: s,
45
+ aside: s,
46
+ audio: {
47
+ attrs: {
48
+ src: null, mediagroup: null,
49
+ crossorigin: ["anonymous", "use-credentials"],
50
+ preload: ["none", "metadata", "auto"],
51
+ autoplay: ["", "autoplay"],
52
+ loop: ["", "loop"],
53
+ controls: ["", "controls"]
54
+ }
55
+ },
56
+ b: s,
57
+ base: { attrs: { href: null, target: targets } },
58
+ basefont: s,
59
+ bdi: s,
60
+ bdo: s,
61
+ big: s,
62
+ blockquote: { attrs: { cite: null } },
63
+ body: s,
64
+ br: s,
65
+ button: {
66
+ attrs: {
67
+ form: null, formaction: null, name: null, value: null,
68
+ autofocus: ["", "autofocus"],
69
+ disabled: ["", "autofocus"],
70
+ formenctype: encs,
71
+ formmethod: methods,
72
+ formnovalidate: ["", "novalidate"],
73
+ formtarget: targets,
74
+ type: ["submit", "reset", "button"]
75
+ }
76
+ },
77
+ canvas: { attrs: { width: null, height: null } },
78
+ caption: s,
79
+ center: s,
80
+ cite: s,
81
+ code: s,
82
+ col: { attrs: { span: null } },
83
+ colgroup: { attrs: { span: null } },
84
+ command: {
85
+ attrs: {
86
+ type: ["command", "checkbox", "radio"],
87
+ label: null, icon: null, radiogroup: null, command: null, title: null,
88
+ disabled: ["", "disabled"],
89
+ checked: ["", "checked"]
90
+ }
91
+ },
92
+ data: { attrs: { value: null } },
93
+ datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } },
94
+ datalist: { attrs: { data: null } },
95
+ dd: s,
96
+ del: { attrs: { cite: null, datetime: null } },
97
+ details: { attrs: { open: ["", "open"] } },
98
+ dfn: s,
99
+ dir: s,
100
+ div: s,
101
+ dl: s,
102
+ dt: s,
103
+ em: s,
104
+ embed: { attrs: { src: null, type: null, width: null, height: null } },
105
+ eventsource: { attrs: { src: null } },
106
+ fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } },
107
+ figcaption: s,
108
+ figure: s,
109
+ font: s,
110
+ footer: s,
111
+ form: {
112
+ attrs: {
113
+ action: null, name: null,
114
+ "accept-charset": charsets,
115
+ autocomplete: ["on", "off"],
116
+ enctype: encs,
117
+ method: methods,
118
+ novalidate: ["", "novalidate"],
119
+ target: targets
120
+ }
121
+ },
122
+ frame: s,
123
+ frameset: s,
124
+ h1: s, h2: s, h3: s, h4: s, h5: s, h6: s,
125
+ head: {
126
+ attrs: {},
127
+ children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"]
128
+ },
129
+ header: s,
130
+ hgroup: s,
131
+ hr: s,
132
+ html: {
133
+ attrs: { manifest: null },
134
+ children: ["head", "body"]
135
+ },
136
+ i: s,
137
+ iframe: {
138
+ attrs: {
139
+ src: null, srcdoc: null, name: null, width: null, height: null,
140
+ sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"],
141
+ seamless: ["", "seamless"]
142
+ }
143
+ },
144
+ img: {
145
+ attrs: {
146
+ alt: null, src: null, ismap: null, usemap: null, width: null, height: null,
147
+ crossorigin: ["anonymous", "use-credentials"]
148
+ }
149
+ },
150
+ input: {
151
+ attrs: {
152
+ alt: null, dirname: null, form: null, formaction: null,
153
+ height: null, list: null, max: null, maxlength: null, min: null,
154
+ name: null, pattern: null, placeholder: null, size: null, src: null,
155
+ step: null, value: null, width: null,
156
+ accept: ["audio/*", "video/*", "image/*"],
157
+ autocomplete: ["on", "off"],
158
+ autofocus: ["", "autofocus"],
159
+ checked: ["", "checked"],
160
+ disabled: ["", "disabled"],
161
+ formenctype: encs,
162
+ formmethod: methods,
163
+ formnovalidate: ["", "novalidate"],
164
+ formtarget: targets,
165
+ multiple: ["", "multiple"],
166
+ readonly: ["", "readonly"],
167
+ required: ["", "required"],
168
+ type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month",
169
+ "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
170
+ "file", "submit", "image", "reset", "button"]
171
+ }
172
+ },
173
+ ins: { attrs: { cite: null, datetime: null } },
174
+ kbd: s,
175
+ keygen: {
176
+ attrs: {
177
+ challenge: null, form: null, name: null,
178
+ autofocus: ["", "autofocus"],
179
+ disabled: ["", "disabled"],
180
+ keytype: ["RSA"]
181
+ }
182
+ },
183
+ label: { attrs: { "for": null, form: null } },
184
+ legend: s,
185
+ li: { attrs: { value: null } },
186
+ link: {
187
+ attrs: {
188
+ href: null, type: null,
189
+ hreflang: langs,
190
+ media: media,
191
+ sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"]
192
+ }
193
+ },
194
+ map: { attrs: { name: null } },
195
+ mark: s,
196
+ menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } },
197
+ meta: {
198
+ attrs: {
199
+ content: null,
200
+ charset: charsets,
201
+ name: ["viewport", "application-name", "author", "description", "generator", "keywords"],
202
+ "http-equiv": ["content-language", "content-type", "default-style", "refresh"]
203
+ }
204
+ },
205
+ meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } },
206
+ nav: s,
207
+ noframes: s,
208
+ noscript: s,
209
+ object: {
210
+ attrs: {
211
+ data: null, type: null, name: null, usemap: null, form: null, width: null, height: null,
212
+ typemustmatch: ["", "typemustmatch"]
213
+ }
214
+ },
215
+ ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } },
216
+ optgroup: { attrs: { disabled: ["", "disabled"], label: null } },
217
+ option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } },
218
+ output: { attrs: { "for": null, form: null, name: null } },
219
+ p: s,
220
+ param: { attrs: { name: null, value: null } },
221
+ pre: s,
222
+ progress: { attrs: { value: null, max: null } },
223
+ q: { attrs: { cite: null } },
224
+ rp: s,
225
+ rt: s,
226
+ ruby: s,
227
+ s: s,
228
+ samp: s,
229
+ script: {
230
+ attrs: {
231
+ type: ["text/javascript"],
232
+ src: null,
233
+ async: ["", "async"],
234
+ defer: ["", "defer"],
235
+ charset: charsets
236
+ }
237
+ },
238
+ section: s,
239
+ select: {
240
+ attrs: {
241
+ form: null, name: null, size: null,
242
+ autofocus: ["", "autofocus"],
243
+ disabled: ["", "disabled"],
244
+ multiple: ["", "multiple"]
245
+ }
246
+ },
247
+ small: s,
248
+ source: { attrs: { src: null, type: null, media: null } },
249
+ span: s,
250
+ strike: s,
251
+ strong: s,
252
+ style: {
253
+ attrs: {
254
+ type: ["text/css"],
255
+ media: media,
256
+ scoped: null
257
+ }
258
+ },
259
+ sub: s,
260
+ summary: s,
261
+ sup: s,
262
+ table: s,
263
+ tbody: s,
264
+ td: { attrs: { colspan: null, rowspan: null, headers: null } },
265
+ textarea: {
266
+ attrs: {
267
+ dirname: null, form: null, maxlength: null, name: null, placeholder: null,
268
+ rows: null, cols: null,
269
+ autofocus: ["", "autofocus"],
270
+ disabled: ["", "disabled"],
271
+ readonly: ["", "readonly"],
272
+ required: ["", "required"],
273
+ wrap: ["soft", "hard"]
274
+ }
275
+ },
276
+ tfoot: s,
277
+ th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } },
278
+ thead: s,
279
+ time: { attrs: { datetime: null } },
280
+ title: s,
281
+ tr: s,
282
+ track: {
283
+ attrs: {
284
+ src: null, label: null, "default": null,
285
+ kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"],
286
+ srclang: langs
287
+ }
288
+ },
289
+ tt: s,
290
+ u: s,
291
+ ul: s,
292
+ "var": s,
293
+ video: {
294
+ attrs: {
295
+ src: null, poster: null, width: null, height: null,
296
+ crossorigin: ["anonymous", "use-credentials"],
297
+ preload: ["auto", "metadata", "none"],
298
+ autoplay: ["", "autoplay"],
299
+ mediagroup: ["movie"],
300
+ muted: ["", "muted"],
301
+ controls: ["", "controls"]
302
+ }
303
+ },
304
+ wbr: s
305
+ };
306
+
307
+ var globalAttrs = {
308
+ accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
309
+ "class": null,
310
+ contenteditable: ["true", "false"],
311
+ contextmenu: null,
312
+ dir: ["ltr", "rtl", "auto"],
313
+ draggable: ["true", "false", "auto"],
314
+ dropzone: ["copy", "move", "link", "string:", "file:"],
315
+ hidden: ["hidden"],
316
+ id: null,
317
+ inert: ["inert"],
318
+ itemid: null,
319
+ itemprop: null,
320
+ itemref: null,
321
+ itemscope: ["itemscope"],
322
+ itemtype: null,
323
+ lang: ["en", "es"],
324
+ spellcheck: ["true", "false"],
325
+ style: null,
326
+ tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
327
+ title: null,
328
+ translate: ["yes", "no"],
329
+ onclick: null,
330
+ rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"]
331
+ };
332
+ function populate(obj) {
333
+ for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr))
334
+ obj.attrs[attr] = globalAttrs[attr];
335
+ }
336
+
337
+ populate(s);
338
+ for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s)
339
+ populate(data[tag]);
340
+
341
+ CodeMirror.htmlSchema = data;
342
+ function htmlHint(cm, options) {
343
+ var local = {schemaInfo: data};
344
+ if (options) for (var opt in options) local[opt] = options[opt];
345
+ return CodeMirror.hint.xml(cm, local);
346
+ }
347
+ CodeMirror.registerHelper("hint", "html", htmlHint);
348
+ });
resources/js/codemirror/addon/hint/javascript-hint.js ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ var Pos = CodeMirror.Pos;
13
+
14
+ function forEach(arr, f) {
15
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
16
+ }
17
+
18
+ function arrayContains(arr, item) {
19
+ if (!Array.prototype.indexOf) {
20
+ var i = arr.length;
21
+ while (i--) {
22
+ if (arr[i] === item) {
23
+ return true;
24
+ }
25
+ }
26
+ return false;
27
+ }
28
+ return arr.indexOf(item) != -1;
29
+ }
30
+
31
+ function scriptHint(editor, keywords, getToken, options) {
32
+ // Find the token at the cursor
33
+ var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
34
+ if (/\b(?:string|comment)\b/.test(token.type)) return;
35
+ token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
36
+
37
+ // If it's not a 'word-style' token, ignore the token.
38
+ if (!/^[\w$_]*$/.test(token.string)) {
39
+ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
40
+ type: token.string == "." ? "property" : null};
41
+ }
42
+ // If it is a property, find out what it is a property of.
43
+ while (tprop.type == "property") {
44
+ tprop = getToken(editor, Pos(cur.line, tprop.start));
45
+ if (tprop.string != ".") return;
46
+ tprop = getToken(editor, Pos(cur.line, tprop.start));
47
+ if (!context) var context = [];
48
+ context.push(tprop);
49
+ }
50
+ return {list: getCompletions(token, context, keywords, options),
51
+ from: Pos(cur.line, token.start),
52
+ to: Pos(cur.line, token.end)};
53
+ }
54
+
55
+ function javascriptHint(editor, options) {
56
+ return scriptHint(editor, javascriptKeywords,
57
+ function (e, cur) {return e.getTokenAt(cur);},
58
+ options);
59
+ };
60
+ CodeMirror.registerHelper("hint", "javascript", javascriptHint);
61
+
62
+ function getCoffeeScriptToken(editor, cur) {
63
+ // This getToken, it is for coffeescript, imitates the behavior of
64
+ // getTokenAt method in javascript.js, that is, returning "property"
65
+ // type and treat "." as indepenent token.
66
+ var token = editor.getTokenAt(cur);
67
+ if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
68
+ token.end = token.start;
69
+ token.string = '.';
70
+ token.type = "property";
71
+ }
72
+ else if (/^\.[\w$_]*$/.test(token.string)) {
73
+ token.type = "property";
74
+ token.start++;
75
+ token.string = token.string.replace(/\./, '');
76
+ }
77
+ return token;
78
+ }
79
+
80
+ function coffeescriptHint(editor, options) {
81
+ return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
82
+ }
83
+ CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
84
+
85
+ var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
86
+ "toUpperCase toLowerCase split concat match replace search").split(" ");
87
+ var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
88
+ "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
89
+ var funcProps = "prototype apply call bind".split(" ");
90
+ var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
91
+ "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
92
+ var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
93
+ "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
94
+
95
+ function getCompletions(token, context, keywords, options) {
96
+ var found = [], start = token.string;
97
+ function maybeAdd(str) {
98
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
99
+ }
100
+ function gatherCompletions(obj) {
101
+ if (typeof obj == "string") forEach(stringProps, maybeAdd);
102
+ else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
103
+ else if (obj instanceof Function) forEach(funcProps, maybeAdd);
104
+ for (var name in obj) maybeAdd(name);
105
+ }
106
+
107
+ if (context && context.length) {
108
+ // If this is a property, see if it belongs to some object we can
109
+ // find in the current environment.
110
+ var obj = context.pop(), base;
111
+ if (obj.type && obj.type.indexOf("variable") === 0) {
112
+ if (options && options.additionalContext)
113
+ base = options.additionalContext[obj.string];
114
+ if (!options || options.useGlobalScope !== false)
115
+ base = base || window[obj.string];
116
+ } else if (obj.type == "string") {
117
+ base = "";
118
+ } else if (obj.type == "atom") {
119
+ base = 1;
120
+ } else if (obj.type == "function") {
121
+ if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
122
+ (typeof window.jQuery == 'function'))
123
+ base = window.jQuery();
124
+ else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
125
+ base = window._();
126
+ }
127
+ while (base != null && context.length)
128
+ base = base[context.pop().string];
129
+ if (base != null) gatherCompletions(base);
130
+ } else {
131
+ // If not, just look in the window object and any local scope
132
+ // (reading into JS mode internals to get at the local and global variables)
133
+ for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
134
+ for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
135
+ if (!options || options.useGlobalScope !== false)
136
+ gatherCompletions(window);
137
+ forEach(keywords, maybeAdd);
138
+ }
139
+ return found;
140
+ }
141
+ });
resources/js/codemirror/addon/hint/python-hint.js ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ function forEach(arr, f) {
15
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
16
+ }
17
+
18
+ function arrayContains(arr, item) {
19
+ if (!Array.prototype.indexOf) {
20
+ var i = arr.length;
21
+ while (i--) {
22
+ if (arr[i] === item) {
23
+ return true;
24
+ }
25
+ }
26
+ return false;
27
+ }
28
+ return arr.indexOf(item) != -1;
29
+ }
30
+
31
+ function scriptHint(editor, _keywords, getToken) {
32
+ // Find the token at the cursor
33
+ var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
34
+ // If it's not a 'word-style' token, ignore the token.
35
+
36
+ if (!/^[\w$_]*$/.test(token.string)) {
37
+ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
38
+ className: token.string == ":" ? "python-type" : null};
39
+ }
40
+
41
+ if (!context) var context = [];
42
+ context.push(tprop);
43
+
44
+ var completionList = getCompletions(token, context);
45
+ completionList = completionList.sort();
46
+
47
+ return {list: completionList,
48
+ from: CodeMirror.Pos(cur.line, token.start),
49
+ to: CodeMirror.Pos(cur.line, token.end)};
50
+ }
51
+
52
+ function pythonHint(editor) {
53
+ return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
54
+ }
55
+ CodeMirror.registerHelper("hint", "python", pythonHint);
56
+
57
+ var pythonKeywords = "and del from not while as elif global or with assert else if pass yield"
58
+ + "break except import print class exec in raise continue finally is return def for lambda try";
59
+ var pythonKeywordsL = pythonKeywords.split(" ");
60
+ var pythonKeywordsU = pythonKeywords.toUpperCase().split(" ");
61
+
62
+ var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str "
63
+ + "any eval isinstance pow sum basestring execfile issubclass print super"
64
+ + "bin file iter property tuple bool filter len range type"
65
+ + "bytearray float list raw_input unichr callable format locals reduce unicode"
66
+ + "chr frozenset long reload vars classmethod getattr map repr xrange"
67
+ + "cmp globals max reversed zip compile hasattr memoryview round __import__"
68
+ + "complex hash min set apply delattr help next setattr buffer"
69
+ + "dict hex object slice coerce dir id oct sorted intern ";
70
+ var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" ");
71
+ var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" ");
72
+
73
+ function getCompletions(token, context) {
74
+ var found = [], start = token.string;
75
+ function maybeAdd(str) {
76
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
77
+ }
78
+
79
+ function gatherCompletions(_obj) {
80
+ forEach(pythonBuiltinsL, maybeAdd);
81
+ forEach(pythonBuiltinsU, maybeAdd);
82
+ forEach(pythonKeywordsL, maybeAdd);
83
+ forEach(pythonKeywordsU, maybeAdd);
84
+ }
85
+
86
+ if (context) {
87
+ // If this is a property, see if it belongs to some object we can
88
+ // find in the current environment.
89
+ var obj = context.pop(), base;
90
+
91
+ if (obj.type == "variable")
92
+ base = obj.string;
93
+ else if(obj.type == "variable-3")
94
+ base = ":" + obj.string;
95
+
96
+ while (base != null && context.length)
97
+ base = base[context.pop().string];
98
+ if (base != null) gatherCompletions(base);
99
+ }
100
+ return found;
101
+ }
102
+ });
resources/js/codemirror/addon/hint/show-hint.css ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-hints {
2
+ position: absolute;
3
+ z-index: 10;
4
+ overflow: hidden;
5
+ list-style: none;
6
+
7
+ margin: 0;
8
+ padding: 2px;
9
+
10
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
11
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
12
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
13
+ border-radius: 3px;
14
+ border: 1px solid silver;
15
+
16
+ background: white;
17
+ font-size: 90%;
18
+ font-family: monospace;
19
+
20
+ max-height: 20em;
21
+ overflow-y: auto;
22
+ }
23
+
24
+ .CodeMirror-hint {
25
+ margin: 0;
26
+ padding: 0 4px;
27
+ border-radius: 2px;
28
+ max-width: 19em;
29
+ overflow: hidden;
30
+ white-space: pre;
31
+ color: black;
32
+ cursor: pointer;
33
+ }
34
+
35
+ .CodeMirror-hint-active {
36
+ background: #08f;
37
+ color: white;
38
+ }
resources/js/codemirror/addon/hint/show-hint.js ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var HINT_ELEMENT_CLASS = "CodeMirror-hint";
15
+ var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
16
+
17
+ // This is the old interface, kept around for now to stay
18
+ // backwards-compatible.
19
+ CodeMirror.showHint = function(cm, getHints, options) {
20
+ if (!getHints) return cm.showHint(options);
21
+ if (options && options.async) getHints.async = true;
22
+ var newOpts = {hint: getHints};
23
+ if (options) for (var prop in options) newOpts[prop] = options[prop];
24
+ return cm.showHint(newOpts);
25
+ };
26
+
27
+ CodeMirror.defineExtension("showHint", function(options) {
28
+ // We want a single cursor position.
29
+ if (this.listSelections().length > 1 || this.somethingSelected()) return;
30
+
31
+ if (this.state.completionActive) this.state.completionActive.close();
32
+ var completion = this.state.completionActive = new Completion(this, options);
33
+ var getHints = completion.options.hint;
34
+ if (!getHints) return;
35
+
36
+ CodeMirror.signal(this, "startCompletion", this);
37
+ if (getHints.async)
38
+ getHints(this, function(hints) { completion.showHints(hints); }, completion.options);
39
+ else
40
+ return completion.showHints(getHints(this, completion.options));
41
+ });
42
+
43
+ function Completion(cm, options) {
44
+ this.cm = cm;
45
+ this.options = this.buildOptions(options);
46
+ this.widget = this.onClose = null;
47
+ }
48
+
49
+ Completion.prototype = {
50
+ close: function() {
51
+ if (!this.active()) return;
52
+ this.cm.state.completionActive = null;
53
+
54
+ if (this.widget) this.widget.close();
55
+ if (this.onClose) this.onClose();
56
+ CodeMirror.signal(this.cm, "endCompletion", this.cm);
57
+ },
58
+
59
+ active: function() {
60
+ return this.cm.state.completionActive == this;
61
+ },
62
+
63
+ pick: function(data, i) {
64
+ var completion = data.list[i];
65
+ if (completion.hint) completion.hint(this.cm, data, completion);
66
+ else this.cm.replaceRange(getText(completion), completion.from || data.from,
67
+ completion.to || data.to, "complete");
68
+ CodeMirror.signal(data, "pick", completion);
69
+ this.close();
70
+ },
71
+
72
+ showHints: function(data) {
73
+ if (!data || !data.list.length || !this.active()) return this.close();
74
+
75
+ if (this.options.completeSingle && data.list.length == 1)
76
+ this.pick(data, 0);
77
+ else
78
+ this.showWidget(data);
79
+ },
80
+
81
+ showWidget: function(data) {
82
+ this.widget = new Widget(this, data);
83
+ CodeMirror.signal(data, "shown");
84
+
85
+ var debounce = 0, completion = this, finished;
86
+ var closeOn = this.options.closeCharacters;
87
+ var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
88
+
89
+ var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
90
+ return setTimeout(fn, 1000/60);
91
+ };
92
+ var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
93
+
94
+ function done() {
95
+ if (finished) return;
96
+ finished = true;
97
+ completion.close();
98
+ completion.cm.off("cursorActivity", activity);
99
+ if (data) CodeMirror.signal(data, "close");
100
+ }
101
+
102
+ function update() {
103
+ if (finished) return;
104
+ CodeMirror.signal(data, "update");
105
+ var getHints = completion.options.hint;
106
+ if (getHints.async)
107
+ getHints(completion.cm, finishUpdate, completion.options);
108
+ else
109
+ finishUpdate(getHints(completion.cm, completion.options));
110
+ }
111
+ function finishUpdate(data_) {
112
+ data = data_;
113
+ if (finished) return;
114
+ if (!data || !data.list.length) return done();
115
+ if (completion.widget) completion.widget.close();
116
+ completion.widget = new Widget(completion, data);
117
+ }
118
+
119
+ function clearDebounce() {
120
+ if (debounce) {
121
+ cancelAnimationFrame(debounce);
122
+ debounce = 0;
123
+ }
124
+ }
125
+
126
+ function activity() {
127
+ clearDebounce();
128
+ var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
129
+ if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
130
+ pos.ch < startPos.ch || completion.cm.somethingSelected() ||
131
+ (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
132
+ completion.close();
133
+ } else {
134
+ debounce = requestAnimationFrame(update);
135
+ if (completion.widget) completion.widget.close();
136
+ }
137
+ }
138
+ this.cm.on("cursorActivity", activity);
139
+ this.onClose = done;
140
+ },
141
+
142
+ buildOptions: function(options) {
143
+ var editor = this.cm.options.hintOptions;
144
+ var out = {};
145
+ for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
146
+ if (editor) for (var prop in editor)
147
+ if (editor[prop] !== undefined) out[prop] = editor[prop];
148
+ if (options) for (var prop in options)
149
+ if (options[prop] !== undefined) out[prop] = options[prop];
150
+ return out;
151
+ }
152
+ };
153
+
154
+ function getText(completion) {
155
+ if (typeof completion == "string") return completion;
156
+ else return completion.text;
157
+ }
158
+
159
+ function buildKeyMap(completion, handle) {
160
+ var baseMap = {
161
+ Up: function() {handle.moveFocus(-1);},
162
+ Down: function() {handle.moveFocus(1);},
163
+ PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
164
+ PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
165
+ Home: function() {handle.setFocus(0);},
166
+ End: function() {handle.setFocus(handle.length - 1);},
167
+ Enter: handle.pick,
168
+ Tab: handle.pick,
169
+ Esc: handle.close
170
+ };
171
+ var custom = completion.options.customKeys;
172
+ var ourMap = custom ? {} : baseMap;
173
+ function addBinding(key, val) {
174
+ var bound;
175
+ if (typeof val != "string")
176
+ bound = function(cm) { return val(cm, handle); };
177
+ // This mechanism is deprecated
178
+ else if (baseMap.hasOwnProperty(val))
179
+ bound = baseMap[val];
180
+ else
181
+ bound = val;
182
+ ourMap[key] = bound;
183
+ }
184
+ if (custom)
185
+ for (var key in custom) if (custom.hasOwnProperty(key))
186
+ addBinding(key, custom[key]);
187
+ var extra = completion.options.extraKeys;
188
+ if (extra)
189
+ for (var key in extra) if (extra.hasOwnProperty(key))
190
+ addBinding(key, extra[key]);
191
+ return ourMap;
192
+ }
193
+
194
+ function getHintElement(hintsElement, el) {
195
+ while (el && el != hintsElement) {
196
+ if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
197
+ el = el.parentNode;
198
+ }
199
+ }
200
+
201
+ function Widget(completion, data) {
202
+ this.completion = completion;
203
+ this.data = data;
204
+ var widget = this, cm = completion.cm;
205
+
206
+ var hints = this.hints = document.createElement("ul");
207
+ hints.className = "CodeMirror-hints";
208
+ this.selectedHint = data.selectedHint || 0;
209
+
210
+ var completions = data.list;
211
+ for (var i = 0; i < completions.length; ++i) {
212
+ var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
213
+ var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
214
+ if (cur.className != null) className = cur.className + " " + className;
215
+ elt.className = className;
216
+ if (cur.render) cur.render(elt, data, cur);
217
+ else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
218
+ elt.hintId = i;
219
+ }
220
+
221
+ var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
222
+ var left = pos.left, top = pos.bottom, below = true;
223
+ hints.style.left = left + "px";
224
+ hints.style.top = top + "px";
225
+ // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
226
+ var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
227
+ var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
228
+ (completion.options.container || document.body).appendChild(hints);
229
+ var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
230
+ if (overlapY > 0) {
231
+ var height = box.bottom - box.top, curTop = box.top - (pos.bottom - pos.top);
232
+ if (curTop - height > 0) { // Fits above cursor
233
+ hints.style.top = (top = curTop - height) + "px";
234
+ below = false;
235
+ } else if (height > winH) {
236
+ hints.style.height = (winH - 5) + "px";
237
+ hints.style.top = (top = pos.bottom - box.top) + "px";
238
+ var cursor = cm.getCursor();
239
+ if (data.from.ch != cursor.ch) {
240
+ pos = cm.cursorCoords(cursor);
241
+ hints.style.left = (left = pos.left) + "px";
242
+ box = hints.getBoundingClientRect();
243
+ }
244
+ }
245
+ }
246
+ var overlapX = box.left - winW;
247
+ if (overlapX > 0) {
248
+ if (box.right - box.left > winW) {
249
+ hints.style.width = (winW - 5) + "px";
250
+ overlapX -= (box.right - box.left) - winW;
251
+ }
252
+ hints.style.left = (left = pos.left - overlapX) + "px";
253
+ }
254
+
255
+ cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
256
+ moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
257
+ setFocus: function(n) { widget.changeActive(n); },
258
+ menuSize: function() { return widget.screenAmount(); },
259
+ length: completions.length,
260
+ close: function() { completion.close(); },
261
+ pick: function() { widget.pick(); },
262
+ data: data
263
+ }));
264
+
265
+ if (completion.options.closeOnUnfocus) {
266
+ var closingOnBlur;
267
+ cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
268
+ cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
269
+ }
270
+
271
+ var startScroll = cm.getScrollInfo();
272
+ cm.on("scroll", this.onScroll = function() {
273
+ var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
274
+ var newTop = top + startScroll.top - curScroll.top;
275
+ var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
276
+ if (!below) point += hints.offsetHeight;
277
+ if (point <= editor.top || point >= editor.bottom) return completion.close();
278
+ hints.style.top = newTop + "px";
279
+ hints.style.left = (left + startScroll.left - curScroll.left) + "px";
280
+ });
281
+
282
+ CodeMirror.on(hints, "dblclick", function(e) {
283
+ var t = getHintElement(hints, e.target || e.srcElement);
284
+ if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
285
+ });
286
+
287
+ CodeMirror.on(hints, "click", function(e) {
288
+ var t = getHintElement(hints, e.target || e.srcElement);
289
+ if (t && t.hintId != null) {
290
+ widget.changeActive(t.hintId);
291
+ if (completion.options.completeOnSingleClick) widget.pick();
292
+ }
293
+ });
294
+
295
+ CodeMirror.on(hints, "mousedown", function() {
296
+ setTimeout(function(){cm.focus();}, 20);
297
+ });
298
+
299
+ CodeMirror.signal(data, "select", completions[0], hints.firstChild);
300
+ return true;
301
+ }
302
+
303
+ Widget.prototype = {
304
+ close: function() {
305
+ if (this.completion.widget != this) return;
306
+ this.completion.widget = null;
307
+ this.hints.parentNode.removeChild(this.hints);
308
+ this.completion.cm.removeKeyMap(this.keyMap);
309
+
310
+ var cm = this.completion.cm;
311
+ if (this.completion.options.closeOnUnfocus) {
312
+ cm.off("blur", this.onBlur);
313
+ cm.off("focus", this.onFocus);
314
+ }
315
+ cm.off("scroll", this.onScroll);
316
+ },
317
+
318
+ pick: function() {
319
+ this.completion.pick(this.data, this.selectedHint);
320
+ },
321
+
322
+ changeActive: function(i, avoidWrap) {
323
+ if (i >= this.data.list.length)
324
+ i = avoidWrap ? this.data.list.length - 1 : 0;
325
+ else if (i < 0)
326
+ i = avoidWrap ? 0 : this.data.list.length - 1;
327
+ if (this.selectedHint == i) return;
328
+ var node = this.hints.childNodes[this.selectedHint];
329
+ node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
330
+ node = this.hints.childNodes[this.selectedHint = i];
331
+ node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
332
+ if (node.offsetTop < this.hints.scrollTop)
333
+ this.hints.scrollTop = node.offsetTop - 3;
334
+ else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
335
+ this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
336
+ CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
337
+ },
338
+
339
+ screenAmount: function() {
340
+ return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
341
+ }
342
+ };
343
+
344
+ CodeMirror.registerHelper("hint", "auto", function(cm, options) {
345
+ var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
346
+ if (helpers.length) {
347
+ for (var i = 0; i < helpers.length; i++) {
348
+ var cur = helpers[i](cm, options);
349
+ if (cur && cur.list.length) return cur;
350
+ }
351
+ } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
352
+ if (words) return CodeMirror.hint.fromList(cm, {words: words});
353
+ } else if (CodeMirror.hint.anyword) {
354
+ return CodeMirror.hint.anyword(cm, options);
355
+ }
356
+ });
357
+
358
+ CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
359
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
360
+ var found = [];
361
+ for (var i = 0; i < options.words.length; i++) {
362
+ var word = options.words[i];
363
+ if (word.slice(0, token.string.length) == token.string)
364
+ found.push(word);
365
+ }
366
+
367
+ if (found.length) return {
368
+ list: found,
369
+ from: CodeMirror.Pos(cur.line, token.start),
370
+ to: CodeMirror.Pos(cur.line, token.end)
371
+ };
372
+ });
373
+
374
+ CodeMirror.commands.autocomplete = CodeMirror.showHint;
375
+
376
+ var defaultOptions = {
377
+ hint: CodeMirror.hint.auto,
378
+ completeSingle: true,
379
+ alignWithWord: true,
380
+ closeCharacters: /[\s()\[\]{};:>,]/,
381
+ closeOnUnfocus: true,
382
+ completeOnSingleClick: false,
383
+ container: null,
384
+ customKeys: null,
385
+ extraKeys: null
386
+ };
387
+
388
+ CodeMirror.defineOption("hintOptions", null);
389
+ });
resources/js/codemirror/addon/hint/sql-hint.js ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var tables;
15
+ var keywords;
16
+ var CONS = {
17
+ QUERY_DIV: ";",
18
+ ALIAS_KEYWORD: "AS"
19
+ };
20
+ var Pos = CodeMirror.Pos;
21
+
22
+ function getKeywords(editor) {
23
+ var mode = editor.doc.modeOption;
24
+ if(mode === "sql") mode = "text/x-sql";
25
+ return CodeMirror.resolveMode(mode).keywords;
26
+ }
27
+
28
+ function match(string, word) {
29
+ var len = string.length;
30
+ var sub = word.substr(0, len);
31
+ return string.toUpperCase() === sub.toUpperCase();
32
+ }
33
+
34
+ function addMatches(result, search, wordlist, formatter) {
35
+ for(var word in wordlist) {
36
+ if(!wordlist.hasOwnProperty(word)) continue;
37
+ if(Array.isArray(wordlist)) {
38
+ word = wordlist[word];
39
+ }
40
+ if(match(search, word)) {
41
+ result.push(formatter(word));
42
+ }
43
+ }
44
+ }
45
+
46
+ function columnCompletion(result, editor) {
47
+ var cur = editor.getCursor();
48
+ var token = editor.getTokenAt(cur);
49
+ var string = token.string.substr(1);
50
+ var prevCur = Pos(cur.line, token.start);
51
+ var table = editor.getTokenAt(prevCur).string;
52
+ if( !tables.hasOwnProperty( table ) ){
53
+ table = findTableByAlias(table, editor);
54
+ }
55
+ var columns = tables[table];
56
+ if(!columns) {
57
+ return;
58
+ }
59
+ addMatches(result, string, columns,
60
+ function(w) {return "." + w;});
61
+ }
62
+
63
+ function eachWord(lineText, f) {
64
+ if( !lineText ){return;}
65
+ var excepted = /[,;]/g;
66
+ var words = lineText.split( " " );
67
+ for( var i = 0; i < words.length; i++ ){
68
+ f( words[i]?words[i].replace( excepted, '' ) : '' );
69
+ }
70
+ }
71
+
72
+ function convertCurToNumber( cur ){
73
+ // max characters of a line is 999,999.
74
+ return cur.line + cur.ch / Math.pow( 10, 6 );
75
+ }
76
+
77
+ function convertNumberToCur( num ){
78
+ return Pos(Math.floor( num ), +num.toString().split( '.' ).pop());
79
+ }
80
+
81
+ function findTableByAlias(alias, editor) {
82
+ var doc = editor.doc;
83
+ var fullQuery = doc.getValue();
84
+ var aliasUpperCase = alias.toUpperCase();
85
+ var previousWord = "";
86
+ var table = "";
87
+ var separator = [];
88
+ var validRange = {
89
+ start: Pos( 0, 0 ),
90
+ end: Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).length )
91
+ };
92
+
93
+ //add separator
94
+ var indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV );
95
+ while( indexOfSeparator != -1 ){
96
+ separator.push( doc.posFromIndex(indexOfSeparator));
97
+ indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV, indexOfSeparator+1);
98
+ }
99
+ separator.unshift( Pos( 0, 0 ) );
100
+ separator.push( Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).text.length ) );
101
+
102
+ //find valieRange
103
+ var prevItem = 0;
104
+ var current = convertCurToNumber( editor.getCursor() );
105
+ for( var i=0; i< separator.length; i++){
106
+ var _v = convertCurToNumber( separator[i] );
107
+ if( current > prevItem && current <= _v ){
108
+ validRange = { start: convertNumberToCur( prevItem ), end: convertNumberToCur( _v ) };
109
+ break;
110
+ }
111
+ prevItem = _v;
112
+ }
113
+
114
+ var query = doc.getRange(validRange.start, validRange.end, false);
115
+
116
+ for(var i=0; i < query.length; i++){
117
+ var lineText = query[i];
118
+ eachWord( lineText, function( word ){
119
+ var wordUpperCase = word.toUpperCase();
120
+ if( wordUpperCase === aliasUpperCase && tables.hasOwnProperty( previousWord ) ){
121
+ table = previousWord;
122
+ }
123
+ if( wordUpperCase !== CONS.ALIAS_KEYWORD ){
124
+ previousWord = word;
125
+ }
126
+ });
127
+ if( table ){ break; }
128
+ }
129
+ return table;
130
+ }
131
+
132
+ function sqlHint(editor, options) {
133
+ tables = (options && options.tables) || {};
134
+ keywords = keywords || getKeywords(editor);
135
+ var cur = editor.getCursor();
136
+ var token = editor.getTokenAt(cur), end = token.end;
137
+ var result = [];
138
+ var search = token.string.trim();
139
+
140
+ if (search.charAt(0) == ".") {
141
+ columnCompletion(result, editor);
142
+ if (!result.length) {
143
+ while (token.start && search.charAt(0) == ".") {
144
+ token = editor.getTokenAt(Pos(cur.line, token.start - 1));
145
+ search = token.string + search;
146
+ }
147
+ addMatches(result, search, tables,
148
+ function(w) {return w;});
149
+ }
150
+ } else {
151
+ addMatches(result, search, keywords,
152
+ function(w) {return w.toUpperCase();});
153
+ addMatches(result, search, tables,
154
+ function(w) {return w;});
155
+ }
156
+
157
+ return {
158
+ list: result,
159
+ from: Pos(cur.line, token.start),
160
+ to: Pos(cur.line, end)
161
+ };
162
+ }
163
+ CodeMirror.registerHelper("hint", "sql", sqlHint);
164
+ });
resources/js/codemirror/addon/hint/xml-hint.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var Pos = CodeMirror.Pos;
15
+
16
+ function getHints(cm, options) {
17
+ var tags = options && options.schemaInfo;
18
+ var quote = (options && options.quoteChar) || '"';
19
+ if (!tags) return;
20
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
21
+ var inner = CodeMirror.innerMode(cm.getMode(), token.state);
22
+ if (inner.mode.name != "xml") return;
23
+ var result = [], replaceToken = false, prefix;
24
+ var tag = /\btag\b/.test(token.type), tagName = tag && /^\w/.test(token.string), tagStart;
25
+ if (tagName) {
26
+ var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start);
27
+ var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null;
28
+ if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1);
29
+ } else if (tag && token.string == "<") {
30
+ tagType = "open";
31
+ } else if (tag && token.string == "</") {
32
+ tagType = "close";
33
+ }
34
+ if (!tag && !inner.state.tagName || tagType) {
35
+ if (tagName)
36
+ prefix = token.string;
37
+ replaceToken = tagType;
38
+ var cx = inner.state.context, curTag = cx && tags[cx.tagName];
39
+ var childList = cx ? curTag && curTag.children : tags["!top"];
40
+ if (childList && tagType != "close") {
41
+ for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
42
+ result.push("<" + childList[i]);
43
+ } else if (tagType != "close") {
44
+ for (var name in tags)
45
+ if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
46
+ result.push("<" + name);
47
+ }
48
+ if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0))
49
+ result.push("</" + cx.tagName + ">");
50
+ } else {
51
+ // Attribute completion
52
+ var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
53
+ var globalAttrs = tags["!attrs"];
54
+ if (!attrs && !globalAttrs) return;
55
+ if (!attrs) {
56
+ attrs = globalAttrs;
57
+ } else if (globalAttrs) { // Combine tag-local and global attributes
58
+ var set = {};
59
+ for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm];
60
+ for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm];
61
+ attrs = set;
62
+ }
63
+ if (token.type == "string" || token.string == "=") { // A value
64
+ var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),
65
+ Pos(cur.line, token.type == "string" ? token.start : token.end));
66
+ var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues;
67
+ if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;
68
+ if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget
69
+ if (token.type == "string") {
70
+ prefix = token.string;
71
+ if (/['"]/.test(token.string.charAt(0))) {
72
+ quote = token.string.charAt(0);
73
+ prefix = token.string.slice(1);
74
+ }
75
+ replaceToken = true;
76
+ }
77
+ for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)
78
+ result.push(quote + atValues[i] + quote);
79
+ } else { // An attribute name
80
+ if (token.type == "attribute") {
81
+ prefix = token.string;
82
+ replaceToken = true;
83
+ }
84
+ for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))
85
+ result.push(attr);
86
+ }
87
+ }
88
+ return {
89
+ list: result,
90
+ from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
91
+ to: replaceToken ? Pos(cur.line, token.end) : cur
92
+ };
93
+ }
94
+
95
+ CodeMirror.registerHelper("hint", "xml", getHints);
96
+ });
resources/js/codemirror/addon/lint/coffeescript-lint.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
5
+
6
+ // declare global: coffeelint
7
+
8
+ (function(mod) {
9
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
10
+ mod(require("../../lib/codemirror"));
11
+ else if (typeof define == "function" && define.amd) // AMD
12
+ define(["../../lib/codemirror"], mod);
13
+ else // Plain browser env
14
+ mod(CodeMirror);
15
+ })(function(CodeMirror) {
16
+ "use strict";
17
+
18
+ CodeMirror.registerHelper("lint", "coffeescript", function(text) {
19
+ var found = [];
20
+ var parseError = function(err) {
21
+ var loc = err.lineNumber;
22
+ found.push({from: CodeMirror.Pos(loc-1, 0),
23
+ to: CodeMirror.Pos(loc, 0),
24
+ severity: err.level,
25
+ message: err.message});
26
+ };
27
+ try {
28
+ var res = coffeelint.lint(text);
29
+ for(var i = 0; i < res.length; i++) {
30
+ parseError(res[i]);
31
+ }
32
+ } catch(e) {
33
+ found.push({from: CodeMirror.Pos(e.location.first_line, 0),
34
+ to: CodeMirror.Pos(e.location.last_line, e.location.last_column),
35
+ severity: 'error',
36
+ message: e.message});
37
+ }
38
+ return found;
39
+ });
40
+
41
+ });
resources/js/codemirror/addon/lint/css-lint.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Depends on csslint.js from https://github.com/stubbornella/csslint
5
+
6
+ // declare global: CSSLint
7
+
8
+ (function(mod) {
9
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
10
+ mod(require("../../lib/codemirror"));
11
+ else if (typeof define == "function" && define.amd) // AMD
12
+ define(["../../lib/codemirror"], mod);
13
+ else // Plain browser env
14
+ mod(CodeMirror);
15
+ })(function(CodeMirror) {
16
+ "use strict";
17
+
18
+ CodeMirror.registerHelper("lint", "css", function(text) {
19
+ var found = [];
20
+ if (!window.CSSLint) return found;
21
+ var results = CSSLint.verify(text), messages = results.messages, message = null;
22
+ for ( var i = 0; i < messages.length; i++) {
23
+ message = messages[i];
24
+ var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
25
+ found.push({
26
+ from: CodeMirror.Pos(startLine, startCol),
27
+ to: CodeMirror.Pos(endLine, endCol),
28
+ message: message.message,
29
+ severity : message.type
30
+ });
31
+ }
32
+ return found;
33
+ });
34
+
35
+ });
resources/js/codemirror/addon/lint/javascript-lint.js ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+ // declare global: JSHINT
14
+
15
+ var bogus = [ "Dangerous comment" ];
16
+
17
+ var warnings = [ [ "Expected '{'",
18
+ "Statement body should be inside '{ }' braces." ] ];
19
+
20
+ var errors = [ "Missing semicolon", "Extra comma", "Missing property name",
21
+ "Unmatched ", " and instead saw", " is not defined",
22
+ "Unclosed string", "Stopping, unable to continue" ];
23
+
24
+ function validator(text, options) {
25
+ if (!window.JSHINT) return [];
26
+ JSHINT(text, options);
27
+ var errors = JSHINT.data().errors, result = [];
28
+ if (errors) parseErrors(errors, result);
29
+ return result;
30
+ }
31
+
32
+ CodeMirror.registerHelper("lint", "javascript", validator);
33
+
34
+ function cleanup(error) {
35
+ // All problems are warnings by default
36
+ fixWith(error, warnings, "warning", true);
37
+ fixWith(error, errors, "error");
38
+
39
+ return isBogus(error) ? null : error;
40
+ }
41
+
42
+ function fixWith(error, fixes, severity, force) {
43
+ var description, fix, find, replace, found;
44
+
45
+ description = error.description;
46
+
47
+ for ( var i = 0; i < fixes.length; i++) {
48
+ fix = fixes[i];
49
+ find = (typeof fix === "string" ? fix : fix[0]);
50
+ replace = (typeof fix === "string" ? null : fix[1]);
51
+ found = description.indexOf(find) !== -1;
52
+
53
+ if (force || found) {
54
+ error.severity = severity;
55
+ }
56
+ if (found && replace) {
57
+ error.description = replace;
58
+ }
59
+ }
60
+ }
61
+
62
+ function isBogus(error) {
63
+ var description = error.description;
64
+ for ( var i = 0; i < bogus.length; i++) {
65
+ if (description.indexOf(bogus[i]) !== -1) {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+
72
+ function parseErrors(errors, output) {
73
+ for ( var i = 0; i < errors.length; i++) {
74
+ var error = errors[i];
75
+ if (error) {
76
+ var linetabpositions, index;
77
+
78
+ linetabpositions = [];
79
+
80
+ // This next block is to fix a problem in jshint. Jshint
81
+ // replaces
82
+ // all tabs with spaces then performs some checks. The error
83
+ // positions (character/space) are then reported incorrectly,
84
+ // not taking the replacement step into account. Here we look
85
+ // at the evidence line and try to adjust the character position
86
+ // to the correct value.
87
+ if (error.evidence) {
88
+ // Tab positions are computed once per line and cached
89
+ var tabpositions = linetabpositions[error.line];
90
+ if (!tabpositions) {
91
+ var evidence = error.evidence;
92
+ tabpositions = [];
93
+ // ugggh phantomjs does not like this
94
+ // forEachChar(evidence, function(item, index) {
95
+ Array.prototype.forEach.call(evidence, function(item,
96
+ index) {
97
+ if (item === '\t') {
98
+ // First col is 1 (not 0) to match error
99
+ // positions
100
+ tabpositions.push(index + 1);
101
+ }
102
+ });
103
+ linetabpositions[error.line] = tabpositions;
104
+ }
105
+ if (tabpositions.length > 0) {
106
+ var pos = error.character;
107
+ tabpositions.forEach(function(tabposition) {
108
+ if (pos > tabposition) pos -= 1;
109
+ });
110
+ error.character = pos;
111
+ }
112
+ }
113
+
114
+ var start = error.character - 1, end = start + 1;
115
+ if (error.evidence) {
116
+ index = error.evidence.substring(start).search(/.\b/);
117
+ if (index > -1) {
118
+ end += index;
119
+ }
120
+ }
121
+
122
+ // Convert to format expected by validation service
123
+ error.description = error.reason;// + "(jshint)";
124
+ error.start = error.character;
125
+ error.end = end;
126
+ error = cleanup(error);
127
+
128
+ if (error)
129
+ output.push({message: error.description,
130
+ severity: error.severity,
131
+ from: CodeMirror.Pos(error.line - 1, start),
132
+ to: CodeMirror.Pos(error.line - 1, end)});
133
+ }
134
+ }
135
+ }
136
+ });
resources/js/codemirror/addon/lint/json-lint.js ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Depends on jsonlint.js from https://github.com/zaach/jsonlint
5
+
6
+ // declare global: jsonlint
7
+
8
+ (function(mod) {
9
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
10
+ mod(require("../../lib/codemirror"));
11
+ else if (typeof define == "function" && define.amd) // AMD
12
+ define(["../../lib/codemirror"], mod);
13
+ else // Plain browser env
14
+ mod(CodeMirror);
15
+ })(function(CodeMirror) {
16
+ "use strict";
17
+
18
+ CodeMirror.registerHelper("lint", "json", function(text) {
19
+ var found = [];
20
+ jsonlint.parseError = function(str, hash) {
21
+ var loc = hash.loc;
22
+ found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
23
+ to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
24
+ message: str});
25
+ };
26
+ try { jsonlint.parse(text); }
27
+ catch(e) {}
28
+ return found;
29
+ });
30
+
31
+ });
resources/js/codemirror/addon/lint/lint.css ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* The lint marker gutter */
2
+ .CodeMirror-lint-markers {
3
+ width: 16px;
4
+ }
5
+
6
+ .CodeMirror-lint-tooltip {
7
+ background-color: infobackground;
8
+ border: 1px solid black;
9
+ border-radius: 4px 4px 4px 4px;
10
+ color: infotext;
11
+ font-family: monospace;
12
+ font-size: 10pt;
13
+ overflow: hidden;
14
+ padding: 2px 5px;
15
+ position: fixed;
16
+ white-space: pre;
17
+ white-space: pre-wrap;
18
+ z-index: 100;
19
+ max-width: 600px;
20
+ opacity: 0;
21
+ transition: opacity .4s;
22
+ -moz-transition: opacity .4s;
23
+ -webkit-transition: opacity .4s;
24
+ -o-transition: opacity .4s;
25
+ -ms-transition: opacity .4s;
26
+ }
27
+
28
+ .CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
29
+ background-position: left bottom;
30
+ background-repeat: repeat-x;
31
+ }
32
+
33
+ .CodeMirror-lint-mark-error {
34
+ background-image:
35
+ url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
36
+ ;
37
+ }
38
+
39
+ .CodeMirror-lint-mark-warning {
40
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
41
+ }
42
+
43
+ .CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
44
+ background-position: center center;
45
+ background-repeat: no-repeat;
46
+ cursor: pointer;
47
+ display: inline-block;
48
+ height: 16px;
49
+ width: 16px;
50
+ vertical-align: middle;
51
+ position: relative;
52
+ }
53
+
54
+ .CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
55
+ padding-left: 18px;
56
+ background-position: top left;
57
+ background-repeat: no-repeat;
58
+ }
59
+
60
+ .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
61
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
62
+ }
63
+
64
+ .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
65
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
66
+ }
67
+
68
+ .CodeMirror-lint-marker-multiple {
69
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
70
+ background-repeat: no-repeat;
71
+ background-position: right bottom;
72
+ width: 100%; height: 100%;
73
+ }
resources/js/codemirror/addon/lint/lint.js ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+ var GUTTER_ID = "CodeMirror-lint-markers";
14
+ var SEVERITIES = /^(?:error|warning)$/;
15
+
16
+ function showTooltip(e, content) {
17
+ var tt = document.createElement("div");
18
+ tt.className = "CodeMirror-lint-tooltip";
19
+ tt.appendChild(content.cloneNode(true));
20
+ document.body.appendChild(tt);
21
+
22
+ function position(e) {
23
+ if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
24
+ tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
25
+ tt.style.left = (e.clientX + 5) + "px";
26
+ }
27
+ CodeMirror.on(document, "mousemove", position);
28
+ position(e);
29
+ if (tt.style.opacity != null) tt.style.opacity = 1;
30
+ return tt;
31
+ }
32
+ function rm(elt) {
33
+ if (elt.parentNode) elt.parentNode.removeChild(elt);
34
+ }
35
+ function hideTooltip(tt) {
36
+ if (!tt.parentNode) return;
37
+ if (tt.style.opacity == null) rm(tt);
38
+ tt.style.opacity = 0;
39
+ setTimeout(function() { rm(tt); }, 600);
40
+ }
41
+
42
+ function showTooltipFor(e, content, node) {
43
+ var tooltip = showTooltip(e, content);
44
+ function hide() {
45
+ CodeMirror.off(node, "mouseout", hide);
46
+ if (tooltip) { hideTooltip(tooltip); tooltip = null; }
47
+ }
48
+ var poll = setInterval(function() {
49
+ if (tooltip) for (var n = node;; n = n.parentNode) {
50
+ if (n == document.body) return;
51
+ if (!n) { hide(); break; }
52
+ }
53
+ if (!tooltip) return clearInterval(poll);
54
+ }, 400);
55
+ CodeMirror.on(node, "mouseout", hide);
56
+ }
57
+
58
+ function LintState(cm, options, hasGutter) {
59
+ this.marked = [];
60
+ this.options = options;
61
+ this.timeout = null;
62
+ this.hasGutter = hasGutter;
63
+ this.onMouseOver = function(e) { onMouseOver(cm, e); };
64
+ }
65
+
66
+ function parseOptions(cm, options) {
67
+ if (options instanceof Function) return {getAnnotations: options};
68
+ if (!options || options === true) options = {};
69
+ if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
70
+ if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
71
+ return options;
72
+ }
73
+
74
+ function clearMarks(cm) {
75
+ var state = cm.state.lint;
76
+ if (state.hasGutter) cm.clearGutter(GUTTER_ID);
77
+ for (var i = 0; i < state.marked.length; ++i)
78
+ state.marked[i].clear();
79
+ state.marked.length = 0;
80
+ }
81
+
82
+ function makeMarker(labels, severity, multiple, tooltips) {
83
+ var marker = document.createElement("div"), inner = marker;
84
+ marker.className = "CodeMirror-lint-marker-" + severity;
85
+ if (multiple) {
86
+ inner = marker.appendChild(document.createElement("div"));
87
+ inner.className = "CodeMirror-lint-marker-multiple";
88
+ }
89
+
90
+ if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
91
+ showTooltipFor(e, labels, inner);
92
+ });
93
+
94
+ return marker;
95
+ }
96
+
97
+ function getMaxSeverity(a, b) {
98
+ if (a == "error") return a;
99
+ else return b;
100
+ }
101
+
102
+ function groupByLine(annotations) {
103
+ var lines = [];
104
+ for (var i = 0; i < annotations.length; ++i) {
105
+ var ann = annotations[i], line = ann.from.line;
106
+ (lines[line] || (lines[line] = [])).push(ann);
107
+ }
108
+ return lines;
109
+ }
110
+
111
+ function annotationTooltip(ann) {
112
+ var severity = ann.severity;
113
+ if (!SEVERITIES.test(severity)) severity = "error";
114
+ var tip = document.createElement("div");
115
+ tip.className = "CodeMirror-lint-message-" + severity;
116
+ tip.appendChild(document.createTextNode(ann.message));
117
+ return tip;
118
+ }
119
+
120
+ function startLinting(cm) {
121
+ var state = cm.state.lint, options = state.options;
122
+ if (options.async)
123
+ options.getAnnotations(cm, updateLinting, options);
124
+ else
125
+ updateLinting(cm, options.getAnnotations(cm.getValue(), options.options));
126
+ }
127
+
128
+ function updateLinting(cm, annotationsNotSorted) {
129
+ clearMarks(cm);
130
+ var state = cm.state.lint, options = state.options;
131
+
132
+ var annotations = groupByLine(annotationsNotSorted);
133
+
134
+ for (var line = 0; line < annotations.length; ++line) {
135
+ var anns = annotations[line];
136
+ if (!anns) continue;
137
+
138
+ var maxSeverity = null;
139
+ var tipLabel = state.hasGutter && document.createDocumentFragment();
140
+
141
+ for (var i = 0; i < anns.length; ++i) {
142
+ var ann = anns[i];
143
+ var severity = ann.severity;
144
+ if (!SEVERITIES.test(severity)) severity = "error";
145
+ maxSeverity = getMaxSeverity(maxSeverity, severity);
146
+
147
+ if (options.formatAnnotation) ann = options.formatAnnotation(ann);
148
+ if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
149
+
150
+ if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
151
+ className: "CodeMirror-lint-mark-" + severity,
152
+ __annotation: ann
153
+ }));
154
+ }
155
+
156
+ if (state.hasGutter)
157
+ cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
158
+ state.options.tooltips));
159
+ }
160
+ if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
161
+ }
162
+
163
+ function onChange(cm) {
164
+ var state = cm.state.lint;
165
+ clearTimeout(state.timeout);
166
+ state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
167
+ }
168
+
169
+ function popupSpanTooltip(ann, e) {
170
+ var target = e.target || e.srcElement;
171
+ showTooltipFor(e, annotationTooltip(ann), target);
172
+ }
173
+
174
+ // When the mouseover fires, the cursor might not actually be over
175
+ // the character itself yet. These pairs of x,y offsets are used to
176
+ // probe a few nearby points when no suitable marked range is found.
177
+ var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];
178
+
179
+ function onMouseOver(cm, e) {
180
+ if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
181
+ for (var i = 0; i < nearby.length; i += 2) {
182
+ var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
183
+ top: e.clientY + nearby[i + 1]}, "client"));
184
+ for (var j = 0; j < spans.length; ++j) {
185
+ var span = spans[j], ann = span.__annotation;
186
+ if (ann) return popupSpanTooltip(ann, e);
187
+ }
188
+ }
189
+ }
190
+
191
+ CodeMirror.defineOption("lint", false, function(cm, val, old) {
192
+ if (old && old != CodeMirror.Init) {
193
+ clearMarks(cm);
194
+ cm.off("change", onChange);
195
+ CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
196
+ delete cm.state.lint;
197
+ }
198
+
199
+ if (val) {
200
+ var gutters = cm.getOption("gutters"), hasLintGutter = false;
201
+ for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
202
+ var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
203
+ cm.on("change", onChange);
204
+ if (state.options.tooltips != false)
205
+ CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
206
+
207
+ startLinting(cm);
208
+ }
209
+ });
210
+ });
resources/js/codemirror/addon/lint/yaml-lint.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ // Depends on js-yaml.js from https://github.com/nodeca/js-yaml
15
+
16
+ // declare global: jsyaml
17
+
18
+ CodeMirror.registerHelper("lint", "yaml", function(text) {
19
+ var found = [];
20
+ try { jsyaml.load(text); }
21
+ catch(e) {
22
+ var loc = e.mark;
23
+ found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });
24
+ }
25
+ return found;
26
+ });
27
+
28
+ });
resources/js/codemirror/addon/merge/merge.css ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-merge {
2
+ position: relative;
3
+ border: 1px solid #ddd;
4
+ white-space: pre;
5
+ }
6
+
7
+ .CodeMirror-merge, .CodeMirror-merge .CodeMirror {
8
+ height: 350px;
9
+ }
10
+
11
+ .CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }
12
+ .CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }
13
+ .CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
14
+ .CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
15
+
16
+ .CodeMirror-merge-pane {
17
+ display: inline-block;
18
+ white-space: normal;
19
+ vertical-align: top;
20
+ }
21
+ .CodeMirror-merge-pane-rightmost {
22
+ position: absolute;
23
+ right: 0px;
24
+ z-index: 1;
25
+ }
26
+
27
+ .CodeMirror-merge-gap {
28
+ z-index: 2;
29
+ display: inline-block;
30
+ height: 100%;
31
+ -moz-box-sizing: border-box;
32
+ box-sizing: border-box;
33
+ overflow: hidden;
34
+ border-left: 1px solid #ddd;
35
+ border-right: 1px solid #ddd;
36
+ position: relative;
37
+ background: #f8f8f8;
38
+ }
39
+
40
+ .CodeMirror-merge-scrolllock-wrap {
41
+ position: absolute;
42
+ bottom: 0; left: 50%;
43
+ }
44
+ .CodeMirror-merge-scrolllock {
45
+ position: relative;
46
+ left: -50%;
47
+ cursor: pointer;
48
+ color: #555;
49
+ line-height: 1;
50
+ }
51
+
52
+ .CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
53
+ position: absolute;
54
+ left: 0; top: 0;
55
+ right: 0; bottom: 0;
56
+ line-height: 1;
57
+ }
58
+
59
+ .CodeMirror-merge-copy {
60
+ position: absolute;
61
+ cursor: pointer;
62
+ color: #44c;
63
+ }
64
+
65
+ .CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
66
+ .CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
67
+
68
+ .CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
69
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
70
+ background-position: bottom left;
71
+ background-repeat: repeat-x;
72
+ }
73
+
74
+ .CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
75
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
76
+ background-position: bottom left;
77
+ background-repeat: repeat-x;
78
+ }
79
+
80
+ .CodeMirror-merge-r-chunk { background: #ffffe0; }
81
+ .CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }
82
+ .CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }
83
+ .CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }
84
+
85
+ .CodeMirror-merge-l-chunk { background: #eef; }
86
+ .CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
87
+ .CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
88
+ .CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
89
+
90
+ .CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
91
+ .CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
92
+ .CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
resources/js/codemirror/addon/merge/merge.js ADDED
@@ -0,0 +1,513 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+ // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL
14
+
15
+ var Pos = CodeMirror.Pos;
16
+ var svgNS = "http://www.w3.org/2000/svg";
17
+
18
+ function DiffView(mv, type) {
19
+ this.mv = mv;
20
+ this.type = type;
21
+ this.classes = type == "left"
22
+ ? {chunk: "CodeMirror-merge-l-chunk",
23
+ start: "CodeMirror-merge-l-chunk-start",
24
+ end: "CodeMirror-merge-l-chunk-end",
25
+ insert: "CodeMirror-merge-l-inserted",
26
+ del: "CodeMirror-merge-l-deleted",
27
+ connect: "CodeMirror-merge-l-connect"}
28
+ : {chunk: "CodeMirror-merge-r-chunk",
29
+ start: "CodeMirror-merge-r-chunk-start",
30
+ end: "CodeMirror-merge-r-chunk-end",
31
+ insert: "CodeMirror-merge-r-inserted",
32
+ del: "CodeMirror-merge-r-deleted",
33
+ connect: "CodeMirror-merge-r-connect"};
34
+ }
35
+
36
+ DiffView.prototype = {
37
+ constructor: DiffView,
38
+ init: function(pane, orig, options) {
39
+ this.edit = this.mv.edit;
40
+ this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options)));
41
+
42
+ this.diff = getDiff(asString(orig), asString(options.value));
43
+ this.diffOutOfDate = false;
44
+
45
+ this.showDifferences = options.showDifferences !== false;
46
+ this.forceUpdate = registerUpdate(this);
47
+ setScrollLock(this, true, false);
48
+ registerScroll(this);
49
+ },
50
+ setShowDifferences: function(val) {
51
+ val = val !== false;
52
+ if (val != this.showDifferences) {
53
+ this.showDifferences = val;
54
+ this.forceUpdate("full");
55
+ }
56
+ }
57
+ };
58
+
59
+ function ensureDiff(dv) {
60
+ if (dv.diffOutOfDate) {
61
+ dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue());
62
+ dv.diffOutOfDate = false;
63
+ CodeMirror.signal(dv.edit, "updateDiff", dv.diff);
64
+ }
65
+ }
66
+
67
+ function registerUpdate(dv) {
68
+ var edit = {from: 0, to: 0, marked: []};
69
+ var orig = {from: 0, to: 0, marked: []};
70
+ var debounceChange;
71
+ function update(mode) {
72
+ if (mode == "full") {
73
+ if (dv.svg) clear(dv.svg);
74
+ clear(dv.copyButtons);
75
+ clearMarks(dv.edit, edit.marked, dv.classes);
76
+ clearMarks(dv.orig, orig.marked, dv.classes);
77
+ edit.from = edit.to = orig.from = orig.to = 0;
78
+ }
79
+ ensureDiff(dv);
80
+ if (dv.showDifferences) {
81
+ updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
82
+ updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
83
+ }
84
+ drawConnectors(dv);
85
+ }
86
+ function set(slow) {
87
+ clearTimeout(debounceChange);
88
+ debounceChange = setTimeout(update, slow == true ? 250 : 100);
89
+ }
90
+ function change() {
91
+ if (!dv.diffOutOfDate) {
92
+ dv.diffOutOfDate = true;
93
+ edit.from = edit.to = orig.from = orig.to = 0;
94
+ }
95
+ set(true);
96
+ }
97
+ dv.edit.on("change", change);
98
+ dv.orig.on("change", change);
99
+ dv.edit.on("markerAdded", set);
100
+ dv.edit.on("markerCleared", set);
101
+ dv.orig.on("markerAdded", set);
102
+ dv.orig.on("markerCleared", set);
103
+ dv.edit.on("viewportChange", set);
104
+ dv.orig.on("viewportChange", set);
105
+ update();
106
+ return update;
107
+ }
108
+
109
+ function registerScroll(dv) {
110
+ dv.edit.on("scroll", function() {
111
+ syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
112
+ });
113
+ dv.orig.on("scroll", function() {
114
+ syncScroll(dv, DIFF_DELETE) && drawConnectors(dv);
115
+ });
116
+ }
117
+
118
+ function syncScroll(dv, type) {
119
+ // Change handler will do a refresh after a timeout when diff is out of date
120
+ if (dv.diffOutOfDate) return false;
121
+ if (!dv.lockScroll) return true;
122
+ var editor, other, now = +new Date;
123
+ if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; }
124
+ else { editor = dv.orig; other = dv.edit; }
125
+ // Don't take action if the position of this editor was recently set
126
+ // (to prevent feedback loops)
127
+ if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;
128
+
129
+ var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
130
+ var mid = editor.lineAtHeight(midY, "local");
131
+ var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
132
+ var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
133
+ var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit);
134
+ var ratio = (midY - off.top) / (off.bot - off.top);
135
+ var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top);
136
+
137
+ var botDist, mix;
138
+ // Some careful tweaking to make sure no space is left out of view
139
+ // when scrolling to top or bottom.
140
+ if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) {
141
+ targetPos = targetPos * mix + sInfo.top * (1 - mix);
142
+ } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) {
143
+ var otherInfo = other.getScrollInfo();
144
+ var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos;
145
+ if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
146
+ targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
147
+ }
148
+
149
+ other.scrollTo(sInfo.left, targetPos);
150
+ other.state.scrollSetAt = now;
151
+ other.state.scrollSetBy = dv;
152
+ return true;
153
+ }
154
+
155
+ function getOffsets(editor, around) {
156
+ var bot = around.after;
157
+ if (bot == null) bot = editor.lastLine() + 1;
158
+ return {top: editor.heightAtLine(around.before || 0, "local"),
159
+ bot: editor.heightAtLine(bot, "local")};
160
+ }
161
+
162
+ function setScrollLock(dv, val, action) {
163
+ dv.lockScroll = val;
164
+ if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
165
+ dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db&nbsp;&nbsp;\u21da";
166
+ }
167
+
168
+ // Updating the marks for editor content
169
+
170
+ function clearMarks(editor, arr, classes) {
171
+ for (var i = 0; i < arr.length; ++i) {
172
+ var mark = arr[i];
173
+ if (mark instanceof CodeMirror.TextMarker) {
174
+ mark.clear();
175
+ } else if (mark.parent) {
176
+ editor.removeLineClass(mark, "background", classes.chunk);
177
+ editor.removeLineClass(mark, "background", classes.start);
178
+ editor.removeLineClass(mark, "background", classes.end);
179
+ }
180
+ }
181
+ arr.length = 0;
182
+ }
183
+
184
+ // FIXME maybe add a margin around viewport to prevent too many updates
185
+ function updateMarks(editor, diff, state, type, classes) {
186
+ var vp = editor.getViewport();
187
+ editor.operation(function() {
188
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
189
+ clearMarks(editor, state.marked, classes);
190
+ markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes);
191
+ state.from = vp.from; state.to = vp.to;
192
+ } else {
193
+ if (vp.from < state.from) {
194
+ markChanges(editor, diff, type, state.marked, vp.from, state.from, classes);
195
+ state.from = vp.from;
196
+ }
197
+ if (vp.to > state.to) {
198
+ markChanges(editor, diff, type, state.marked, state.to, vp.to, classes);
199
+ state.to = vp.to;
200
+ }
201
+ }
202
+ });
203
+ }
204
+
205
+ function markChanges(editor, diff, type, marks, from, to, classes) {
206
+ var pos = Pos(0, 0);
207
+ var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1));
208
+ var cls = type == DIFF_DELETE ? classes.del : classes.insert;
209
+ function markChunk(start, end) {
210
+ var bfrom = Math.max(from, start), bto = Math.min(to, end);
211
+ for (var i = bfrom; i < bto; ++i) {
212
+ var line = editor.addLineClass(i, "background", classes.chunk);
213
+ if (i == start) editor.addLineClass(line, "background", classes.start);
214
+ if (i == end - 1) editor.addLineClass(line, "background", classes.end);
215
+ marks.push(line);
216
+ }
217
+ // When the chunk is empty, make sure a horizontal line shows up
218
+ if (start == end && bfrom == end && bto == end) {
219
+ if (bfrom)
220
+ marks.push(editor.addLineClass(bfrom - 1, "background", classes.end));
221
+ else
222
+ marks.push(editor.addLineClass(bfrom, "background", classes.start));
223
+ }
224
+ }
225
+
226
+ var chunkStart = 0;
227
+ for (var i = 0; i < diff.length; ++i) {
228
+ var part = diff[i], tp = part[0], str = part[1];
229
+ if (tp == DIFF_EQUAL) {
230
+ var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1);
231
+ moveOver(pos, str);
232
+ var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0);
233
+ if (cleanTo > cleanFrom) {
234
+ if (i) markChunk(chunkStart, cleanFrom);
235
+ chunkStart = cleanTo;
236
+ }
237
+ } else {
238
+ if (tp == type) {
239
+ var end = moveOver(pos, str, true);
240
+ var a = posMax(top, pos), b = posMin(bot, end);
241
+ if (!posEq(a, b))
242
+ marks.push(editor.markText(a, b, {className: cls}));
243
+ pos = end;
244
+ }
245
+ }
246
+ }
247
+ if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1);
248
+ }
249
+
250
+ // Updating the gap between editor and original
251
+
252
+ function drawConnectors(dv) {
253
+ if (!dv.showDifferences) return;
254
+
255
+ if (dv.svg) {
256
+ clear(dv.svg);
257
+ var w = dv.gap.offsetWidth;
258
+ attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
259
+ }
260
+ clear(dv.copyButtons);
261
+
262
+ var flip = dv.type == "left";
263
+ var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
264
+ var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
265
+ iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
266
+ if (topEdit > vpEdit.to || botEdit < vpEdit.from ||
267
+ topOrig > vpOrig.to || botOrig < vpOrig.from)
268
+ return;
269
+ var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx;
270
+ if (dv.svg) {
271
+ var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
272
+ if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
273
+ var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
274
+ var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
275
+ if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
276
+ var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
277
+ var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
278
+ attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
279
+ "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
280
+ "class", dv.classes.connect);
281
+ }
282
+ var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
283
+ "CodeMirror-merge-copy"));
284
+ copy.title = "Revert chunk";
285
+ copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
286
+ copy.style.top = top + "px";
287
+ });
288
+ }
289
+
290
+ function copyChunk(dv, chunk) {
291
+ if (dv.diffOutOfDate) return;
292
+ dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
293
+ Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0));
294
+ }
295
+
296
+ // Merge view, containing 0, 1, or 2 diff views.
297
+
298
+ var MergeView = CodeMirror.MergeView = function(node, options) {
299
+ if (!(this instanceof MergeView)) return new MergeView(node, options);
300
+
301
+ var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
302
+ var hasLeft = origLeft != null, hasRight = origRight != null;
303
+ var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
304
+ var wrap = [], left = this.left = null, right = this.right = null;
305
+
306
+ if (hasLeft) {
307
+ left = this.left = new DiffView(this, "left");
308
+ var leftPane = elt("div", null, "CodeMirror-merge-pane");
309
+ wrap.push(leftPane);
310
+ wrap.push(buildGap(left));
311
+ }
312
+
313
+ var editPane = elt("div", null, "CodeMirror-merge-pane");
314
+ wrap.push(editPane);
315
+
316
+ if (hasRight) {
317
+ right = this.right = new DiffView(this, "right");
318
+ wrap.push(buildGap(right));
319
+ var rightPane = elt("div", null, "CodeMirror-merge-pane");
320
+ wrap.push(rightPane);
321
+ }
322
+
323
+ (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost";
324
+
325
+ wrap.push(elt("div", null, null, "height: 0; clear: both;"));
326
+ var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane"));
327
+ this.edit = CodeMirror(editPane, copyObj(options));
328
+
329
+ if (left) left.init(leftPane, origLeft, options);
330
+ if (right) right.init(rightPane, origRight, options);
331
+
332
+ var onResize = function() {
333
+ if (left) drawConnectors(left);
334
+ if (right) drawConnectors(right);
335
+ };
336
+ CodeMirror.on(window, "resize", onResize);
337
+ var resizeInterval = setInterval(function() {
338
+ for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {}
339
+ if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); }
340
+ }, 5000);
341
+ };
342
+
343
+ function buildGap(dv) {
344
+ var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock");
345
+ lock.title = "Toggle locked scrolling";
346
+ var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap");
347
+ CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); });
348
+ dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type);
349
+ CodeMirror.on(dv.copyButtons, "click", function(e) {
350
+ var node = e.target || e.srcElement;
351
+ if (node.chunk) copyChunk(dv, node.chunk);
352
+ });
353
+ var gapElts = [dv.copyButtons, lockWrap];
354
+ var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
355
+ if (svg && !svg.createSVGRect) svg = null;
356
+ dv.svg = svg;
357
+ if (svg) gapElts.push(svg);
358
+
359
+ return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
360
+ }
361
+
362
+ MergeView.prototype = {
363
+ constuctor: MergeView,
364
+ editor: function() { return this.edit; },
365
+ rightOriginal: function() { return this.right && this.right.orig; },
366
+ leftOriginal: function() { return this.left && this.left.orig; },
367
+ setShowDifferences: function(val) {
368
+ if (this.right) this.right.setShowDifferences(val);
369
+ if (this.left) this.left.setShowDifferences(val);
370
+ },
371
+ rightChunks: function() {
372
+ return this.right && getChunks(this.right);
373
+ },
374
+ leftChunks: function() {
375
+ return this.left && getChunks(this.left);
376
+ }
377
+ };
378
+
379
+ function asString(obj) {
380
+ if (typeof obj == "string") return obj;
381
+ else return obj.getValue();
382
+ }
383
+
384
+ // Operations on diffs
385
+
386
+ var dmp = new diff_match_patch();
387
+ function getDiff(a, b) {
388
+ var diff = dmp.diff_main(a, b);
389
+ dmp.diff_cleanupSemantic(diff);
390
+ // The library sometimes leaves in empty parts, which confuse the algorithm
391
+ for (var i = 0; i < diff.length; ++i) {
392
+ var part = diff[i];
393
+ if (!part[1]) {
394
+ diff.splice(i--, 1);
395
+ } else if (i && diff[i - 1][0] == part[0]) {
396
+ diff.splice(i--, 1);
397
+ diff[i][1] += part[1];
398
+ }
399
+ }
400
+ return diff;
401
+ }
402
+
403
+ function iterateChunks(diff, f) {
404
+ var startEdit = 0, startOrig = 0;
405
+ var edit = Pos(0, 0), orig = Pos(0, 0);
406
+ for (var i = 0; i < diff.length; ++i) {
407
+ var part = diff[i], tp = part[0];
408
+ if (tp == DIFF_EQUAL) {
409
+ var startOff = startOfLineClean(diff, i) ? 0 : 1;
410
+ var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff;
411
+ moveOver(edit, part[1], null, orig);
412
+ var endOff = endOfLineClean(diff, i) ? 1 : 0;
413
+ var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff;
414
+ if (cleanToEdit > cleanFromEdit) {
415
+ if (i) f(startOrig, cleanFromOrig, startEdit, cleanFromEdit);
416
+ startEdit = cleanToEdit; startOrig = cleanToOrig;
417
+ }
418
+ } else {
419
+ moveOver(tp == DIFF_INSERT ? edit : orig, part[1]);
420
+ }
421
+ }
422
+ if (startEdit <= edit.line || startOrig <= orig.line)
423
+ f(startOrig, orig.line + 1, startEdit, edit.line + 1);
424
+ }
425
+
426
+ function getChunks(dv) {
427
+ ensureDiff(dv);
428
+ var collect = [];
429
+ iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
430
+ collect.push({origFrom: topOrig, origTo: botOrig,
431
+ editFrom: topEdit, editTo: botEdit});
432
+ });
433
+ return collect;
434
+ }
435
+
436
+ function endOfLineClean(diff, i) {
437
+ if (i == diff.length - 1) return true;
438
+ var next = diff[i + 1][1];
439
+ if (next.length == 1 || next.charCodeAt(0) != 10) return false;
440
+ if (i == diff.length - 2) return true;
441
+ next = diff[i + 2][1];
442
+ return next.length > 1 && next.charCodeAt(0) == 10;
443
+ }
444
+
445
+ function startOfLineClean(diff, i) {
446
+ if (i == 0) return true;
447
+ var last = diff[i - 1][1];
448
+ if (last.charCodeAt(last.length - 1) != 10) return false;
449
+ if (i == 1) return true;
450
+ last = diff[i - 2][1];
451
+ return last.charCodeAt(last.length - 1) == 10;
452
+ }
453
+
454
+ function chunkBoundariesAround(diff, n, nInEdit) {
455
+ var beforeE, afterE, beforeO, afterO;
456
+ iterateChunks(diff, function(fromOrig, toOrig, fromEdit, toEdit) {
457
+ var fromLocal = nInEdit ? fromEdit : fromOrig;
458
+ var toLocal = nInEdit ? toEdit : toOrig;
459
+ if (afterE == null) {
460
+ if (fromLocal > n) { afterE = fromEdit; afterO = fromOrig; }
461
+ else if (toLocal > n) { afterE = toEdit; afterO = toOrig; }
462
+ }
463
+ if (toLocal <= n) { beforeE = toEdit; beforeO = toOrig; }
464
+ else if (fromLocal <= n) { beforeE = fromEdit; beforeO = fromOrig; }
465
+ });
466
+ return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
467
+ }
468
+
469
+ // General utilities
470
+
471
+ function elt(tag, content, className, style) {
472
+ var e = document.createElement(tag);
473
+ if (className) e.className = className;
474
+ if (style) e.style.cssText = style;
475
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
476
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
477
+ return e;
478
+ }
479
+
480
+ function clear(node) {
481
+ for (var count = node.childNodes.length; count > 0; --count)
482
+ node.removeChild(node.firstChild);
483
+ }
484
+
485
+ function attrs(elt) {
486
+ for (var i = 1; i < arguments.length; i += 2)
487
+ elt.setAttribute(arguments[i], arguments[i+1]);
488
+ }
489
+
490
+ function copyObj(obj, target) {
491
+ if (!target) target = {};
492
+ for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
493
+ return target;
494
+ }
495
+
496
+ function moveOver(pos, str, copy, other) {
497
+ var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0;
498
+ for (;;) {
499
+ var nl = str.indexOf("\n", at);
500
+ if (nl == -1) break;
501
+ ++out.line;
502
+ if (other) ++other.line;
503
+ at = nl + 1;
504
+ }
505
+ out.ch = (at ? 0 : out.ch) + (str.length - at);
506
+ if (other) other.ch = (at ? 0 : other.ch) + (str.length - at);
507
+ return out;
508
+ }
509
+
510
+ function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; }
511
+ function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; }
512
+ function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
513
+ });
resources/js/codemirror/addon/mode/loadmode.js ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
13
+
14
+ var loading = {};
15
+ function splitCallback(cont, n) {
16
+ var countDown = n;
17
+ return function() { if (--countDown == 0) cont(); };
18
+ }
19
+ function ensureDeps(mode, cont) {
20
+ var deps = CodeMirror.modes[mode].dependencies;
21
+ if (!deps) return cont();
22
+ var missing = [];
23
+ for (var i = 0; i < deps.length; ++i) {
24
+ if (!CodeMirror.modes.hasOwnProperty(deps[i]))
25
+ missing.push(deps[i]);
26
+ }
27
+ if (!missing.length) return cont();
28
+ var split = splitCallback(cont, missing.length);
29
+ for (var i = 0; i < missing.length; ++i)
30
+ CodeMirror.requireMode(missing[i], split);
31
+ }
32
+
33
+ CodeMirror.requireMode = function(mode, cont) {
34
+ if (typeof mode != "string") mode = mode.name;
35
+ if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
36
+ if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
37
+
38
+ var script = document.createElement("script");
39
+ script.src = CodeMirror.modeURL.replace(/%N/g, mode);
40
+ var others = document.getElementsByTagName("script")[0];
41
+ others.parentNode.insertBefore(script, others);
42
+ var list = loading[mode] = [cont];
43
+ var count = 0, poll = setInterval(function() {
44
+ if (++count > 100) return clearInterval(poll);
45
+ if (CodeMirror.modes.hasOwnProperty(mode)) {
46
+ clearInterval(poll);
47
+ loading[mode] = null;
48
+ ensureDeps(mode, function() {
49
+ for (var i = 0; i < list.length; ++i) list[i]();
50
+ });
51
+ }
52
+ }, 200);
53
+ };
54
+
55
+ CodeMirror.autoLoadMode = function(instance, mode) {
56
+ if (!CodeMirror.modes.hasOwnProperty(mode))
57
+ CodeMirror.requireMode(mode, function() {
58
+ instance.setOption("mode", instance.getOption("mode"));
59
+ });
60
+ };
61
+ });
resources/js/codemirror/addon/mode/multiplex.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.multiplexingMode = function(outer /*, others */) {
15
+ // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
16
+ var others = Array.prototype.slice.call(arguments, 1);
17
+ var n_others = others.length;
18
+
19
+ function indexOf(string, pattern, from) {
20
+ if (typeof pattern == "string") return string.indexOf(pattern, from);
21
+ var m = pattern.exec(from ? string.slice(from) : string);
22
+ return m ? m.index + from : -1;
23
+ }
24
+
25
+ return {
26
+ startState: function() {
27
+ return {
28
+ outer: CodeMirror.startState(outer),
29
+ innerActive: null,
30
+ inner: null
31
+ };
32
+ },
33
+
34
+ copyState: function(state) {
35
+ return {
36
+ outer: CodeMirror.copyState(outer, state.outer),
37
+ innerActive: state.innerActive,
38
+ inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
39
+ };
40
+ },
41
+
42
+ token: function(stream, state) {
43
+ if (!state.innerActive) {
44
+ var cutOff = Infinity, oldContent = stream.string;
45
+ for (var i = 0; i < n_others; ++i) {
46
+ var other = others[i];
47
+ var found = indexOf(oldContent, other.open, stream.pos);
48
+ if (found == stream.pos) {
49
+ stream.match(other.open);
50
+ state.innerActive = other;
51
+ state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
52
+ return other.delimStyle;
53
+ } else if (found != -1 && found < cutOff) {
54
+ cutOff = found;
55
+ }
56
+ }
57
+ if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
58
+ var outerToken = outer.token(stream, state.outer);
59
+ if (cutOff != Infinity) stream.string = oldContent;
60
+ return outerToken;
61
+ } else {
62
+ var curInner = state.innerActive, oldContent = stream.string;
63
+ if (!curInner.close && stream.sol()) {
64
+ state.innerActive = state.inner = null;
65
+ return this.token(stream, state);
66
+ }
67
+ var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1;
68
+ if (found == stream.pos) {
69
+ stream.match(curInner.close);
70
+ state.innerActive = state.inner = null;
71
+ return curInner.delimStyle;
72
+ }
73
+ if (found > -1) stream.string = oldContent.slice(0, found);
74
+ var innerToken = curInner.mode.token(stream, state.inner);
75
+ if (found > -1) stream.string = oldContent;
76
+
77
+ if (curInner.innerStyle) {
78
+ if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle;
79
+ else innerToken = curInner.innerStyle;
80
+ }
81
+
82
+ return innerToken;
83
+ }
84
+ },
85
+
86
+ indent: function(state, textAfter) {
87
+ var mode = state.innerActive ? state.innerActive.mode : outer;
88
+ if (!mode.indent) return CodeMirror.Pass;
89
+ return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
90
+ },
91
+
92
+ blankLine: function(state) {
93
+ var mode = state.innerActive ? state.innerActive.mode : outer;
94
+ if (mode.blankLine) {
95
+ mode.blankLine(state.innerActive ? state.inner : state.outer);
96
+ }
97
+ if (!state.innerActive) {
98
+ for (var i = 0; i < n_others; ++i) {
99
+ var other = others[i];
100
+ if (other.open === "\n") {
101
+ state.innerActive = other;
102
+ state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0);
103
+ }
104
+ }
105
+ } else if (state.innerActive.close === "\n") {
106
+ state.innerActive = state.inner = null;
107
+ }
108
+ },
109
+
110
+ electricChars: outer.electricChars,
111
+
112
+ innerMode: function(state) {
113
+ return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
114
+ }
115
+ };
116
+ };
117
+
118
+ });
resources/js/codemirror/addon/mode/multiplex_test.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function() {
5
+ CodeMirror.defineMode("markdown_with_stex", function(){
6
+ var inner = CodeMirror.getMode({}, "stex");
7
+ var outer = CodeMirror.getMode({}, "markdown");
8
+
9
+ var innerOptions = {
10
+ open: '$',
11
+ close: '$',
12
+ mode: inner,
13
+ delimStyle: 'delim',
14
+ innerStyle: 'inner'
15
+ };
16
+
17
+ return CodeMirror.multiplexingMode(outer, innerOptions);
18
+ });
19
+
20
+ var mode = CodeMirror.getMode({}, "markdown_with_stex");
21
+
22
+ function MT(name) {
23
+ test.mode(
24
+ name,
25
+ mode,
26
+ Array.prototype.slice.call(arguments, 1),
27
+ 'multiplexing');
28
+ }
29
+
30
+ MT(
31
+ "stexInsideMarkdown",
32
+ "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]");
33
+ })();
resources/js/codemirror/addon/mode/overlay.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Utility function that allows modes to be combined. The mode given
5
+ // as the base argument takes care of most of the normal mode
6
+ // functionality, but a second (typically simple) mode is used, which
7
+ // can override the style of text. Both modes get to parse all of the
8
+ // text, but when both assign a non-null style to a piece of code, the
9
+ // overlay wins, unless the combine argument was true and not overridden,
10
+ // or state.overlay.combineTokens was true, in which case the styles are
11
+ // combined.
12
+
13
+ (function(mod) {
14
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
15
+ mod(require("../../lib/codemirror"));
16
+ else if (typeof define == "function" && define.amd) // AMD
17
+ define(["../../lib/codemirror"], mod);
18
+ else // Plain browser env
19
+ mod(CodeMirror);
20
+ })(function(CodeMirror) {
21
+ "use strict";
22
+
23
+ CodeMirror.overlayMode = function(base, overlay, combine) {
24
+ return {
25
+ startState: function() {
26
+ return {
27
+ base: CodeMirror.startState(base),
28
+ overlay: CodeMirror.startState(overlay),
29
+ basePos: 0, baseCur: null,
30
+ overlayPos: 0, overlayCur: null,
31
+ lineSeen: null
32
+ };
33
+ },
34
+ copyState: function(state) {
35
+ return {
36
+ base: CodeMirror.copyState(base, state.base),
37
+ overlay: CodeMirror.copyState(overlay, state.overlay),
38
+ basePos: state.basePos, baseCur: null,
39
+ overlayPos: state.overlayPos, overlayCur: null
40
+ };
41
+ },
42
+
43
+ token: function(stream, state) {
44
+ if (stream.sol() || stream.string != state.lineSeen ||
45
+ Math.min(state.basePos, state.overlayPos) < stream.start) {
46
+ state.lineSeen = stream.string;
47
+ state.basePos = state.overlayPos = stream.start;
48
+ }
49
+
50
+ if (stream.start == state.basePos) {
51
+ state.baseCur = base.token(stream, state.base);
52
+ state.basePos = stream.pos;
53
+ }
54
+ if (stream.start == state.overlayPos) {
55
+ stream.pos = stream.start;
56
+ state.overlayCur = overlay.token(stream, state.overlay);
57
+ state.overlayPos = stream.pos;
58
+ }
59
+ stream.pos = Math.min(state.basePos, state.overlayPos);
60
+
61
+ // state.overlay.combineTokens always takes precedence over combine,
62
+ // unless set to null
63
+ if (state.overlayCur == null) return state.baseCur;
64
+ else if (state.baseCur != null &&
65
+ state.overlay.combineTokens ||
66
+ combine && state.overlay.combineTokens == null)
67
+ return state.baseCur + " " + state.overlayCur;
68
+ else return state.overlayCur;
69
+ },
70
+
71
+ indent: base.indent && function(state, textAfter) {
72
+ return base.indent(state.base, textAfter);
73
+ },
74
+ electricChars: base.electricChars,
75
+
76
+ innerMode: function(state) { return {state: state.base, mode: base}; },
77
+
78
+ blankLine: function(state) {
79
+ if (base.blankLine) base.blankLine(state.base);
80
+ if (overlay.blankLine) overlay.blankLine(state.overlay);
81
+ }
82
+ };
83
+ };
84
+
85
+ });
resources/js/codemirror/addon/runmode/colorize.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("./runmode"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "./runmode"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/;
15
+
16
+ function textContent(node, out) {
17
+ if (node.nodeType == 3) return out.push(node.nodeValue);
18
+ for (var ch = node.firstChild; ch; ch = ch.nextSibling) {
19
+ textContent(ch, out);
20
+ if (isBlock.test(node.nodeType)) out.push("\n");
21
+ }
22
+ }
23
+
24
+ CodeMirror.colorize = function(collection, defaultMode) {
25
+ if (!collection) collection = document.body.getElementsByTagName("pre");
26
+
27
+ for (var i = 0; i < collection.length; ++i) {
28
+ var node = collection[i];
29
+ var mode = node.getAttribute("data-lang") || defaultMode;
30
+ if (!mode) continue;
31
+
32
+ var text = [];
33
+ textContent(node, text);
34
+ node.innerHTML = "";
35
+ CodeMirror.runMode(text.join(""), mode, node);
36
+
37
+ node.className += " cm-s-default";
38
+ }
39
+ };
40
+ });
resources/js/codemirror/addon/runmode/runmode-standalone.js ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ window.CodeMirror = {};
5
+
6
+ (function() {
7
+ "use strict";
8
+
9
+ function splitLines(string){ return string.split(/\r?\n|\r/); };
10
+
11
+ function StringStream(string) {
12
+ this.pos = this.start = 0;
13
+ this.string = string;
14
+ this.lineStart = 0;
15
+ }
16
+ StringStream.prototype = {
17
+ eol: function() {return this.pos >= this.string.length;},
18
+ sol: function() {return this.pos == 0;},
19
+ peek: function() {return this.string.charAt(this.pos) || null;},
20
+ next: function() {
21
+ if (this.pos < this.string.length)
22
+ return this.string.charAt(this.pos++);
23
+ },
24
+ eat: function(match) {
25
+ var ch = this.string.charAt(this.pos);
26
+ if (typeof match == "string") var ok = ch == match;
27
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
28
+ if (ok) {++this.pos; return ch;}
29
+ },
30
+ eatWhile: function(match) {
31
+ var start = this.pos;
32
+ while (this.eat(match)){}
33
+ return this.pos > start;
34
+ },
35
+ eatSpace: function() {
36
+ var start = this.pos;
37
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
38
+ return this.pos > start;
39
+ },
40
+ skipToEnd: function() {this.pos = this.string.length;},
41
+ skipTo: function(ch) {
42
+ var found = this.string.indexOf(ch, this.pos);
43
+ if (found > -1) {this.pos = found; return true;}
44
+ },
45
+ backUp: function(n) {this.pos -= n;},
46
+ column: function() {return this.start - this.lineStart;},
47
+ indentation: function() {return 0;},
48
+ match: function(pattern, consume, caseInsensitive) {
49
+ if (typeof pattern == "string") {
50
+ var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
51
+ var substr = this.string.substr(this.pos, pattern.length);
52
+ if (cased(substr) == cased(pattern)) {
53
+ if (consume !== false) this.pos += pattern.length;
54
+ return true;
55
+ }
56
+ } else {
57
+ var match = this.string.slice(this.pos).match(pattern);
58
+ if (match && match.index > 0) return null;
59
+ if (match && consume !== false) this.pos += match[0].length;
60
+ return match;
61
+ }
62
+ },
63
+ current: function(){return this.string.slice(this.start, this.pos);},
64
+ hideFirstChars: function(n, inner) {
65
+ this.lineStart += n;
66
+ try { return inner(); }
67
+ finally { this.lineStart -= n; }
68
+ }
69
+ };
70
+ CodeMirror.StringStream = StringStream;
71
+
72
+ CodeMirror.startState = function (mode, a1, a2) {
73
+ return mode.startState ? mode.startState(a1, a2) : true;
74
+ };
75
+
76
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
77
+ CodeMirror.defineMode = function (name, mode) { modes[name] = mode; };
78
+ CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
79
+ CodeMirror.resolveMode = function(spec) {
80
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
81
+ spec = mimeModes[spec];
82
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
83
+ spec = mimeModes[spec.name];
84
+ }
85
+ if (typeof spec == "string") return {name: spec};
86
+ else return spec || {name: "null"};
87
+ };
88
+ CodeMirror.getMode = function (options, spec) {
89
+ spec = CodeMirror.resolveMode(spec);
90
+ var mfactory = modes[spec.name];
91
+ if (!mfactory) throw new Error("Unknown mode: " + spec);
92
+ return mfactory(options, spec);
93
+ };
94
+ CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
95
+ CodeMirror.defineMode("null", function() {
96
+ return {token: function(stream) {stream.skipToEnd();}};
97
+ });
98
+ CodeMirror.defineMIME("text/plain", "null");
99
+
100
+ CodeMirror.runMode = function (string, modespec, callback, options) {
101
+ var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);
102
+
103
+ if (callback.nodeType == 1) {
104
+ var tabSize = (options && options.tabSize) || 4;
105
+ var node = callback, col = 0;
106
+ node.innerHTML = "";
107
+ callback = function (text, style) {
108
+ if (text == "\n") {
109
+ node.appendChild(document.createElement("br"));
110
+ col = 0;
111
+ return;
112
+ }
113
+ var content = "";
114
+ // replace tabs
115
+ for (var pos = 0; ;) {
116
+ var idx = text.indexOf("\t", pos);
117
+ if (idx == -1) {
118
+ content += text.slice(pos);
119
+ col += text.length - pos;
120
+ break;
121
+ } else {
122
+ col += idx - pos;
123
+ content += text.slice(pos, idx);
124
+ var size = tabSize - col % tabSize;
125
+ col += size;
126
+ for (var i = 0; i < size; ++i) content += " ";
127
+ pos = idx + 1;
128
+ }
129
+ }
130
+
131
+ if (style) {
132
+ var sp = node.appendChild(document.createElement("span"));
133
+ sp.className = "cm-" + style.replace(/ +/g, " cm-");
134
+ sp.appendChild(document.createTextNode(content));
135
+ } else {
136
+ node.appendChild(document.createTextNode(content));
137
+ }
138
+ };
139
+ }
140
+
141
+ var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
142
+ for (var i = 0, e = lines.length; i < e; ++i) {
143
+ if (i) callback("\n");
144
+ var stream = new CodeMirror.StringStream(lines[i]);
145
+ if (!stream.string && mode.blankLine) mode.blankLine(state);
146
+ while (!stream.eol()) {
147
+ var style = mode.token(stream, state);
148
+ callback(stream.current(), style, i, stream.start, state);
149
+ stream.start = stream.pos;
150
+ }
151
+ }
152
+ };
153
+ })();
resources/js/codemirror/addon/runmode/runmode.js ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.runMode = function(string, modespec, callback, options) {
15
+ var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
16
+ var ie = /MSIE \d/.test(navigator.userAgent);
17
+ var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
18
+
19
+ if (callback.nodeType == 1) {
20
+ var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
21
+ var node = callback, col = 0;
22
+ node.innerHTML = "";
23
+ callback = function(text, style) {
24
+ if (text == "\n") {
25
+ // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
26
+ // Emitting a carriage return makes everything ok.
27
+ node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
28
+ col = 0;
29
+ return;
30
+ }
31
+ var content = "";
32
+ // replace tabs
33
+ for (var pos = 0;;) {
34
+ var idx = text.indexOf("\t", pos);
35
+ if (idx == -1) {
36
+ content += text.slice(pos);
37
+ col += text.length - pos;
38
+ break;
39
+ } else {
40
+ col += idx - pos;
41
+ content += text.slice(pos, idx);
42
+ var size = tabSize - col % tabSize;
43
+ col += size;
44
+ for (var i = 0; i < size; ++i) content += " ";
45
+ pos = idx + 1;
46
+ }
47
+ }
48
+
49
+ if (style) {
50
+ var sp = node.appendChild(document.createElement("span"));
51
+ sp.className = "cm-" + style.replace(/ +/g, " cm-");
52
+ sp.appendChild(document.createTextNode(content));
53
+ } else {
54
+ node.appendChild(document.createTextNode(content));
55
+ }
56
+ };
57
+ }
58
+
59
+ var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
60
+ for (var i = 0, e = lines.length; i < e; ++i) {
61
+ if (i) callback("\n");
62
+ var stream = new CodeMirror.StringStream(lines[i]);
63
+ if (!stream.string && mode.blankLine) mode.blankLine(state);
64
+ while (!stream.eol()) {
65
+ var style = mode.token(stream, state);
66
+ callback(stream.current(), style, i, stream.start, state);
67
+ stream.start = stream.pos;
68
+ }
69
+ }
70
+ };
71
+
72
+ });
resources/js/codemirror/addon/runmode/runmode.node.js ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ /* Just enough of CodeMirror to run runMode under node.js */
5
+
6
+ // declare global: StringStream
7
+
8
+ function splitLines(string){ return string.split(/\r?\n|\r/); };
9
+
10
+ function StringStream(string) {
11
+ this.pos = this.start = 0;
12
+ this.string = string;
13
+ this.lineStart = 0;
14
+ }
15
+ StringStream.prototype = {
16
+ eol: function() {return this.pos >= this.string.length;},
17
+ sol: function() {return this.pos == 0;},
18
+ peek: function() {return this.string.charAt(this.pos) || null;},
19
+ next: function() {
20
+ if (this.pos < this.string.length)
21
+ return this.string.charAt(this.pos++);
22
+ },
23
+ eat: function(match) {
24
+ var ch = this.string.charAt(this.pos);
25
+ if (typeof match == "string") var ok = ch == match;
26
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
27
+ if (ok) {++this.pos; return ch;}
28
+ },
29
+ eatWhile: function(match) {
30
+ var start = this.pos;
31
+ while (this.eat(match)){}
32
+ return this.pos > start;
33
+ },
34
+ eatSpace: function() {
35
+ var start = this.pos;
36
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
37
+ return this.pos > start;
38
+ },
39
+ skipToEnd: function() {this.pos = this.string.length;},
40
+ skipTo: function(ch) {
41
+ var found = this.string.indexOf(ch, this.pos);
42
+ if (found > -1) {this.pos = found; return true;}
43
+ },
44
+ backUp: function(n) {this.pos -= n;},
45
+ column: function() {return this.start - this.lineStart;},
46
+ indentation: function() {return 0;},
47
+ match: function(pattern, consume, caseInsensitive) {
48
+ if (typeof pattern == "string") {
49
+ var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
50
+ var substr = this.string.substr(this.pos, pattern.length);
51
+ if (cased(substr) == cased(pattern)) {
52
+ if (consume !== false) this.pos += pattern.length;
53
+ return true;
54
+ }
55
+ } else {
56
+ var match = this.string.slice(this.pos).match(pattern);
57
+ if (match && match.index > 0) return null;
58
+ if (match && consume !== false) this.pos += match[0].length;
59
+ return match;
60
+ }
61
+ },
62
+ current: function(){return this.string.slice(this.start, this.pos);},
63
+ hideFirstChars: function(n, inner) {
64
+ this.lineStart += n;
65
+ try { return inner(); }
66
+ finally { this.lineStart -= n; }
67
+ }
68
+ };
69
+ exports.StringStream = StringStream;
70
+
71
+ exports.startState = function(mode, a1, a2) {
72
+ return mode.startState ? mode.startState(a1, a2) : true;
73
+ };
74
+
75
+ var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
76
+ exports.defineMode = function(name, mode) {
77
+ if (arguments.length > 2) {
78
+ mode.dependencies = [];
79
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
80
+ }
81
+ modes[name] = mode;
82
+ };
83
+ exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
84
+
85
+ exports.defineMode("null", function() {
86
+ return {token: function(stream) {stream.skipToEnd();}};
87
+ });
88
+ exports.defineMIME("text/plain", "null");
89
+
90
+ exports.resolveMode = function(spec) {
91
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
92
+ spec = mimeModes[spec];
93
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
94
+ spec = mimeModes[spec.name];
95
+ }
96
+ if (typeof spec == "string") return {name: spec};
97
+ else return spec || {name: "null"};
98
+ };
99
+ exports.getMode = function(options, spec) {
100
+ spec = exports.resolveMode(spec);
101
+ var mfactory = modes[spec.name];
102
+ if (!mfactory) throw new Error("Unknown mode: " + spec);
103
+ return mfactory(options, spec);
104
+ };
105
+ exports.registerHelper = exports.registerGlobalHelper = Math.min;
106
+
107
+ exports.runMode = function(string, modespec, callback, options) {
108
+ var mode = exports.getMode({indentUnit: 2}, modespec);
109
+ var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
110
+ for (var i = 0, e = lines.length; i < e; ++i) {
111
+ if (i) callback("\n");
112
+ var stream = new exports.StringStream(lines[i]);
113
+ if (!stream.string && mode.blankLine) mode.blankLine(state);
114
+ while (!stream.eol()) {
115
+ var style = mode.token(stream, state);
116
+ callback(stream.current(), style, i, stream.start, state);
117
+ stream.start = stream.pos;
118
+ }
119
+ }
120
+ };
121
+
122
+ require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")];
resources/js/codemirror/addon/scroll/scrollpastend.js ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
15
+ if (old && old != CodeMirror.Init) {
16
+ cm.off("change", onChange);
17
+ cm.off("refresh", updateBottomMargin);
18
+ cm.display.lineSpace.parentNode.style.paddingBottom = "";
19
+ cm.state.scrollPastEndPadding = null;
20
+ }
21
+ if (val) {
22
+ cm.on("change", onChange);
23
+ cm.on("refresh", updateBottomMargin);
24
+ updateBottomMargin(cm);
25
+ }
26
+ });
27
+
28
+ function onChange(cm, change) {
29
+ if (CodeMirror.changeEnd(change).line == cm.lastLine())
30
+ updateBottomMargin(cm);
31
+ }
32
+
33
+ function updateBottomMargin(cm) {
34
+ var padding = "";
35
+ if (cm.lineCount() > 1) {
36
+ var totalH = cm.display.scroller.clientHeight - 30,
37
+ lastLineH = cm.getLineHandle(cm.lastLine()).height;
38
+ padding = (totalH - lastLineH) + "px";
39
+ }
40
+ if (cm.state.scrollPastEndPadding != padding) {
41
+ cm.state.scrollPastEndPadding = padding;
42
+ cm.display.lineSpace.parentNode.style.paddingBottom = padding;
43
+ cm.setSize();
44
+ }
45
+ }
46
+ });
resources/js/codemirror/addon/search/match-highlighter.js ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Highlighting text that matches the selection
5
+ //
6
+ // Defines an option highlightSelectionMatches, which, when enabled,
7
+ // will style strings that match the selection throughout the
8
+ // document.
9
+ //
10
+ // The option can be set to true to simply enable it, or to a
11
+ // {minChars, style, showToken} object to explicitly configure it.
12
+ // minChars is the minimum amount of characters that should be
13
+ // selected for the behavior to occur, and style is the token style to
14
+ // apply to the matches. This will be prefixed by "cm-" to create an
15
+ // actual CSS class name. showToken, when enabled, will cause the
16
+ // current token to be highlighted when nothing is selected.
17
+
18
+ (function(mod) {
19
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
20
+ mod(require("../../lib/codemirror"));
21
+ else if (typeof define == "function" && define.amd) // AMD
22
+ define(["../../lib/codemirror"], mod);
23
+ else // Plain browser env
24
+ mod(CodeMirror);
25
+ })(function(CodeMirror) {
26
+ "use strict";
27
+
28
+ var DEFAULT_MIN_CHARS = 2;
29
+ var DEFAULT_TOKEN_STYLE = "matchhighlight";
30
+ var DEFAULT_DELAY = 100;
31
+
32
+ function State(options) {
33
+ if (typeof options == "object") {
34
+ this.minChars = options.minChars;
35
+ this.style = options.style;
36
+ this.showToken = options.showToken;
37
+ this.delay = options.delay;
38
+ }
39
+ if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
40
+ if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
41
+ if (this.delay == null) this.delay = DEFAULT_DELAY;
42
+ this.overlay = this.timeout = null;
43
+ }
44
+
45
+ CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
46
+ if (old && old != CodeMirror.Init) {
47
+ var over = cm.state.matchHighlighter.overlay;
48
+ if (over) cm.removeOverlay(over);
49
+ clearTimeout(cm.state.matchHighlighter.timeout);
50
+ cm.state.matchHighlighter = null;
51
+ cm.off("cursorActivity", cursorActivity);
52
+ }
53
+ if (val) {
54
+ cm.state.matchHighlighter = new State(val);
55
+ highlightMatches(cm);
56
+ cm.on("cursorActivity", cursorActivity);
57
+ }
58
+ });
59
+
60
+ function cursorActivity(cm) {
61
+ var state = cm.state.matchHighlighter;
62
+ clearTimeout(state.timeout);
63
+ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);
64
+ }
65
+
66
+ function highlightMatches(cm) {
67
+ cm.operation(function() {
68
+ var state = cm.state.matchHighlighter;
69
+ if (state.overlay) {
70
+ cm.removeOverlay(state.overlay);
71
+ state.overlay = null;
72
+ }
73
+ if (!cm.somethingSelected() && state.showToken) {
74
+ var re = state.showToken === true ? /[\w$]/ : state.showToken;
75
+ var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
76
+ while (start && re.test(line.charAt(start - 1))) --start;
77
+ while (end < line.length && re.test(line.charAt(end))) ++end;
78
+ if (start < end)
79
+ cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style));
80
+ return;
81
+ }
82
+ var from = cm.getCursor("from"), to = cm.getCursor("to");
83
+ if (from.line != to.line) return;
84
+ var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, "");
85
+ if (selection.length >= state.minChars)
86
+ cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style));
87
+ });
88
+ }
89
+
90
+ function boundariesAround(stream, re) {
91
+ return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
92
+ (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
93
+ }
94
+
95
+ function makeOverlay(query, hasBoundary, style) {
96
+ return {token: function(stream) {
97
+ if (stream.match(query) &&
98
+ (!hasBoundary || boundariesAround(stream, hasBoundary)))
99
+ return style;
100
+ stream.next();
101
+ stream.skipTo(query.charAt(0)) || stream.skipToEnd();
102
+ }};
103
+ }
104
+ });
resources/js/codemirror/addon/search/search.js ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Define search commands. Depends on dialog.js or another
5
+ // implementation of the openDialog method.
6
+
7
+ // Replace works a little oddly -- it will do the replace on the next
8
+ // Ctrl-G (or whatever is bound to findNext) press. You prevent a
9
+ // replace by making sure the match is no longer selected when hitting
10
+ // Ctrl-G.
11
+
12
+ (function(mod) {
13
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
14
+ mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
15
+ else if (typeof define == "function" && define.amd) // AMD
16
+ define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
17
+ else // Plain browser env
18
+ mod(CodeMirror);
19
+ })(function(CodeMirror) {
20
+ "use strict";
21
+ function searchOverlay(query, caseInsensitive) {
22
+ if (typeof query == "string")
23
+ query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
24
+ else if (!query.global)
25
+ query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
26
+
27
+ return {token: function(stream) {
28
+ query.lastIndex = stream.pos;
29
+ var match = query.exec(stream.string);
30
+ if (match && match.index == stream.pos) {
31
+ stream.pos += match[0].length;
32
+ return "searching";
33
+ } else if (match) {
34
+ stream.pos = match.index;
35
+ } else {
36
+ stream.skipToEnd();
37
+ }
38
+ }};
39
+ }
40
+
41
+ function SearchState() {
42
+ this.posFrom = this.posTo = this.query = null;
43
+ this.overlay = null;
44
+ }
45
+ function getSearchState(cm) {
46
+ return cm.state.search || (cm.state.search = new SearchState());
47
+ }
48
+ function queryCaseInsensitive(query) {
49
+ return typeof query == "string" && query == query.toLowerCase();
50
+ }
51
+ function getSearchCursor(cm, query, pos) {
52
+ // Heuristic: if the query string is all lowercase, do a case insensitive search.
53
+ return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
54
+ }
55
+ function dialog(cm, text, shortText, deflt, f) {
56
+ if (cm.openDialog) cm.openDialog(text, f, {value: deflt});
57
+ else f(prompt(shortText, deflt));
58
+ }
59
+ function confirmDialog(cm, text, shortText, fs) {
60
+ if (cm.openConfirm) cm.openConfirm(text, fs);
61
+ else if (confirm(shortText)) fs[0]();
62
+ }
63
+ function parseQuery(query) {
64
+ var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
65
+ if (isRE) {
66
+ query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
67
+ if (query.test("")) query = /x^/;
68
+ } else if (query == "") {
69
+ query = /x^/;
70
+ }
71
+ return query;
72
+ }
73
+ var queryDialog =
74
+ 'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
75
+ function doSearch(cm, rev) {
76
+ var state = getSearchState(cm);
77
+ if (state.query) return findNext(cm, rev);
78
+ dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
79
+ cm.operation(function() {
80
+ if (!query || state.query) return;
81
+ state.query = parseQuery(query);
82
+ cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
83
+ state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
84
+ cm.addOverlay(state.overlay);
85
+ state.posFrom = state.posTo = cm.getCursor();
86
+ findNext(cm, rev);
87
+ });
88
+ });
89
+ }
90
+ function findNext(cm, rev) {cm.operation(function() {
91
+ var state = getSearchState(cm);
92
+ var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
93
+ if (!cursor.find(rev)) {
94
+ cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
95
+ if (!cursor.find(rev)) return;
96
+ }
97
+ cm.setSelection(cursor.from(), cursor.to());
98
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
99
+ state.posFrom = cursor.from(); state.posTo = cursor.to();
100
+ });}
101
+ function clearSearch(cm) {cm.operation(function() {
102
+ var state = getSearchState(cm);
103
+ if (!state.query) return;
104
+ state.query = null;
105
+ cm.removeOverlay(state.overlay);
106
+ });}
107
+
108
+ var replaceQueryDialog =
109
+ 'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
110
+ var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
111
+ var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
112
+ function replace(cm, all) {
113
+ dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
114
+ if (!query) return;
115
+ query = parseQuery(query);
116
+ dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
117
+ if (all) {
118
+ cm.operation(function() {
119
+ for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
120
+ if (typeof query != "string") {
121
+ var match = cm.getRange(cursor.from(), cursor.to()).match(query);
122
+ cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
123
+ } else cursor.replace(text);
124
+ }
125
+ });
126
+ } else {
127
+ clearSearch(cm);
128
+ var cursor = getSearchCursor(cm, query, cm.getCursor());
129
+ var advance = function() {
130
+ var start = cursor.from(), match;
131
+ if (!(match = cursor.findNext())) {
132
+ cursor = getSearchCursor(cm, query);
133
+ if (!(match = cursor.findNext()) ||
134
+ (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
135
+ }
136
+ cm.setSelection(cursor.from(), cursor.to());
137
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
138
+ confirmDialog(cm, doReplaceConfirm, "Replace?",
139
+ [function() {doReplace(match);}, advance]);
140
+ };
141
+ var doReplace = function(match) {
142
+ cursor.replace(typeof query == "string" ? text :
143
+ text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
144
+ advance();
145
+ };
146
+ advance();
147
+ }
148
+ });
149
+ });
150
+ }
151
+
152
+ CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
153
+ CodeMirror.commands.findNext = doSearch;
154
+ CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
155
+ CodeMirror.commands.clearSearch = clearSearch;
156
+ CodeMirror.commands.replace = replace;
157
+ CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
158
+ });
resources/js/codemirror/addon/search/searchcursor.js ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+ var Pos = CodeMirror.Pos;
14
+
15
+ function SearchCursor(doc, query, pos, caseFold) {
16
+ this.atOccurrence = false; this.doc = doc;
17
+ if (caseFold == null && typeof query == "string") caseFold = false;
18
+
19
+ pos = pos ? doc.clipPos(pos) : Pos(0, 0);
20
+ this.pos = {from: pos, to: pos};
21
+
22
+ // The matches method is filled in based on the type of query.
23
+ // It takes a position and a direction, and returns an object
24
+ // describing the next occurrence of the query, or null if no
25
+ // more matches were found.
26
+ if (typeof query != "string") { // Regexp match
27
+ if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
28
+ this.matches = function(reverse, pos) {
29
+ if (reverse) {
30
+ query.lastIndex = 0;
31
+ var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
32
+ for (;;) {
33
+ query.lastIndex = cutOff;
34
+ var newMatch = query.exec(line);
35
+ if (!newMatch) break;
36
+ match = newMatch;
37
+ start = match.index;
38
+ cutOff = match.index + (match[0].length || 1);
39
+ if (cutOff == line.length) break;
40
+ }
41
+ var matchLen = (match && match[0].length) || 0;
42
+ if (!matchLen) {
43
+ if (start == 0 && line.length == 0) {match = undefined;}
44
+ else if (start != doc.getLine(pos.line).length) {
45
+ matchLen++;
46
+ }
47
+ }
48
+ } else {
49
+ query.lastIndex = pos.ch;
50
+ var line = doc.getLine(pos.line), match = query.exec(line);
51
+ var matchLen = (match && match[0].length) || 0;
52
+ var start = match && match.index;
53
+ if (start + matchLen != line.length && !matchLen) matchLen = 1;
54
+ }
55
+ if (match && matchLen)
56
+ return {from: Pos(pos.line, start),
57
+ to: Pos(pos.line, start + matchLen),
58
+ match: match};
59
+ };
60
+ } else { // String query
61
+ var origQuery = query;
62
+ if (caseFold) query = query.toLowerCase();
63
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
64
+ var target = query.split("\n");
65
+ // Different methods for single-line and multi-line queries
66
+ if (target.length == 1) {
67
+ if (!query.length) {
68
+ // Empty string would match anything and never progress, so
69
+ // we define it to match nothing instead.
70
+ this.matches = function() {};
71
+ } else {
72
+ this.matches = function(reverse, pos) {
73
+ if (reverse) {
74
+ var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
75
+ var match = line.lastIndexOf(query);
76
+ if (match > -1) {
77
+ match = adjustPos(orig, line, match);
78
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
79
+ }
80
+ } else {
81
+ var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
82
+ var match = line.indexOf(query);
83
+ if (match > -1) {
84
+ match = adjustPos(orig, line, match) + pos.ch;
85
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
86
+ }
87
+ }
88
+ };
89
+ }
90
+ } else {
91
+ var origTarget = origQuery.split("\n");
92
+ this.matches = function(reverse, pos) {
93
+ var last = target.length - 1;
94
+ if (reverse) {
95
+ if (pos.line - (target.length - 1) < doc.firstLine()) return;
96
+ if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
97
+ var to = Pos(pos.line, origTarget[last].length);
98
+ for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
99
+ if (target[i] != fold(doc.getLine(ln))) return;
100
+ var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
101
+ if (fold(line.slice(cut)) != target[0]) return;
102
+ return {from: Pos(ln, cut), to: to};
103
+ } else {
104
+ if (pos.line + (target.length - 1) > doc.lastLine()) return;
105
+ var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
106
+ if (fold(line.slice(cut)) != target[0]) return;
107
+ var from = Pos(pos.line, cut);
108
+ for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
109
+ if (target[i] != fold(doc.getLine(ln))) return;
110
+ if (doc.getLine(ln).slice(0, origTarget[last].length) != target[last]) return;
111
+ return {from: from, to: Pos(ln, origTarget[last].length)};
112
+ }
113
+ };
114
+ }
115
+ }
116
+ }
117
+
118
+ SearchCursor.prototype = {
119
+ findNext: function() {return this.find(false);},
120
+ findPrevious: function() {return this.find(true);},
121
+
122
+ find: function(reverse) {
123
+ var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
124
+ function savePosAndFail(line) {
125
+ var pos = Pos(line, 0);
126
+ self.pos = {from: pos, to: pos};
127
+ self.atOccurrence = false;
128
+ return false;
129
+ }
130
+
131
+ for (;;) {
132
+ if (this.pos = this.matches(reverse, pos)) {
133
+ this.atOccurrence = true;
134
+ return this.pos.match || true;
135
+ }
136
+ if (reverse) {
137
+ if (!pos.line) return savePosAndFail(0);
138
+ pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
139
+ }
140
+ else {
141
+ var maxLine = this.doc.lineCount();
142
+ if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
143
+ pos = Pos(pos.line + 1, 0);
144
+ }
145
+ }
146
+ },
147
+
148
+ from: function() {if (this.atOccurrence) return this.pos.from;},
149
+ to: function() {if (this.atOccurrence) return this.pos.to;},
150
+
151
+ replace: function(newText) {
152
+ if (!this.atOccurrence) return;
153
+ var lines = CodeMirror.splitLines(newText);
154
+ this.doc.replaceRange(lines, this.pos.from, this.pos.to);
155
+ this.pos.to = Pos(this.pos.from.line + lines.length - 1,
156
+ lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
157
+ }
158
+ };
159
+
160
+ // Maps a position in a case-folded line back to a position in the original line
161
+ // (compensating for codepoints increasing in number during folding)
162
+ function adjustPos(orig, folded, pos) {
163
+ if (orig.length == folded.length) return pos;
164
+ for (var pos1 = Math.min(pos, orig.length);;) {
165
+ var len1 = orig.slice(0, pos1).toLowerCase().length;
166
+ if (len1 < pos) ++pos1;
167
+ else if (len1 > pos) --pos1;
168
+ else return pos1;
169
+ }
170
+ }
171
+
172
+ CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
173
+ return new SearchCursor(this.doc, query, pos, caseFold);
174
+ });
175
+ CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
176
+ return new SearchCursor(this, query, pos, caseFold);
177
+ });
178
+
179
+ CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
180
+ var ranges = [], next;
181
+ var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
182
+ while (next = cur.findNext()) {
183
+ if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
184
+ ranges.push({anchor: cur.from(), head: cur.to()});
185
+ }
186
+ if (ranges.length)
187
+ this.setSelections(ranges, 0);
188
+ });
189
+ });
resources/js/codemirror/addon/selection/active-line.js ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Because sometimes you need to style the cursor's line.
5
+ //
6
+ // Adds an option 'styleActiveLine' which, when enabled, gives the
7
+ // active line's wrapping <div> the CSS class "CodeMirror-activeline",
8
+ // and gives its background <div> the class "CodeMirror-activeline-background".
9
+
10
+ (function(mod) {
11
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
12
+ mod(require("../../lib/codemirror"));
13
+ else if (typeof define == "function" && define.amd) // AMD
14
+ define(["../../lib/codemirror"], mod);
15
+ else // Plain browser env
16
+ mod(CodeMirror);
17
+ })(function(CodeMirror) {
18
+ "use strict";
19
+ var WRAP_CLASS = "CodeMirror-activeline";
20
+ var BACK_CLASS = "CodeMirror-activeline-background";
21
+
22
+ CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
23
+ var prev = old && old != CodeMirror.Init;
24
+ if (val && !prev) {
25
+ cm.state.activeLines = [];
26
+ updateActiveLines(cm, cm.listSelections());
27
+ cm.on("beforeSelectionChange", selectionChange);
28
+ } else if (!val && prev) {
29
+ cm.off("beforeSelectionChange", selectionChange);
30
+ clearActiveLines(cm);
31
+ delete cm.state.activeLines;
32
+ }
33
+ });
34
+
35
+ function clearActiveLines(cm) {
36
+ for (var i = 0; i < cm.state.activeLines.length; i++) {
37
+ cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
38
+ cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
39
+ }
40
+ }
41
+
42
+ function sameArray(a, b) {
43
+ if (a.length != b.length) return false;
44
+ for (var i = 0; i < a.length; i++)
45
+ if (a[i] != b[i]) return false;
46
+ return true;
47
+ }
48
+
49
+ function updateActiveLines(cm, ranges) {
50
+ var active = [];
51
+ for (var i = 0; i < ranges.length; i++) {
52
+ var line = cm.getLineHandleVisualStart(ranges[i].head.line);
53
+ if (active[active.length - 1] != line) active.push(line);
54
+ }
55
+ if (sameArray(cm.state.activeLines, active)) return;
56
+ cm.operation(function() {
57
+ clearActiveLines(cm);
58
+ for (var i = 0; i < active.length; i++) {
59
+ cm.addLineClass(active[i], "wrap", WRAP_CLASS);
60
+ cm.addLineClass(active[i], "background", BACK_CLASS);
61
+ }
62
+ cm.state.activeLines = active;
63
+ });
64
+ }
65
+
66
+ function selectionChange(cm, sel) {
67
+ updateActiveLines(cm, sel.ranges);
68
+ }
69
+ });
resources/js/codemirror/addon/selection/mark-selection.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Because sometimes you need to mark the selected *text*.
5
+ //
6
+ // Adds an option 'styleSelectedText' which, when enabled, gives
7
+ // selected text the CSS class given as option value, or
8
+ // "CodeMirror-selectedtext" when the value is not a string.
9
+
10
+ (function(mod) {
11
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
12
+ mod(require("../../lib/codemirror"));
13
+ else if (typeof define == "function" && define.amd) // AMD
14
+ define(["../../lib/codemirror"], mod);
15
+ else // Plain browser env
16
+ mod(CodeMirror);
17
+ })(function(CodeMirror) {
18
+ "use strict";
19
+
20
+ CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
21
+ var prev = old && old != CodeMirror.Init;
22
+ if (val && !prev) {
23
+ cm.state.markedSelection = [];
24
+ cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
25
+ reset(cm);
26
+ cm.on("cursorActivity", onCursorActivity);
27
+ cm.on("change", onChange);
28
+ } else if (!val && prev) {
29
+ cm.off("cursorActivity", onCursorActivity);
30
+ cm.off("change", onChange);
31
+ clear(cm);
32
+ cm.state.markedSelection = cm.state.markedSelectionStyle = null;
33
+ }
34
+ });
35
+
36
+ function onCursorActivity(cm) {
37
+ cm.operation(function() { update(cm); });
38
+ }
39
+
40
+ function onChange(cm) {
41
+ if (cm.state.markedSelection.length)
42
+ cm.operation(function() { clear(cm); });
43
+ }
44
+
45
+ var CHUNK_SIZE = 8;
46
+ var Pos = CodeMirror.Pos;
47
+ var cmp = CodeMirror.cmpPos;
48
+
49
+ function coverRange(cm, from, to, addAt) {
50
+ if (cmp(from, to) == 0) return;
51
+ var array = cm.state.markedSelection;
52
+ var cls = cm.state.markedSelectionStyle;
53
+ for (var line = from.line;;) {
54
+ var start = line == from.line ? from : Pos(line, 0);
55
+ var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
56
+ var end = atEnd ? to : Pos(endLine, 0);
57
+ var mark = cm.markText(start, end, {className: cls});
58
+ if (addAt == null) array.push(mark);
59
+ else array.splice(addAt++, 0, mark);
60
+ if (atEnd) break;
61
+ line = endLine;
62
+ }
63
+ }
64
+
65
+ function clear(cm) {
66
+ var array = cm.state.markedSelection;
67
+ for (var i = 0; i < array.length; ++i) array[i].clear();
68
+ array.length = 0;
69
+ }
70
+
71
+ function reset(cm) {
72
+ clear(cm);
73
+ var ranges = cm.listSelections();
74
+ for (var i = 0; i < ranges.length; i++)
75
+ coverRange(cm, ranges[i].from(), ranges[i].to());
76
+ }
77
+
78
+ function update(cm) {
79
+ if (!cm.somethingSelected()) return clear(cm);
80
+ if (cm.listSelections().length > 1) return reset(cm);
81
+
82
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
83
+
84
+ var array = cm.state.markedSelection;
85
+ if (!array.length) return coverRange(cm, from, to);
86
+
87
+ var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
88
+ if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
89
+ cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
90
+ return reset(cm);
91
+
92
+ while (cmp(from, coverStart.from) > 0) {
93
+ array.shift().clear();
94
+ coverStart = array[0].find();
95
+ }
96
+ if (cmp(from, coverStart.from) < 0) {
97
+ if (coverStart.to.line - from.line < CHUNK_SIZE) {
98
+ array.shift().clear();
99
+ coverRange(cm, from, coverStart.to, 0);
100
+ } else {
101
+ coverRange(cm, from, coverStart.from, 0);
102
+ }
103
+ }
104
+
105
+ while (cmp(to, coverEnd.to) < 0) {
106
+ array.pop().clear();
107
+ coverEnd = array[array.length - 1].find();
108
+ }
109
+ if (cmp(to, coverEnd.to) > 0) {
110
+ if (to.line - coverEnd.from.line < CHUNK_SIZE) {
111
+ array.pop().clear();
112
+ coverRange(cm, coverEnd.from, to);
113
+ } else {
114
+ coverRange(cm, coverEnd.to, to);
115
+ }
116
+ }
117
+ }
118
+ });
resources/js/codemirror/addon/tern/tern.css ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .CodeMirror-Tern-completion {
2
+ padding-left: 22px;
3
+ position: relative;
4
+ }
5
+ .CodeMirror-Tern-completion:before {
6
+ position: absolute;
7
+ left: 2px;
8
+ bottom: 2px;
9
+ border-radius: 50%;
10
+ font-size: 12px;
11
+ font-weight: bold;
12
+ height: 15px;
13
+ width: 15px;
14
+ line-height: 16px;
15
+ text-align: center;
16
+ color: white;
17
+ -moz-box-sizing: border-box;
18
+ box-sizing: border-box;
19
+ }
20
+ .CodeMirror-Tern-completion-unknown:before {
21
+ content: "?";
22
+ background: #4bb;
23
+ }
24
+ .CodeMirror-Tern-completion-object:before {
25
+ content: "O";
26
+ background: #77c;
27
+ }
28
+ .CodeMirror-Tern-completion-fn:before {
29
+ content: "F";
30
+ background: #7c7;
31
+ }
32
+ .CodeMirror-Tern-completion-array:before {
33
+ content: "A";
34
+ background: #c66;
35
+ }
36
+ .CodeMirror-Tern-completion-number:before {
37
+ content: "1";
38
+ background: #999;
39
+ }
40
+ .CodeMirror-Tern-completion-string:before {
41
+ content: "S";
42
+ background: #999;
43
+ }
44
+ .CodeMirror-Tern-completion-bool:before {
45
+ content: "B";
46
+ background: #999;
47
+ }
48
+
49
+ .CodeMirror-Tern-completion-guess {
50
+ color: #999;
51
+ }
52
+
53
+ .CodeMirror-Tern-tooltip {
54
+ border: 1px solid silver;
55
+ border-radius: 3px;
56
+ color: #444;
57
+ padding: 2px 5px;
58
+ font-size: 90%;
59
+ font-family: monospace;
60
+ background-color: white;
61
+ white-space: pre-wrap;
62
+
63
+ max-width: 40em;
64
+ position: absolute;
65
+ z-index: 10;
66
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
67
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
68
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
69
+
70
+ transition: opacity 1s;
71
+ -moz-transition: opacity 1s;
72
+ -webkit-transition: opacity 1s;
73
+ -o-transition: opacity 1s;
74
+ -ms-transition: opacity 1s;
75
+ }
76
+
77
+ .CodeMirror-Tern-hint-doc {
78
+ max-width: 25em;
79
+ margin-top: -3px;
80
+ }
81
+
82
+ .CodeMirror-Tern-fname { color: black; }
83
+ .CodeMirror-Tern-farg { color: #70a; }
84
+ .CodeMirror-Tern-farg-current { text-decoration: underline; }
85
+ .CodeMirror-Tern-type { color: #07c; }
86
+ .CodeMirror-Tern-fhint-guess { opacity: .7; }
resources/js/codemirror/addon/tern/tern.js ADDED
@@ -0,0 +1,667 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Glue code between CodeMirror and Tern.
5
+ //
6
+ // Create a CodeMirror.TernServer to wrap an actual Tern server,
7
+ // register open documents (CodeMirror.Doc instances) with it, and
8
+ // call its methods to activate the assisting functions that Tern
9
+ // provides.
10
+ //
11
+ // Options supported (all optional):
12
+ // * defs: An array of JSON definition data structures.
13
+ // * plugins: An object mapping plugin names to configuration
14
+ // options.
15
+ // * getFile: A function(name, c) that can be used to access files in
16
+ // the project that haven't been loaded yet. Simply do c(null) to
17
+ // indicate that a file is not available.
18
+ // * fileFilter: A function(value, docName, doc) that will be applied
19
+ // to documents before passing them on to Tern.
20
+ // * switchToDoc: A function(name, doc) that should, when providing a
21
+ // multi-file view, switch the view or focus to the named file.
22
+ // * showError: A function(editor, message) that can be used to
23
+ // override the way errors are displayed.
24
+ // * completionTip: Customize the content in tooltips for completions.
25
+ // Is passed a single argument—the completion's data as returned by
26
+ // Tern—and may return a string, DOM node, or null to indicate that
27
+ // no tip should be shown. By default the docstring is shown.
28
+ // * typeTip: Like completionTip, but for the tooltips shown for type
29
+ // queries.
30
+ // * responseFilter: A function(doc, query, request, error, data) that
31
+ // will be applied to the Tern responses before treating them
32
+ //
33
+ //
34
+ // It is possible to run the Tern server in a web worker by specifying
35
+ // these additional options:
36
+ // * useWorker: Set to true to enable web worker mode. You'll probably
37
+ // want to feature detect the actual value you use here, for example
38
+ // !!window.Worker.
39
+ // * workerScript: The main script of the worker. Point this to
40
+ // wherever you are hosting worker.js from this directory.
41
+ // * workerDeps: An array of paths pointing (relative to workerScript)
42
+ // to the Acorn and Tern libraries and any Tern plugins you want to
43
+ // load. Or, if you minified those into a single script and included
44
+ // them in the workerScript, simply leave this undefined.
45
+
46
+ (function(mod) {
47
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
48
+ mod(require("../../lib/codemirror"));
49
+ else if (typeof define == "function" && define.amd) // AMD
50
+ define(["../../lib/codemirror"], mod);
51
+ else // Plain browser env
52
+ mod(CodeMirror);
53
+ })(function(CodeMirror) {
54
+ "use strict";
55
+ // declare global: tern
56
+
57
+ CodeMirror.TernServer = function(options) {
58
+ var self = this;
59
+ this.options = options || {};
60
+ var plugins = this.options.plugins || (this.options.plugins = {});
61
+ if (!plugins.doc_comment) plugins.doc_comment = true;
62
+ if (this.options.useWorker) {
63
+ this.server = new WorkerServer(this);
64
+ } else {
65
+ this.server = new tern.Server({
66
+ getFile: function(name, c) { return getFile(self, name, c); },
67
+ async: true,
68
+ defs: this.options.defs || [],
69
+ plugins: plugins
70
+ });
71
+ }
72
+ this.docs = Object.create(null);
73
+ this.trackChange = function(doc, change) { trackChange(self, doc, change); };
74
+
75
+ this.cachedArgHints = null;
76
+ this.activeArgHints = null;
77
+ this.jumpStack = [];
78
+
79
+ this.getHint = function(cm, c) { return hint(self, cm, c); };
80
+ this.getHint.async = true;
81
+ };
82
+
83
+ CodeMirror.TernServer.prototype = {
84
+ addDoc: function(name, doc) {
85
+ var data = {doc: doc, name: name, changed: null};
86
+ this.server.addFile(name, docValue(this, data));
87
+ CodeMirror.on(doc, "change", this.trackChange);
88
+ return this.docs[name] = data;
89
+ },
90
+
91
+ delDoc: function(id) {
92
+ var found = resolveDoc(this, id);
93
+ if (!found) return;
94
+ CodeMirror.off(found.doc, "change", this.trackChange);
95
+ delete this.docs[found.name];
96
+ this.server.delFile(found.name);
97
+ },
98
+
99
+ hideDoc: function(id) {
100
+ closeArgHints(this);
101
+ var found = resolveDoc(this, id);
102
+ if (found && found.changed) sendDoc(this, found);
103
+ },
104
+
105
+ complete: function(cm) {
106
+ cm.showHint({hint: this.getHint});
107
+ },
108
+
109
+ showType: function(cm, pos) { showType(this, cm, pos); },
110
+
111
+ updateArgHints: function(cm) { updateArgHints(this, cm); },
112
+
113
+ jumpToDef: function(cm) { jumpToDef(this, cm); },
114
+
115
+ jumpBack: function(cm) { jumpBack(this, cm); },
116
+
117
+ rename: function(cm) { rename(this, cm); },
118
+
119
+ selectName: function(cm) { selectName(this, cm); },
120
+
121
+ request: function (cm, query, c, pos) {
122
+ var self = this;
123
+ var doc = findDoc(this, cm.getDoc());
124
+ var request = buildRequest(this, doc, query, pos);
125
+
126
+ this.server.request(request, function (error, data) {
127
+ if (!error && self.options.responseFilter)
128
+ data = self.options.responseFilter(doc, query, request, error, data);
129
+ c(error, data);
130
+ });
131
+ }
132
+ };
133
+
134
+ var Pos = CodeMirror.Pos;
135
+ var cls = "CodeMirror-Tern-";
136
+ var bigDoc = 250;
137
+
138
+ function getFile(ts, name, c) {
139
+ var buf = ts.docs[name];
140
+ if (buf)
141
+ c(docValue(ts, buf));
142
+ else if (ts.options.getFile)
143
+ ts.options.getFile(name, c);
144
+ else
145
+ c(null);
146
+ }
147
+
148
+ function findDoc(ts, doc, name) {
149
+ for (var n in ts.docs) {
150
+ var cur = ts.docs[n];
151
+ if (cur.doc == doc) return cur;
152
+ }
153
+ if (!name) for (var i = 0;; ++i) {
154
+ n = "[doc" + (i || "") + "]";
155
+ if (!ts.docs[n]) { name = n; break; }
156
+ }
157
+ return ts.addDoc(name, doc);
158
+ }
159
+
160
+ function resolveDoc(ts, id) {
161
+ if (typeof id == "string") return ts.docs[id];
162
+ if (id instanceof CodeMirror) id = id.getDoc();
163
+ if (id instanceof CodeMirror.Doc) return findDoc(ts, id);
164
+ }
165
+
166
+ function trackChange(ts, doc, change) {
167
+ var data = findDoc(ts, doc);
168
+
169
+ var argHints = ts.cachedArgHints;
170
+ if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0)
171
+ ts.cachedArgHints = null;
172
+
173
+ var changed = data.changed;
174
+ if (changed == null)
175
+ data.changed = changed = {from: change.from.line, to: change.from.line};
176
+ var end = change.from.line + (change.text.length - 1);
177
+ if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);
178
+ if (end >= changed.to) changed.to = end + 1;
179
+ if (changed.from > change.from.line) changed.from = change.from.line;
180
+
181
+ if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {
182
+ if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);
183
+ }, 200);
184
+ }
185
+
186
+ function sendDoc(ts, doc) {
187
+ ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) {
188
+ if (error) window.console.error(error);
189
+ else doc.changed = null;
190
+ });
191
+ }
192
+
193
+ // Completion
194
+
195
+ function hint(ts, cm, c) {
196
+ ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) {
197
+ if (error) return showError(ts, cm, error);
198
+ var completions = [], after = "";
199
+ var from = data.start, to = data.end;
200
+ if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" &&
201
+ cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]")
202
+ after = "\"]";
203
+
204
+ for (var i = 0; i < data.completions.length; ++i) {
205
+ var completion = data.completions[i], className = typeToIcon(completion.type);
206
+ if (data.guess) className += " " + cls + "guess";
207
+ completions.push({text: completion.name + after,
208
+ displayText: completion.name,
209
+ className: className,
210
+ data: completion});
211
+ }
212
+
213
+ var obj = {from: from, to: to, list: completions};
214
+ var tooltip = null;
215
+ CodeMirror.on(obj, "close", function() { remove(tooltip); });
216
+ CodeMirror.on(obj, "update", function() { remove(tooltip); });
217
+ CodeMirror.on(obj, "select", function(cur, node) {
218
+ remove(tooltip);
219
+ var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
220
+ if (content) {
221
+ tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
222
+ node.getBoundingClientRect().top + window.pageYOffset, content);
223
+ tooltip.className += " " + cls + "hint-doc";
224
+ }
225
+ });
226
+ c(obj);
227
+ });
228
+ }
229
+
230
+ function typeToIcon(type) {
231
+ var suffix;
232
+ if (type == "?") suffix = "unknown";
233
+ else if (type == "number" || type == "string" || type == "bool") suffix = type;
234
+ else if (/^fn\(/.test(type)) suffix = "fn";
235
+ else if (/^\[/.test(type)) suffix = "array";
236
+ else suffix = "object";
237
+ return cls + "completion " + cls + "completion-" + suffix;
238
+ }
239
+
240
+ // Type queries
241
+
242
+ function showType(ts, cm, pos) {
243
+ ts.request(cm, "type", function(error, data) {
244
+ if (error) return showError(ts, cm, error);
245
+ if (ts.options.typeTip) {
246
+ var tip = ts.options.typeTip(data);
247
+ } else {
248
+ var tip = elt("span", null, elt("strong", null, data.type || "not found"));
249
+ if (data.doc)
250
+ tip.appendChild(document.createTextNode(" — " + data.doc));
251
+ if (data.url) {
252
+ tip.appendChild(document.createTextNode(" "));
253
+ tip.appendChild(elt("a", null, "[docs]")).href = data.url;
254
+ }
255
+ }
256
+ tempTooltip(cm, tip);
257
+ }, pos);
258
+ }
259
+
260
+ // Maintaining argument hints
261
+
262
+ function updateArgHints(ts, cm) {
263
+ closeArgHints(ts);
264
+
265
+ if (cm.somethingSelected()) return;
266
+ var state = cm.getTokenAt(cm.getCursor()).state;
267
+ var inner = CodeMirror.innerMode(cm.getMode(), state);
268
+ if (inner.mode.name != "javascript") return;
269
+ var lex = inner.state.lexical;
270
+ if (lex.info != "call") return;
271
+
272
+ var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
273
+ for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
274
+ var str = cm.getLine(line), extra = 0;
275
+ for (var pos = 0;;) {
276
+ var tab = str.indexOf("\t", pos);
277
+ if (tab == -1) break;
278
+ extra += tabSize - (tab + extra) % tabSize - 1;
279
+ pos = tab + 1;
280
+ }
281
+ ch = lex.column - extra;
282
+ if (str.charAt(ch) == "(") {found = true; break;}
283
+ }
284
+ if (!found) return;
285
+
286
+ var start = Pos(line, ch);
287
+ var cache = ts.cachedArgHints;
288
+ if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
289
+ return showArgHints(ts, cm, argPos);
290
+
291
+ ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
292
+ if (error || !data.type || !(/^fn\(/).test(data.type)) return;
293
+ ts.cachedArgHints = {
294
+ start: pos,
295
+ type: parseFnType(data.type),
296
+ name: data.exprName || data.name || "fn",
297
+ guess: data.guess,
298
+ doc: cm.getDoc()
299
+ };
300
+ showArgHints(ts, cm, argPos);
301
+ });
302
+ }
303
+
304
+ function showArgHints(ts, cm, pos) {
305
+ closeArgHints(ts);
306
+
307
+ var cache = ts.cachedArgHints, tp = cache.type;
308
+ var tip = elt("span", cache.guess ? cls + "fhint-guess" : null,
309
+ elt("span", cls + "fname", cache.name), "(");
310
+ for (var i = 0; i < tp.args.length; ++i) {
311
+ if (i) tip.appendChild(document.createTextNode(", "));
312
+ var arg = tp.args[i];
313
+ tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?"));
314
+ if (arg.type != "?") {
315
+ tip.appendChild(document.createTextNode(":\u00a0"));
316
+ tip.appendChild(elt("span", cls + "type", arg.type));
317
+ }
318
+ }
319
+ tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
320
+ if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
321
+ var place = cm.cursorCoords(null, "page");
322
+ ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip);
323
+ }
324
+
325
+ function parseFnType(text) {
326
+ var args = [], pos = 3;
327
+
328
+ function skipMatching(upto) {
329
+ var depth = 0, start = pos;
330
+ for (;;) {
331
+ var next = text.charAt(pos);
332
+ if (upto.test(next) && !depth) return text.slice(start, pos);
333
+ if (/[{\[\(]/.test(next)) ++depth;
334
+ else if (/[}\]\)]/.test(next)) --depth;
335
+ ++pos;
336
+ }
337
+ }
338
+
339
+ // Parse arguments
340
+ if (text.charAt(pos) != ")") for (;;) {
341
+ var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
342
+ if (name) {
343
+ pos += name[0].length;
344
+ name = name[1];
345
+ }
346
+ args.push({name: name, type: skipMatching(/[\),]/)});
347
+ if (text.charAt(pos) == ")") break;
348
+ pos += 2;
349
+ }
350
+
351
+ var rettype = text.slice(pos).match(/^\) -> (.*)$/);
352
+
353
+ return {args: args, rettype: rettype && rettype[1]};
354
+ }
355
+
356
+ // Moving to the definition of something
357
+
358
+ function jumpToDef(ts, cm) {
359
+ function inner(varName) {
360
+ var req = {type: "definition", variable: varName || null};
361
+ var doc = findDoc(ts, cm.getDoc());
362
+ ts.server.request(buildRequest(ts, doc, req), function(error, data) {
363
+ if (error) return showError(ts, cm, error);
364
+ if (!data.file && data.url) { window.open(data.url); return; }
365
+
366
+ if (data.file) {
367
+ var localDoc = ts.docs[data.file], found;
368
+ if (localDoc && (found = findContext(localDoc.doc, data))) {
369
+ ts.jumpStack.push({file: doc.name,
370
+ start: cm.getCursor("from"),
371
+ end: cm.getCursor("to")});
372
+ moveTo(ts, doc, localDoc, found.start, found.end);
373
+ return;
374
+ }
375
+ }
376
+ showError(ts, cm, "Could not find a definition.");
377
+ });
378
+ }
379
+
380
+ if (!atInterestingExpression(cm))
381
+ dialog(cm, "Jump to variable", function(name) { if (name) inner(name); });
382
+ else
383
+ inner();
384
+ }
385
+
386
+ function jumpBack(ts, cm) {
387
+ var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];
388
+ if (!doc) return;
389
+ moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);
390
+ }
391
+
392
+ function moveTo(ts, curDoc, doc, start, end) {
393
+ doc.doc.setSelection(start, end);
394
+ if (curDoc != doc && ts.options.switchToDoc) {
395
+ closeArgHints(ts);
396
+ ts.options.switchToDoc(doc.name, doc.doc);
397
+ }
398
+ }
399
+
400
+ // The {line,ch} representation of positions makes this rather awkward.
401
+ function findContext(doc, data) {
402
+ var before = data.context.slice(0, data.contextOffset).split("\n");
403
+ var startLine = data.start.line - (before.length - 1);
404
+ var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);
405
+
406
+ var text = doc.getLine(startLine).slice(start.ch);
407
+ for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)
408
+ text += "\n" + doc.getLine(cur);
409
+ if (text.slice(0, data.context.length) == data.context) return data;
410
+
411
+ var cursor = doc.getSearchCursor(data.context, 0, false);
412
+ var nearest, nearestDist = Infinity;
413
+ while (cursor.findNext()) {
414
+ var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;
415
+ if (!dist) dist = Math.abs(from.ch - start.ch);
416
+ if (dist < nearestDist) { nearest = from; nearestDist = dist; }
417
+ }
418
+ if (!nearest) return null;
419
+
420
+ if (before.length == 1)
421
+ nearest.ch += before[0].length;
422
+ else
423
+ nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);
424
+ if (data.start.line == data.end.line)
425
+ var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));
426
+ else
427
+ var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);
428
+ return {start: nearest, end: end};
429
+ }
430
+
431
+ function atInterestingExpression(cm) {
432
+ var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos);
433
+ if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false;
434
+ return /\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));
435
+ }
436
+
437
+ // Variable renaming
438
+
439
+ function rename(ts, cm) {
440
+ var token = cm.getTokenAt(cm.getCursor());
441
+ if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable");
442
+ dialog(cm, "New name for " + token.string, function(newName) {
443
+ ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) {
444
+ if (error) return showError(ts, cm, error);
445
+ applyChanges(ts, data.changes);
446
+ });
447
+ });
448
+ }
449
+
450
+ function selectName(ts, cm) {
451
+ var name = findDoc(ts, cm.doc).name;
452
+ ts.request(cm, {type: "refs"}, function(error, data) {
453
+ if (error) return showError(ts, cm, error);
454
+ var ranges = [], cur = 0;
455
+ for (var i = 0; i < data.refs.length; i++) {
456
+ var ref = data.refs[i];
457
+ if (ref.file == name) {
458
+ ranges.push({anchor: ref.start, head: ref.end});
459
+ if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0)
460
+ cur = ranges.length - 1;
461
+ }
462
+ }
463
+ cm.setSelections(ranges, cur);
464
+ });
465
+ }
466
+
467
+ var nextChangeOrig = 0;
468
+ function applyChanges(ts, changes) {
469
+ var perFile = Object.create(null);
470
+ for (var i = 0; i < changes.length; ++i) {
471
+ var ch = changes[i];
472
+ (perFile[ch.file] || (perFile[ch.file] = [])).push(ch);
473
+ }
474
+ for (var file in perFile) {
475
+ var known = ts.docs[file], chs = perFile[file];;
476
+ if (!known) continue;
477
+ chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
478
+ var origin = "*rename" + (++nextChangeOrig);
479
+ for (var i = 0; i < chs.length; ++i) {
480
+ var ch = chs[i];
481
+ known.doc.replaceRange(ch.text, ch.start, ch.end, origin);
482
+ }
483
+ }
484
+ }
485
+
486
+ // Generic request-building helper
487
+
488
+ function buildRequest(ts, doc, query, pos) {
489
+ var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
490
+ if (!allowFragments) delete query.fullDocs;
491
+ if (typeof query == "string") query = {type: query};
492
+ query.lineCharPositions = true;
493
+ if (query.end == null) {
494
+ query.end = pos || doc.doc.getCursor("end");
495
+ if (doc.doc.somethingSelected())
496
+ query.start = doc.doc.getCursor("start");
497
+ }
498
+ var startPos = query.start || query.end;
499
+
500
+ if (doc.changed) {
501
+ if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&
502
+ doc.changed.to - doc.changed.from < 100 &&
503
+ doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
504
+ files.push(getFragmentAround(doc, startPos, query.end));
505
+ query.file = "#0";
506
+ var offsetLines = files[0].offsetLines;
507
+ if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
508
+ query.end = Pos(query.end.line - offsetLines, query.end.ch);
509
+ } else {
510
+ files.push({type: "full",
511
+ name: doc.name,
512
+ text: docValue(ts, doc)});
513
+ query.file = doc.name;
514
+ doc.changed = null;
515
+ }
516
+ } else {
517
+ query.file = doc.name;
518
+ }
519
+ for (var name in ts.docs) {
520
+ var cur = ts.docs[name];
521
+ if (cur.changed && cur != doc) {
522
+ files.push({type: "full", name: cur.name, text: docValue(ts, cur)});
523
+ cur.changed = null;
524
+ }
525
+ }
526
+
527
+ return {query: query, files: files};
528
+ }
529
+
530
+ function getFragmentAround(data, start, end) {
531
+ var doc = data.doc;
532
+ var minIndent = null, minLine = null, endLine, tabSize = 4;
533
+ for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
534
+ var line = doc.getLine(p), fn = line.search(/\bfunction\b/);
535
+ if (fn < 0) continue;
536
+ var indent = CodeMirror.countColumn(line, null, tabSize);
537
+ if (minIndent != null && minIndent <= indent) continue;
538
+ minIndent = indent;
539
+ minLine = p;
540
+ }
541
+ if (minLine == null) minLine = min;
542
+ var max = Math.min(doc.lastLine(), end.line + 20);
543
+ if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))
544
+ endLine = max;
545
+ else for (endLine = end.line + 1; endLine < max; ++endLine) {
546
+ var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
547
+ if (indent <= minIndent) break;
548
+ }
549
+ var from = Pos(minLine, 0);
550
+
551
+ return {type: "part",
552
+ name: data.name,
553
+ offsetLines: from.line,
554
+ text: doc.getRange(from, Pos(endLine, 0))};
555
+ }
556
+
557
+ // Generic utilities
558
+
559
+ var cmpPos = CodeMirror.cmpPos;
560
+
561
+ function elt(tagname, cls /*, ... elts*/) {
562
+ var e = document.createElement(tagname);
563
+ if (cls) e.className = cls;
564
+ for (var i = 2; i < arguments.length; ++i) {
565
+ var elt = arguments[i];
566
+ if (typeof elt == "string") elt = document.createTextNode(elt);
567
+ e.appendChild(elt);
568
+ }
569
+ return e;
570
+ }
571
+
572
+ function dialog(cm, text, f) {
573
+ if (cm.openDialog)
574
+ cm.openDialog(text + ": <input type=text>", f);
575
+ else
576
+ f(prompt(text, ""));
577
+ }
578
+
579
+ // Tooltips
580
+
581
+ function tempTooltip(cm, content) {
582
+ var where = cm.cursorCoords();
583
+ var tip = makeTooltip(where.right + 1, where.bottom, content);
584
+ function clear() {
585
+ if (!tip.parentNode) return;
586
+ cm.off("cursorActivity", clear);
587
+ fadeOut(tip);
588
+ }
589
+ setTimeout(clear, 1700);
590
+ cm.on("cursorActivity", clear);
591
+ }
592
+
593
+ function makeTooltip(x, y, content) {
594
+ var node = elt("div", cls + "tooltip", content);
595
+ node.style.left = x + "px";
596
+ node.style.top = y + "px";
597
+ document.body.appendChild(node);
598
+ return node;
599
+ }
600
+
601
+ function remove(node) {
602
+ var p = node && node.parentNode;
603
+ if (p) p.removeChild(node);
604
+ }
605
+
606
+ function fadeOut(tooltip) {
607
+ tooltip.style.opacity = "0";
608
+ setTimeout(function() { remove(tooltip); }, 1100);
609
+ }
610
+
611
+ function showError(ts, cm, msg) {
612
+ if (ts.options.showError)
613
+ ts.options.showError(cm, msg);
614
+ else
615
+ tempTooltip(cm, String(msg));
616
+ }
617
+
618
+ function closeArgHints(ts) {
619
+ if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; }
620
+ }
621
+
622
+ function docValue(ts, doc) {
623
+ var val = doc.doc.getValue();
624
+ if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);
625
+ return val;
626
+ }
627
+
628
+ // Worker wrapper
629
+
630
+ function WorkerServer(ts) {
631
+ var worker = new Worker(ts.options.workerScript);
632
+ worker.postMessage({type: "init",
633
+ defs: ts.options.defs,
634
+ plugins: ts.options.plugins,
635
+ scripts: ts.options.workerDeps});
636
+ var msgId = 0, pending = {};
637
+
638
+ function send(data, c) {
639
+ if (c) {
640
+ data.id = ++msgId;
641
+ pending[msgId] = c;
642
+ }
643
+ worker.postMessage(data);
644
+ }
645
+ worker.onmessage = function(e) {
646
+ var data = e.data;
647
+ if (data.type == "getFile") {
648
+ getFile(ts, data.name, function(err, text) {
649
+ send({type: "getFile", err: String(err), text: text, id: data.id});
650
+ });
651
+ } else if (data.type == "debug") {
652
+ window.console.log(data.message);
653
+ } else if (data.id && pending[data.id]) {
654
+ pending[data.id](data.err, data.body);
655
+ delete pending[data.id];
656
+ }
657
+ };
658
+ worker.onerror = function(e) {
659
+ for (var id in pending) pending[id](e);
660
+ pending = {};
661
+ };
662
+
663
+ this.addFile = function(name, text) { send({type: "add", name: name, text: text}); };
664
+ this.delFile = function(name) { send({type: "del", name: name}); };
665
+ this.request = function(body, c) { send({type: "req", body: body}, c); };
666
+ }
667
+ });
resources/js/codemirror/addon/tern/worker.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // declare global: tern, server
5
+
6
+ var server;
7
+
8
+ this.onmessage = function(e) {
9
+ var data = e.data;
10
+ switch (data.type) {
11
+ case "init": return startServer(data.defs, data.plugins, data.scripts);
12
+ case "add": return server.addFile(data.name, data.text);
13
+ case "del": return server.delFile(data.name);
14
+ case "req": return server.request(data.body, function(err, reqData) {
15
+ postMessage({id: data.id, body: reqData, err: err && String(err)});
16
+ });
17
+ case "getFile":
18
+ var c = pending[data.id];
19
+ delete pending[data.id];
20
+ return c(data.err, data.text);
21
+ default: throw new Error("Unknown message type: " + data.type);
22
+ }
23
+ };
24
+
25
+ var nextId = 0, pending = {};
26
+ function getFile(file, c) {
27
+ postMessage({type: "getFile", name: file, id: ++nextId});
28
+ pending[nextId] = c;
29
+ }
30
+
31
+ function startServer(defs, plugins, scripts) {
32
+ if (scripts) importScripts.apply(null, scripts);
33
+
34
+ server = new tern.Server({
35
+ getFile: getFile,
36
+ async: true,
37
+ defs: defs,
38
+ plugins: plugins
39
+ });
40
+ }
41
+
42
+ var console = {
43
+ log: function(v) { postMessage({type: "debug", message: v}); }
44
+ };
resources/js/codemirror/addon/wrap/hardwrap.js ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var Pos = CodeMirror.Pos;
15
+
16
+ function findParagraph(cm, pos, options) {
17
+ var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
18
+ for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
19
+ var line = cm.getLine(start);
20
+ if (startRE && startRE.test(line)) break;
21
+ if (!/\S/.test(line)) { ++start; break; }
22
+ }
23
+ var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
24
+ for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
25
+ var line = cm.getLine(end);
26
+ if (endRE && endRE.test(line)) { ++end; break; }
27
+ if (!/\S/.test(line)) break;
28
+ }
29
+ return {from: start, to: end};
30
+ }
31
+
32
+ function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
33
+ for (var at = column; at > 0; --at)
34
+ if (wrapOn.test(text.slice(at - 1, at + 1))) break;
35
+ if (at == 0) at = column;
36
+ var endOfText = at;
37
+ if (killTrailingSpace)
38
+ while (text.charAt(endOfText - 1) == " ") --endOfText;
39
+ return {from: endOfText, to: at};
40
+ }
41
+
42
+ function wrapRange(cm, from, to, options) {
43
+ from = cm.clipPos(from); to = cm.clipPos(to);
44
+ var column = options.column || 80;
45
+ var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
46
+ var killTrailing = options.killTrailingSpace !== false;
47
+ var changes = [], curLine = "", curNo = from.line;
48
+ var lines = cm.getRange(from, to, false);
49
+ if (!lines.length) return null;
50
+ var leadingSpace = lines[0].match(/^[ \t]*/)[0];
51
+
52
+ for (var i = 0; i < lines.length; ++i) {
53
+ var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
54
+ if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
55
+ curLine += " ";
56
+ spaceInserted = 1;
57
+ }
58
+ var spaceTrimmed = "";
59
+ if (i) {
60
+ spaceTrimmed = text.match(/^\s*/)[0];
61
+ text = text.slice(spaceTrimmed.length);
62
+ }
63
+ curLine += text;
64
+ if (i) {
65
+ var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
66
+ findBreakPoint(curLine, column, wrapOn, killTrailing);
67
+ // If this isn't broken, or is broken at a different point, remove old break
68
+ if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
69
+ changes.push({text: [spaceInserted ? " " : ""],
70
+ from: Pos(curNo, oldLen),
71
+ to: Pos(curNo + 1, spaceTrimmed.length)});
72
+ } else {
73
+ curLine = leadingSpace + text;
74
+ ++curNo;
75
+ }
76
+ }
77
+ while (curLine.length > column) {
78
+ var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
79
+ changes.push({text: ["", leadingSpace],
80
+ from: Pos(curNo, bp.from),
81
+ to: Pos(curNo, bp.to)});
82
+ curLine = leadingSpace + curLine.slice(bp.to);
83
+ ++curNo;
84
+ }
85
+ }
86
+ if (changes.length) cm.operation(function() {
87
+ for (var i = 0; i < changes.length; ++i) {
88
+ var change = changes[i];
89
+ cm.replaceRange(change.text, change.from, change.to);
90
+ }
91
+ });
92
+ return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;
93
+ }
94
+
95
+ CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
96
+ options = options || {};
97
+ if (!pos) pos = this.getCursor();
98
+ var para = findParagraph(this, pos, options);
99
+ return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
100
+ });
101
+
102
+ CodeMirror.commands.wrapLines = function(cm) {
103
+ cm.operation(function() {
104
+ var ranges = cm.listSelections(), at = cm.lastLine() + 1;
105
+ for (var i = ranges.length - 1; i >= 0; i--) {
106
+ var range = ranges[i], span;
107
+ if (range.empty()) {
108
+ var para = findParagraph(cm, range.head, {});
109
+ span = {from: Pos(para.from, 0), to: Pos(para.to - 1)};
110
+ } else {
111
+ span = {from: range.from(), to: range.to()};
112
+ }
113
+ if (span.to.line >= at) continue;
114
+ at = span.from.line;
115
+ wrapRange(cm, span.from, span.to, {});
116
+ }
117
+ });
118
+ };
119
+
120
+ CodeMirror.defineExtension("wrapRange", function(from, to, options) {
121
+ return wrapRange(this, from, to, options || {});
122
+ });
123
+
124
+ CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
125
+ options = options || {};
126
+ var cm = this, paras = [];
127
+ for (var line = from.line; line <= to.line;) {
128
+ var para = findParagraph(cm, Pos(line, 0), options);
129
+ paras.push(para);
130
+ line = para.to;
131
+ }
132
+ var madeChange = false;
133
+ if (paras.length) cm.operation(function() {
134
+ for (var i = paras.length - 1; i >= 0; --i)
135
+ madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
136
+ });
137
+ return madeChange;
138
+ });
139
+ });
resources/js/codemirror/lib/codemirror.js ADDED
@@ -0,0 +1,7601 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // This is CodeMirror (http://codemirror.net), a code editor
5
+ // implemented in JavaScript on top of the browser's DOM.
6
+ //
7
+ // You can find some technical background for some of the code below
8
+ // at http://marijnhaverbeke.nl/blog/#cm-internals .
9
+
10
+ (function(mod) {
11
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
12
+ module.exports = mod();
13
+ else if (typeof define == "function" && define.amd) // AMD
14
+ return define([], mod);
15
+ else // Plain browser env
16
+ this.CodeMirror = mod();
17
+ })(function() {
18
+ "use strict";
19
+
20
+ // BROWSER SNIFFING
21
+
22
+ // Kludges for bugs and behavior differences that can't be feature
23
+ // detected are enabled based on userAgent etc sniffing.
24
+
25
+ var gecko = /gecko\/\d/i.test(navigator.userAgent);
26
+ // ie_uptoN means Internet Explorer version N or lower
27
+ var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
28
+ var ie_upto7 = ie_upto10 && (document.documentMode == null || document.documentMode < 8);
29
+ var ie_upto8 = ie_upto10 && (document.documentMode == null || document.documentMode < 9);
30
+ var ie_upto9 = ie_upto10 && (document.documentMode == null || document.documentMode < 10);
31
+ var ie_11up = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
32
+ var ie = ie_upto10 || ie_11up;
33
+ var webkit = /WebKit\//.test(navigator.userAgent);
34
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
35
+ var chrome = /Chrome\//.test(navigator.userAgent);
36
+ var presto = /Opera\//.test(navigator.userAgent);
37
+ var safari = /Apple Computer/.test(navigator.vendor);
38
+ var khtml = /KHTML\//.test(navigator.userAgent);
39
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
40
+ var phantom = /PhantomJS/.test(navigator.userAgent);
41
+
42
+ var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
43
+ // This is woefully incomplete. Suggestions for alternative methods welcome.
44
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
45
+ var mac = ios || /Mac/.test(navigator.platform);
46
+ var windows = /win/i.test(navigator.platform);
47
+
48
+ var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
49
+ if (presto_version) presto_version = Number(presto_version[1]);
50
+ if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
51
+ // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
52
+ var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
53
+ var captureRightClick = gecko || (ie && !ie_upto8);
54
+
55
+ // Optimize some code when these features are not used.
56
+ var sawReadOnlySpans = false, sawCollapsedSpans = false;
57
+
58
+ // EDITOR CONSTRUCTOR
59
+
60
+ // A CodeMirror instance represents an editor. This is the object
61
+ // that user code is usually dealing with.
62
+
63
+ function CodeMirror(place, options) {
64
+ if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
65
+
66
+ this.options = options = options || {};
67
+ // Determine effective options based on given values and defaults.
68
+ copyObj(defaults, options, false);
69
+ setGuttersForLineNumbers(options);
70
+
71
+ var doc = options.value;
72
+ if (typeof doc == "string") doc = new Doc(doc, options.mode);
73
+ this.doc = doc;
74
+
75
+ var display = this.display = new Display(place, doc);
76
+ display.wrapper.CodeMirror = this;
77
+ updateGutters(this);
78
+ themeChanged(this);
79
+ if (options.lineWrapping)
80
+ this.display.wrapper.className += " CodeMirror-wrap";
81
+ if (options.autofocus && !mobile) focusInput(this);
82
+
83
+ this.state = {
84
+ keyMaps: [], // stores maps added by addKeyMap
85
+ overlays: [], // highlighting overlays, as added by addOverlay
86
+ modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
87
+ overwrite: false, focused: false,
88
+ suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
89
+ pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
90
+ draggingText: false,
91
+ highlight: new Delayed() // stores highlight worker timeout
92
+ };
93
+
94
+ // Override magic textarea content restore that IE sometimes does
95
+ // on our hidden textarea on reload
96
+ if (ie_upto10) setTimeout(bind(resetInput, this, true), 20);
97
+
98
+ registerEventHandlers(this);
99
+ ensureGlobalHandlers();
100
+
101
+ var cm = this;
102
+ runInOp(this, function() {
103
+ cm.curOp.forceUpdate = true;
104
+ attachDoc(cm, doc);
105
+
106
+ if ((options.autofocus && !mobile) || activeElt() == display.input)
107
+ setTimeout(bind(onFocus, cm), 20);
108
+ else
109
+ onBlur(cm);
110
+
111
+ for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
112
+ optionHandlers[opt](cm, options[opt], Init);
113
+ for (var i = 0; i < initHooks.length; ++i) initHooks[i](cm);
114
+ });
115
+ }
116
+
117
+ // DISPLAY CONSTRUCTOR
118
+
119
+ // The display handles the DOM integration, both for input reading
120
+ // and content drawing. It holds references to DOM nodes and
121
+ // display-related state.
122
+
123
+ function Display(place, doc) {
124
+ var d = this;
125
+
126
+ // The semihidden textarea that is focused when the editor is
127
+ // focused, and receives input.
128
+ var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
129
+ // The textarea is kept positioned near the cursor to prevent the
130
+ // fact that it'll be scrolled into view on input from scrolling
131
+ // our fake cursor out of view. On webkit, when wrap=off, paste is
132
+ // very slow. So make the area wide instead.
133
+ if (webkit) input.style.width = "1000px";
134
+ else input.setAttribute("wrap", "off");
135
+ // If border: 0; -- iOS fails to open keyboard (issue #1287)
136
+ if (ios) input.style.border = "1px solid black";
137
+ input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
138
+
139
+ // Wraps and hides input textarea
140
+ d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
141
+ // The fake scrollbar elements.
142
+ d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
143
+ d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
144
+ // Covers bottom-right square when both scrollbars are present.
145
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
146
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
147
+ // and h scrollbar is present.
148
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
149
+ // Will contain the actual code, positioned to cover the viewport.
150
+ d.lineDiv = elt("div", null, "CodeMirror-code");
151
+ // Elements are added to these to represent selection and cursors.
152
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
153
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors");
154
+ // A visibility: hidden element used to find the size of things.
155
+ d.measure = elt("div", null, "CodeMirror-measure");
156
+ // When lines outside of the viewport are measured, they are drawn in this.
157
+ d.lineMeasure = elt("div", null, "CodeMirror-measure");
158
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
159
+ d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
160
+ null, "position: relative; outline: none");
161
+ // Moved around its parent to cover visible view.
162
+ d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
163
+ // Set to the height of the document, allowing scrolling.
164
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
165
+ // Behavior of elts with overflow: auto and padding is
166
+ // inconsistent across browsers. This is used to ensure the
167
+ // scrollable area is big enough.
168
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
169
+ // Will contain the gutters, if any.
170
+ d.gutters = elt("div", null, "CodeMirror-gutters");
171
+ d.lineGutter = null;
172
+ // Actual scrollable element.
173
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
174
+ d.scroller.setAttribute("tabIndex", "-1");
175
+ // The element in which the editor lives.
176
+ d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
177
+ d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
178
+
179
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
180
+ if (ie_upto7) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
181
+ // Needed to hide big blue blinking cursor on Mobile Safari
182
+ if (ios) input.style.width = "0px";
183
+ if (!webkit) d.scroller.draggable = true;
184
+ // Needed to handle Tab key in KHTML
185
+ if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
186
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
187
+ if (ie_upto7) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
188
+
189
+ if (place.appendChild) place.appendChild(d.wrapper);
190
+ else place(d.wrapper);
191
+
192
+ // Current rendered range (may be bigger than the view window).
193
+ d.viewFrom = d.viewTo = doc.first;
194
+ // Information about the rendered lines.
195
+ d.view = [];
196
+ // Holds info about a single rendered line when it was rendered
197
+ // for measurement, while not in view.
198
+ d.externalMeasured = null;
199
+ // Empty space (in pixels) above the view
200
+ d.viewOffset = 0;
201
+ d.lastSizeC = 0;
202
+ d.updateLineNumbers = null;
203
+
204
+ // Used to only resize the line number gutter when necessary (when
205
+ // the amount of lines crosses a boundary that makes its width change)
206
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
207
+ // See readInput and resetInput
208
+ d.prevInput = "";
209
+ // Set to true when a non-horizontal-scrolling line widget is
210
+ // added. As an optimization, line widget aligning is skipped when
211
+ // this is false.
212
+ d.alignWidgets = false;
213
+ // Flag that indicates whether we expect input to appear real soon
214
+ // now (after some event like 'keypress' or 'input') and are
215
+ // polling intensively.
216
+ d.pollingFast = false;
217
+ // Self-resetting timeout for the poller
218
+ d.poll = new Delayed();
219
+
220
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
221
+
222
+ // Tracks when resetInput has punted to just putting a short
223
+ // string into the textarea instead of the full selection.
224
+ d.inaccurateSelection = false;
225
+
226
+ // Tracks the maximum line length so that the horizontal scrollbar
227
+ // can be kept static when scrolling.
228
+ d.maxLine = null;
229
+ d.maxLineLength = 0;
230
+ d.maxLineChanged = false;
231
+
232
+ // Used for measuring wheel scrolling granularity
233
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
234
+
235
+ // True when shift is held down.
236
+ d.shift = false;
237
+
238
+ // Used to track whether anything happened since the context menu
239
+ // was opened.
240
+ d.selForContextMenu = null;
241
+ }
242
+
243
+ // STATE UPDATES
244
+
245
+ // Used to get the editor into a consistent state again when options change.
246
+
247
+ function loadMode(cm) {
248
+ cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
249
+ resetModeState(cm);
250
+ }
251
+
252
+ function resetModeState(cm) {
253
+ cm.doc.iter(function(line) {
254
+ if (line.stateAfter) line.stateAfter = null;
255
+ if (line.styles) line.styles = null;
256
+ });
257
+ cm.doc.frontier = cm.doc.first;
258
+ startWorker(cm, 100);
259
+ cm.state.modeGen++;
260
+ if (cm.curOp) regChange(cm);
261
+ }
262
+
263
+ function wrappingChanged(cm) {
264
+ if (cm.options.lineWrapping) {
265
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
266
+ cm.display.sizer.style.minWidth = "";
267
+ } else {
268
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
269
+ findMaxLine(cm);
270
+ }
271
+ estimateLineHeights(cm);
272
+ regChange(cm);
273
+ clearCaches(cm);
274
+ setTimeout(function(){updateScrollbars(cm);}, 100);
275
+ }
276
+
277
+ // Returns a function that estimates the height of a line, to use as
278
+ // first approximation until the line becomes visible (and is thus
279
+ // properly measurable).
280
+ function estimateHeight(cm) {
281
+ var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
282
+ var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
283
+ return function(line) {
284
+ if (lineIsHidden(cm.doc, line)) return 0;
285
+
286
+ var widgetsHeight = 0;
287
+ if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
288
+ if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
289
+ }
290
+
291
+ if (wrapping)
292
+ return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
293
+ else
294
+ return widgetsHeight + th;
295
+ };
296
+ }
297
+
298
+ function estimateLineHeights(cm) {
299
+ var doc = cm.doc, est = estimateHeight(cm);
300
+ doc.iter(function(line) {
301
+ var estHeight = est(line);
302
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
303
+ });
304
+ }
305
+
306
+ function keyMapChanged(cm) {
307
+ var map = keyMap[cm.options.keyMap], style = map.style;
308
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
309
+ (style ? " cm-keymap-" + style : "");
310
+ }
311
+
312
+ function themeChanged(cm) {
313
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
314
+ cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
315
+ clearCaches(cm);
316
+ }
317
+
318
+ function guttersChanged(cm) {
319
+ updateGutters(cm);
320
+ regChange(cm);
321
+ setTimeout(function(){alignHorizontally(cm);}, 20);
322
+ }
323
+
324
+ // Rebuild the gutter elements, ensure the margin to the left of the
325
+ // code matches their width.
326
+ function updateGutters(cm) {
327
+ var gutters = cm.display.gutters, specs = cm.options.gutters;
328
+ removeChildren(gutters);
329
+ for (var i = 0; i < specs.length; ++i) {
330
+ var gutterClass = specs[i];
331
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
332
+ if (gutterClass == "CodeMirror-linenumbers") {
333
+ cm.display.lineGutter = gElt;
334
+ gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
335
+ }
336
+ }
337
+ gutters.style.display = i ? "" : "none";
338
+ updateGutterSpace(cm);
339
+ }
340
+
341
+ function updateGutterSpace(cm) {
342
+ var width = cm.display.gutters.offsetWidth;
343
+ cm.display.sizer.style.marginLeft = width + "px";
344
+ cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
345
+ }
346
+
347
+ // Compute the character length of a line, taking into account
348
+ // collapsed ranges (see markText) that might hide parts, and join
349
+ // other lines onto it.
350
+ function lineLength(line) {
351
+ if (line.height == 0) return 0;
352
+ var len = line.text.length, merged, cur = line;
353
+ while (merged = collapsedSpanAtStart(cur)) {
354
+ var found = merged.find(0, true);
355
+ cur = found.from.line;
356
+ len += found.from.ch - found.to.ch;
357
+ }
358
+ cur = line;
359
+ while (merged = collapsedSpanAtEnd(cur)) {
360
+ var found = merged.find(0, true);
361
+ len -= cur.text.length - found.from.ch;
362
+ cur = found.to.line;
363
+ len += cur.text.length - found.to.ch;
364
+ }
365
+ return len;
366
+ }
367
+
368
+ // Find the longest line in the document.
369
+ function findMaxLine(cm) {
370
+ var d = cm.display, doc = cm.doc;
371
+ d.maxLine = getLine(doc, doc.first);
372
+ d.maxLineLength = lineLength(d.maxLine);
373
+ d.maxLineChanged = true;
374
+ doc.iter(function(line) {
375
+ var len = lineLength(line);
376
+ if (len > d.maxLineLength) {
377
+ d.maxLineLength = len;
378
+ d.maxLine = line;
379
+ }
380
+ });
381
+ }
382
+
383
+ // Make sure the gutters options contains the element
384
+ // "CodeMirror-linenumbers" when the lineNumbers option is true.
385
+ function setGuttersForLineNumbers(options) {
386
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers");
387
+ if (found == -1 && options.lineNumbers) {
388
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
389
+ } else if (found > -1 && !options.lineNumbers) {
390
+ options.gutters = options.gutters.slice(0);
391
+ options.gutters.splice(found, 1);
392
+ }
393
+ }
394
+
395
+ // SCROLLBARS
396
+
397
+ // Prepare DOM reads needed to update the scrollbars. Done in one
398
+ // shot to minimize update/measure roundtrips.
399
+ function measureForScrollbars(cm) {
400
+ var scroll = cm.display.scroller;
401
+ return {
402
+ clientHeight: scroll.clientHeight,
403
+ barHeight: cm.display.scrollbarV.clientHeight,
404
+ scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
405
+ barWidth: cm.display.scrollbarH.clientWidth,
406
+ docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
407
+ };
408
+ }
409
+
410
+ // Re-synchronize the fake scrollbars with the actual size of the
411
+ // content.
412
+ function updateScrollbars(cm, measure) {
413
+ if (!measure) measure = measureForScrollbars(cm);
414
+ var d = cm.display;
415
+ var scrollHeight = measure.docHeight + scrollerCutOff;
416
+ var needsH = measure.scrollWidth > measure.clientWidth;
417
+ var needsV = scrollHeight > measure.clientHeight;
418
+ if (needsV) {
419
+ d.scrollbarV.style.display = "block";
420
+ d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
421
+ // A bug in IE8 can cause this value to be negative, so guard it.
422
+ d.scrollbarV.firstChild.style.height =
423
+ Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
424
+ } else {
425
+ d.scrollbarV.style.display = "";
426
+ d.scrollbarV.firstChild.style.height = "0";
427
+ }
428
+ if (needsH) {
429
+ d.scrollbarH.style.display = "block";
430
+ d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
431
+ d.scrollbarH.firstChild.style.width =
432
+ (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
433
+ } else {
434
+ d.scrollbarH.style.display = "";
435
+ d.scrollbarH.firstChild.style.width = "0";
436
+ }
437
+ if (needsH && needsV) {
438
+ d.scrollbarFiller.style.display = "block";
439
+ d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
440
+ } else d.scrollbarFiller.style.display = "";
441
+ if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
442
+ d.gutterFiller.style.display = "block";
443
+ d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px";
444
+ d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
445
+ } else d.gutterFiller.style.display = "";
446
+
447
+ if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
448
+ if (scrollbarWidth(d.measure) === 0) {
449
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
450
+ d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
451
+ var barMouseDown = function(e) {
452
+ if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
453
+ operation(cm, onMouseDown)(e);
454
+ };
455
+ on(d.scrollbarV, "mousedown", barMouseDown);
456
+ on(d.scrollbarH, "mousedown", barMouseDown);
457
+ }
458
+ cm.state.checkedOverlayScrollbar = true;
459
+ }
460
+ }
461
+
462
+ // Compute the lines that are visible in a given viewport (defaults
463
+ // the the current scroll position). viewPort may contain top,
464
+ // height, and ensure (see op.scrollToPos) properties.
465
+ function visibleLines(display, doc, viewPort) {
466
+ var top = viewPort && viewPort.top != null ? Math.max(0, viewPort.top) : display.scroller.scrollTop;
467
+ top = Math.floor(top - paddingTop(display));
468
+ var bottom = viewPort && viewPort.bottom != null ? viewPort.bottom : top + display.wrapper.clientHeight;
469
+
470
+ var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
471
+ // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
472
+ // forces those lines into the viewport (if possible).
473
+ if (viewPort && viewPort.ensure) {
474
+ var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.line;
475
+ if (ensureFrom < from)
476
+ return {from: ensureFrom,
477
+ to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
478
+ if (Math.min(ensureTo, doc.lastLine()) >= to)
479
+ return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
480
+ to: ensureTo};
481
+ }
482
+ return {from: from, to: Math.max(to, from + 1)};
483
+ }
484
+
485
+ // LINE NUMBERS
486
+
487
+ // Re-align line numbers and gutter marks to compensate for
488
+ // horizontal scrolling.
489
+ function alignHorizontally(cm) {
490
+ var display = cm.display, view = display.view;
491
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
492
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
493
+ var gutterW = display.gutters.offsetWidth, left = comp + "px";
494
+ for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
495
+ if (cm.options.fixedGutter && view[i].gutter)
496
+ view[i].gutter.style.left = left;
497
+ var align = view[i].alignable;
498
+ if (align) for (var j = 0; j < align.length; j++)
499
+ align[j].style.left = left;
500
+ }
501
+ if (cm.options.fixedGutter)
502
+ display.gutters.style.left = (comp + gutterW) + "px";
503
+ }
504
+
505
+ // Used to ensure that the line number gutter is still the right
506
+ // size for the current document size. Returns true when an update
507
+ // is needed.
508
+ function maybeUpdateLineNumberWidth(cm) {
509
+ if (!cm.options.lineNumbers) return false;
510
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
511
+ if (last.length != display.lineNumChars) {
512
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
513
+ "CodeMirror-linenumber CodeMirror-gutter-elt"));
514
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
515
+ display.lineGutter.style.width = "";
516
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
517
+ display.lineNumWidth = display.lineNumInnerWidth + padding;
518
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
519
+ display.lineGutter.style.width = display.lineNumWidth + "px";
520
+ updateGutterSpace(cm);
521
+ return true;
522
+ }
523
+ return false;
524
+ }
525
+
526
+ function lineNumberFor(options, i) {
527
+ return String(options.lineNumberFormatter(i + options.firstLineNumber));
528
+ }
529
+
530
+ // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
531
+ // but using getBoundingClientRect to get a sub-pixel-accurate
532
+ // result.
533
+ function compensateForHScroll(display) {
534
+ return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
535
+ }
536
+
537
+ // DISPLAY DRAWING
538
+
539
+ // Updates the display, selection, and scrollbars, using the
540
+ // information in display.view to find out which nodes are no longer
541
+ // up-to-date. Tries to bail out early when no changes are needed,
542
+ // unless forced is true.
543
+ // Returns true if an actual update happened, false otherwise.
544
+ function updateDisplay(cm, viewPort, forced) {
545
+ var oldFrom = cm.display.viewFrom, oldTo = cm.display.viewTo, updated;
546
+ var visible = visibleLines(cm.display, cm.doc, viewPort);
547
+ for (var first = true;; first = false) {
548
+ var oldWidth = cm.display.scroller.clientWidth;
549
+ if (!updateDisplayInner(cm, visible, forced)) break;
550
+ updated = true;
551
+
552
+ // If the max line changed since it was last measured, measure it,
553
+ // and ensure the document's width matches it.
554
+ if (cm.display.maxLineChanged && !cm.options.lineWrapping)
555
+ adjustContentWidth(cm);
556
+
557
+ var barMeasure = measureForScrollbars(cm);
558
+ updateSelection(cm);
559
+ setDocumentHeight(cm, barMeasure);
560
+ updateScrollbars(cm, barMeasure);
561
+ if (webkit && cm.options.lineWrapping)
562
+ checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420)
563
+ if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
564
+ forced = true;
565
+ continue;
566
+ }
567
+ forced = false;
568
+
569
+ // Clip forced viewport to actual scrollable area.
570
+ if (viewPort && viewPort.top != null)
571
+ viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMeasure.clientHeight, viewPort.top)};
572
+ // Updated line heights might result in the drawn area not
573
+ // actually covering the viewport. Keep looping until it does.
574
+ visible = visibleLines(cm.display, cm.doc, viewPort);
575
+ if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo)
576
+ break;
577
+ }
578
+
579
+ cm.display.updateLineNumbers = null;
580
+ if (updated) {
581
+ signalLater(cm, "update", cm);
582
+ if (cm.display.viewFrom != oldFrom || cm.display.viewTo != oldTo)
583
+ signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
584
+ }
585
+ return updated;
586
+ }
587
+
588
+ // Does the actual updating of the line display. Bails out
589
+ // (returning false) when there is nothing to be done and forced is
590
+ // false.
591
+ function updateDisplayInner(cm, visible, forced) {
592
+ var display = cm.display, doc = cm.doc;
593
+ if (!display.wrapper.offsetWidth) {
594
+ resetView(cm);
595
+ return;
596
+ }
597
+
598
+ // Bail out if the visible area is already rendered and nothing changed.
599
+ if (!forced && visible.from >= display.viewFrom && visible.to <= display.viewTo &&
600
+ countDirtyView(cm) == 0)
601
+ return;
602
+
603
+ if (maybeUpdateLineNumberWidth(cm))
604
+ resetView(cm);
605
+ var dims = getDimensions(cm);
606
+
607
+ // Compute a suitable new viewport (from & to)
608
+ var end = doc.first + doc.size;
609
+ var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
610
+ var to = Math.min(end, visible.to + cm.options.viewportMargin);
611
+ if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
612
+ if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
613
+ if (sawCollapsedSpans) {
614
+ from = visualLineNo(cm.doc, from);
615
+ to = visualLineEndNo(cm.doc, to);
616
+ }
617
+
618
+ var different = from != display.viewFrom || to != display.viewTo ||
619
+ display.lastSizeC != display.wrapper.clientHeight;
620
+ adjustView(cm, from, to);
621
+
622
+ display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
623
+ // Position the mover div to align with the current scroll position
624
+ cm.display.mover.style.top = display.viewOffset + "px";
625
+
626
+ var toUpdate = countDirtyView(cm);
627
+ if (!different && toUpdate == 0 && !forced) return;
628
+
629
+ // For big changes, we hide the enclosing element during the
630
+ // update, since that speeds up the operations on most browsers.
631
+ var focused = activeElt();
632
+ if (toUpdate > 4) display.lineDiv.style.display = "none";
633
+ patchDisplay(cm, display.updateLineNumbers, dims);
634
+ if (toUpdate > 4) display.lineDiv.style.display = "";
635
+ // There might have been a widget with a focused element that got
636
+ // hidden or updated, if so re-focus it.
637
+ if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
638
+
639
+ // Prevent selection and cursors from interfering with the scroll
640
+ // width.
641
+ removeChildren(display.cursorDiv);
642
+ removeChildren(display.selectionDiv);
643
+
644
+ if (different) {
645
+ display.lastSizeC = display.wrapper.clientHeight;
646
+ startWorker(cm, 400);
647
+ }
648
+
649
+ updateHeightsInViewport(cm);
650
+
651
+ return true;
652
+ }
653
+
654
+ function adjustContentWidth(cm) {
655
+ var display = cm.display;
656
+ var width = measureChar(cm, display.maxLine, display.maxLine.text.length).left;
657
+ display.maxLineChanged = false;
658
+ var minWidth = Math.max(0, width + 3);
659
+ var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + minWidth + scrollerCutOff - display.scroller.clientWidth);
660
+ display.sizer.style.minWidth = minWidth + "px";
661
+ if (maxScrollLeft < cm.doc.scrollLeft)
662
+ setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
663
+ }
664
+
665
+ function setDocumentHeight(cm, measure) {
666
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
667
+ cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
668
+ }
669
+
670
+ function checkForWebkitWidthBug(cm, measure) {
671
+ // Work around Webkit bug where it sometimes reserves space for a
672
+ // non-existing phantom scrollbar in the scroller (Issue #2420)
673
+ if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
674
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
675
+ cm.display.gutters.style.height = measure.docHeight + "px";
676
+ }
677
+ }
678
+
679
+ // Read the actual heights of the rendered lines, and update their
680
+ // stored heights to match.
681
+ function updateHeightsInViewport(cm) {
682
+ var display = cm.display;
683
+ var prevBottom = display.lineDiv.offsetTop;
684
+ for (var i = 0; i < display.view.length; i++) {
685
+ var cur = display.view[i], height;
686
+ if (cur.hidden) continue;
687
+ if (ie_upto7) {
688
+ var bot = cur.node.offsetTop + cur.node.offsetHeight;
689
+ height = bot - prevBottom;
690
+ prevBottom = bot;
691
+ } else {
692
+ var box = cur.node.getBoundingClientRect();
693
+ height = box.bottom - box.top;
694
+ }
695
+ var diff = cur.line.height - height;
696
+ if (height < 2) height = textHeight(display);
697
+ if (diff > .001 || diff < -.001) {
698
+ updateLineHeight(cur.line, height);
699
+ updateWidgetHeight(cur.line);
700
+ if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
701
+ updateWidgetHeight(cur.rest[j]);
702
+ }
703
+ }
704
+ }
705
+
706
+ // Read and store the height of line widgets associated with the
707
+ // given line.
708
+ function updateWidgetHeight(line) {
709
+ if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
710
+ line.widgets[i].height = line.widgets[i].node.offsetHeight;
711
+ }
712
+
713
+ // Do a bulk-read of the DOM positions and sizes needed to draw the
714
+ // view, so that we don't interleave reading and writing to the DOM.
715
+ function getDimensions(cm) {
716
+ var d = cm.display, left = {}, width = {};
717
+ for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
718
+ left[cm.options.gutters[i]] = n.offsetLeft;
719
+ width[cm.options.gutters[i]] = n.offsetWidth;
720
+ }
721
+ return {fixedPos: compensateForHScroll(d),
722
+ gutterTotalWidth: d.gutters.offsetWidth,
723
+ gutterLeft: left,
724
+ gutterWidth: width,
725
+ wrapperWidth: d.wrapper.clientWidth};
726
+ }
727
+
728
+ // Sync the actual display DOM structure with display.view, removing
729
+ // nodes for lines that are no longer in view, and creating the ones
730
+ // that are not there yet, and updating the ones that are out of
731
+ // date.
732
+ function patchDisplay(cm, updateNumbersFrom, dims) {
733
+ var display = cm.display, lineNumbers = cm.options.lineNumbers;
734
+ var container = display.lineDiv, cur = container.firstChild;
735
+
736
+ function rm(node) {
737
+ var next = node.nextSibling;
738
+ // Works around a throw-scroll bug in OS X Webkit
739
+ if (webkit && mac && cm.display.currentWheelTarget == node)
740
+ node.style.display = "none";
741
+ else
742
+ node.parentNode.removeChild(node);
743
+ return next;
744
+ }
745
+
746
+ var view = display.view, lineN = display.viewFrom;
747
+ // Loop over the elements in the view, syncing cur (the DOM nodes
748
+ // in display.lineDiv) with the view as we go.
749
+ for (var i = 0; i < view.length; i++) {
750
+ var lineView = view[i];
751
+ if (lineView.hidden) {
752
+ } else if (!lineView.node) { // Not drawn yet
753
+ var node = buildLineElement(cm, lineView, lineN, dims);
754
+ container.insertBefore(node, cur);
755
+ } else { // Already drawn
756
+ while (cur != lineView.node) cur = rm(cur);
757
+ var updateNumber = lineNumbers && updateNumbersFrom != null &&
758
+ updateNumbersFrom <= lineN && lineView.lineNumber;
759
+ if (lineView.changes) {
760
+ if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
761
+ updateLineForChanges(cm, lineView, lineN, dims);
762
+ }
763
+ if (updateNumber) {
764
+ removeChildren(lineView.lineNumber);
765
+ lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
766
+ }
767
+ cur = lineView.node.nextSibling;
768
+ }
769
+ lineN += lineView.size;
770
+ }
771
+ while (cur) cur = rm(cur);
772
+ }
773
+
774
+ // When an aspect of a line changes, a string is added to
775
+ // lineView.changes. This updates the relevant part of the line's
776
+ // DOM structure.
777
+ function updateLineForChanges(cm, lineView, lineN, dims) {
778
+ for (var j = 0; j < lineView.changes.length; j++) {
779
+ var type = lineView.changes[j];
780
+ if (type == "text") updateLineText(cm, lineView);
781
+ else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
782
+ else if (type == "class") updateLineClasses(lineView);
783
+ else if (type == "widget") updateLineWidgets(lineView, dims);
784
+ }
785
+ lineView.changes = null;
786
+ }
787
+
788
+ // Lines with gutter elements, widgets or a background class need to
789
+ // be wrapped, and have the extra elements added to the wrapper div
790
+ function ensureLineWrapped(lineView) {
791
+ if (lineView.node == lineView.text) {
792
+ lineView.node = elt("div", null, null, "position: relative");
793
+ if (lineView.text.parentNode)
794
+ lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
795
+ lineView.node.appendChild(lineView.text);
796
+ if (ie_upto7) lineView.node.style.zIndex = 2;
797
+ }
798
+ return lineView.node;
799
+ }
800
+
801
+ function updateLineBackground(lineView) {
802
+ var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
803
+ if (cls) cls += " CodeMirror-linebackground";
804
+ if (lineView.background) {
805
+ if (cls) lineView.background.className = cls;
806
+ else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
807
+ } else if (cls) {
808
+ var wrap = ensureLineWrapped(lineView);
809
+ lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
810
+ }
811
+ }
812
+
813
+ // Wrapper around buildLineContent which will reuse the structure
814
+ // in display.externalMeasured when possible.
815
+ function getLineContent(cm, lineView) {
816
+ var ext = cm.display.externalMeasured;
817
+ if (ext && ext.line == lineView.line) {
818
+ cm.display.externalMeasured = null;
819
+ lineView.measure = ext.measure;
820
+ return ext.built;
821
+ }
822
+ return buildLineContent(cm, lineView);
823
+ }
824
+
825
+ // Redraw the line's text. Interacts with the background and text
826
+ // classes because the mode may output tokens that influence these
827
+ // classes.
828
+ function updateLineText(cm, lineView) {
829
+ var cls = lineView.text.className;
830
+ var built = getLineContent(cm, lineView);
831
+ if (lineView.text == lineView.node) lineView.node = built.pre;
832
+ lineView.text.parentNode.replaceChild(built.pre, lineView.text);
833
+ lineView.text = built.pre;
834
+ if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
835
+ lineView.bgClass = built.bgClass;
836
+ lineView.textClass = built.textClass;
837
+ updateLineClasses(lineView);
838
+ } else if (cls) {
839
+ lineView.text.className = cls;
840
+ }
841
+ }
842
+
843
+ function updateLineClasses(lineView) {
844
+ updateLineBackground(lineView);
845
+ if (lineView.line.wrapClass)
846
+ ensureLineWrapped(lineView).className = lineView.line.wrapClass;
847
+ else if (lineView.node != lineView.text)
848
+ lineView.node.className = "";
849
+ var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
850
+ lineView.text.className = textClass || "";
851
+ }
852
+
853
+ function updateLineGutter(cm, lineView, lineN, dims) {
854
+ if (lineView.gutter) {
855
+ lineView.node.removeChild(lineView.gutter);
856
+ lineView.gutter = null;
857
+ }
858
+ var markers = lineView.line.gutterMarkers;
859
+ if (cm.options.lineNumbers || markers) {
860
+ var wrap = ensureLineWrapped(lineView);
861
+ var gutterWrap = lineView.gutter =
862
+ wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
863
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
864
+ lineView.text);
865
+ if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
866
+ lineView.lineNumber = gutterWrap.appendChild(
867
+ elt("div", lineNumberFor(cm.options, lineN),
868
+ "CodeMirror-linenumber CodeMirror-gutter-elt",
869
+ "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
870
+ + cm.display.lineNumInnerWidth + "px"));
871
+ if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
872
+ var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
873
+ if (found)
874
+ gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
875
+ dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
876
+ }
877
+ }
878
+ }
879
+
880
+ function updateLineWidgets(lineView, dims) {
881
+ if (lineView.alignable) lineView.alignable = null;
882
+ for (var node = lineView.node.firstChild, next; node; node = next) {
883
+ var next = node.nextSibling;
884
+ if (node.className == "CodeMirror-linewidget")
885
+ lineView.node.removeChild(node);
886
+ }
887
+ insertLineWidgets(lineView, dims);
888
+ }
889
+
890
+ // Build a line's DOM representation from scratch
891
+ function buildLineElement(cm, lineView, lineN, dims) {
892
+ var built = getLineContent(cm, lineView);
893
+ lineView.text = lineView.node = built.pre;
894
+ if (built.bgClass) lineView.bgClass = built.bgClass;
895
+ if (built.textClass) lineView.textClass = built.textClass;
896
+
897
+ updateLineClasses(lineView);
898
+ updateLineGutter(cm, lineView, lineN, dims);
899
+ insertLineWidgets(lineView, dims);
900
+ return lineView.node;
901
+ }
902
+
903
+ // A lineView may contain multiple logical lines (when merged by
904
+ // collapsed spans). The widgets for all of them need to be drawn.
905
+ function insertLineWidgets(lineView, dims) {
906
+ insertLineWidgetsFor(lineView.line, lineView, dims, true);
907
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
908
+ insertLineWidgetsFor(lineView.rest[i], lineView, dims, false);
909
+ }
910
+
911
+ function insertLineWidgetsFor(line, lineView, dims, allowAbove) {
912
+ if (!line.widgets) return;
913
+ var wrap = ensureLineWrapped(lineView);
914
+ for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
915
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
916
+ if (!widget.handleMouseEvents) node.ignoreEvents = true;
917
+ positionLineWidget(widget, node, lineView, dims);
918
+ if (allowAbove && widget.above)
919
+ wrap.insertBefore(node, lineView.gutter || lineView.text);
920
+ else
921
+ wrap.appendChild(node);
922
+ signalLater(widget, "redraw");
923
+ }
924
+ }
925
+
926
+ function positionLineWidget(widget, node, lineView, dims) {
927
+ if (widget.noHScroll) {
928
+ (lineView.alignable || (lineView.alignable = [])).push(node);
929
+ var width = dims.wrapperWidth;
930
+ node.style.left = dims.fixedPos + "px";
931
+ if (!widget.coverGutter) {
932
+ width -= dims.gutterTotalWidth;
933
+ node.style.paddingLeft = dims.gutterTotalWidth + "px";
934
+ }
935
+ node.style.width = width + "px";
936
+ }
937
+ if (widget.coverGutter) {
938
+ node.style.zIndex = 5;
939
+ node.style.position = "relative";
940
+ if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
941
+ }
942
+ }
943
+
944
+ // POSITION OBJECT
945
+
946
+ // A Pos instance represents a position within the text.
947
+ var Pos = CodeMirror.Pos = function(line, ch) {
948
+ if (!(this instanceof Pos)) return new Pos(line, ch);
949
+ this.line = line; this.ch = ch;
950
+ };
951
+
952
+ // Compare two positions, return 0 if they are the same, a negative
953
+ // number when a is less, and a positive number otherwise.
954
+ var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
955
+
956
+ function copyPos(x) {return Pos(x.line, x.ch);}
957
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
958
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
959
+
960
+ // SELECTION / CURSOR
961
+
962
+ // Selection objects are immutable. A new one is created every time
963
+ // the selection changes. A selection is one or more non-overlapping
964
+ // (and non-touching) ranges, sorted, and an integer that indicates
965
+ // which one is the primary selection (the one that's scrolled into
966
+ // view, that getCursor returns, etc).
967
+ function Selection(ranges, primIndex) {
968
+ this.ranges = ranges;
969
+ this.primIndex = primIndex;
970
+ }
971
+
972
+ Selection.prototype = {
973
+ primary: function() { return this.ranges[this.primIndex]; },
974
+ equals: function(other) {
975
+ if (other == this) return true;
976
+ if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
977
+ for (var i = 0; i < this.ranges.length; i++) {
978
+ var here = this.ranges[i], there = other.ranges[i];
979
+ if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
980
+ }
981
+ return true;
982
+ },
983
+ deepCopy: function() {
984
+ for (var out = [], i = 0; i < this.ranges.length; i++)
985
+ out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
986
+ return new Selection(out, this.primIndex);
987
+ },
988
+ somethingSelected: function() {
989
+ for (var i = 0; i < this.ranges.length; i++)
990
+ if (!this.ranges[i].empty()) return true;
991
+ return false;
992
+ },
993
+ contains: function(pos, end) {
994
+ if (!end) end = pos;
995
+ for (var i = 0; i < this.ranges.length; i++) {
996
+ var range = this.ranges[i];
997
+ if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
998
+ return i;
999
+ }
1000
+ return -1;
1001
+ }
1002
+ };
1003
+
1004
+ function Range(anchor, head) {
1005
+ this.anchor = anchor; this.head = head;
1006
+ }
1007
+
1008
+ Range.prototype = {
1009
+ from: function() { return minPos(this.anchor, this.head); },
1010
+ to: function() { return maxPos(this.anchor, this.head); },
1011
+ empty: function() {
1012
+ return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
1013
+ }
1014
+ };
1015
+
1016
+ // Take an unsorted, potentially overlapping set of ranges, and
1017
+ // build a selection out of it. 'Consumes' ranges array (modifying
1018
+ // it).
1019
+ function normalizeSelection(ranges, primIndex) {
1020
+ var prim = ranges[primIndex];
1021
+ ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
1022
+ primIndex = indexOf(ranges, prim);
1023
+ for (var i = 1; i < ranges.length; i++) {
1024
+ var cur = ranges[i], prev = ranges[i - 1];
1025
+ if (cmp(prev.to(), cur.from()) >= 0) {
1026
+ var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
1027
+ var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
1028
+ if (i <= primIndex) --primIndex;
1029
+ ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
1030
+ }
1031
+ }
1032
+ return new Selection(ranges, primIndex);
1033
+ }
1034
+
1035
+ function simpleSelection(anchor, head) {
1036
+ return new Selection([new Range(anchor, head || anchor)], 0);
1037
+ }
1038
+
1039
+ // Most of the external API clips given positions to make sure they
1040
+ // actually exist within the document.
1041
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
1042
+ function clipPos(doc, pos) {
1043
+ if (pos.line < doc.first) return Pos(doc.first, 0);
1044
+ var last = doc.first + doc.size - 1;
1045
+ if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
1046
+ return clipToLen(pos, getLine(doc, pos.line).text.length);
1047
+ }
1048
+ function clipToLen(pos, linelen) {
1049
+ var ch = pos.ch;
1050
+ if (ch == null || ch > linelen) return Pos(pos.line, linelen);
1051
+ else if (ch < 0) return Pos(pos.line, 0);
1052
+ else return pos;
1053
+ }
1054
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
1055
+ function clipPosArray(doc, array) {
1056
+ for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
1057
+ return out;
1058
+ }
1059
+
1060
+ // SELECTION UPDATES
1061
+
1062
+ // The 'scroll' parameter given to many of these indicated whether
1063
+ // the new cursor position should be scrolled into view after
1064
+ // modifying the selection.
1065
+
1066
+ // If shift is held or the extend flag is set, extends a range to
1067
+ // include a given position (and optionally a second position).
1068
+ // Otherwise, simply returns the range between the given positions.
1069
+ // Used for cursor motion and such.
1070
+ function extendRange(doc, range, head, other) {
1071
+ if (doc.cm && doc.cm.display.shift || doc.extend) {
1072
+ var anchor = range.anchor;
1073
+ if (other) {
1074
+ var posBefore = cmp(head, anchor) < 0;
1075
+ if (posBefore != (cmp(other, anchor) < 0)) {
1076
+ anchor = head;
1077
+ head = other;
1078
+ } else if (posBefore != (cmp(head, other) < 0)) {
1079
+ head = other;
1080
+ }
1081
+ }
1082
+ return new Range(anchor, head);
1083
+ } else {
1084
+ return new Range(other || head, head);
1085
+ }
1086
+ }
1087
+
1088
+ // Extend the primary selection range, discard the rest.
1089
+ function extendSelection(doc, head, other, options) {
1090
+ setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
1091
+ }
1092
+
1093
+ // Extend all selections (pos is an array of selections with length
1094
+ // equal the number of selections)
1095
+ function extendSelections(doc, heads, options) {
1096
+ for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
1097
+ out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
1098
+ var newSel = normalizeSelection(out, doc.sel.primIndex);
1099
+ setSelection(doc, newSel, options);
1100
+ }
1101
+
1102
+ // Updates a single range in the selection.
1103
+ function replaceOneSelection(doc, i, range, options) {
1104
+ var ranges = doc.sel.ranges.slice(0);
1105
+ ranges[i] = range;
1106
+ setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
1107
+ }
1108
+
1109
+ // Reset the selection to a single range.
1110
+ function setSimpleSelection(doc, anchor, head, options) {
1111
+ setSelection(doc, simpleSelection(anchor, head), options);
1112
+ }
1113
+
1114
+ // Give beforeSelectionChange handlers a change to influence a
1115
+ // selection update.
1116
+ function filterSelectionChange(doc, sel) {
1117
+ var obj = {
1118
+ ranges: sel.ranges,
1119
+ update: function(ranges) {
1120
+ this.ranges = [];
1121
+ for (var i = 0; i < ranges.length; i++)
1122
+ this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
1123
+ clipPos(doc, ranges[i].head));
1124
+ }
1125
+ };
1126
+ signal(doc, "beforeSelectionChange", doc, obj);
1127
+ if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
1128
+ if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
1129
+ else return sel;
1130
+ }
1131
+
1132
+ function setSelectionReplaceHistory(doc, sel, options) {
1133
+ var done = doc.history.done, last = lst(done);
1134
+ if (last && last.ranges) {
1135
+ done[done.length - 1] = sel;
1136
+ setSelectionNoUndo(doc, sel, options);
1137
+ } else {
1138
+ setSelection(doc, sel, options);
1139
+ }
1140
+ }
1141
+
1142
+ // Set a new selection.
1143
+ function setSelection(doc, sel, options) {
1144
+ setSelectionNoUndo(doc, sel, options);
1145
+ addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
1146
+ }
1147
+
1148
+ function setSelectionNoUndo(doc, sel, options) {
1149
+ if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
1150
+ sel = filterSelectionChange(doc, sel);
1151
+
1152
+ var bias = options && options.bias ||
1153
+ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
1154
+ setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
1155
+
1156
+ if (!(options && options.scroll === false) && doc.cm)
1157
+ ensureCursorVisible(doc.cm);
1158
+ }
1159
+
1160
+ function setSelectionInner(doc, sel) {
1161
+ if (sel.equals(doc.sel)) return;
1162
+
1163
+ doc.sel = sel;
1164
+
1165
+ if (doc.cm) {
1166
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
1167
+ signalCursorActivity(doc.cm);
1168
+ }
1169
+ signalLater(doc, "cursorActivity", doc);
1170
+ }
1171
+
1172
+ // Verify that the selection does not partially select any atomic
1173
+ // marked ranges.
1174
+ function reCheckSelection(doc) {
1175
+ setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
1176
+ }
1177
+
1178
+ // Return a selection that does not partially select any atomic
1179
+ // ranges.
1180
+ function skipAtomicInSelection(doc, sel, bias, mayClear) {
1181
+ var out;
1182
+ for (var i = 0; i < sel.ranges.length; i++) {
1183
+ var range = sel.ranges[i];
1184
+ var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
1185
+ var newHead = skipAtomic(doc, range.head, bias, mayClear);
1186
+ if (out || newAnchor != range.anchor || newHead != range.head) {
1187
+ if (!out) out = sel.ranges.slice(0, i);
1188
+ out[i] = new Range(newAnchor, newHead);
1189
+ }
1190
+ }
1191
+ return out ? normalizeSelection(out, sel.primIndex) : sel;
1192
+ }
1193
+
1194
+ // Ensure a given position is not inside an atomic range.
1195
+ function skipAtomic(doc, pos, bias, mayClear) {
1196
+ var flipped = false, curPos = pos;
1197
+ var dir = bias || 1;
1198
+ doc.cantEdit = false;
1199
+ search: for (;;) {
1200
+ var line = getLine(doc, curPos.line);
1201
+ if (line.markedSpans) {
1202
+ for (var i = 0; i < line.markedSpans.length; ++i) {
1203
+ var sp = line.markedSpans[i], m = sp.marker;
1204
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
1205
+ (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
1206
+ if (mayClear) {
1207
+ signal(m, "beforeCursorEnter");
1208
+ if (m.explicitlyCleared) {
1209
+ if (!line.markedSpans) break;
1210
+ else {--i; continue;}
1211
+ }
1212
+ }
1213
+ if (!m.atomic) continue;
1214
+ var newPos = m.find(dir < 0 ? -1 : 1);
1215
+ if (cmp(newPos, curPos) == 0) {
1216
+ newPos.ch += dir;
1217
+ if (newPos.ch < 0) {
1218
+ if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
1219
+ else newPos = null;
1220
+ } else if (newPos.ch > line.text.length) {
1221
+ if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
1222
+ else newPos = null;
1223
+ }
1224
+ if (!newPos) {
1225
+ if (flipped) {
1226
+ // Driven in a corner -- no valid cursor position found at all
1227
+ // -- try again *with* clearing, if we didn't already
1228
+ if (!mayClear) return skipAtomic(doc, pos, bias, true);
1229
+ // Otherwise, turn off editing until further notice, and return the start of the doc
1230
+ doc.cantEdit = true;
1231
+ return Pos(doc.first, 0);
1232
+ }
1233
+ flipped = true; newPos = pos; dir = -dir;
1234
+ }
1235
+ }
1236
+ curPos = newPos;
1237
+ continue search;
1238
+ }
1239
+ }
1240
+ }
1241
+ return curPos;
1242
+ }
1243
+ }
1244
+
1245
+ // SELECTION DRAWING
1246
+
1247
+ // Redraw the selection and/or cursor
1248
+ function updateSelection(cm) {
1249
+ var display = cm.display, doc = cm.doc;
1250
+ var curFragment = document.createDocumentFragment();
1251
+ var selFragment = document.createDocumentFragment();
1252
+
1253
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
1254
+ var range = doc.sel.ranges[i];
1255
+ var collapsed = range.empty();
1256
+ if (collapsed || cm.options.showCursorWhenSelecting)
1257
+ drawSelectionCursor(cm, range, curFragment);
1258
+ if (!collapsed)
1259
+ drawSelectionRange(cm, range, selFragment);
1260
+ }
1261
+
1262
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
1263
+ if (cm.options.moveInputWithCursor) {
1264
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
1265
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
1266
+ var top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
1267
+ headPos.top + lineOff.top - wrapOff.top));
1268
+ var left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
1269
+ headPos.left + lineOff.left - wrapOff.left));
1270
+ display.inputDiv.style.top = top + "px";
1271
+ display.inputDiv.style.left = left + "px";
1272
+ }
1273
+
1274
+ removeChildrenAndAdd(display.cursorDiv, curFragment);
1275
+ removeChildrenAndAdd(display.selectionDiv, selFragment);
1276
+ }
1277
+
1278
+ // Draws a cursor for the given range
1279
+ function drawSelectionCursor(cm, range, output) {
1280
+ var pos = cursorCoords(cm, range.head, "div");
1281
+
1282
+ var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
1283
+ cursor.style.left = pos.left + "px";
1284
+ cursor.style.top = pos.top + "px";
1285
+ cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
1286
+
1287
+ if (pos.other) {
1288
+ // Secondary cursor, shown when on a 'jump' in bi-directional text
1289
+ var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
1290
+ otherCursor.style.display = "";
1291
+ otherCursor.style.left = pos.other.left + "px";
1292
+ otherCursor.style.top = pos.other.top + "px";
1293
+ otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
1294
+ }
1295
+ }
1296
+
1297
+ // Draws the given range as a highlighted selection
1298
+ function drawSelectionRange(cm, range, output) {
1299
+ var display = cm.display, doc = cm.doc;
1300
+ var fragment = document.createDocumentFragment();
1301
+ var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
1302
+
1303
+ function add(left, top, width, bottom) {
1304
+ if (top < 0) top = 0;
1305
+ top = Math.round(top);
1306
+ bottom = Math.round(bottom);
1307
+ fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
1308
+ "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
1309
+ "px; height: " + (bottom - top) + "px"));
1310
+ }
1311
+
1312
+ function drawForLine(line, fromArg, toArg) {
1313
+ var lineObj = getLine(doc, line);
1314
+ var lineLen = lineObj.text.length;
1315
+ var start, end;
1316
+ function coords(ch, bias) {
1317
+ return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
1318
+ }
1319
+
1320
+ iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
1321
+ var leftPos = coords(from, "left"), rightPos, left, right;
1322
+ if (from == to) {
1323
+ rightPos = leftPos;
1324
+ left = right = leftPos.left;
1325
+ } else {
1326
+ rightPos = coords(to - 1, "right");
1327
+ if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
1328
+ left = leftPos.left;
1329
+ right = rightPos.right;
1330
+ }
1331
+ if (fromArg == null && from == 0) left = leftSide;
1332
+ if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
1333
+ add(left, leftPos.top, null, leftPos.bottom);
1334
+ left = leftSide;
1335
+ if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
1336
+ }
1337
+ if (toArg == null && to == lineLen) right = rightSide;
1338
+ if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
1339
+ start = leftPos;
1340
+ if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
1341
+ end = rightPos;
1342
+ if (left < leftSide + 1) left = leftSide;
1343
+ add(left, rightPos.top, right - left, rightPos.bottom);
1344
+ });
1345
+ return {start: start, end: end};
1346
+ }
1347
+
1348
+ var sFrom = range.from(), sTo = range.to();
1349
+ if (sFrom.line == sTo.line) {
1350
+ drawForLine(sFrom.line, sFrom.ch, sTo.ch);
1351
+ } else {
1352
+ var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
1353
+ var singleVLine = visualLine(fromLine) == visualLine(toLine);
1354
+ var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
1355
+ var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
1356
+ if (singleVLine) {
1357
+ if (leftEnd.top < rightStart.top - 2) {
1358
+ add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
1359
+ add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
1360
+ } else {
1361
+ add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
1362
+ }
1363
+ }
1364
+ if (leftEnd.bottom < rightStart.top)
1365
+ add(leftSide, leftEnd.bottom, null, rightStart.top);
1366
+ }
1367
+
1368
+ output.appendChild(fragment);
1369
+ }
1370
+
1371
+ // Cursor-blinking
1372
+ function restartBlink(cm) {
1373
+ if (!cm.state.focused) return;
1374
+ var display = cm.display;
1375
+ clearInterval(display.blinker);
1376
+ var on = true;
1377
+ display.cursorDiv.style.visibility = "";
1378
+ if (cm.options.cursorBlinkRate > 0)
1379
+ display.blinker = setInterval(function() {
1380
+ display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
1381
+ }, cm.options.cursorBlinkRate);
1382
+ }
1383
+
1384
+ // HIGHLIGHT WORKER
1385
+
1386
+ function startWorker(cm, time) {
1387
+ if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
1388
+ cm.state.highlight.set(time, bind(highlightWorker, cm));
1389
+ }
1390
+
1391
+ function highlightWorker(cm) {
1392
+ var doc = cm.doc;
1393
+ if (doc.frontier < doc.first) doc.frontier = doc.first;
1394
+ if (doc.frontier >= cm.display.viewTo) return;
1395
+ var end = +new Date + cm.options.workTime;
1396
+ var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
1397
+
1398
+ runInOp(cm, function() {
1399
+ doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
1400
+ if (doc.frontier >= cm.display.viewFrom) { // Visible
1401
+ var oldStyles = line.styles;
1402
+ var highlighted = highlightLine(cm, line, state, true);
1403
+ line.styles = highlighted.styles;
1404
+ if (highlighted.classes) line.styleClasses = highlighted.classes;
1405
+ else if (line.styleClasses) line.styleClasses = null;
1406
+ var ischange = !oldStyles || oldStyles.length != line.styles.length;
1407
+ for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
1408
+ if (ischange) regLineChange(cm, doc.frontier, "text");
1409
+ line.stateAfter = copyState(doc.mode, state);
1410
+ } else {
1411
+ processLine(cm, line.text, state);
1412
+ line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
1413
+ }
1414
+ ++doc.frontier;
1415
+ if (+new Date > end) {
1416
+ startWorker(cm, cm.options.workDelay);
1417
+ return true;
1418
+ }
1419
+ });
1420
+ });
1421
+ }
1422
+
1423
+ // Finds the line to start with when starting a parse. Tries to
1424
+ // find a line with a stateAfter, so that it can start with a
1425
+ // valid state. If that fails, it returns the line with the
1426
+ // smallest indentation, which tends to need the least context to
1427
+ // parse correctly.
1428
+ function findStartLine(cm, n, precise) {
1429
+ var minindent, minline, doc = cm.doc;
1430
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
1431
+ for (var search = n; search > lim; --search) {
1432
+ if (search <= doc.first) return doc.first;
1433
+ var line = getLine(doc, search - 1);
1434
+ if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
1435
+ var indented = countColumn(line.text, null, cm.options.tabSize);
1436
+ if (minline == null || minindent > indented) {
1437
+ minline = search - 1;
1438
+ minindent = indented;
1439
+ }
1440
+ }
1441
+ return minline;
1442
+ }
1443
+
1444
+ function getStateBefore(cm, n, precise) {
1445
+ var doc = cm.doc, display = cm.display;
1446
+ if (!doc.mode.startState) return true;
1447
+ var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
1448
+ if (!state) state = startState(doc.mode);
1449
+ else state = copyState(doc.mode, state);
1450
+ doc.iter(pos, n, function(line) {
1451
+ processLine(cm, line.text, state);
1452
+ var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
1453
+ line.stateAfter = save ? copyState(doc.mode, state) : null;
1454
+ ++pos;
1455
+ });
1456
+ if (precise) doc.frontier = pos;
1457
+ return state;
1458
+ }
1459
+
1460
+ // POSITION MEASUREMENT
1461
+
1462
+ function paddingTop(display) {return display.lineSpace.offsetTop;}
1463
+ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
1464
+ function paddingH(display) {
1465
+ if (display.cachedPaddingH) return display.cachedPaddingH;
1466
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
1467
+ var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
1468
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
1469
+ if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
1470
+ return data;
1471
+ }
1472
+
1473
+ // Ensure the lineView.wrapping.heights array is populated. This is
1474
+ // an array of bottom offsets for the lines that make up a drawn
1475
+ // line. When lineWrapping is on, there might be more than one
1476
+ // height.
1477
+ function ensureLineHeights(cm, lineView, rect) {
1478
+ var wrapping = cm.options.lineWrapping;
1479
+ var curWidth = wrapping && cm.display.scroller.clientWidth;
1480
+ if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
1481
+ var heights = lineView.measure.heights = [];
1482
+ if (wrapping) {
1483
+ lineView.measure.width = curWidth;
1484
+ var rects = lineView.text.firstChild.getClientRects();
1485
+ for (var i = 0; i < rects.length - 1; i++) {
1486
+ var cur = rects[i], next = rects[i + 1];
1487
+ if (Math.abs(cur.bottom - next.bottom) > 2)
1488
+ heights.push((cur.bottom + next.top) / 2 - rect.top);
1489
+ }
1490
+ }
1491
+ heights.push(rect.bottom - rect.top);
1492
+ }
1493
+ }
1494
+
1495
+ // Find a line map (mapping character offsets to text nodes) and a
1496
+ // measurement cache for the given line number. (A line view might
1497
+ // contain multiple lines when collapsed ranges are present.)
1498
+ function mapFromLineView(lineView, line, lineN) {
1499
+ if (lineView.line == line)
1500
+ return {map: lineView.measure.map, cache: lineView.measure.cache};
1501
+ for (var i = 0; i < lineView.rest.length; i++)
1502
+ if (lineView.rest[i] == line)
1503
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
1504
+ for (var i = 0; i < lineView.rest.length; i++)
1505
+ if (lineNo(lineView.rest[i]) > lineN)
1506
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
1507
+ }
1508
+
1509
+ // Render a line into the hidden node display.externalMeasured. Used
1510
+ // when measurement is needed for a line that's not in the viewport.
1511
+ function updateExternalMeasurement(cm, line) {
1512
+ line = visualLine(line);
1513
+ var lineN = lineNo(line);
1514
+ var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
1515
+ view.lineN = lineN;
1516
+ var built = view.built = buildLineContent(cm, view);
1517
+ view.text = built.pre;
1518
+ removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
1519
+ return view;
1520
+ }
1521
+
1522
+ // Get a {top, bottom, left, right} box (in line-local coordinates)
1523
+ // for a given character.
1524
+ function measureChar(cm, line, ch, bias) {
1525
+ return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
1526
+ }
1527
+
1528
+ // Find a line view that corresponds to the given line number.
1529
+ function findViewForLine(cm, lineN) {
1530
+ if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
1531
+ return cm.display.view[findViewIndex(cm, lineN)];
1532
+ var ext = cm.display.externalMeasured;
1533
+ if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
1534
+ return ext;
1535
+ }
1536
+
1537
+ // Measurement can be split in two steps, the set-up work that
1538
+ // applies to the whole line, and the measurement of the actual
1539
+ // character. Functions like coordsChar, that need to do a lot of
1540
+ // measurements in a row, can thus ensure that the set-up work is
1541
+ // only done once.
1542
+ function prepareMeasureForLine(cm, line) {
1543
+ var lineN = lineNo(line);
1544
+ var view = findViewForLine(cm, lineN);
1545
+ if (view && !view.text)
1546
+ view = null;
1547
+ else if (view && view.changes)
1548
+ updateLineForChanges(cm, view, lineN, getDimensions(cm));
1549
+ if (!view)
1550
+ view = updateExternalMeasurement(cm, line);
1551
+
1552
+ var info = mapFromLineView(view, line, lineN);
1553
+ return {
1554
+ line: line, view: view, rect: null,
1555
+ map: info.map, cache: info.cache, before: info.before,
1556
+ hasHeights: false
1557
+ };
1558
+ }
1559
+
1560
+ // Given a prepared measurement object, measures the position of an
1561
+ // actual character (or fetches it from the cache).
1562
+ function measureCharPrepared(cm, prepared, ch, bias) {
1563
+ if (prepared.before) ch = -1;
1564
+ var key = ch + (bias || ""), found;
1565
+ if (prepared.cache.hasOwnProperty(key)) {
1566
+ found = prepared.cache[key];
1567
+ } else {
1568
+ if (!prepared.rect)
1569
+ prepared.rect = prepared.view.text.getBoundingClientRect();
1570
+ if (!prepared.hasHeights) {
1571
+ ensureLineHeights(cm, prepared.view, prepared.rect);
1572
+ prepared.hasHeights = true;
1573
+ }
1574
+ found = measureCharInner(cm, prepared, ch, bias);
1575
+ if (!found.bogus) prepared.cache[key] = found;
1576
+ }
1577
+ return {left: found.left, right: found.right, top: found.top, bottom: found.bottom};
1578
+ }
1579
+
1580
+ var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
1581
+
1582
+ function measureCharInner(cm, prepared, ch, bias) {
1583
+ var map = prepared.map;
1584
+
1585
+ var node, start, end, collapse;
1586
+ // First, search the line map for the text node corresponding to,
1587
+ // or closest to, the target character.
1588
+ for (var i = 0; i < map.length; i += 3) {
1589
+ var mStart = map[i], mEnd = map[i + 1];
1590
+ if (ch < mStart) {
1591
+ start = 0; end = 1;
1592
+ collapse = "left";
1593
+ } else if (ch < mEnd) {
1594
+ start = ch - mStart;
1595
+ end = start + 1;
1596
+ } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
1597
+ end = mEnd - mStart;
1598
+ start = end - 1;
1599
+ if (ch >= mEnd) collapse = "right";
1600
+ }
1601
+ if (start != null) {
1602
+ node = map[i + 2];
1603
+ if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
1604
+ collapse = bias;
1605
+ if (bias == "left" && start == 0)
1606
+ while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
1607
+ node = map[(i -= 3) + 2];
1608
+ collapse = "left";
1609
+ }
1610
+ if (bias == "right" && start == mEnd - mStart)
1611
+ while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
1612
+ node = map[(i += 3) + 2];
1613
+ collapse = "right";
1614
+ }
1615
+ break;
1616
+ }
1617
+ }
1618
+
1619
+ var rect;
1620
+ if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
1621
+ while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
1622
+ while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
1623
+ if (ie_upto8 && start == 0 && end == mEnd - mStart) {
1624
+ rect = node.parentNode.getBoundingClientRect();
1625
+ } else if (ie && cm.options.lineWrapping) {
1626
+ var rects = range(node, start, end).getClientRects();
1627
+ if (rects.length)
1628
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
1629
+ else
1630
+ rect = nullRect;
1631
+ } else {
1632
+ rect = range(node, start, end).getBoundingClientRect() || nullRect;
1633
+ }
1634
+ } else { // If it is a widget, simply get the box for the whole widget.
1635
+ if (start > 0) collapse = bias = "right";
1636
+ var rects;
1637
+ if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
1638
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
1639
+ else
1640
+ rect = node.getBoundingClientRect();
1641
+ }
1642
+ if (ie_upto8 && !start && (!rect || !rect.left && !rect.right)) {
1643
+ var rSpan = node.parentNode.getClientRects()[0];
1644
+ if (rSpan)
1645
+ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
1646
+ else
1647
+ rect = nullRect;
1648
+ }
1649
+
1650
+ var top, bot = (rect.bottom + rect.top) / 2 - prepared.rect.top;
1651
+ var heights = prepared.view.measure.heights;
1652
+ for (var i = 0; i < heights.length - 1; i++)
1653
+ if (bot < heights[i]) break;
1654
+ top = i ? heights[i - 1] : 0; bot = heights[i];
1655
+ var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
1656
+ right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
1657
+ top: top, bottom: bot};
1658
+ if (!rect.left && !rect.right) result.bogus = true;
1659
+ return result;
1660
+ }
1661
+
1662
+ function clearLineMeasurementCacheFor(lineView) {
1663
+ if (lineView.measure) {
1664
+ lineView.measure.cache = {};
1665
+ lineView.measure.heights = null;
1666
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
1667
+ lineView.measure.caches[i] = {};
1668
+ }
1669
+ }
1670
+
1671
+ function clearLineMeasurementCache(cm) {
1672
+ cm.display.externalMeasure = null;
1673
+ removeChildren(cm.display.lineMeasure);
1674
+ for (var i = 0; i < cm.display.view.length; i++)
1675
+ clearLineMeasurementCacheFor(cm.display.view[i]);
1676
+ }
1677
+
1678
+ function clearCaches(cm) {
1679
+ clearLineMeasurementCache(cm);
1680
+ cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
1681
+ if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
1682
+ cm.display.lineNumChars = null;
1683
+ }
1684
+
1685
+ function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
1686
+ function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
1687
+
1688
+ // Converts a {top, bottom, left, right} box from line-local
1689
+ // coordinates into another coordinate system. Context may be one of
1690
+ // "line", "div" (display.lineDiv), "local"/null (editor), or "page".
1691
+ function intoCoordSystem(cm, lineObj, rect, context) {
1692
+ if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
1693
+ var size = widgetHeight(lineObj.widgets[i]);
1694
+ rect.top += size; rect.bottom += size;
1695
+ }
1696
+ if (context == "line") return rect;
1697
+ if (!context) context = "local";
1698
+ var yOff = heightAtLine(lineObj);
1699
+ if (context == "local") yOff += paddingTop(cm.display);
1700
+ else yOff -= cm.display.viewOffset;
1701
+ if (context == "page" || context == "window") {
1702
+ var lOff = cm.display.lineSpace.getBoundingClientRect();
1703
+ yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
1704
+ var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
1705
+ rect.left += xOff; rect.right += xOff;
1706
+ }
1707
+ rect.top += yOff; rect.bottom += yOff;
1708
+ return rect;
1709
+ }
1710
+
1711
+ // Coverts a box from "div" coords to another coordinate system.
1712
+ // Context may be "window", "page", "div", or "local"/null.
1713
+ function fromCoordSystem(cm, coords, context) {
1714
+ if (context == "div") return coords;
1715
+ var left = coords.left, top = coords.top;
1716
+ // First move into "page" coordinate system
1717
+ if (context == "page") {
1718
+ left -= pageScrollX();
1719
+ top -= pageScrollY();
1720
+ } else if (context == "local" || !context) {
1721
+ var localBox = cm.display.sizer.getBoundingClientRect();
1722
+ left += localBox.left;
1723
+ top += localBox.top;
1724
+ }
1725
+
1726
+ var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
1727
+ return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
1728
+ }
1729
+
1730
+ function charCoords(cm, pos, context, lineObj, bias) {
1731
+ if (!lineObj) lineObj = getLine(cm.doc, pos.line);
1732
+ return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
1733
+ }
1734
+
1735
+ // Returns a box for a given cursor position, which may have an
1736
+ // 'other' property containing the position of the secondary cursor
1737
+ // on a bidi boundary.
1738
+ function cursorCoords(cm, pos, context, lineObj, preparedMeasure) {
1739
+ lineObj = lineObj || getLine(cm.doc, pos.line);
1740
+ if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
1741
+ function get(ch, right) {
1742
+ var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left");
1743
+ if (right) m.left = m.right; else m.right = m.left;
1744
+ return intoCoordSystem(cm, lineObj, m, context);
1745
+ }
1746
+ function getBidi(ch, partPos) {
1747
+ var part = order[partPos], right = part.level % 2;
1748
+ if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
1749
+ part = order[--partPos];
1750
+ ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
1751
+ right = true;
1752
+ } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
1753
+ part = order[++partPos];
1754
+ ch = bidiLeft(part) - part.level % 2;
1755
+ right = false;
1756
+ }
1757
+ if (right && ch == part.to && ch > part.from) return get(ch - 1);
1758
+ return get(ch, right);
1759
+ }
1760
+ var order = getOrder(lineObj), ch = pos.ch;
1761
+ if (!order) return get(ch);
1762
+ var partPos = getBidiPartAt(order, ch);
1763
+ var val = getBidi(ch, partPos);
1764
+ if (bidiOther != null) val.other = getBidi(ch, bidiOther);
1765
+ return val;
1766
+ }
1767
+
1768
+ // Used to cheaply estimate the coordinates for a position. Used for
1769
+ // intermediate scroll updates.
1770
+ function estimateCoords(cm, pos) {
1771
+ var left = 0, pos = clipPos(cm.doc, pos);
1772
+ if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
1773
+ var lineObj = getLine(cm.doc, pos.line);
1774
+ var top = heightAtLine(lineObj) + paddingTop(cm.display);
1775
+ return {left: left, right: left, top: top, bottom: top + lineObj.height};
1776
+ }
1777
+
1778
+ // Positions returned by coordsChar contain some extra information.
1779
+ // xRel is the relative x position of the input coordinates compared
1780
+ // to the found position (so xRel > 0 means the coordinates are to
1781
+ // the right of the character position, for example). When outside
1782
+ // is true, that means the coordinates lie outside the line's
1783
+ // vertical range.
1784
+ function PosWithInfo(line, ch, outside, xRel) {
1785
+ var pos = Pos(line, ch);
1786
+ pos.xRel = xRel;
1787
+ if (outside) pos.outside = true;
1788
+ return pos;
1789
+ }
1790
+
1791
+ // Compute the character position closest to the given coordinates.
1792
+ // Input must be lineSpace-local ("div" coordinate system).
1793
+ function coordsChar(cm, x, y) {
1794
+ var doc = cm.doc;
1795
+ y += cm.display.viewOffset;
1796
+ if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
1797
+ var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
1798
+ if (lineN > last)
1799
+ return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
1800
+ if (x < 0) x = 0;
1801
+
1802
+ var lineObj = getLine(doc, lineN);
1803
+ for (;;) {
1804
+ var found = coordsCharInner(cm, lineObj, lineN, x, y);
1805
+ var merged = collapsedSpanAtEnd(lineObj);
1806
+ var mergedPos = merged && merged.find(0, true);
1807
+ if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
1808
+ lineN = lineNo(lineObj = mergedPos.to.line);
1809
+ else
1810
+ return found;
1811
+ }
1812
+ }
1813
+
1814
+ function coordsCharInner(cm, lineObj, lineNo, x, y) {
1815
+ var innerOff = y - heightAtLine(lineObj);
1816
+ var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
1817
+ var preparedMeasure = prepareMeasureForLine(cm, lineObj);
1818
+
1819
+ function getX(ch) {
1820
+ var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
1821
+ wrongLine = true;
1822
+ if (innerOff > sp.bottom) return sp.left - adjust;
1823
+ else if (innerOff < sp.top) return sp.left + adjust;
1824
+ else wrongLine = false;
1825
+ return sp.left;
1826
+ }
1827
+
1828
+ var bidi = getOrder(lineObj), dist = lineObj.text.length;
1829
+ var from = lineLeft(lineObj), to = lineRight(lineObj);
1830
+ var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
1831
+
1832
+ if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
1833
+ // Do a binary search between these bounds.
1834
+ for (;;) {
1835
+ if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
1836
+ var ch = x < fromX || x - fromX <= toX - x ? from : to;
1837
+ var xDiff = x - (ch == from ? fromX : toX);
1838
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
1839
+ var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
1840
+ xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
1841
+ return pos;
1842
+ }
1843
+ var step = Math.ceil(dist / 2), middle = from + step;
1844
+ if (bidi) {
1845
+ middle = from;
1846
+ for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
1847
+ }
1848
+ var middleX = getX(middle);
1849
+ if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
1850
+ else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
1851
+ }
1852
+ }
1853
+
1854
+ var measureText;
1855
+ // Compute the default text height.
1856
+ function textHeight(display) {
1857
+ if (display.cachedTextHeight != null) return display.cachedTextHeight;
1858
+ if (measureText == null) {
1859
+ measureText = elt("pre");
1860
+ // Measure a bunch of lines, for browsers that compute
1861
+ // fractional heights.
1862
+ for (var i = 0; i < 49; ++i) {
1863
+ measureText.appendChild(document.createTextNode("x"));
1864
+ measureText.appendChild(elt("br"));
1865
+ }
1866
+ measureText.appendChild(document.createTextNode("x"));
1867
+ }
1868
+ removeChildrenAndAdd(display.measure, measureText);
1869
+ var height = measureText.offsetHeight / 50;
1870
+ if (height > 3) display.cachedTextHeight = height;
1871
+ removeChildren(display.measure);
1872
+ return height || 1;
1873
+ }
1874
+
1875
+ // Compute the default character width.
1876
+ function charWidth(display) {
1877
+ if (display.cachedCharWidth != null) return display.cachedCharWidth;
1878
+ var anchor = elt("span", "xxxxxxxxxx");
1879
+ var pre = elt("pre", [anchor]);
1880
+ removeChildrenAndAdd(display.measure, pre);
1881
+ var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
1882
+ if (width > 2) display.cachedCharWidth = width;
1883
+ return width || 10;
1884
+ }
1885
+
1886
+ // OPERATIONS
1887
+
1888
+ // Operations are used to wrap a series of changes to the editor
1889
+ // state in such a way that each change won't have to update the
1890
+ // cursor and display (which would be awkward, slow, and
1891
+ // error-prone). Instead, display updates are batched and then all
1892
+ // combined and executed at once.
1893
+
1894
+ var nextOpId = 0;
1895
+ // Start a new operation.
1896
+ function startOperation(cm) {
1897
+ cm.curOp = {
1898
+ viewChanged: false, // Flag that indicates that lines might need to be redrawn
1899
+ startHeight: cm.doc.height, // Used to detect need to update scrollbar
1900
+ forceUpdate: false, // Used to force a redraw
1901
+ updateInput: null, // Whether to reset the input textarea
1902
+ typing: false, // Whether this reset should be careful to leave existing text (for compositing)
1903
+ changeObjs: null, // Accumulated changes, for firing change events
1904
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
1905
+ selectionChanged: false, // Whether the selection needs to be redrawn
1906
+ updateMaxLine: false, // Set when the widest line needs to be determined anew
1907
+ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
1908
+ scrollToPos: null, // Used to scroll to a specific position
1909
+ id: ++nextOpId // Unique ID
1910
+ };
1911
+ if (!delayedCallbackDepth++) delayedCallbacks = [];
1912
+ }
1913
+
1914
+ // Finish an operation, updating the display and signalling delayed events
1915
+ function endOperation(cm) {
1916
+ var op = cm.curOp, doc = cm.doc, display = cm.display;
1917
+ cm.curOp = null;
1918
+
1919
+ if (op.updateMaxLine) findMaxLine(cm);
1920
+
1921
+ // If it looks like an update might be needed, call updateDisplay
1922
+ if (op.viewChanged || op.forceUpdate || op.scrollTop != null ||
1923
+ op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
1924
+ op.scrollToPos.to.line >= display.viewTo) ||
1925
+ display.maxLineChanged && cm.options.lineWrapping) {
1926
+ var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
1927
+ if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop;
1928
+ }
1929
+ // If no update was run, but the selection changed, redraw that.
1930
+ if (!updated && op.selectionChanged) updateSelection(cm);
1931
+ if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm);
1932
+
1933
+ // Abort mouse wheel delta measurement, when scrolling explicitly
1934
+ if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
1935
+ display.wheelStartX = display.wheelStartY = null;
1936
+
1937
+ // Propagate the scroll position to the actual DOM scroller
1938
+ if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) {
1939
+ var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
1940
+ display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
1941
+ }
1942
+ if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) {
1943
+ var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
1944
+ display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
1945
+ alignHorizontally(cm);
1946
+ }
1947
+ // If we need to scroll a specific position into view, do so.
1948
+ if (op.scrollToPos) {
1949
+ var coords = scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
1950
+ clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin);
1951
+ if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
1952
+ }
1953
+
1954
+ if (op.selectionChanged) restartBlink(cm);
1955
+
1956
+ if (cm.state.focused && op.updateInput)
1957
+ resetInput(cm, op.typing);
1958
+
1959
+ // Fire events for markers that are hidden/unidden by editing or
1960
+ // undoing
1961
+ var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
1962
+ if (hidden) for (var i = 0; i < hidden.length; ++i)
1963
+ if (!hidden[i].lines.length) signal(hidden[i], "hide");
1964
+ if (unhidden) for (var i = 0; i < unhidden.length; ++i)
1965
+ if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
1966
+
1967
+ var delayed;
1968
+ if (!--delayedCallbackDepth) {
1969
+ delayed = delayedCallbacks;
1970
+ delayedCallbacks = null;
1971
+ }
1972
+ // Fire change events, and delayed event handlers
1973
+ if (op.changeObjs)
1974
+ signal(cm, "changes", cm, op.changeObjs);
1975
+ if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
1976
+ if (op.cursorActivityHandlers)
1977
+ for (var i = 0; i < op.cursorActivityHandlers.length; i++)
1978
+ op.cursorActivityHandlers[i](cm);
1979
+ }
1980
+
1981
+ // Run the given function in an operation
1982
+ function runInOp(cm, f) {
1983
+ if (cm.curOp) return f();
1984
+ startOperation(cm);
1985
+ try { return f(); }
1986
+ finally { endOperation(cm); }
1987
+ }
1988
+ // Wraps a function in an operation. Returns the wrapped function.
1989
+ function operation(cm, f) {
1990
+ return function() {
1991
+ if (cm.curOp) return f.apply(cm, arguments);
1992
+ startOperation(cm);
1993
+ try { return f.apply(cm, arguments); }
1994
+ finally { endOperation(cm); }
1995
+ };
1996
+ }
1997
+ // Used to add methods to editor and doc instances, wrapping them in
1998
+ // operations.
1999
+ function methodOp(f) {
2000
+ return function() {
2001
+ if (this.curOp) return f.apply(this, arguments);
2002
+ startOperation(this);
2003
+ try { return f.apply(this, arguments); }
2004
+ finally { endOperation(this); }
2005
+ };
2006
+ }
2007
+ function docMethodOp(f) {
2008
+ return function() {
2009
+ var cm = this.cm;
2010
+ if (!cm || cm.curOp) return f.apply(this, arguments);
2011
+ startOperation(cm);
2012
+ try { return f.apply(this, arguments); }
2013
+ finally { endOperation(cm); }
2014
+ };
2015
+ }
2016
+
2017
+ // VIEW TRACKING
2018
+
2019
+ // These objects are used to represent the visible (currently drawn)
2020
+ // part of the document. A LineView may correspond to multiple
2021
+ // logical lines, if those are connected by collapsed ranges.
2022
+ function LineView(doc, line, lineN) {
2023
+ // The starting line
2024
+ this.line = line;
2025
+ // Continuing lines, if any
2026
+ this.rest = visualLineContinued(line);
2027
+ // Number of logical lines in this visual line
2028
+ this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
2029
+ this.node = this.text = null;
2030
+ this.hidden = lineIsHidden(doc, line);
2031
+ }
2032
+
2033
+ // Create a range of LineView objects for the given lines.
2034
+ function buildViewArray(cm, from, to) {
2035
+ var array = [], nextPos;
2036
+ for (var pos = from; pos < to; pos = nextPos) {
2037
+ var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
2038
+ nextPos = pos + view.size;
2039
+ array.push(view);
2040
+ }
2041
+ return array;
2042
+ }
2043
+
2044
+ // Updates the display.view data structure for a given change to the
2045
+ // document. From and to are in pre-change coordinates. Lendiff is
2046
+ // the amount of lines added or subtracted by the change. This is
2047
+ // used for changes that span multiple lines, or change the way
2048
+ // lines are divided into visual lines. regLineChange (below)
2049
+ // registers single-line changes.
2050
+ function regChange(cm, from, to, lendiff) {
2051
+ if (from == null) from = cm.doc.first;
2052
+ if (to == null) to = cm.doc.first + cm.doc.size;
2053
+ if (!lendiff) lendiff = 0;
2054
+
2055
+ var display = cm.display;
2056
+ if (lendiff && to < display.viewTo &&
2057
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
2058
+ display.updateLineNumbers = from;
2059
+
2060
+ cm.curOp.viewChanged = true;
2061
+
2062
+ if (from >= display.viewTo) { // Change after
2063
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
2064
+ resetView(cm);
2065
+ } else if (to <= display.viewFrom) { // Change before
2066
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
2067
+ resetView(cm);
2068
+ } else {
2069
+ display.viewFrom += lendiff;
2070
+ display.viewTo += lendiff;
2071
+ }
2072
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
2073
+ resetView(cm);
2074
+ } else if (from <= display.viewFrom) { // Top overlap
2075
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
2076
+ if (cut) {
2077
+ display.view = display.view.slice(cut.index);
2078
+ display.viewFrom = cut.lineN;
2079
+ display.viewTo += lendiff;
2080
+ } else {
2081
+ resetView(cm);
2082
+ }
2083
+ } else if (to >= display.viewTo) { // Bottom overlap
2084
+ var cut = viewCuttingPoint(cm, from, from, -1);
2085
+ if (cut) {
2086
+ display.view = display.view.slice(0, cut.index);
2087
+ display.viewTo = cut.lineN;
2088
+ } else {
2089
+ resetView(cm);
2090
+ }
2091
+ } else { // Gap in the middle
2092
+ var cutTop = viewCuttingPoint(cm, from, from, -1);
2093
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
2094
+ if (cutTop && cutBot) {
2095
+ display.view = display.view.slice(0, cutTop.index)
2096
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
2097
+ .concat(display.view.slice(cutBot.index));
2098
+ display.viewTo += lendiff;
2099
+ } else {
2100
+ resetView(cm);
2101
+ }
2102
+ }
2103
+
2104
+ var ext = display.externalMeasured;
2105
+ if (ext) {
2106
+ if (to < ext.lineN)
2107
+ ext.lineN += lendiff;
2108
+ else if (from < ext.lineN + ext.size)
2109
+ display.externalMeasured = null;
2110
+ }
2111
+ }
2112
+
2113
+ // Register a change to a single line. Type must be one of "text",
2114
+ // "gutter", "class", "widget"
2115
+ function regLineChange(cm, line, type) {
2116
+ cm.curOp.viewChanged = true;
2117
+ var display = cm.display, ext = cm.display.externalMeasured;
2118
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
2119
+ display.externalMeasured = null;
2120
+
2121
+ if (line < display.viewFrom || line >= display.viewTo) return;
2122
+ var lineView = display.view[findViewIndex(cm, line)];
2123
+ if (lineView.node == null) return;
2124
+ var arr = lineView.changes || (lineView.changes = []);
2125
+ if (indexOf(arr, type) == -1) arr.push(type);
2126
+ }
2127
+
2128
+ // Clear the view.
2129
+ function resetView(cm) {
2130
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
2131
+ cm.display.view = [];
2132
+ cm.display.viewOffset = 0;
2133
+ }
2134
+
2135
+ // Find the view element corresponding to a given line. Return null
2136
+ // when the line isn't visible.
2137
+ function findViewIndex(cm, n) {
2138
+ if (n >= cm.display.viewTo) return null;
2139
+ n -= cm.display.viewFrom;
2140
+ if (n < 0) return null;
2141
+ var view = cm.display.view;
2142
+ for (var i = 0; i < view.length; i++) {
2143
+ n -= view[i].size;
2144
+ if (n < 0) return i;
2145
+ }
2146
+ }
2147
+
2148
+ function viewCuttingPoint(cm, oldN, newN, dir) {
2149
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
2150
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
2151
+ return {index: index, lineN: newN};
2152
+ for (var i = 0, n = cm.display.viewFrom; i < index; i++)
2153
+ n += view[i].size;
2154
+ if (n != oldN) {
2155
+ if (dir > 0) {
2156
+ if (index == view.length - 1) return null;
2157
+ diff = (n + view[index].size) - oldN;
2158
+ index++;
2159
+ } else {
2160
+ diff = n - oldN;
2161
+ }
2162
+ oldN += diff; newN += diff;
2163
+ }
2164
+ while (visualLineNo(cm.doc, newN) != newN) {
2165
+ if (index == (dir < 0 ? 0 : view.length - 1)) return null;
2166
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
2167
+ index += dir;
2168
+ }
2169
+ return {index: index, lineN: newN};
2170
+ }
2171
+
2172
+ // Force the view to cover a given range, adding empty view element
2173
+ // or clipping off existing ones as needed.
2174
+ function adjustView(cm, from, to) {
2175
+ var display = cm.display, view = display.view;
2176
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
2177
+ display.view = buildViewArray(cm, from, to);
2178
+ display.viewFrom = from;
2179
+ } else {
2180
+ if (display.viewFrom > from)
2181
+ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
2182
+ else if (display.viewFrom < from)
2183
+ display.view = display.view.slice(findViewIndex(cm, from));
2184
+ display.viewFrom = from;
2185
+ if (display.viewTo < to)
2186
+ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
2187
+ else if (display.viewTo > to)
2188
+ display.view = display.view.slice(0, findViewIndex(cm, to));
2189
+ }
2190
+ display.viewTo = to;
2191
+ }
2192
+
2193
+ // Count the number of lines in the view whose DOM representation is
2194
+ // out of date (or nonexistent).
2195
+ function countDirtyView(cm) {
2196
+ var view = cm.display.view, dirty = 0;
2197
+ for (var i = 0; i < view.length; i++) {
2198
+ var lineView = view[i];
2199
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
2200
+ }
2201
+ return dirty;
2202
+ }
2203
+
2204
+ // INPUT HANDLING
2205
+
2206
+ // Poll for input changes, using the normal rate of polling. This
2207
+ // runs as long as the editor is focused.
2208
+ function slowPoll(cm) {
2209
+ if (cm.display.pollingFast) return;
2210
+ cm.display.poll.set(cm.options.pollInterval, function() {
2211
+ readInput(cm);
2212
+ if (cm.state.focused) slowPoll(cm);
2213
+ });
2214
+ }
2215
+
2216
+ // When an event has just come in that is likely to add or change
2217
+ // something in the input textarea, we poll faster, to ensure that
2218
+ // the change appears on the screen quickly.
2219
+ function fastPoll(cm) {
2220
+ var missed = false;
2221
+ cm.display.pollingFast = true;
2222
+ function p() {
2223
+ var changed = readInput(cm);
2224
+ if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
2225
+ else {cm.display.pollingFast = false; slowPoll(cm);}
2226
+ }
2227
+ cm.display.poll.set(20, p);
2228
+ }
2229
+
2230
+ // Read input from the textarea, and update the document to match.
2231
+ // When something is selected, it is present in the textarea, and
2232
+ // selected (unless it is huge, in which case a placeholder is
2233
+ // used). When nothing is selected, the cursor sits after previously
2234
+ // seen text (can be empty), which is stored in prevInput (we must
2235
+ // not reset the textarea when typing, because that breaks IME).
2236
+ function readInput(cm) {
2237
+ var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc;
2238
+ // Since this is called a *lot*, try to bail out as cheaply as
2239
+ // possible when it is clear that nothing happened. hasSelection
2240
+ // will be the case when there is a lot of text in the textarea,
2241
+ // in which case reading its value would be expensive.
2242
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
2243
+ return false;
2244
+ // See paste handler for more on the fakedLastChar kludge
2245
+ if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
2246
+ input.value = input.value.substring(0, input.value.length - 1);
2247
+ cm.state.fakedLastChar = false;
2248
+ }
2249
+ var text = input.value;
2250
+ // If nothing changed, bail.
2251
+ if (text == prevInput && !cm.somethingSelected()) return false;
2252
+ // Work around nonsensical selection resetting in IE9/10
2253
+ if (ie && !ie_upto8 && cm.display.inputHasSelection === text) {
2254
+ resetInput(cm);
2255
+ return false;
2256
+ }
2257
+
2258
+ var withOp = !cm.curOp;
2259
+ if (withOp) startOperation(cm);
2260
+ cm.display.shift = false;
2261
+
2262
+ if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput)
2263
+ prevInput = "\u200b";
2264
+ // Find the part of the input that is actually new
2265
+ var same = 0, l = Math.min(prevInput.length, text.length);
2266
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
2267
+ var inserted = text.slice(same), textLines = splitLines(inserted);
2268
+
2269
+ // When pasing N lines into N selections, insert one line per selection
2270
+ var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.ranges.length == textLines.length;
2271
+
2272
+ // Normal behavior is to insert the new text into every selection
2273
+ for (var i = doc.sel.ranges.length - 1; i >= 0; i--) {
2274
+ var range = doc.sel.ranges[i];
2275
+ var from = range.from(), to = range.to();
2276
+ // Handle deletion
2277
+ if (same < prevInput.length)
2278
+ from = Pos(from.line, from.ch - (prevInput.length - same));
2279
+ // Handle overwrite
2280
+ else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming)
2281
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
2282
+ var updateInput = cm.curOp.updateInput;
2283
+ var changeEvent = {from: from, to: to, text: multiPaste ? [textLines[i]] : textLines,
2284
+ origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
2285
+ makeChange(cm.doc, changeEvent);
2286
+ signalLater(cm, "inputRead", cm, changeEvent);
2287
+ // When an 'electric' character is inserted, immediately trigger a reindent
2288
+ if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
2289
+ cm.options.smartIndent && range.head.ch < 100 &&
2290
+ (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
2291
+ var mode = cm.getModeAt(range.head);
2292
+ if (mode.electricChars) {
2293
+ for (var j = 0; j < mode.electricChars.length; j++)
2294
+ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
2295
+ indentLine(cm, range.head.line, "smart");
2296
+ break;
2297
+ }
2298
+ } else if (mode.electricInput) {
2299
+ var end = changeEnd(changeEvent);
2300
+ if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
2301
+ indentLine(cm, range.head.line, "smart");
2302
+ }
2303
+ }
2304
+ }
2305
+ ensureCursorVisible(cm);
2306
+ cm.curOp.updateInput = updateInput;
2307
+ cm.curOp.typing = true;
2308
+
2309
+ // Don't leave long text in the textarea, since it makes further polling slow
2310
+ if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
2311
+ else cm.display.prevInput = text;
2312
+ if (withOp) endOperation(cm);
2313
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
2314
+ return true;
2315
+ }
2316
+
2317
+ // Reset the input to correspond to the selection (or to be empty,
2318
+ // when not typing and nothing is selected)
2319
+ function resetInput(cm, typing) {
2320
+ var minimal, selected, doc = cm.doc;
2321
+ if (cm.somethingSelected()) {
2322
+ cm.display.prevInput = "";
2323
+ var range = doc.sel.primary();
2324
+ minimal = hasCopyEvent &&
2325
+ (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
2326
+ var content = minimal ? "-" : selected || cm.getSelection();
2327
+ cm.display.input.value = content;
2328
+ if (cm.state.focused) selectInput(cm.display.input);
2329
+ if (ie && !ie_upto8) cm.display.inputHasSelection = content;
2330
+ } else if (!typing) {
2331
+ cm.display.prevInput = cm.display.input.value = "";
2332
+ if (ie && !ie_upto8) cm.display.inputHasSelection = null;
2333
+ }
2334
+ cm.display.inaccurateSelection = minimal;
2335
+ }
2336
+
2337
+ function focusInput(cm) {
2338
+ if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input))
2339
+ cm.display.input.focus();
2340
+ }
2341
+
2342
+ function ensureFocus(cm) {
2343
+ if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
2344
+ }
2345
+
2346
+ function isReadOnly(cm) {
2347
+ return cm.options.readOnly || cm.doc.cantEdit;
2348
+ }
2349
+
2350
+ // EVENT HANDLERS
2351
+
2352
+ // Attach the necessary event handlers when initializing the editor
2353
+ function registerEventHandlers(cm) {
2354
+ var d = cm.display;
2355
+ on(d.scroller, "mousedown", operation(cm, onMouseDown));
2356
+ // Older IE's will not fire a second mousedown for a double click
2357
+ if (ie_upto10)
2358
+ on(d.scroller, "dblclick", operation(cm, function(e) {
2359
+ if (signalDOMEvent(cm, e)) return;
2360
+ var pos = posFromMouse(cm, e);
2361
+ if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
2362
+ e_preventDefault(e);
2363
+ var word = findWordAt(cm, pos);
2364
+ extendSelection(cm.doc, word.anchor, word.head);
2365
+ }));
2366
+ else
2367
+ on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
2368
+ // Prevent normal selection in the editor (we handle our own)
2369
+ on(d.lineSpace, "selectstart", function(e) {
2370
+ if (!eventInWidget(d, e)) e_preventDefault(e);
2371
+ });
2372
+ // Some browsers fire contextmenu *after* opening the menu, at
2373
+ // which point we can't mess with it anymore. Context menu is
2374
+ // handled in onMouseDown for these browsers.
2375
+ if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
2376
+
2377
+ // Sync scrolling between fake scrollbars and real scrollable
2378
+ // area, ensure viewport is updated when scrolling.
2379
+ on(d.scroller, "scroll", function() {
2380
+ if (d.scroller.clientHeight) {
2381
+ setScrollTop(cm, d.scroller.scrollTop);
2382
+ setScrollLeft(cm, d.scroller.scrollLeft, true);
2383
+ signal(cm, "scroll", cm);
2384
+ }
2385
+ });
2386
+ on(d.scrollbarV, "scroll", function() {
2387
+ if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
2388
+ });
2389
+ on(d.scrollbarH, "scroll", function() {
2390
+ if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
2391
+ });
2392
+
2393
+ // Listen to wheel events in order to try and update the viewport on time.
2394
+ on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
2395
+ on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
2396
+
2397
+ // Prevent clicks in the scrollbars from killing focus
2398
+ function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
2399
+ on(d.scrollbarH, "mousedown", reFocus);
2400
+ on(d.scrollbarV, "mousedown", reFocus);
2401
+ // Prevent wrapper from ever scrolling
2402
+ on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
2403
+
2404
+ on(d.input, "keyup", operation(cm, onKeyUp));
2405
+ on(d.input, "input", function() {
2406
+ if (ie && !ie_upto8 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
2407
+ fastPoll(cm);
2408
+ });
2409
+ on(d.input, "keydown", operation(cm, onKeyDown));
2410
+ on(d.input, "keypress", operation(cm, onKeyPress));
2411
+ on(d.input, "focus", bind(onFocus, cm));
2412
+ on(d.input, "blur", bind(onBlur, cm));
2413
+
2414
+ function drag_(e) {
2415
+ if (!signalDOMEvent(cm, e)) e_stop(e);
2416
+ }
2417
+ if (cm.options.dragDrop) {
2418
+ on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
2419
+ on(d.scroller, "dragenter", drag_);
2420
+ on(d.scroller, "dragover", drag_);
2421
+ on(d.scroller, "drop", operation(cm, onDrop));
2422
+ }
2423
+ on(d.scroller, "paste", function(e) {
2424
+ if (eventInWidget(d, e)) return;
2425
+ cm.state.pasteIncoming = true;
2426
+ focusInput(cm);
2427
+ fastPoll(cm);
2428
+ });
2429
+ on(d.input, "paste", function() {
2430
+ // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
2431
+ // Add a char to the end of textarea before paste occur so that
2432
+ // selection doesn't span to the end of textarea.
2433
+ if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
2434
+ var start = d.input.selectionStart, end = d.input.selectionEnd;
2435
+ d.input.value += "$";
2436
+ d.input.selectionStart = start;
2437
+ d.input.selectionEnd = end;
2438
+ cm.state.fakedLastChar = true;
2439
+ }
2440
+ cm.state.pasteIncoming = true;
2441
+ fastPoll(cm);
2442
+ });
2443
+
2444
+ function prepareCopyCut(e) {
2445
+ if (cm.somethingSelected()) {
2446
+ if (d.inaccurateSelection) {
2447
+ d.prevInput = "";
2448
+ d.inaccurateSelection = false;
2449
+ d.input.value = cm.getSelection();
2450
+ selectInput(d.input);
2451
+ }
2452
+ } else {
2453
+ var text = "", ranges = [];
2454
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
2455
+ var line = cm.doc.sel.ranges[i].head.line;
2456
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
2457
+ ranges.push(lineRange);
2458
+ text += cm.getRange(lineRange.anchor, lineRange.head);
2459
+ }
2460
+ if (e.type == "cut") {
2461
+ cm.setSelections(ranges, null, sel_dontScroll);
2462
+ } else {
2463
+ d.prevInput = "";
2464
+ d.input.value = text;
2465
+ selectInput(d.input);
2466
+ }
2467
+ }
2468
+ if (e.type == "cut") cm.state.cutIncoming = true;
2469
+ }
2470
+ on(d.input, "cut", prepareCopyCut);
2471
+ on(d.input, "copy", prepareCopyCut);
2472
+
2473
+ // Needed to handle Tab key in KHTML
2474
+ if (khtml) on(d.sizer, "mouseup", function() {
2475
+ if (activeElt() == d.input) d.input.blur();
2476
+ focusInput(cm);
2477
+ });
2478
+ }
2479
+
2480
+ // Called when the window resizes
2481
+ function onResize(cm) {
2482
+ // Might be a text scaling operation, clear size caches.
2483
+ var d = cm.display;
2484
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
2485
+ cm.setSize();
2486
+ }
2487
+
2488
+ // MOUSE EVENTS
2489
+
2490
+ // Return true when the given mouse event happened in a widget
2491
+ function eventInWidget(display, e) {
2492
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
2493
+ if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
2494
+ }
2495
+ }
2496
+
2497
+ // Given a mouse event, find the corresponding position. If liberal
2498
+ // is false, it checks whether a gutter or scrollbar was clicked,
2499
+ // and returns null if it was. forRect is used by rectangular
2500
+ // selections, and tries to estimate a character position even for
2501
+ // coordinates beyond the right of the text.
2502
+ function posFromMouse(cm, e, liberal, forRect) {
2503
+ var display = cm.display;
2504
+ if (!liberal) {
2505
+ var target = e_target(e);
2506
+ if (target == display.scrollbarH || target == display.scrollbarV ||
2507
+ target == display.scrollbarFiller || target == display.gutterFiller) return null;
2508
+ }
2509
+ var x, y, space = display.lineSpace.getBoundingClientRect();
2510
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
2511
+ try { x = e.clientX - space.left; y = e.clientY - space.top; }
2512
+ catch (e) { return null; }
2513
+ var coords = coordsChar(cm, x, y), line;
2514
+ if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
2515
+ var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
2516
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
2517
+ }
2518
+ return coords;
2519
+ }
2520
+
2521
+ // A mouse down can be a single click, double click, triple click,
2522
+ // start of selection drag, start of text drag, new cursor
2523
+ // (ctrl-click), rectangle drag (alt-drag), or xwin
2524
+ // middle-click-paste. Or it might be a click on something we should
2525
+ // not interfere with, such as a scrollbar or widget.
2526
+ function onMouseDown(e) {
2527
+ if (signalDOMEvent(this, e)) return;
2528
+ var cm = this, display = cm.display;
2529
+ display.shift = e.shiftKey;
2530
+
2531
+ if (eventInWidget(display, e)) {
2532
+ if (!webkit) {
2533
+ // Briefly turn off draggability, to allow widgets to do
2534
+ // normal dragging things.
2535
+ display.scroller.draggable = false;
2536
+ setTimeout(function(){display.scroller.draggable = true;}, 100);
2537
+ }
2538
+ return;
2539
+ }
2540
+ if (clickInGutter(cm, e)) return;
2541
+ var start = posFromMouse(cm, e);
2542
+ window.focus();
2543
+
2544
+ switch (e_button(e)) {
2545
+ case 1:
2546
+ if (start)
2547
+ leftButtonDown(cm, e, start);
2548
+ else if (e_target(e) == display.scroller)
2549
+ e_preventDefault(e);
2550
+ break;
2551
+ case 2:
2552
+ if (webkit) cm.state.lastMiddleDown = +new Date;
2553
+ if (start) extendSelection(cm.doc, start);
2554
+ setTimeout(bind(focusInput, cm), 20);
2555
+ e_preventDefault(e);
2556
+ break;
2557
+ case 3:
2558
+ if (captureRightClick) onContextMenu(cm, e);
2559
+ break;
2560
+ }
2561
+ }
2562
+
2563
+ var lastClick, lastDoubleClick;
2564
+ function leftButtonDown(cm, e, start) {
2565
+ setTimeout(bind(ensureFocus, cm), 0);
2566
+
2567
+ var now = +new Date, type;
2568
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
2569
+ type = "triple";
2570
+ } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
2571
+ type = "double";
2572
+ lastDoubleClick = {time: now, pos: start};
2573
+ } else {
2574
+ type = "single";
2575
+ lastClick = {time: now, pos: start};
2576
+ }
2577
+
2578
+ var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
2579
+ if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
2580
+ type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
2581
+ leftButtonStartDrag(cm, e, start, modifier);
2582
+ else
2583
+ leftButtonSelect(cm, e, start, type, modifier);
2584
+ }
2585
+
2586
+ // Start a text drag. When it ends, see if any dragging actually
2587
+ // happen, and treat as a click if it didn't.
2588
+ function leftButtonStartDrag(cm, e, start, modifier) {
2589
+ var display = cm.display;
2590
+ var dragEnd = operation(cm, function(e2) {
2591
+ if (webkit) display.scroller.draggable = false;
2592
+ cm.state.draggingText = false;
2593
+ off(document, "mouseup", dragEnd);
2594
+ off(display.scroller, "drop", dragEnd);
2595
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
2596
+ e_preventDefault(e2);
2597
+ if (!modifier)
2598
+ extendSelection(cm.doc, start);
2599
+ focusInput(cm);
2600
+ // Work around unexplainable focus problem in IE9 (#2127)
2601
+ if (ie_upto10 && !ie_upto8)
2602
+ setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
2603
+ }
2604
+ });
2605
+ // Let the drag handler handle this.
2606
+ if (webkit) display.scroller.draggable = true;
2607
+ cm.state.draggingText = dragEnd;
2608
+ // IE's approach to draggable
2609
+ if (display.scroller.dragDrop) display.scroller.dragDrop();
2610
+ on(document, "mouseup", dragEnd);
2611
+ on(display.scroller, "drop", dragEnd);
2612
+ }
2613
+
2614
+ // Normal selection, as opposed to text dragging.
2615
+ function leftButtonSelect(cm, e, start, type, addNew) {
2616
+ var display = cm.display, doc = cm.doc;
2617
+ e_preventDefault(e);
2618
+
2619
+ var ourRange, ourIndex, startSel = doc.sel;
2620
+ if (addNew && !e.shiftKey) {
2621
+ ourIndex = doc.sel.contains(start);
2622
+ if (ourIndex > -1)
2623
+ ourRange = doc.sel.ranges[ourIndex];
2624
+ else
2625
+ ourRange = new Range(start, start);
2626
+ } else {
2627
+ ourRange = doc.sel.primary();
2628
+ }
2629
+
2630
+ if (e.altKey) {
2631
+ type = "rect";
2632
+ if (!addNew) ourRange = new Range(start, start);
2633
+ start = posFromMouse(cm, e, true, true);
2634
+ ourIndex = -1;
2635
+ } else if (type == "double") {
2636
+ var word = findWordAt(cm, start);
2637
+ if (cm.display.shift || doc.extend)
2638
+ ourRange = extendRange(doc, ourRange, word.anchor, word.head);
2639
+ else
2640
+ ourRange = word;
2641
+ } else if (type == "triple") {
2642
+ var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
2643
+ if (cm.display.shift || doc.extend)
2644
+ ourRange = extendRange(doc, ourRange, line.anchor, line.head);
2645
+ else
2646
+ ourRange = line;
2647
+ } else {
2648
+ ourRange = extendRange(doc, ourRange, start);
2649
+ }
2650
+
2651
+ if (!addNew) {
2652
+ ourIndex = 0;
2653
+ setSelection(doc, new Selection([ourRange], 0), sel_mouse);
2654
+ startSel = doc.sel;
2655
+ } else if (ourIndex > -1) {
2656
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
2657
+ } else {
2658
+ ourIndex = doc.sel.ranges.length;
2659
+ setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
2660
+ {scroll: false, origin: "*mouse"});
2661
+ }
2662
+
2663
+ var lastPos = start;
2664
+ function extendTo(pos) {
2665
+ if (cmp(lastPos, pos) == 0) return;
2666
+ lastPos = pos;
2667
+
2668
+ if (type == "rect") {
2669
+ var ranges = [], tabSize = cm.options.tabSize;
2670
+ var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
2671
+ var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
2672
+ var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
2673
+ for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
2674
+ line <= end; line++) {
2675
+ var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
2676
+ if (left == right)
2677
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
2678
+ else if (text.length > leftPos)
2679
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
2680
+ }
2681
+ if (!ranges.length) ranges.push(new Range(start, start));
2682
+ setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
2683
+ {origin: "*mouse", scroll: false});
2684
+ cm.scrollIntoView(pos);
2685
+ } else {
2686
+ var oldRange = ourRange;
2687
+ var anchor = oldRange.anchor, head = pos;
2688
+ if (type != "single") {
2689
+ if (type == "double")
2690
+ var range = findWordAt(cm, pos);
2691
+ else
2692
+ var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
2693
+ if (cmp(range.anchor, anchor) > 0) {
2694
+ head = range.head;
2695
+ anchor = minPos(oldRange.from(), range.anchor);
2696
+ } else {
2697
+ head = range.anchor;
2698
+ anchor = maxPos(oldRange.to(), range.head);
2699
+ }
2700
+ }
2701
+ var ranges = startSel.ranges.slice(0);
2702
+ ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
2703
+ setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
2704
+ }
2705
+ }
2706
+
2707
+ var editorSize = display.wrapper.getBoundingClientRect();
2708
+ // Used to ensure timeout re-tries don't fire when another extend
2709
+ // happened in the meantime (clearTimeout isn't reliable -- at
2710
+ // least on Chrome, the timeouts still happen even when cleared,
2711
+ // if the clear happens after their scheduled firing time).
2712
+ var counter = 0;
2713
+
2714
+ function extend(e) {
2715
+ var curCount = ++counter;
2716
+ var cur = posFromMouse(cm, e, true, type == "rect");
2717
+ if (!cur) return;
2718
+ if (cmp(cur, lastPos) != 0) {
2719
+ ensureFocus(cm);
2720
+ extendTo(cur);
2721
+ var visible = visibleLines(display, doc);
2722
+ if (cur.line >= visible.to || cur.line < visible.from)
2723
+ setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
2724
+ } else {
2725
+ var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
2726
+ if (outside) setTimeout(operation(cm, function() {
2727
+ if (counter != curCount) return;
2728
+ display.scroller.scrollTop += outside;
2729
+ extend(e);
2730
+ }), 50);
2731
+ }
2732
+ }
2733
+
2734
+ function done(e) {
2735
+ counter = Infinity;
2736
+ e_preventDefault(e);
2737
+ focusInput(cm);
2738
+ off(document, "mousemove", move);
2739
+ off(document, "mouseup", up);
2740
+ doc.history.lastSelOrigin = null;
2741
+ }
2742
+
2743
+ var move = operation(cm, function(e) {
2744
+ if ((ie && !ie_upto9) ? !e.buttons : !e_button(e)) done(e);
2745
+ else extend(e);
2746
+ });
2747
+ var up = operation(cm, done);
2748
+ on(document, "mousemove", move);
2749
+ on(document, "mouseup", up);
2750
+ }
2751
+
2752
+ // Determines whether an event happened in the gutter, and fires the
2753
+ // handlers for the corresponding event.
2754
+ function gutterEvent(cm, e, type, prevent, signalfn) {
2755
+ try { var mX = e.clientX, mY = e.clientY; }
2756
+ catch(e) { return false; }
2757
+ if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
2758
+ if (prevent) e_preventDefault(e);
2759
+
2760
+ var display = cm.display;
2761
+ var lineBox = display.lineDiv.getBoundingClientRect();
2762
+
2763
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
2764
+ mY -= lineBox.top - display.viewOffset;
2765
+
2766
+ for (var i = 0; i < cm.options.gutters.length; ++i) {
2767
+ var g = display.gutters.childNodes[i];
2768
+ if (g && g.getBoundingClientRect().right >= mX) {
2769
+ var line = lineAtHeight(cm.doc, mY);
2770
+ var gutter = cm.options.gutters[i];
2771
+ signalfn(cm, type, cm, line, gutter, e);
2772
+ return e_defaultPrevented(e);
2773
+ }
2774
+ }
2775
+ }
2776
+
2777
+ function clickInGutter(cm, e) {
2778
+ return gutterEvent(cm, e, "gutterClick", true, signalLater);
2779
+ }
2780
+
2781
+ // Kludge to work around strange IE behavior where it'll sometimes
2782
+ // re-fire a series of drag-related events right after the drop (#1551)
2783
+ var lastDrop = 0;
2784
+
2785
+ function onDrop(e) {
2786
+ var cm = this;
2787
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
2788
+ return;
2789
+ e_preventDefault(e);
2790
+ if (ie) lastDrop = +new Date;
2791
+ var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
2792
+ if (!pos || isReadOnly(cm)) return;
2793
+ // Might be a file drop, in which case we simply extract the text
2794
+ // and insert it.
2795
+ if (files && files.length && window.FileReader && window.File) {
2796
+ var n = files.length, text = Array(n), read = 0;
2797
+ var loadFile = function(file, i) {
2798
+ var reader = new FileReader;
2799
+ reader.onload = operation(cm, function() {
2800
+ text[i] = reader.result;
2801
+ if (++read == n) {
2802
+ pos = clipPos(cm.doc, pos);
2803
+ var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
2804
+ makeChange(cm.doc, change);
2805
+ setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
2806
+ }
2807
+ });
2808
+ reader.readAsText(file);
2809
+ };
2810
+ for (var i = 0; i < n; ++i) loadFile(files[i], i);
2811
+ } else { // Normal drop
2812
+ // Don't do a replace if the drop happened inside of the selected text.
2813
+ if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
2814
+ cm.state.draggingText(e);
2815
+ // Ensure the editor is re-focused
2816
+ setTimeout(bind(focusInput, cm), 20);
2817
+ return;
2818
+ }
2819
+ try {
2820
+ var text = e.dataTransfer.getData("Text");
2821
+ if (text) {
2822
+ if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey))
2823
+ var selected = cm.listSelections();
2824
+ setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
2825
+ if (selected) for (var i = 0; i < selected.length; ++i)
2826
+ replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
2827
+ cm.replaceSelection(text, "around", "paste");
2828
+ focusInput(cm);
2829
+ }
2830
+ }
2831
+ catch(e){}
2832
+ }
2833
+ }
2834
+
2835
+ function onDragStart(cm, e) {
2836
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
2837
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
2838
+
2839
+ e.dataTransfer.setData("Text", cm.getSelection());
2840
+
2841
+ // Use dummy image instead of default browsers image.
2842
+ // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
2843
+ if (e.dataTransfer.setDragImage && !safari) {
2844
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
2845
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
2846
+ if (presto) {
2847
+ img.width = img.height = 1;
2848
+ cm.display.wrapper.appendChild(img);
2849
+ // Force a relayout, or Opera won't use our image for some obscure reason
2850
+ img._top = img.offsetTop;
2851
+ }
2852
+ e.dataTransfer.setDragImage(img, 0, 0);
2853
+ if (presto) img.parentNode.removeChild(img);
2854
+ }
2855
+ }
2856
+
2857
+ // SCROLL EVENTS
2858
+
2859
+ // Sync the scrollable area and scrollbars, ensure the viewport
2860
+ // covers the visible area.
2861
+ function setScrollTop(cm, val) {
2862
+ if (Math.abs(cm.doc.scrollTop - val) < 2) return;
2863
+ cm.doc.scrollTop = val;
2864
+ if (!gecko) updateDisplay(cm, {top: val});
2865
+ if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
2866
+ if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
2867
+ if (gecko) updateDisplay(cm);
2868
+ startWorker(cm, 100);
2869
+ }
2870
+ // Sync scroller and scrollbar, ensure the gutter elements are
2871
+ // aligned.
2872
+ function setScrollLeft(cm, val, isScroller) {
2873
+ if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
2874
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
2875
+ cm.doc.scrollLeft = val;
2876
+ alignHorizontally(cm);
2877
+ if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
2878
+ if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
2879
+ }
2880
+
2881
+ // Since the delta values reported on mouse wheel events are
2882
+ // unstandardized between browsers and even browser versions, and
2883
+ // generally horribly unpredictable, this code starts by measuring
2884
+ // the scroll effect that the first few mouse wheel events have,
2885
+ // and, from that, detects the way it can convert deltas to pixel
2886
+ // offsets afterwards.
2887
+ //
2888
+ // The reason we want to know the amount a wheel event will scroll
2889
+ // is that it gives us a chance to update the display before the
2890
+ // actual scrolling happens, reducing flickering.
2891
+
2892
+ var wheelSamples = 0, wheelPixelsPerUnit = null;
2893
+ // Fill in a browser-detected starting value on browsers where we
2894
+ // know one. These don't have to be accurate -- the result of them
2895
+ // being wrong would just be a slight flicker on the first wheel
2896
+ // scroll (if it is large enough).
2897
+ if (ie) wheelPixelsPerUnit = -.53;
2898
+ else if (gecko) wheelPixelsPerUnit = 15;
2899
+ else if (chrome) wheelPixelsPerUnit = -.7;
2900
+ else if (safari) wheelPixelsPerUnit = -1/3;
2901
+
2902
+ function onScrollWheel(cm, e) {
2903
+ var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
2904
+ if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
2905
+ if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
2906
+ else if (dy == null) dy = e.wheelDelta;
2907
+
2908
+ var display = cm.display, scroll = display.scroller;
2909
+ // Quit if there's nothing to scroll here
2910
+ if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
2911
+ dy && scroll.scrollHeight > scroll.clientHeight)) return;
2912
+
2913
+ // Webkit browsers on OS X abort momentum scrolls when the target
2914
+ // of the scroll event is removed from the scrollable element.
2915
+ // This hack (see related code in patchDisplay) makes sure the
2916
+ // element is kept around.
2917
+ if (dy && mac && webkit) {
2918
+ outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
2919
+ for (var i = 0; i < view.length; i++) {
2920
+ if (view[i].node == cur) {
2921
+ cm.display.currentWheelTarget = cur;
2922
+ break outer;
2923
+ }
2924
+ }
2925
+ }
2926
+ }
2927
+
2928
+ // On some browsers, horizontal scrolling will cause redraws to
2929
+ // happen before the gutter has been realigned, causing it to
2930
+ // wriggle around in a most unseemly way. When we have an
2931
+ // estimated pixels/delta value, we just handle horizontal
2932
+ // scrolling entirely here. It'll be slightly off from native, but
2933
+ // better than glitching out.
2934
+ if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
2935
+ if (dy)
2936
+ setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
2937
+ setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
2938
+ e_preventDefault(e);
2939
+ display.wheelStartX = null; // Abort measurement, if in progress
2940
+ return;
2941
+ }
2942
+
2943
+ // 'Project' the visible viewport to cover the area that is being
2944
+ // scrolled into view (if we know enough to estimate it).
2945
+ if (dy && wheelPixelsPerUnit != null) {
2946
+ var pixels = dy * wheelPixelsPerUnit;
2947
+ var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
2948
+ if (pixels < 0) top = Math.max(0, top + pixels - 50);
2949
+ else bot = Math.min(cm.doc.height, bot + pixels + 50);
2950
+ updateDisplay(cm, {top: top, bottom: bot});
2951
+ }
2952
+
2953
+ if (wheelSamples < 20) {
2954
+ if (display.wheelStartX == null) {
2955
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
2956
+ display.wheelDX = dx; display.wheelDY = dy;
2957
+ setTimeout(function() {
2958
+ if (display.wheelStartX == null) return;
2959
+ var movedX = scroll.scrollLeft - display.wheelStartX;
2960
+ var movedY = scroll.scrollTop - display.wheelStartY;
2961
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
2962
+ (movedX && display.wheelDX && movedX / display.wheelDX);
2963
+ display.wheelStartX = display.wheelStartY = null;
2964
+ if (!sample) return;
2965
+ wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
2966
+ ++wheelSamples;
2967
+ }, 200);
2968
+ } else {
2969
+ display.wheelDX += dx; display.wheelDY += dy;
2970
+ }
2971
+ }
2972
+ }
2973
+
2974
+ // KEY EVENTS
2975
+
2976
+ // Run a handler that was bound to a key.
2977
+ function doHandleBinding(cm, bound, dropShift) {
2978
+ if (typeof bound == "string") {
2979
+ bound = commands[bound];
2980
+ if (!bound) return false;
2981
+ }
2982
+ // Ensure previous input has been read, so that the handler sees a
2983
+ // consistent view of the document
2984
+ if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
2985
+ var prevShift = cm.display.shift, done = false;
2986
+ try {
2987
+ if (isReadOnly(cm)) cm.state.suppressEdits = true;
2988
+ if (dropShift) cm.display.shift = false;
2989
+ done = bound(cm) != Pass;
2990
+ } finally {
2991
+ cm.display.shift = prevShift;
2992
+ cm.state.suppressEdits = false;
2993
+ }
2994
+ return done;
2995
+ }
2996
+
2997
+ // Collect the currently active keymaps.
2998
+ function allKeyMaps(cm) {
2999
+ var maps = cm.state.keyMaps.slice(0);
3000
+ if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
3001
+ maps.push(cm.options.keyMap);
3002
+ return maps;
3003
+ }
3004
+
3005
+ var maybeTransition;
3006
+ // Handle a key from the keydown event.
3007
+ function handleKeyBinding(cm, e) {
3008
+ // Handle automatic keymap transitions
3009
+ var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
3010
+ clearTimeout(maybeTransition);
3011
+ if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
3012
+ if (getKeyMap(cm.options.keyMap) == startMap) {
3013
+ cm.options.keyMap = (next.call ? next.call(null, cm) : next);
3014
+ keyMapChanged(cm);
3015
+ }
3016
+ }, 50);
3017
+
3018
+ var name = keyName(e, true), handled = false;
3019
+ if (!name) return false;
3020
+ var keymaps = allKeyMaps(cm);
3021
+
3022
+ if (e.shiftKey) {
3023
+ // First try to resolve full name (including 'Shift-'). Failing
3024
+ // that, see if there is a cursor-motion command (starting with
3025
+ // 'go') bound to the keyname without 'Shift-'.
3026
+ handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
3027
+ || lookupKey(name, keymaps, function(b) {
3028
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
3029
+ return doHandleBinding(cm, b);
3030
+ });
3031
+ } else {
3032
+ handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
3033
+ }
3034
+
3035
+ if (handled) {
3036
+ e_preventDefault(e);
3037
+ restartBlink(cm);
3038
+ signalLater(cm, "keyHandled", cm, name, e);
3039
+ }
3040
+ return handled;
3041
+ }
3042
+
3043
+ // Handle a key from the keypress event
3044
+ function handleCharBinding(cm, e, ch) {
3045
+ var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
3046
+ function(b) { return doHandleBinding(cm, b, true); });
3047
+ if (handled) {
3048
+ e_preventDefault(e);
3049
+ restartBlink(cm);
3050
+ signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
3051
+ }
3052
+ return handled;
3053
+ }
3054
+
3055
+ var lastStoppedKey = null;
3056
+ function onKeyDown(e) {
3057
+ var cm = this;
3058
+ ensureFocus(cm);
3059
+ if (signalDOMEvent(cm, e)) return;
3060
+ // IE does strange things with escape.
3061
+ if (ie_upto10 && e.keyCode == 27) e.returnValue = false;
3062
+ var code = e.keyCode;
3063
+ cm.display.shift = code == 16 || e.shiftKey;
3064
+ var handled = handleKeyBinding(cm, e);
3065
+ if (presto) {
3066
+ lastStoppedKey = handled ? code : null;
3067
+ // Opera has no cut event... we try to at least catch the key combo
3068
+ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
3069
+ cm.replaceSelection("", null, "cut");
3070
+ }
3071
+
3072
+ // Turn mouse into crosshair when Alt is held on Mac.
3073
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
3074
+ showCrossHair(cm);
3075
+ }
3076
+
3077
+ function showCrossHair(cm) {
3078
+ var lineDiv = cm.display.lineDiv;
3079
+ addClass(lineDiv, "CodeMirror-crosshair");
3080
+
3081
+ function up(e) {
3082
+ if (e.keyCode == 18 || !e.altKey) {
3083
+ rmClass(lineDiv, "CodeMirror-crosshair");
3084
+ off(document, "keyup", up);
3085
+ off(document, "mouseover", up);
3086
+ }
3087
+ }
3088
+ on(document, "keyup", up);
3089
+ on(document, "mouseover", up);
3090
+ }
3091
+
3092
+ function onKeyUp(e) {
3093
+ if (signalDOMEvent(this, e)) return;
3094
+ if (e.keyCode == 16) this.doc.sel.shift = false;
3095
+ }
3096
+
3097
+ function onKeyPress(e) {
3098
+ var cm = this;
3099
+ if (signalDOMEvent(cm, e)) return;
3100
+ var keyCode = e.keyCode, charCode = e.charCode;
3101
+ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
3102
+ if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
3103
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
3104
+ if (handleCharBinding(cm, e, ch)) return;
3105
+ if (ie && !ie_upto8) cm.display.inputHasSelection = null;
3106
+ fastPoll(cm);
3107
+ }
3108
+
3109
+ // FOCUS/BLUR EVENTS
3110
+
3111
+ function onFocus(cm) {
3112
+ if (cm.options.readOnly == "nocursor") return;
3113
+ if (!cm.state.focused) {
3114
+ signal(cm, "focus", cm);
3115
+ cm.state.focused = true;
3116
+ addClass(cm.display.wrapper, "CodeMirror-focused");
3117
+ // The prevInput test prevents this from firing when a context
3118
+ // menu is closed (since the resetInput would kill the
3119
+ // select-all detection hack)
3120
+ if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
3121
+ resetInput(cm);
3122
+ if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
3123
+ }
3124
+ }
3125
+ slowPoll(cm);
3126
+ restartBlink(cm);
3127
+ }
3128
+ function onBlur(cm) {
3129
+ if (cm.state.focused) {
3130
+ signal(cm, "blur", cm);
3131
+ cm.state.focused = false;
3132
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
3133
+ }
3134
+ clearInterval(cm.display.blinker);
3135
+ setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
3136
+ }
3137
+
3138
+ // CONTEXT MENU HANDLING
3139
+
3140
+ // To make the context menu work, we need to briefly unhide the
3141
+ // textarea (making it as unobtrusive as possible) to let the
3142
+ // right-click take effect on it.
3143
+ function onContextMenu(cm, e) {
3144
+ if (signalDOMEvent(cm, e, "contextmenu")) return;
3145
+ var display = cm.display;
3146
+ if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
3147
+
3148
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
3149
+ if (!pos || presto) return; // Opera is difficult.
3150
+
3151
+ // Reset the current text selection only if the click is done outside of the selection
3152
+ // and 'resetSelectionOnContextMenu' option is true.
3153
+ var reset = cm.options.resetSelectionOnContextMenu;
3154
+ if (reset && cm.doc.sel.contains(pos) == -1)
3155
+ operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
3156
+
3157
+ var oldCSS = display.input.style.cssText;
3158
+ display.inputDiv.style.position = "absolute";
3159
+ display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
3160
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
3161
+ (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
3162
+ "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
3163
+ focusInput(cm);
3164
+ resetInput(cm);
3165
+ // Adds "Select all" to context menu in FF
3166
+ if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
3167
+ display.selForContextMenu = cm.doc.sel;
3168
+ clearTimeout(display.detectingSelectAll);
3169
+
3170
+ // Select-all will be greyed out if there's nothing to select, so
3171
+ // this adds a zero-width space so that we can later check whether
3172
+ // it got selected.
3173
+ function prepareSelectAllHack() {
3174
+ if (display.input.selectionStart != null) {
3175
+ var selected = cm.somethingSelected();
3176
+ var extval = display.input.value = "\u200b" + (selected ? display.input.value : "");
3177
+ display.prevInput = selected ? "" : "\u200b";
3178
+ display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
3179
+ // Re-set this, in case some other handler touched the
3180
+ // selection in the meantime.
3181
+ display.selForContextMenu = cm.doc.sel;
3182
+ }
3183
+ }
3184
+ function rehide() {
3185
+ display.inputDiv.style.position = "relative";
3186
+ display.input.style.cssText = oldCSS;
3187
+ if (ie_upto8) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
3188
+ slowPoll(cm);
3189
+
3190
+ // Try to detect the user choosing select-all
3191
+ if (display.input.selectionStart != null) {
3192
+ if (!ie || ie_upto8) prepareSelectAllHack();
3193
+ var i = 0, poll = function() {
3194
+ if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0)
3195
+ operation(cm, commands.selectAll)(cm);
3196
+ else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
3197
+ else resetInput(cm);
3198
+ };
3199
+ display.detectingSelectAll = setTimeout(poll, 200);
3200
+ }
3201
+ }
3202
+
3203
+ if (ie && !ie_upto8) prepareSelectAllHack();
3204
+ if (captureRightClick) {
3205
+ e_stop(e);
3206
+ var mouseup = function() {
3207
+ off(window, "mouseup", mouseup);
3208
+ setTimeout(rehide, 20);
3209
+ };
3210
+ on(window, "mouseup", mouseup);
3211
+ } else {
3212
+ setTimeout(rehide, 50);
3213
+ }
3214
+ }
3215
+
3216
+ function contextMenuInGutter(cm, e) {
3217
+ if (!hasHandler(cm, "gutterContextMenu")) return false;
3218
+ return gutterEvent(cm, e, "gutterContextMenu", false, signal);
3219
+ }
3220
+
3221
+ // UPDATING
3222
+
3223
+ // Compute the position of the end of a change (its 'to' property
3224
+ // refers to the pre-change end).
3225
+ var changeEnd = CodeMirror.changeEnd = function(change) {
3226
+ if (!change.text) return change.to;
3227
+ return Pos(change.from.line + change.text.length - 1,
3228
+ lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
3229
+ };
3230
+
3231
+ // Adjust a position to refer to the post-change position of the
3232
+ // same text, or the end of the change if the change covers it.
3233
+ function adjustForChange(pos, change) {
3234
+ if (cmp(pos, change.from) < 0) return pos;
3235
+ if (cmp(pos, change.to) <= 0) return changeEnd(change);
3236
+
3237
+ var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
3238
+ if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
3239
+ return Pos(line, ch);
3240
+ }
3241
+
3242
+ function computeSelAfterChange(doc, change) {
3243
+ var out = [];
3244
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
3245
+ var range = doc.sel.ranges[i];
3246
+ out.push(new Range(adjustForChange(range.anchor, change),
3247
+ adjustForChange(range.head, change)));
3248
+ }
3249
+ return normalizeSelection(out, doc.sel.primIndex);
3250
+ }
3251
+
3252
+ function offsetPos(pos, old, nw) {
3253
+ if (pos.line == old.line)
3254
+ return Pos(nw.line, pos.ch - old.ch + nw.ch);
3255
+ else
3256
+ return Pos(nw.line + (pos.line - old.line), pos.ch);
3257
+ }
3258
+
3259
+ // Used by replaceSelections to allow moving the selection to the
3260
+ // start or around the replaced test. Hint may be "start" or "around".
3261
+ function computeReplacedSel(doc, changes, hint) {
3262
+ var out = [];
3263
+ var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
3264
+ for (var i = 0; i < changes.length; i++) {
3265
+ var change = changes[i];
3266
+ var from = offsetPos(change.from, oldPrev, newPrev);
3267
+ var to = offsetPos(changeEnd(change), oldPrev, newPrev);
3268
+ oldPrev = change.to;
3269
+ newPrev = to;
3270
+ if (hint == "around") {
3271
+ var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
3272
+ out[i] = new Range(inv ? to : from, inv ? from : to);
3273
+ } else {
3274
+ out[i] = new Range(from, from);
3275
+ }
3276
+ }
3277
+ return new Selection(out, doc.sel.primIndex);
3278
+ }
3279
+
3280
+ // Allow "beforeChange" event handlers to influence a change
3281
+ function filterChange(doc, change, update) {
3282
+ var obj = {
3283
+ canceled: false,
3284
+ from: change.from,
3285
+ to: change.to,
3286
+ text: change.text,
3287
+ origin: change.origin,
3288
+ cancel: function() { this.canceled = true; }
3289
+ };
3290
+ if (update) obj.update = function(from, to, text, origin) {
3291
+ if (from) this.from = clipPos(doc, from);
3292
+ if (to) this.to = clipPos(doc, to);
3293
+ if (text) this.text = text;
3294
+ if (origin !== undefined) this.origin = origin;
3295
+ };
3296
+ signal(doc, "beforeChange", doc, obj);
3297
+ if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
3298
+
3299
+ if (obj.canceled) return null;
3300
+ return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
3301
+ }
3302
+
3303
+ // Apply a change to a document, and add it to the document's
3304
+ // history, and propagating it to all linked documents.
3305
+ function makeChange(doc, change, ignoreReadOnly) {
3306
+ if (doc.cm) {
3307
+ if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
3308
+ if (doc.cm.state.suppressEdits) return;
3309
+ }
3310
+
3311
+ if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
3312
+ change = filterChange(doc, change, true);
3313
+ if (!change) return;
3314
+ }
3315
+
3316
+ // Possibly split or suppress the update based on the presence
3317
+ // of read-only spans in its range.
3318
+ var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
3319
+ if (split) {
3320
+ for (var i = split.length - 1; i >= 0; --i)
3321
+ makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
3322
+ } else {
3323
+ makeChangeInner(doc, change);
3324
+ }
3325
+ }
3326
+
3327
+ function makeChangeInner(doc, change) {
3328
+ if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
3329
+ var selAfter = computeSelAfterChange(doc, change);
3330
+ addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
3331
+
3332
+ makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
3333
+ var rebased = [];
3334
+
3335
+ linkedDocs(doc, function(doc, sharedHist) {
3336
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
3337
+ rebaseHist(doc.history, change);
3338
+ rebased.push(doc.history);
3339
+ }
3340
+ makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
3341
+ });
3342
+ }
3343
+
3344
+ // Revert a change stored in a document's history.
3345
+ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
3346
+ if (doc.cm && doc.cm.state.suppressEdits) return;
3347
+
3348
+ var hist = doc.history, event, selAfter = doc.sel;
3349
+ var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
3350
+
3351
+ // Verify that there is a useable event (so that ctrl-z won't
3352
+ // needlessly clear selection events)
3353
+ for (var i = 0; i < source.length; i++) {
3354
+ event = source[i];
3355
+ if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
3356
+ break;
3357
+ }
3358
+ if (i == source.length) return;
3359
+ hist.lastOrigin = hist.lastSelOrigin = null;
3360
+
3361
+ for (;;) {
3362
+ event = source.pop();
3363
+ if (event.ranges) {
3364
+ pushSelectionToHistory(event, dest);
3365
+ if (allowSelectionOnly && !event.equals(doc.sel)) {
3366
+ setSelection(doc, event, {clearRedo: false});
3367
+ return;
3368
+ }
3369
+ selAfter = event;
3370
+ }
3371
+ else break;
3372
+ }
3373
+
3374
+ // Build up a reverse change object to add to the opposite history
3375
+ // stack (redo when undoing, and vice versa).
3376
+ var antiChanges = [];
3377
+ pushSelectionToHistory(selAfter, dest);
3378
+ dest.push({changes: antiChanges, generation: hist.generation});
3379
+ hist.generation = event.generation || ++hist.maxGeneration;
3380
+
3381
+ var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
3382
+
3383
+ for (var i = event.changes.length - 1; i >= 0; --i) {
3384
+ var change = event.changes[i];
3385
+ change.origin = type;
3386
+ if (filter && !filterChange(doc, change, false)) {
3387
+ source.length = 0;
3388
+ return;
3389
+ }
3390
+
3391
+ antiChanges.push(historyChangeFromChange(doc, change));
3392
+
3393
+ var after = i ? computeSelAfterChange(doc, change, null) : lst(source);
3394
+ makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
3395
+ if (!i && doc.cm) doc.cm.scrollIntoView(change);
3396
+ var rebased = [];
3397
+
3398
+ // Propagate to the linked documents
3399
+ linkedDocs(doc, function(doc, sharedHist) {
3400
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
3401
+ rebaseHist(doc.history, change);
3402
+ rebased.push(doc.history);
3403
+ }
3404
+ makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
3405
+ });
3406
+ }
3407
+ }
3408
+
3409
+ // Sub-views need their line numbers shifted when text is added
3410
+ // above or below them in the parent document.
3411
+ function shiftDoc(doc, distance) {
3412
+ if (distance == 0) return;
3413
+ doc.first += distance;
3414
+ doc.sel = new Selection(map(doc.sel.ranges, function(range) {
3415
+ return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
3416
+ Pos(range.head.line + distance, range.head.ch));
3417
+ }), doc.sel.primIndex);
3418
+ if (doc.cm) {
3419
+ regChange(doc.cm, doc.first, doc.first - distance, distance);
3420
+ for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
3421
+ regLineChange(doc.cm, l, "gutter");
3422
+ }
3423
+ }
3424
+
3425
+ // More lower-level change function, handling only a single document
3426
+ // (not linked ones).
3427
+ function makeChangeSingleDoc(doc, change, selAfter, spans) {
3428
+ if (doc.cm && !doc.cm.curOp)
3429
+ return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
3430
+
3431
+ if (change.to.line < doc.first) {
3432
+ shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
3433
+ return;
3434
+ }
3435
+ if (change.from.line > doc.lastLine()) return;
3436
+
3437
+ // Clip the change to the size of this doc
3438
+ if (change.from.line < doc.first) {
3439
+ var shift = change.text.length - 1 - (doc.first - change.from.line);
3440
+ shiftDoc(doc, shift);
3441
+ change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
3442
+ text: [lst(change.text)], origin: change.origin};
3443
+ }
3444
+ var last = doc.lastLine();
3445
+ if (change.to.line > last) {
3446
+ change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
3447
+ text: [change.text[0]], origin: change.origin};
3448
+ }
3449
+
3450
+ change.removed = getBetween(doc, change.from, change.to);
3451
+
3452
+ if (!selAfter) selAfter = computeSelAfterChange(doc, change, null);
3453
+ if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
3454
+ else updateDoc(doc, change, spans);
3455
+ setSelectionNoUndo(doc, selAfter, sel_dontScroll);
3456
+ }
3457
+
3458
+ // Handle the interaction of a change to a document with the editor
3459
+ // that this document is part of.
3460
+ function makeChangeSingleDocInEditor(cm, change, spans) {
3461
+ var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
3462
+
3463
+ var recomputeMaxLength = false, checkWidthStart = from.line;
3464
+ if (!cm.options.lineWrapping) {
3465
+ checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
3466
+ doc.iter(checkWidthStart, to.line + 1, function(line) {
3467
+ if (line == display.maxLine) {
3468
+ recomputeMaxLength = true;
3469
+ return true;
3470
+ }
3471
+ });
3472
+ }
3473
+
3474
+ if (doc.sel.contains(change.from, change.to) > -1)
3475
+ signalCursorActivity(cm);
3476
+
3477
+ updateDoc(doc, change, spans, estimateHeight(cm));
3478
+
3479
+ if (!cm.options.lineWrapping) {
3480
+ doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
3481
+ var len = lineLength(line);
3482
+ if (len > display.maxLineLength) {
3483
+ display.maxLine = line;
3484
+ display.maxLineLength = len;
3485
+ display.maxLineChanged = true;
3486
+ recomputeMaxLength = false;
3487
+ }
3488
+ });
3489
+ if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
3490
+ }
3491
+
3492
+ // Adjust frontier, schedule worker
3493
+ doc.frontier = Math.min(doc.frontier, from.line);
3494
+ startWorker(cm, 400);
3495
+
3496
+ var lendiff = change.text.length - (to.line - from.line) - 1;
3497
+ // Remember that these lines changed, for updating the display
3498
+ if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
3499
+ regLineChange(cm, from.line, "text");
3500
+ else
3501
+ regChange(cm, from.line, to.line + 1, lendiff);
3502
+
3503
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
3504
+ if (changeHandler || changesHandler) {
3505
+ var obj = {
3506
+ from: from, to: to,
3507
+ text: change.text,
3508
+ removed: change.removed,
3509
+ origin: change.origin
3510
+ };
3511
+ if (changeHandler) signalLater(cm, "change", cm, obj);
3512
+ if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
3513
+ }
3514
+ cm.display.selForContextMenu = null;
3515
+ }
3516
+
3517
+ function replaceRange(doc, code, from, to, origin) {
3518
+ if (!to) to = from;
3519
+ if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
3520
+ if (typeof code == "string") code = splitLines(code);
3521
+ makeChange(doc, {from: from, to: to, text: code, origin: origin});
3522
+ }
3523
+
3524
+ // SCROLLING THINGS INTO VIEW
3525
+
3526
+ // If an editor sits on the top or bottom of the window, partially
3527
+ // scrolled out of view, this ensures that the cursor is visible.
3528
+ function maybeScrollWindow(cm, coords) {
3529
+ var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
3530
+ if (coords.top + box.top < 0) doScroll = true;
3531
+ else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
3532
+ if (doScroll != null && !phantom) {
3533
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
3534
+ (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
3535
+ (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
3536
+ coords.left + "px; width: 2px;");
3537
+ cm.display.lineSpace.appendChild(scrollNode);
3538
+ scrollNode.scrollIntoView(doScroll);
3539
+ cm.display.lineSpace.removeChild(scrollNode);
3540
+ }
3541
+ }
3542
+
3543
+ // Scroll a given position into view (immediately), verifying that
3544
+ // it actually became visible (as line heights are accurately
3545
+ // measured, the position of something may 'drift' during drawing).
3546
+ function scrollPosIntoView(cm, pos, end, margin) {
3547
+ if (margin == null) margin = 0;
3548
+ for (;;) {
3549
+ var changed = false, coords = cursorCoords(cm, pos);
3550
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
3551
+ var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
3552
+ Math.min(coords.top, endCoords.top) - margin,
3553
+ Math.max(coords.left, endCoords.left),
3554
+ Math.max(coords.bottom, endCoords.bottom) + margin);
3555
+ var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
3556
+ if (scrollPos.scrollTop != null) {
3557
+ setScrollTop(cm, scrollPos.scrollTop);
3558
+ if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
3559
+ }
3560
+ if (scrollPos.scrollLeft != null) {
3561
+ setScrollLeft(cm, scrollPos.scrollLeft);
3562
+ if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
3563
+ }
3564
+ if (!changed) return coords;
3565
+ }
3566
+ }
3567
+
3568
+ // Scroll a given set of coordinates into view (immediately).
3569
+ function scrollIntoView(cm, x1, y1, x2, y2) {
3570
+ var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
3571
+ if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
3572
+ if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
3573
+ }
3574
+
3575
+ // Calculate a new scroll position needed to scroll the given
3576
+ // rectangle into view. Returns an object with scrollTop and
3577
+ // scrollLeft properties. When these are undefined, the
3578
+ // vertical/horizontal position does not need to be adjusted.
3579
+ function calculateScrollPos(cm, x1, y1, x2, y2) {
3580
+ var display = cm.display, snapMargin = textHeight(cm.display);
3581
+ if (y1 < 0) y1 = 0;
3582
+ var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
3583
+ var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
3584
+ var docBottom = cm.doc.height + paddingVert(display);
3585
+ var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
3586
+ if (y1 < screentop) {
3587
+ result.scrollTop = atTop ? 0 : y1;
3588
+ } else if (y2 > screentop + screen) {
3589
+ var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
3590
+ if (newTop != screentop) result.scrollTop = newTop;
3591
+ }
3592
+
3593
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
3594
+ var screenw = display.scroller.clientWidth - scrollerCutOff;
3595
+ x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
3596
+ var gutterw = display.gutters.offsetWidth;
3597
+ var atLeft = x1 < gutterw + 10;
3598
+ if (x1 < screenleft + gutterw || atLeft) {
3599
+ if (atLeft) x1 = 0;
3600
+ result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
3601
+ } else if (x2 > screenw + screenleft - 3) {
3602
+ result.scrollLeft = x2 + 10 - screenw;
3603
+ }
3604
+ return result;
3605
+ }
3606
+
3607
+ // Store a relative adjustment to the scroll position in the current
3608
+ // operation (to be applied when the operation finishes).
3609
+ function addToScrollPos(cm, left, top) {
3610
+ if (left != null || top != null) resolveScrollToPos(cm);
3611
+ if (left != null)
3612
+ cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
3613
+ if (top != null)
3614
+ cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
3615
+ }
3616
+
3617
+ // Make sure that at the end of the operation the current cursor is
3618
+ // shown.
3619
+ function ensureCursorVisible(cm) {
3620
+ resolveScrollToPos(cm);
3621
+ var cur = cm.getCursor(), from = cur, to = cur;
3622
+ if (!cm.options.lineWrapping) {
3623
+ from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
3624
+ to = Pos(cur.line, cur.ch + 1);
3625
+ }
3626
+ cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
3627
+ }
3628
+
3629
+ // When an operation has its scrollToPos property set, and another
3630
+ // scroll action is applied before the end of the operation, this
3631
+ // 'simulates' scrolling that position into view in a cheap way, so
3632
+ // that the effect of intermediate scroll commands is not ignored.
3633
+ function resolveScrollToPos(cm) {
3634
+ var range = cm.curOp.scrollToPos;
3635
+ if (range) {
3636
+ cm.curOp.scrollToPos = null;
3637
+ var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
3638
+ var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
3639
+ Math.min(from.top, to.top) - range.margin,
3640
+ Math.max(from.right, to.right),
3641
+ Math.max(from.bottom, to.bottom) + range.margin);
3642
+ cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
3643
+ }
3644
+ }
3645
+
3646
+ // API UTILITIES
3647
+
3648
+ // Indent the given line. The how parameter can be "smart",
3649
+ // "add"/null, "subtract", or "prev". When aggressive is false
3650
+ // (typically set to true for forced single-line indents), empty
3651
+ // lines are not indented, and places where the mode returns Pass
3652
+ // are left alone.
3653
+ function indentLine(cm, n, how, aggressive) {
3654
+ var doc = cm.doc, state;
3655
+ if (how == null) how = "add";
3656
+ if (how == "smart") {
3657
+ // Fall back to "prev" when the mode doesn't have an indentation
3658
+ // method.
3659
+ if (!cm.doc.mode.indent) how = "prev";
3660
+ else state = getStateBefore(cm, n);
3661
+ }
3662
+
3663
+ var tabSize = cm.options.tabSize;
3664
+ var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
3665
+ if (line.stateAfter) line.stateAfter = null;
3666
+ var curSpaceString = line.text.match(/^\s*/)[0], indentation;
3667
+ if (!aggressive && !/\S/.test(line.text)) {
3668
+ indentation = 0;
3669
+ how = "not";
3670
+ } else if (how == "smart") {
3671
+ indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
3672
+ if (indentation == Pass) {
3673
+ if (!aggressive) return;
3674
+ how = "prev";
3675
+ }
3676
+ }
3677
+ if (how == "prev") {
3678
+ if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
3679
+ else indentation = 0;
3680
+ } else if (how == "add") {
3681
+ indentation = curSpace + cm.options.indentUnit;
3682
+ } else if (how == "subtract") {
3683
+ indentation = curSpace - cm.options.indentUnit;
3684
+ } else if (typeof how == "number") {
3685
+ indentation = curSpace + how;
3686
+ }
3687
+ indentation = Math.max(0, indentation);
3688
+
3689
+ var indentString = "", pos = 0;
3690
+ if (cm.options.indentWithTabs)
3691
+ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
3692
+ if (pos < indentation) indentString += spaceStr(indentation - pos);
3693
+
3694
+ if (indentString != curSpaceString) {
3695
+ replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
3696
+ } else {
3697
+ // Ensure that, if the cursor was in the whitespace at the start
3698
+ // of the line, it is moved to the end of that space.
3699
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
3700
+ var range = doc.sel.ranges[i];
3701
+ if (range.head.line == n && range.head.ch < curSpaceString.length) {
3702
+ var pos = Pos(n, curSpaceString.length);
3703
+ replaceOneSelection(doc, i, new Range(pos, pos));
3704
+ break;
3705
+ }
3706
+ }
3707
+ }
3708
+ line.stateAfter = null;
3709
+ }
3710
+
3711
+ // Utility for applying a change to a line by handle or number,
3712
+ // returning the number and optionally registering the line as
3713
+ // changed.
3714
+ function changeLine(cm, handle, changeType, op) {
3715
+ var no = handle, line = handle, doc = cm.doc;
3716
+ if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
3717
+ else no = lineNo(handle);
3718
+ if (no == null) return null;
3719
+ if (op(line, no)) regLineChange(cm, no, changeType);
3720
+ return line;
3721
+ }
3722
+
3723
+ // Helper for deleting text near the selection(s), used to implement
3724
+ // backspace, delete, and similar functionality.
3725
+ function deleteNearSelection(cm, compute) {
3726
+ var ranges = cm.doc.sel.ranges, kill = [];
3727
+ // Build up a set of ranges to kill first, merging overlapping
3728
+ // ranges.
3729
+ for (var i = 0; i < ranges.length; i++) {
3730
+ var toKill = compute(ranges[i]);
3731
+ while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
3732
+ var replaced = kill.pop();
3733
+ if (cmp(replaced.from, toKill.from) < 0) {
3734
+ toKill.from = replaced.from;
3735
+ break;
3736
+ }
3737
+ }
3738
+ kill.push(toKill);
3739
+ }
3740
+ // Next, remove those actual ranges.
3741
+ runInOp(cm, function() {
3742
+ for (var i = kill.length - 1; i >= 0; i--)
3743
+ replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
3744
+ ensureCursorVisible(cm);
3745
+ });
3746
+ }
3747
+
3748
+ // Used for horizontal relative motion. Dir is -1 or 1 (left or
3749
+ // right), unit can be "char", "column" (like char, but doesn't
3750
+ // cross line boundaries), "word" (across next word), or "group" (to
3751
+ // the start of next group of word or non-word-non-whitespace
3752
+ // chars). The visually param controls whether, in right-to-left
3753
+ // text, direction 1 means to move towards the next index in the
3754
+ // string, or towards the character to the right of the current
3755
+ // position. The resulting position will have a hitSide=true
3756
+ // property if it reached the end of the document.
3757
+ function findPosH(doc, pos, dir, unit, visually) {
3758
+ var line = pos.line, ch = pos.ch, origDir = dir;
3759
+ var lineObj = getLine(doc, line);
3760
+ var possible = true;
3761
+ function findNextLine() {
3762
+ var l = line + dir;
3763
+ if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
3764
+ line = l;
3765
+ return lineObj = getLine(doc, l);
3766
+ }
3767
+ function moveOnce(boundToLine) {
3768
+ var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
3769
+ if (next == null) {
3770
+ if (!boundToLine && findNextLine()) {
3771
+ if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
3772
+ else ch = dir < 0 ? lineObj.text.length : 0;
3773
+ } else return (possible = false);
3774
+ } else ch = next;
3775
+ return true;
3776
+ }
3777
+
3778
+ if (unit == "char") moveOnce();
3779
+ else if (unit == "column") moveOnce(true);
3780
+ else if (unit == "word" || unit == "group") {
3781
+ var sawType = null, group = unit == "group";
3782
+ var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
3783
+ for (var first = true;; first = false) {
3784
+ if (dir < 0 && !moveOnce(!first)) break;
3785
+ var cur = lineObj.text.charAt(ch) || "\n";
3786
+ var type = isWordChar(cur, helper) ? "w"
3787
+ : group && cur == "\n" ? "n"
3788
+ : !group || /\s/.test(cur) ? null
3789
+ : "p";
3790
+ if (group && !first && !type) type = "s";
3791
+ if (sawType && sawType != type) {
3792
+ if (dir < 0) {dir = 1; moveOnce();}
3793
+ break;
3794
+ }
3795
+
3796
+ if (type) sawType = type;
3797
+ if (dir > 0 && !moveOnce(!first)) break;
3798
+ }
3799
+ }
3800
+ var result = skipAtomic(doc, Pos(line, ch), origDir, true);
3801
+ if (!possible) result.hitSide = true;
3802
+ return result;
3803
+ }
3804
+
3805
+ // For relative vertical movement. Dir may be -1 or 1. Unit can be
3806
+ // "page" or "line". The resulting position will have a hitSide=true
3807
+ // property if it reached the end of the document.
3808
+ function findPosV(cm, pos, dir, unit) {
3809
+ var doc = cm.doc, x = pos.left, y;
3810
+ if (unit == "page") {
3811
+ var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
3812
+ y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
3813
+ } else if (unit == "line") {
3814
+ y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
3815
+ }
3816
+ for (;;) {
3817
+ var target = coordsChar(cm, x, y);
3818
+ if (!target.outside) break;
3819
+ if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
3820
+ y += dir * 5;
3821
+ }
3822
+ return target;
3823
+ }
3824
+
3825
+ // Find the word at the given position (as returned by coordsChar).
3826
+ function findWordAt(cm, pos) {
3827
+ var doc = cm.doc, line = getLine(doc, pos.line).text;
3828
+ var start = pos.ch, end = pos.ch;
3829
+ if (line) {
3830
+ var helper = cm.getHelper(pos, "wordChars");
3831
+ if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
3832
+ var startChar = line.charAt(start);
3833
+ var check = isWordChar(startChar, helper)
3834
+ ? function(ch) { return isWordChar(ch, helper); }
3835
+ : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
3836
+ : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
3837
+ while (start > 0 && check(line.charAt(start - 1))) --start;
3838
+ while (end < line.length && check(line.charAt(end))) ++end;
3839
+ }
3840
+ return new Range(Pos(pos.line, start), Pos(pos.line, end));
3841
+ }
3842
+
3843
+ // EDITOR METHODS
3844
+
3845
+ // The publicly visible API. Note that methodOp(f) means
3846
+ // 'wrap f in an operation, performed on its `this` parameter'.
3847
+
3848
+ // This is not the complete set of editor methods. Most of the
3849
+ // methods defined on the Doc type are also injected into
3850
+ // CodeMirror.prototype, for backwards compatibility and
3851
+ // convenience.
3852
+
3853
+ CodeMirror.prototype = {
3854
+ constructor: CodeMirror,
3855
+ focus: function(){window.focus(); focusInput(this); fastPoll(this);},
3856
+
3857
+ setOption: function(option, value) {
3858
+ var options = this.options, old = options[option];
3859
+ if (options[option] == value && option != "mode") return;
3860
+ options[option] = value;
3861
+ if (optionHandlers.hasOwnProperty(option))
3862
+ operation(this, optionHandlers[option])(this, value, old);
3863
+ },
3864
+
3865
+ getOption: function(option) {return this.options[option];},
3866
+ getDoc: function() {return this.doc;},
3867
+
3868
+ addKeyMap: function(map, bottom) {
3869
+ this.state.keyMaps[bottom ? "push" : "unshift"](map);
3870
+ },
3871
+ removeKeyMap: function(map) {
3872
+ var maps = this.state.keyMaps;
3873
+ for (var i = 0; i < maps.length; ++i)
3874
+ if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
3875
+ maps.splice(i, 1);
3876
+ return true;
3877
+ }
3878
+ },
3879
+
3880
+ addOverlay: methodOp(function(spec, options) {
3881
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
3882
+ if (mode.startState) throw new Error("Overlays may not be stateful.");
3883
+ this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
3884
+ this.state.modeGen++;
3885
+ regChange(this);
3886
+ }),
3887
+ removeOverlay: methodOp(function(spec) {
3888
+ var overlays = this.state.overlays;
3889
+ for (var i = 0; i < overlays.length; ++i) {
3890
+ var cur = overlays[i].modeSpec;
3891
+ if (cur == spec || typeof spec == "string" && cur.name == spec) {
3892
+ overlays.splice(i, 1);
3893
+ this.state.modeGen++;
3894
+ regChange(this);
3895
+ return;
3896
+ }
3897
+ }
3898
+ }),
3899
+
3900
+ indentLine: methodOp(function(n, dir, aggressive) {
3901
+ if (typeof dir != "string" && typeof dir != "number") {
3902
+ if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
3903
+ else dir = dir ? "add" : "subtract";
3904
+ }
3905
+ if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
3906
+ }),
3907
+ indentSelection: methodOp(function(how) {
3908
+ var ranges = this.doc.sel.ranges, end = -1;
3909
+ for (var i = 0; i < ranges.length; i++) {
3910
+ var range = ranges[i];
3911
+ if (!range.empty()) {
3912
+ var start = Math.max(end, range.from().line);
3913
+ var to = range.to();
3914
+ end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
3915
+ for (var j = start; j < end; ++j)
3916
+ indentLine(this, j, how);
3917
+ } else if (range.head.line > end) {
3918
+ indentLine(this, range.head.line, how, true);
3919
+ end = range.head.line;
3920
+ if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
3921
+ }
3922
+ }
3923
+ }),
3924
+
3925
+ // Fetch the parser token for a given character. Useful for hacks
3926
+ // that want to inspect the mode state (say, for completion).
3927
+ getTokenAt: function(pos, precise) {
3928
+ var doc = this.doc;
3929
+ pos = clipPos(doc, pos);
3930
+ var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
3931
+ var line = getLine(doc, pos.line);
3932
+ var stream = new StringStream(line.text, this.options.tabSize);
3933
+ while (stream.pos < pos.ch && !stream.eol()) {
3934
+ stream.start = stream.pos;
3935
+ var style = readToken(mode, stream, state);
3936
+ }
3937
+ return {start: stream.start,
3938
+ end: stream.pos,
3939
+ string: stream.current(),
3940
+ type: style || null,
3941
+ state: state};
3942
+ },
3943
+
3944
+ getTokenTypeAt: function(pos) {
3945
+ pos = clipPos(this.doc, pos);
3946
+ var styles = getLineStyles(this, getLine(this.doc, pos.line));
3947
+ var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
3948
+ var type;
3949
+ if (ch == 0) type = styles[2];
3950
+ else for (;;) {
3951
+ var mid = (before + after) >> 1;
3952
+ if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
3953
+ else if (styles[mid * 2 + 1] < ch) before = mid + 1;
3954
+ else { type = styles[mid * 2 + 2]; break; }
3955
+ }
3956
+ var cut = type ? type.indexOf("cm-overlay ") : -1;
3957
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
3958
+ },
3959
+
3960
+ getModeAt: function(pos) {
3961
+ var mode = this.doc.mode;
3962
+ if (!mode.innerMode) return mode;
3963
+ return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
3964
+ },
3965
+
3966
+ getHelper: function(pos, type) {
3967
+ return this.getHelpers(pos, type)[0];
3968
+ },
3969
+
3970
+ getHelpers: function(pos, type) {
3971
+ var found = [];
3972
+ if (!helpers.hasOwnProperty(type)) return helpers;
3973
+ var help = helpers[type], mode = this.getModeAt(pos);
3974
+ if (typeof mode[type] == "string") {
3975
+ if (help[mode[type]]) found.push(help[mode[type]]);
3976
+ } else if (mode[type]) {
3977
+ for (var i = 0; i < mode[type].length; i++) {
3978
+ var val = help[mode[type][i]];
3979
+ if (val) found.push(val);
3980
+ }
3981
+ } else if (mode.helperType && help[mode.helperType]) {
3982
+ found.push(help[mode.helperType]);
3983
+ } else if (help[mode.name]) {
3984
+ found.push(help[mode.name]);
3985
+ }
3986
+ for (var i = 0; i < help._global.length; i++) {
3987
+ var cur = help._global[i];
3988
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
3989
+ found.push(cur.val);
3990
+ }
3991
+ return found;
3992
+ },
3993
+
3994
+ getStateAfter: function(line, precise) {
3995
+ var doc = this.doc;
3996
+ line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
3997
+ return getStateBefore(this, line + 1, precise);
3998
+ },
3999
+
4000
+ cursorCoords: function(start, mode) {
4001
+ var pos, range = this.doc.sel.primary();
4002
+ if (start == null) pos = range.head;
4003
+ else if (typeof start == "object") pos = clipPos(this.doc, start);
4004
+ else pos = start ? range.from() : range.to();
4005
+ return cursorCoords(this, pos, mode || "page");
4006
+ },
4007
+
4008
+ charCoords: function(pos, mode) {
4009
+ return charCoords(this, clipPos(this.doc, pos), mode || "page");
4010
+ },
4011
+
4012
+ coordsChar: function(coords, mode) {
4013
+ coords = fromCoordSystem(this, coords, mode || "page");
4014
+ return coordsChar(this, coords.left, coords.top);
4015
+ },
4016
+
4017
+ lineAtHeight: function(height, mode) {
4018
+ height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
4019
+ return lineAtHeight(this.doc, height + this.display.viewOffset);
4020
+ },
4021
+ heightAtLine: function(line, mode) {
4022
+ var end = false, last = this.doc.first + this.doc.size - 1;
4023
+ if (line < this.doc.first) line = this.doc.first;
4024
+ else if (line > last) { line = last; end = true; }
4025
+ var lineObj = getLine(this.doc, line);
4026
+ return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
4027
+ (end ? this.doc.height - heightAtLine(lineObj) : 0);
4028
+ },
4029
+
4030
+ defaultTextHeight: function() { return textHeight(this.display); },
4031
+ defaultCharWidth: function() { return charWidth(this.display); },
4032
+
4033
+ setGutterMarker: methodOp(function(line, gutterID, value) {
4034
+ return changeLine(this, line, "gutter", function(line) {
4035
+ var markers = line.gutterMarkers || (line.gutterMarkers = {});
4036
+ markers[gutterID] = value;
4037
+ if (!value && isEmpty(markers)) line.gutterMarkers = null;
4038
+ return true;
4039
+ });
4040
+ }),
4041
+
4042
+ clearGutter: methodOp(function(gutterID) {
4043
+ var cm = this, doc = cm.doc, i = doc.first;
4044
+ doc.iter(function(line) {
4045
+ if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
4046
+ line.gutterMarkers[gutterID] = null;
4047
+ regLineChange(cm, i, "gutter");
4048
+ if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
4049
+ }
4050
+ ++i;
4051
+ });
4052
+ }),
4053
+
4054
+ addLineClass: methodOp(function(handle, where, cls) {
4055
+ return changeLine(this, handle, "class", function(line) {
4056
+ var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
4057
+ if (!line[prop]) line[prop] = cls;
4058
+ else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
4059
+ else line[prop] += " " + cls;
4060
+ return true;
4061
+ });
4062
+ }),
4063
+
4064
+ removeLineClass: methodOp(function(handle, where, cls) {
4065
+ return changeLine(this, handle, "class", function(line) {
4066
+ var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
4067
+ var cur = line[prop];
4068
+ if (!cur) return false;
4069
+ else if (cls == null) line[prop] = null;
4070
+ else {
4071
+ var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
4072
+ if (!found) return false;
4073
+ var end = found.index + found[0].length;
4074
+ line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
4075
+ }
4076
+ return true;
4077
+ });
4078
+ }),
4079
+
4080
+ addLineWidget: methodOp(function(handle, node, options) {
4081
+ return addLineWidget(this, handle, node, options);
4082
+ }),
4083
+
4084
+ removeLineWidget: function(widget) { widget.clear(); },
4085
+
4086
+ lineInfo: function(line) {
4087
+ if (typeof line == "number") {
4088
+ if (!isLine(this.doc, line)) return null;
4089
+ var n = line;
4090
+ line = getLine(this.doc, line);
4091
+ if (!line) return null;
4092
+ } else {
4093
+ var n = lineNo(line);
4094
+ if (n == null) return null;
4095
+ }
4096
+ return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
4097
+ textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
4098
+ widgets: line.widgets};
4099
+ },
4100
+
4101
+ getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
4102
+
4103
+ addWidget: function(pos, node, scroll, vert, horiz) {
4104
+ var display = this.display;
4105
+ pos = cursorCoords(this, clipPos(this.doc, pos));
4106
+ var top = pos.bottom, left = pos.left;
4107
+ node.style.position = "absolute";
4108
+ display.sizer.appendChild(node);
4109
+ if (vert == "over") {
4110
+ top = pos.top;
4111
+ } else if (vert == "above" || vert == "near") {
4112
+ var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
4113
+ hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
4114
+ // Default to positioning above (if specified and possible); otherwise default to positioning below
4115
+ if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
4116
+ top = pos.top - node.offsetHeight;
4117
+ else if (pos.bottom + node.offsetHeight <= vspace)
4118
+ top = pos.bottom;
4119
+ if (left + node.offsetWidth > hspace)
4120
+ left = hspace - node.offsetWidth;
4121
+ }
4122
+ node.style.top = top + "px";
4123
+ node.style.left = node.style.right = "";
4124
+ if (horiz == "right") {
4125
+ left = display.sizer.clientWidth - node.offsetWidth;
4126
+ node.style.right = "0px";
4127
+ } else {
4128
+ if (horiz == "left") left = 0;
4129
+ else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
4130
+ node.style.left = left + "px";
4131
+ }
4132
+ if (scroll)
4133
+ scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
4134
+ },
4135
+
4136
+ triggerOnKeyDown: methodOp(onKeyDown),
4137
+ triggerOnKeyPress: methodOp(onKeyPress),
4138
+ triggerOnKeyUp: methodOp(onKeyUp),
4139
+
4140
+ execCommand: function(cmd) {
4141
+ if (commands.hasOwnProperty(cmd))
4142
+ return commands[cmd](this);
4143
+ },
4144
+
4145
+ findPosH: function(from, amount, unit, visually) {
4146
+ var dir = 1;
4147
+ if (amount < 0) { dir = -1; amount = -amount; }
4148
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
4149
+ cur = findPosH(this.doc, cur, dir, unit, visually);
4150
+ if (cur.hitSide) break;
4151
+ }
4152
+ return cur;
4153
+ },
4154
+
4155
+ moveH: methodOp(function(dir, unit) {
4156
+ var cm = this;
4157
+ cm.extendSelectionsBy(function(range) {
4158
+ if (cm.display.shift || cm.doc.extend || range.empty())
4159
+ return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
4160
+ else
4161
+ return dir < 0 ? range.from() : range.to();
4162
+ }, sel_move);
4163
+ }),
4164
+
4165
+ deleteH: methodOp(function(dir, unit) {
4166
+ var sel = this.doc.sel, doc = this.doc;
4167
+ if (sel.somethingSelected())
4168
+ doc.replaceSelection("", null, "+delete");
4169
+ else
4170
+ deleteNearSelection(this, function(range) {
4171
+ var other = findPosH(doc, range.head, dir, unit, false);
4172
+ return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
4173
+ });
4174
+ }),
4175
+
4176
+ findPosV: function(from, amount, unit, goalColumn) {
4177
+ var dir = 1, x = goalColumn;
4178
+ if (amount < 0) { dir = -1; amount = -amount; }
4179
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
4180
+ var coords = cursorCoords(this, cur, "div");
4181
+ if (x == null) x = coords.left;
4182
+ else coords.left = x;
4183
+ cur = findPosV(this, coords, dir, unit);
4184
+ if (cur.hitSide) break;
4185
+ }
4186
+ return cur;
4187
+ },
4188
+
4189
+ moveV: methodOp(function(dir, unit) {
4190
+ var cm = this, doc = this.doc, goals = [];
4191
+ var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
4192
+ doc.extendSelectionsBy(function(range) {
4193
+ if (collapse)
4194
+ return dir < 0 ? range.from() : range.to();
4195
+ var headPos = cursorCoords(cm, range.head, "div");
4196
+ if (range.goalColumn != null) headPos.left = range.goalColumn;
4197
+ goals.push(headPos.left);
4198
+ var pos = findPosV(cm, headPos, dir, unit);
4199
+ if (unit == "page" && range == doc.sel.primary())
4200
+ addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
4201
+ return pos;
4202
+ }, sel_move);
4203
+ if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
4204
+ doc.sel.ranges[i].goalColumn = goals[i];
4205
+ }),
4206
+
4207
+ toggleOverwrite: function(value) {
4208
+ if (value != null && value == this.state.overwrite) return;
4209
+ if (this.state.overwrite = !this.state.overwrite)
4210
+ addClass(this.display.cursorDiv, "CodeMirror-overwrite");
4211
+ else
4212
+ rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
4213
+
4214
+ signal(this, "overwriteToggle", this, this.state.overwrite);
4215
+ },
4216
+ hasFocus: function() { return activeElt() == this.display.input; },
4217
+
4218
+ scrollTo: methodOp(function(x, y) {
4219
+ if (x != null || y != null) resolveScrollToPos(this);
4220
+ if (x != null) this.curOp.scrollLeft = x;
4221
+ if (y != null) this.curOp.scrollTop = y;
4222
+ }),
4223
+ getScrollInfo: function() {
4224
+ var scroller = this.display.scroller, co = scrollerCutOff;
4225
+ return {left: scroller.scrollLeft, top: scroller.scrollTop,
4226
+ height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
4227
+ clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
4228
+ },
4229
+
4230
+ scrollIntoView: methodOp(function(range, margin) {
4231
+ if (range == null) {
4232
+ range = {from: this.doc.sel.primary().head, to: null};
4233
+ if (margin == null) margin = this.options.cursorScrollMargin;
4234
+ } else if (typeof range == "number") {
4235
+ range = {from: Pos(range, 0), to: null};
4236
+ } else if (range.from == null) {
4237
+ range = {from: range, to: null};
4238
+ }
4239
+ if (!range.to) range.to = range.from;
4240
+ range.margin = margin || 0;
4241
+
4242
+ if (range.from.line != null) {
4243
+ resolveScrollToPos(this);
4244
+ this.curOp.scrollToPos = range;
4245
+ } else {
4246
+ var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
4247
+ Math.min(range.from.top, range.to.top) - range.margin,
4248
+ Math.max(range.from.right, range.to.right),
4249
+ Math.max(range.from.bottom, range.to.bottom) + range.margin);
4250
+ this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
4251
+ }
4252
+ }),
4253
+
4254
+ setSize: methodOp(function(width, height) {
4255
+ function interpret(val) {
4256
+ return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
4257
+ }
4258
+ if (width != null) this.display.wrapper.style.width = interpret(width);
4259
+ if (height != null) this.display.wrapper.style.height = interpret(height);
4260
+ if (this.options.lineWrapping) clearLineMeasurementCache(this);
4261
+ this.curOp.forceUpdate = true;
4262
+ signal(this, "refresh", this);
4263
+ }),
4264
+
4265
+ operation: function(f){return runInOp(this, f);},
4266
+
4267
+ refresh: methodOp(function() {
4268
+ var oldHeight = this.display.cachedTextHeight;
4269
+ regChange(this);
4270
+ this.curOp.forceUpdate = true;
4271
+ clearCaches(this);
4272
+ this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
4273
+ updateGutterSpace(this);
4274
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
4275
+ estimateLineHeights(this);
4276
+ signal(this, "refresh", this);
4277
+ }),
4278
+
4279
+ swapDoc: methodOp(function(doc) {
4280
+ var old = this.doc;
4281
+ old.cm = null;
4282
+ attachDoc(this, doc);
4283
+ clearCaches(this);
4284
+ resetInput(this);
4285
+ this.scrollTo(doc.scrollLeft, doc.scrollTop);
4286
+ signalLater(this, "swapDoc", this, old);
4287
+ return old;
4288
+ }),
4289
+
4290
+ getInputField: function(){return this.display.input;},
4291
+ getWrapperElement: function(){return this.display.wrapper;},
4292
+ getScrollerElement: function(){return this.display.scroller;},
4293
+ getGutterElement: function(){return this.display.gutters;}
4294
+ };
4295
+ eventMixin(CodeMirror);
4296
+
4297
+ // OPTION DEFAULTS
4298
+
4299
+ // The default configuration options.
4300
+ var defaults = CodeMirror.defaults = {};
4301
+ // Functions to run when options are changed.
4302
+ var optionHandlers = CodeMirror.optionHandlers = {};
4303
+
4304
+ function option(name, deflt, handle, notOnInit) {
4305
+ CodeMirror.defaults[name] = deflt;
4306
+ if (handle) optionHandlers[name] =
4307
+ notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
4308
+ }
4309
+
4310
+ // Passed to option handlers when there is no old value.
4311
+ var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
4312
+
4313
+ // These two are, on init, called from the constructor because they
4314
+ // have to be initialized before the editor can start at all.
4315
+ option("value", "", function(cm, val) {
4316
+ cm.setValue(val);
4317
+ }, true);
4318
+ option("mode", null, function(cm, val) {
4319
+ cm.doc.modeOption = val;
4320
+ loadMode(cm);
4321
+ }, true);
4322
+
4323
+ option("indentUnit", 2, loadMode, true);
4324
+ option("indentWithTabs", false);
4325
+ option("smartIndent", true);
4326
+ option("tabSize", 4, function(cm) {
4327
+ resetModeState(cm);
4328
+ clearCaches(cm);
4329
+ regChange(cm);
4330
+ }, true);
4331
+ option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
4332
+ cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
4333
+ cm.refresh();
4334
+ }, true);
4335
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
4336
+ option("electricChars", true);
4337
+ option("rtlMoveVisually", !windows);
4338
+ option("wholeLineUpdateBefore", true);
4339
+
4340
+ option("theme", "default", function(cm) {
4341
+ themeChanged(cm);
4342
+ guttersChanged(cm);
4343
+ }, true);
4344
+ option("keyMap", "default", keyMapChanged);
4345
+ option("extraKeys", null);
4346
+
4347
+ option("lineWrapping", false, wrappingChanged, true);
4348
+ option("gutters", [], function(cm) {
4349
+ setGuttersForLineNumbers(cm.options);
4350
+ guttersChanged(cm);
4351
+ }, true);
4352
+ option("fixedGutter", true, function(cm, val) {
4353
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
4354
+ cm.refresh();
4355
+ }, true);
4356
+ option("coverGutterNextToScrollbar", false, updateScrollbars, true);
4357
+ option("lineNumbers", false, function(cm) {
4358
+ setGuttersForLineNumbers(cm.options);
4359
+ guttersChanged(cm);
4360
+ }, true);
4361
+ option("firstLineNumber", 1, guttersChanged, true);
4362
+ option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
4363
+ option("showCursorWhenSelecting", false, updateSelection, true);
4364
+
4365
+ option("resetSelectionOnContextMenu", true);
4366
+
4367
+ option("readOnly", false, function(cm, val) {
4368
+ if (val == "nocursor") {
4369
+ onBlur(cm);
4370
+ cm.display.input.blur();
4371
+ cm.display.disabled = true;
4372
+ } else {
4373
+ cm.display.disabled = false;
4374
+ if (!val) resetInput(cm);
4375
+ }
4376
+ });
4377
+ option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, true);
4378
+ option("dragDrop", true);
4379
+
4380
+ option("cursorBlinkRate", 530);
4381
+ option("cursorScrollMargin", 0);
4382
+ option("cursorHeight", 1);
4383
+ option("workTime", 100);
4384
+ option("workDelay", 100);
4385
+ option("flattenSpans", true, resetModeState, true);
4386
+ option("addModeClass", false, resetModeState, true);
4387
+ option("pollInterval", 100);
4388
+ option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
4389
+ option("historyEventDelay", 1250);
4390
+ option("viewportMargin", 10, function(cm){cm.refresh();}, true);
4391
+ option("maxHighlightLength", 10000, resetModeState, true);
4392
+ option("moveInputWithCursor", true, function(cm, val) {
4393
+ if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
4394
+ });
4395
+
4396
+ option("tabindex", null, function(cm, val) {
4397
+ cm.display.input.tabIndex = val || "";
4398
+ });
4399
+ option("autofocus", null);
4400
+
4401
+ // MODE DEFINITION AND QUERYING
4402
+
4403
+ // Known modes, by name and by MIME
4404
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
4405
+
4406
+ // Extra arguments are stored as the mode's dependencies, which is
4407
+ // used by (legacy) mechanisms like loadmode.js to automatically
4408
+ // load a mode. (Preferred mechanism is the require/define calls.)
4409
+ CodeMirror.defineMode = function(name, mode) {
4410
+ if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
4411
+ if (arguments.length > 2) {
4412
+ mode.dependencies = [];
4413
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
4414
+ }
4415
+ modes[name] = mode;
4416
+ };
4417
+
4418
+ CodeMirror.defineMIME = function(mime, spec) {
4419
+ mimeModes[mime] = spec;
4420
+ };
4421
+
4422
+ // Given a MIME type, a {name, ...options} config object, or a name
4423
+ // string, return a mode config object.
4424
+ CodeMirror.resolveMode = function(spec) {
4425
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
4426
+ spec = mimeModes[spec];
4427
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
4428
+ var found = mimeModes[spec.name];
4429
+ if (typeof found == "string") found = {name: found};
4430
+ spec = createObj(found, spec);
4431
+ spec.name = found.name;
4432
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
4433
+ return CodeMirror.resolveMode("application/xml");
4434
+ }
4435
+ if (typeof spec == "string") return {name: spec};
4436
+ else return spec || {name: "null"};
4437
+ };
4438
+
4439
+ // Given a mode spec (anything that resolveMode accepts), find and
4440
+ // initialize an actual mode object.
4441
+ CodeMirror.getMode = function(options, spec) {
4442
+ var spec = CodeMirror.resolveMode(spec);
4443
+ var mfactory = modes[spec.name];
4444
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
4445
+ var modeObj = mfactory(options, spec);
4446
+ if (modeExtensions.hasOwnProperty(spec.name)) {
4447
+ var exts = modeExtensions[spec.name];
4448
+ for (var prop in exts) {
4449
+ if (!exts.hasOwnProperty(prop)) continue;
4450
+ if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
4451
+ modeObj[prop] = exts[prop];
4452
+ }
4453
+ }
4454
+ modeObj.name = spec.name;
4455
+ if (spec.helperType) modeObj.helperType = spec.helperType;
4456
+ if (spec.modeProps) for (var prop in spec.modeProps)
4457
+ modeObj[prop] = spec.modeProps[prop];
4458
+
4459
+ return modeObj;
4460
+ };
4461
+
4462
+ // Minimal default mode.
4463
+ CodeMirror.defineMode("null", function() {
4464
+ return {token: function(stream) {stream.skipToEnd();}};
4465
+ });
4466
+ CodeMirror.defineMIME("text/plain", "null");
4467
+
4468
+ // This can be used to attach properties to mode objects from
4469
+ // outside the actual mode definition.
4470
+ var modeExtensions = CodeMirror.modeExtensions = {};
4471
+ CodeMirror.extendMode = function(mode, properties) {
4472
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
4473
+ copyObj(properties, exts);
4474
+ };
4475
+
4476
+ // EXTENSIONS
4477
+
4478
+ CodeMirror.defineExtension = function(name, func) {
4479
+ CodeMirror.prototype[name] = func;
4480
+ };
4481
+ CodeMirror.defineDocExtension = function(name, func) {
4482
+ Doc.prototype[name] = func;
4483
+ };
4484
+ CodeMirror.defineOption = option;
4485
+
4486
+ var initHooks = [];
4487
+ CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
4488
+
4489
+ var helpers = CodeMirror.helpers = {};
4490
+ CodeMirror.registerHelper = function(type, name, value) {
4491
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
4492
+ helpers[type][name] = value;
4493
+ };
4494
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
4495
+ CodeMirror.registerHelper(type, name, value);
4496
+ helpers[type]._global.push({pred: predicate, val: value});
4497
+ };
4498
+
4499
+ // MODE STATE HANDLING
4500
+
4501
+ // Utility functions for working with state. Exported because nested
4502
+ // modes need to do this for their inner modes.
4503
+
4504
+ var copyState = CodeMirror.copyState = function(mode, state) {
4505
+ if (state === true) return state;
4506
+ if (mode.copyState) return mode.copyState(state);
4507
+ var nstate = {};
4508
+ for (var n in state) {
4509
+ var val = state[n];
4510
+ if (val instanceof Array) val = val.concat([]);
4511
+ nstate[n] = val;
4512
+ }
4513
+ return nstate;
4514
+ };
4515
+
4516
+ var startState = CodeMirror.startState = function(mode, a1, a2) {
4517
+ return mode.startState ? mode.startState(a1, a2) : true;
4518
+ };
4519
+
4520
+ // Given a mode and a state (for that mode), find the inner mode and
4521
+ // state at the position that the state refers to.
4522
+ CodeMirror.innerMode = function(mode, state) {
4523
+ while (mode.innerMode) {
4524
+ var info = mode.innerMode(state);
4525
+ if (!info || info.mode == mode) break;
4526
+ state = info.state;
4527
+ mode = info.mode;
4528
+ }
4529
+ return info || {mode: mode, state: state};
4530
+ };
4531
+
4532
+ // STANDARD COMMANDS
4533
+
4534
+ // Commands are parameter-less actions that can be performed on an
4535
+ // editor, mostly used for keybindings.
4536
+ var commands = CodeMirror.commands = {
4537
+ selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
4538
+ singleSelection: function(cm) {
4539
+ cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
4540
+ },
4541
+ killLine: function(cm) {
4542
+ deleteNearSelection(cm, function(range) {
4543
+ if (range.empty()) {
4544
+ var len = getLine(cm.doc, range.head.line).text.length;
4545
+ if (range.head.ch == len && range.head.line < cm.lastLine())
4546
+ return {from: range.head, to: Pos(range.head.line + 1, 0)};
4547
+ else
4548
+ return {from: range.head, to: Pos(range.head.line, len)};
4549
+ } else {
4550
+ return {from: range.from(), to: range.to()};
4551
+ }
4552
+ });
4553
+ },
4554
+ deleteLine: function(cm) {
4555
+ deleteNearSelection(cm, function(range) {
4556
+ return {from: Pos(range.from().line, 0),
4557
+ to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
4558
+ });
4559
+ },
4560
+ delLineLeft: function(cm) {
4561
+ deleteNearSelection(cm, function(range) {
4562
+ return {from: Pos(range.from().line, 0), to: range.from()};
4563
+ });
4564
+ },
4565
+ undo: function(cm) {cm.undo();},
4566
+ redo: function(cm) {cm.redo();},
4567
+ undoSelection: function(cm) {cm.undoSelection();},
4568
+ redoSelection: function(cm) {cm.redoSelection();},
4569
+ goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
4570
+ goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
4571
+ goLineStart: function(cm) {
4572
+ cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, sel_move);
4573
+ },
4574
+ goLineStartSmart: function(cm) {
4575
+ cm.extendSelectionsBy(function(range) {
4576
+ var start = lineStart(cm, range.head.line);
4577
+ var line = cm.getLineHandle(start.line);
4578
+ var order = getOrder(line);
4579
+ if (!order || order[0].level == 0) {
4580
+ var firstNonWS = Math.max(0, line.text.search(/\S/));
4581
+ var inWS = range.head.line == start.line && range.head.ch <= firstNonWS && range.head.ch;
4582
+ return Pos(start.line, inWS ? 0 : firstNonWS);
4583
+ }
4584
+ return start;
4585
+ }, sel_move);
4586
+ },
4587
+ goLineEnd: function(cm) {
4588
+ cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, sel_move);
4589
+ },
4590
+ goLineRight: function(cm) {
4591
+ cm.extendSelectionsBy(function(range) {
4592
+ var top = cm.charCoords(range.head, "div").top + 5;
4593
+ return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
4594
+ }, sel_move);
4595
+ },
4596
+ goLineLeft: function(cm) {
4597
+ cm.extendSelectionsBy(function(range) {
4598
+ var top = cm.charCoords(range.head, "div").top + 5;
4599
+ return cm.coordsChar({left: 0, top: top}, "div");
4600
+ }, sel_move);
4601
+ },
4602
+ goLineUp: function(cm) {cm.moveV(-1, "line");},
4603
+ goLineDown: function(cm) {cm.moveV(1, "line");},
4604
+ goPageUp: function(cm) {cm.moveV(-1, "page");},
4605
+ goPageDown: function(cm) {cm.moveV(1, "page");},
4606
+ goCharLeft: function(cm) {cm.moveH(-1, "char");},
4607
+ goCharRight: function(cm) {cm.moveH(1, "char");},
4608
+ goColumnLeft: function(cm) {cm.moveH(-1, "column");},
4609
+ goColumnRight: function(cm) {cm.moveH(1, "column");},
4610
+ goWordLeft: function(cm) {cm.moveH(-1, "word");},
4611
+ goGroupRight: function(cm) {cm.moveH(1, "group");},
4612
+ goGroupLeft: function(cm) {cm.moveH(-1, "group");},
4613
+ goWordRight: function(cm) {cm.moveH(1, "word");},
4614
+ delCharBefore: function(cm) {cm.deleteH(-1, "char");},
4615
+ delCharAfter: function(cm) {cm.deleteH(1, "char");},
4616
+ delWordBefore: function(cm) {cm.deleteH(-1, "word");},
4617
+ delWordAfter: function(cm) {cm.deleteH(1, "word");},
4618
+ delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
4619
+ delGroupAfter: function(cm) {cm.deleteH(1, "group");},
4620
+ indentAuto: function(cm) {cm.indentSelection("smart");},
4621
+ indentMore: function(cm) {cm.indentSelection("add");},
4622
+ indentLess: function(cm) {cm.indentSelection("subtract");},
4623
+ insertTab: function(cm) {cm.replaceSelection("\t");},
4624
+ insertSoftTab: function(cm) {
4625
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
4626
+ for (var i = 0; i < ranges.length; i++) {
4627
+ var pos = ranges[i].from();
4628
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
4629
+ spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
4630
+ }
4631
+ cm.replaceSelections(spaces);
4632
+ },
4633
+ defaultTab: function(cm) {
4634
+ if (cm.somethingSelected()) cm.indentSelection("add");
4635
+ else cm.execCommand("insertTab");
4636
+ },
4637
+ transposeChars: function(cm) {
4638
+ runInOp(cm, function() {
4639
+ var ranges = cm.listSelections(), newSel = [];
4640
+ for (var i = 0; i < ranges.length; i++) {
4641
+ var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
4642
+ if (line) {
4643
+ if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
4644
+ if (cur.ch > 0) {
4645
+ cur = new Pos(cur.line, cur.ch + 1);
4646
+ cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
4647
+ Pos(cur.line, cur.ch - 2), cur, "+transpose");
4648
+ } else if (cur.line > cm.doc.first) {
4649
+ var prev = getLine(cm.doc, cur.line - 1).text;
4650
+ if (prev)
4651
+ cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
4652
+ Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
4653
+ }
4654
+ }
4655
+ newSel.push(new Range(cur, cur));
4656
+ }
4657
+ cm.setSelections(newSel);
4658
+ });
4659
+ },
4660
+ newlineAndIndent: function(cm) {
4661
+ runInOp(cm, function() {
4662
+ var len = cm.listSelections().length;
4663
+ for (var i = 0; i < len; i++) {
4664
+ var range = cm.listSelections()[i];
4665
+ cm.replaceRange("\n", range.anchor, range.head, "+input");
4666
+ cm.indentLine(range.from().line + 1, null, true);
4667
+ ensureCursorVisible(cm);
4668
+ }
4669
+ });
4670
+ },
4671
+ toggleOverwrite: function(cm) {cm.toggleOverwrite();}
4672
+ };
4673
+
4674
+ // STANDARD KEYMAPS
4675
+
4676
+ var keyMap = CodeMirror.keyMap = {};
4677
+ keyMap.basic = {
4678
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
4679
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
4680
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
4681
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
4682
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
4683
+ "Esc": "singleSelection"
4684
+ };
4685
+ // Note that the save and find-related commands aren't defined by
4686
+ // default. User code or addons can define them. Unknown commands
4687
+ // are simply ignored.
4688
+ keyMap.pcDefault = {
4689
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
4690
+ "Ctrl-Home": "goDocStart", "Ctrl-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
4691
+ "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
4692
+ "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
4693
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
4694
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
4695
+ "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
4696
+ fallthrough: "basic"
4697
+ };
4698
+ keyMap.macDefault = {
4699
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
4700
+ "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
4701
+ "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore",
4702
+ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
4703
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
4704
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft",
4705
+ "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection",
4706
+ fallthrough: ["basic", "emacsy"]
4707
+ };
4708
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
4709
+ keyMap.emacsy = {
4710
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
4711
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
4712
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
4713
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
4714
+ };
4715
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
4716
+
4717
+ // KEYMAP DISPATCH
4718
+
4719
+ function getKeyMap(val) {
4720
+ if (typeof val == "string") return keyMap[val];
4721
+ else return val;
4722
+ }
4723
+
4724
+ // Given an array of keymaps and a key name, call handle on any
4725
+ // bindings found, until that returns a truthy value, at which point
4726
+ // we consider the key handled. Implements things like binding a key
4727
+ // to false stopping further handling and keymap fallthrough.
4728
+ var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
4729
+ function lookup(map) {
4730
+ map = getKeyMap(map);
4731
+ var found = map[name];
4732
+ if (found === false) return "stop";
4733
+ if (found != null && handle(found)) return true;
4734
+ if (map.nofallthrough) return "stop";
4735
+
4736
+ var fallthrough = map.fallthrough;
4737
+ if (fallthrough == null) return false;
4738
+ if (Object.prototype.toString.call(fallthrough) != "[object Array]")
4739
+ return lookup(fallthrough);
4740
+ for (var i = 0; i < fallthrough.length; ++i) {
4741
+ var done = lookup(fallthrough[i]);
4742
+ if (done) return done;
4743
+ }
4744
+ return false;
4745
+ }
4746
+
4747
+ for (var i = 0; i < maps.length; ++i) {
4748
+ var done = lookup(maps[i]);
4749
+ if (done) return done != "stop";
4750
+ }
4751
+ };
4752
+
4753
+ // Modifier key presses don't count as 'real' key presses for the
4754
+ // purpose of keymap fallthrough.
4755
+ var isModifierKey = CodeMirror.isModifierKey = function(event) {
4756
+ var name = keyNames[event.keyCode];
4757
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
4758
+ };
4759
+
4760
+ // Look up the name of a key as indicated by an event object.
4761
+ var keyName = CodeMirror.keyName = function(event, noShift) {
4762
+ if (presto && event.keyCode == 34 && event["char"]) return false;
4763
+ var name = keyNames[event.keyCode];
4764
+ if (name == null || event.altGraphKey) return false;
4765
+ if (event.altKey) name = "Alt-" + name;
4766
+ if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
4767
+ if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
4768
+ if (!noShift && event.shiftKey) name = "Shift-" + name;
4769
+ return name;
4770
+ };
4771
+
4772
+ // FROMTEXTAREA
4773
+
4774
+ CodeMirror.fromTextArea = function(textarea, options) {
4775
+ if (!options) options = {};
4776
+ options.value = textarea.value;
4777
+ if (!options.tabindex && textarea.tabindex)
4778
+ options.tabindex = textarea.tabindex;
4779
+ if (!options.placeholder && textarea.placeholder)
4780
+ options.placeholder = textarea.placeholder;
4781
+ // Set autofocus to true if this textarea is focused, or if it has
4782
+ // autofocus and no other element is focused.
4783
+ if (options.autofocus == null) {
4784
+ var hasFocus = activeElt();
4785
+ options.autofocus = hasFocus == textarea ||
4786
+ textarea.getAttribute("autofocus") != null && hasFocus == document.body;
4787
+ }
4788
+
4789
+ function save() {textarea.value = cm.getValue();}
4790
+ if (textarea.form) {
4791
+ on(textarea.form, "submit", save);
4792
+ // Deplorable hack to make the submit method do the right thing.
4793
+ if (!options.leaveSubmitMethodAlone) {
4794
+ var form = textarea.form, realSubmit = form.submit;
4795
+ try {
4796
+ var wrappedSubmit = form.submit = function() {
4797
+ save();
4798
+ form.submit = realSubmit;
4799
+ form.submit();
4800
+ form.submit = wrappedSubmit;
4801
+ };
4802
+ } catch(e) {}
4803
+ }
4804
+ }
4805
+
4806
+ textarea.style.display = "none";
4807
+ var cm = CodeMirror(function(node) {
4808
+ textarea.parentNode.insertBefore(node, textarea.nextSibling);
4809
+ }, options);
4810
+ cm.save = save;
4811
+ cm.getTextArea = function() { return textarea; };
4812
+ cm.toTextArea = function() {
4813
+ save();
4814
+ textarea.parentNode.removeChild(cm.getWrapperElement());
4815
+ textarea.style.display = "";
4816
+ if (textarea.form) {
4817
+ off(textarea.form, "submit", save);
4818
+ if (typeof textarea.form.submit == "function")
4819
+ textarea.form.submit = realSubmit;
4820
+ }
4821
+ };
4822
+ return cm;
4823
+ };
4824
+
4825
+ // STRING STREAM
4826
+
4827
+ // Fed to the mode parsers, provides helper functions to make
4828
+ // parsers more succinct.
4829
+
4830
+ var StringStream = CodeMirror.StringStream = function(string, tabSize) {
4831
+ this.pos = this.start = 0;
4832
+ this.string = string;
4833
+ this.tabSize = tabSize || 8;
4834
+ this.lastColumnPos = this.lastColumnValue = 0;
4835
+ this.lineStart = 0;
4836
+ };
4837
+
4838
+ StringStream.prototype = {
4839
+ eol: function() {return this.pos >= this.string.length;},
4840
+ sol: function() {return this.pos == this.lineStart;},
4841
+ peek: function() {return this.string.charAt(this.pos) || undefined;},
4842
+ next: function() {
4843
+ if (this.pos < this.string.length)
4844
+ return this.string.charAt(this.pos++);
4845
+ },
4846
+ eat: function(match) {
4847
+ var ch = this.string.charAt(this.pos);
4848
+ if (typeof match == "string") var ok = ch == match;
4849
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
4850
+ if (ok) {++this.pos; return ch;}
4851
+ },
4852
+ eatWhile: function(match) {
4853
+ var start = this.pos;
4854
+ while (this.eat(match)){}
4855
+ return this.pos > start;
4856
+ },
4857
+ eatSpace: function() {
4858
+ var start = this.pos;
4859
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
4860
+ return this.pos > start;
4861
+ },
4862
+ skipToEnd: function() {this.pos = this.string.length;},
4863
+ skipTo: function(ch) {
4864
+ var found = this.string.indexOf(ch, this.pos);
4865
+ if (found > -1) {this.pos = found; return true;}
4866
+ },
4867
+ backUp: function(n) {this.pos -= n;},
4868
+ column: function() {
4869
+ if (this.lastColumnPos < this.start) {
4870
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
4871
+ this.lastColumnPos = this.start;
4872
+ }
4873
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
4874
+ },
4875
+ indentation: function() {
4876
+ return countColumn(this.string, null, this.tabSize) -
4877
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
4878
+ },
4879
+ match: function(pattern, consume, caseInsensitive) {
4880
+ if (typeof pattern == "string") {
4881
+ var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
4882
+ var substr = this.string.substr(this.pos, pattern.length);
4883
+ if (cased(substr) == cased(pattern)) {
4884
+ if (consume !== false) this.pos += pattern.length;
4885
+ return true;
4886
+ }
4887
+ } else {
4888
+ var match = this.string.slice(this.pos).match(pattern);
4889
+ if (match && match.index > 0) return null;
4890
+ if (match && consume !== false) this.pos += match[0].length;
4891
+ return match;
4892
+ }
4893
+ },
4894
+ current: function(){return this.string.slice(this.start, this.pos);},
4895
+ hideFirstChars: function(n, inner) {
4896
+ this.lineStart += n;
4897
+ try { return inner(); }
4898
+ finally { this.lineStart -= n; }
4899
+ }
4900
+ };
4901
+
4902
+ // TEXTMARKERS
4903
+
4904
+ // Created with markText and setBookmark methods. A TextMarker is a
4905
+ // handle that can be used to clear or find a marked position in the
4906
+ // document. Line objects hold arrays (markedSpans) containing
4907
+ // {from, to, marker} object pointing to such marker objects, and
4908
+ // indicating that such a marker is present on that line. Multiple
4909
+ // lines may point to the same marker when it spans across lines.
4910
+ // The spans will have null for their from/to properties when the
4911
+ // marker continues beyond the start/end of the line. Markers have
4912
+ // links back to the lines they currently touch.
4913
+
4914
+ var TextMarker = CodeMirror.TextMarker = function(doc, type) {
4915
+ this.lines = [];
4916
+ this.type = type;
4917
+ this.doc = doc;
4918
+ };
4919
+ eventMixin(TextMarker);
4920
+
4921
+ // Clear the marker.
4922
+ TextMarker.prototype.clear = function() {
4923
+ if (this.explicitlyCleared) return;
4924
+ var cm = this.doc.cm, withOp = cm && !cm.curOp;
4925
+ if (withOp) startOperation(cm);
4926
+ if (hasHandler(this, "clear")) {
4927
+ var found = this.find();
4928
+ if (found) signalLater(this, "clear", found.from, found.to);
4929
+ }
4930
+ var min = null, max = null;
4931
+ for (var i = 0; i < this.lines.length; ++i) {
4932
+ var line = this.lines[i];
4933
+ var span = getMarkedSpanFor(line.markedSpans, this);
4934
+ if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
4935
+ else if (cm) {
4936
+ if (span.to != null) max = lineNo(line);
4937
+ if (span.from != null) min = lineNo(line);
4938
+ }
4939
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span);
4940
+ if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
4941
+ updateLineHeight(line, textHeight(cm.display));
4942
+ }
4943
+ if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
4944
+ var visual = visualLine(this.lines[i]), len = lineLength(visual);
4945
+ if (len > cm.display.maxLineLength) {
4946
+ cm.display.maxLine = visual;
4947
+ cm.display.maxLineLength = len;
4948
+ cm.display.maxLineChanged = true;
4949
+ }
4950
+ }
4951
+
4952
+ if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
4953
+ this.lines.length = 0;
4954
+ this.explicitlyCleared = true;
4955
+ if (this.atomic && this.doc.cantEdit) {
4956
+ this.doc.cantEdit = false;
4957
+ if (cm) reCheckSelection(cm.doc);
4958
+ }
4959
+ if (cm) signalLater(cm, "markerCleared", cm, this);
4960
+ if (withOp) endOperation(cm);
4961
+ if (this.parent) this.parent.clear();
4962
+ };
4963
+
4964
+ // Find the position of the marker in the document. Returns a {from,
4965
+ // to} object by default. Side can be passed to get a specific side
4966
+ // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
4967
+ // Pos objects returned contain a line object, rather than a line
4968
+ // number (used to prevent looking up the same line twice).
4969
+ TextMarker.prototype.find = function(side, lineObj) {
4970
+ if (side == null && this.type == "bookmark") side = 1;
4971
+ var from, to;
4972
+ for (var i = 0; i < this.lines.length; ++i) {
4973
+ var line = this.lines[i];
4974
+ var span = getMarkedSpanFor(line.markedSpans, this);
4975
+ if (span.from != null) {
4976
+ from = Pos(lineObj ? line : lineNo(line), span.from);
4977
+ if (side == -1) return from;
4978
+ }
4979
+ if (span.to != null) {
4980
+ to = Pos(lineObj ? line : lineNo(line), span.to);
4981
+ if (side == 1) return to;
4982
+ }
4983
+ }
4984
+ return from && {from: from, to: to};
4985
+ };
4986
+
4987
+ // Signals that the marker's widget changed, and surrounding layout
4988
+ // should be recomputed.
4989
+ TextMarker.prototype.changed = function() {
4990
+ var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
4991
+ if (!pos || !cm) return;
4992
+ runInOp(cm, function() {
4993
+ var line = pos.line, lineN = lineNo(pos.line);
4994
+ var view = findViewForLine(cm, lineN);
4995
+ if (view) {
4996
+ clearLineMeasurementCacheFor(view);
4997
+ cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
4998
+ }
4999
+ cm.curOp.updateMaxLine = true;
5000
+ if (!lineIsHidden(widget.doc, line) && widget.height != null) {
5001
+ var oldHeight = widget.height;
5002
+ widget.height = null;
5003
+ var dHeight = widgetHeight(widget) - oldHeight;
5004
+ if (dHeight)
5005
+ updateLineHeight(line, line.height + dHeight);
5006
+ }
5007
+ });
5008
+ };
5009
+
5010
+ TextMarker.prototype.attachLine = function(line) {
5011
+ if (!this.lines.length && this.doc.cm) {
5012
+ var op = this.doc.cm.curOp;
5013
+ if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
5014
+ (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
5015
+ }
5016
+ this.lines.push(line);
5017
+ };
5018
+ TextMarker.prototype.detachLine = function(line) {
5019
+ this.lines.splice(indexOf(this.lines, line), 1);
5020
+ if (!this.lines.length && this.doc.cm) {
5021
+ var op = this.doc.cm.curOp;
5022
+ (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
5023
+ }
5024
+ };
5025
+
5026
+ // Collapsed markers have unique ids, in order to be able to order
5027
+ // them, which is needed for uniquely determining an outer marker
5028
+ // when they overlap (they may nest, but not partially overlap).
5029
+ var nextMarkerId = 0;
5030
+
5031
+ // Create a marker, wire it up to the right lines, and
5032
+ function markText(doc, from, to, options, type) {
5033
+ // Shared markers (across linked documents) are handled separately
5034
+ // (markTextShared will call out to this again, once per
5035
+ // document).
5036
+ if (options && options.shared) return markTextShared(doc, from, to, options, type);
5037
+ // Ensure we are in an operation.
5038
+ if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
5039
+
5040
+ var marker = new TextMarker(doc, type), diff = cmp(from, to);
5041
+ if (options) copyObj(options, marker, false);
5042
+ // Don't connect empty markers unless clearWhenEmpty is false
5043
+ if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
5044
+ return marker;
5045
+ if (marker.replacedWith) {
5046
+ // Showing up as a widget implies collapsed (widget replaces text)
5047
+ marker.collapsed = true;
5048
+ marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
5049
+ if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
5050
+ if (options.insertLeft) marker.widgetNode.insertLeft = true;
5051
+ }
5052
+ if (marker.collapsed) {
5053
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
5054
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
5055
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
5056
+ sawCollapsedSpans = true;
5057
+ }
5058
+
5059
+ if (marker.addToHistory)
5060
+ addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
5061
+
5062
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
5063
+ doc.iter(curLine, to.line + 1, function(line) {
5064
+ if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
5065
+ updateMaxLine = true;
5066
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
5067
+ addMarkedSpan(line, new MarkedSpan(marker,
5068
+ curLine == from.line ? from.ch : null,
5069
+ curLine == to.line ? to.ch : null));
5070
+ ++curLine;
5071
+ });
5072
+ // lineIsHidden depends on the presence of the spans, so needs a second pass
5073
+ if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
5074
+ if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
5075
+ });
5076
+
5077
+ if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
5078
+
5079
+ if (marker.readOnly) {
5080
+ sawReadOnlySpans = true;
5081
+ if (doc.history.done.length || doc.history.undone.length)
5082
+ doc.clearHistory();
5083
+ }
5084
+ if (marker.collapsed) {
5085
+ marker.id = ++nextMarkerId;
5086
+ marker.atomic = true;
5087
+ }
5088
+ if (cm) {
5089
+ // Sync editor state
5090
+ if (updateMaxLine) cm.curOp.updateMaxLine = true;
5091
+ if (marker.collapsed)
5092
+ regChange(cm, from.line, to.line + 1);
5093
+ else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
5094
+ for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
5095
+ if (marker.atomic) reCheckSelection(cm.doc);
5096
+ signalLater(cm, "markerAdded", cm, marker);
5097
+ }
5098
+ return marker;
5099
+ }
5100
+
5101
+ // SHARED TEXTMARKERS
5102
+
5103
+ // A shared marker spans multiple linked documents. It is
5104
+ // implemented as a meta-marker-object controlling multiple normal
5105
+ // markers.
5106
+ var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
5107
+ this.markers = markers;
5108
+ this.primary = primary;
5109
+ for (var i = 0; i < markers.length; ++i)
5110
+ markers[i].parent = this;
5111
+ };
5112
+ eventMixin(SharedTextMarker);
5113
+
5114
+ SharedTextMarker.prototype.clear = function() {
5115
+ if (this.explicitlyCleared) return;
5116
+ this.explicitlyCleared = true;
5117
+ for (var i = 0; i < this.markers.length; ++i)
5118
+ this.markers[i].clear();
5119
+ signalLater(this, "clear");
5120
+ };
5121
+ SharedTextMarker.prototype.find = function(side, lineObj) {
5122
+ return this.primary.find(side, lineObj);
5123
+ };
5124
+
5125
+ function markTextShared(doc, from, to, options, type) {
5126
+ options = copyObj(options);
5127
+ options.shared = false;
5128
+ var markers = [markText(doc, from, to, options, type)], primary = markers[0];
5129
+ var widget = options.widgetNode;
5130
+ linkedDocs(doc, function(doc) {
5131
+ if (widget) options.widgetNode = widget.cloneNode(true);
5132
+ markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
5133
+ for (var i = 0; i < doc.linked.length; ++i)
5134
+ if (doc.linked[i].isParent) return;
5135
+ primary = lst(markers);
5136
+ });
5137
+ return new SharedTextMarker(markers, primary);
5138
+ }
5139
+
5140
+ function findSharedMarkers(doc) {
5141
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
5142
+ function(m) { return m.parent; });
5143
+ }
5144
+
5145
+ function copySharedMarkers(doc, markers) {
5146
+ for (var i = 0; i < markers.length; i++) {
5147
+ var marker = markers[i], pos = marker.find();
5148
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
5149
+ if (cmp(mFrom, mTo)) {
5150
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
5151
+ marker.markers.push(subMark);
5152
+ subMark.parent = marker;
5153
+ }
5154
+ }
5155
+ }
5156
+
5157
+ function detachSharedMarkers(markers) {
5158
+ for (var i = 0; i < markers.length; i++) {
5159
+ var marker = markers[i], linked = [marker.primary.doc];;
5160
+ linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
5161
+ for (var j = 0; j < marker.markers.length; j++) {
5162
+ var subMarker = marker.markers[j];
5163
+ if (indexOf(linked, subMarker.doc) == -1) {
5164
+ subMarker.parent = null;
5165
+ marker.markers.splice(j--, 1);
5166
+ }
5167
+ }
5168
+ }
5169
+ }
5170
+
5171
+ // TEXTMARKER SPANS
5172
+
5173
+ function MarkedSpan(marker, from, to) {
5174
+ this.marker = marker;
5175
+ this.from = from; this.to = to;
5176
+ }
5177
+
5178
+ // Search an array of spans for a span matching the given marker.
5179
+ function getMarkedSpanFor(spans, marker) {
5180
+ if (spans) for (var i = 0; i < spans.length; ++i) {
5181
+ var span = spans[i];
5182
+ if (span.marker == marker) return span;
5183
+ }
5184
+ }
5185
+ // Remove a span from an array, returning undefined if no spans are
5186
+ // left (we don't store arrays for lines without spans).
5187
+ function removeMarkedSpan(spans, span) {
5188
+ for (var r, i = 0; i < spans.length; ++i)
5189
+ if (spans[i] != span) (r || (r = [])).push(spans[i]);
5190
+ return r;
5191
+ }
5192
+ // Add a span to a line.
5193
+ function addMarkedSpan(line, span) {
5194
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
5195
+ span.marker.attachLine(line);
5196
+ }
5197
+
5198
+ // Used for the algorithm that adjusts markers for a change in the
5199
+ // document. These functions cut an array of spans at a given
5200
+ // character position, returning an array of remaining chunks (or
5201
+ // undefined if nothing remains).
5202
+ function markedSpansBefore(old, startCh, isInsert) {
5203
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
5204
+ var span = old[i], marker = span.marker;
5205
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
5206
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
5207
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
5208
+ (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
5209
+ }
5210
+ }
5211
+ return nw;
5212
+ }
5213
+ function markedSpansAfter(old, endCh, isInsert) {
5214
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
5215
+ var span = old[i], marker = span.marker;
5216
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
5217
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
5218
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
5219
+ (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
5220
+ span.to == null ? null : span.to - endCh));
5221
+ }
5222
+ }
5223
+ return nw;
5224
+ }
5225
+
5226
+ // Given a change object, compute the new set of marker spans that
5227
+ // cover the line in which the change took place. Removes spans
5228
+ // entirely within the change, reconnects spans belonging to the
5229
+ // same marker that appear on both sides of the change, and cuts off
5230
+ // spans partially within the change. Returns an array of span
5231
+ // arrays with one element for each line in (after) the change.
5232
+ function stretchSpansOverChange(doc, change) {
5233
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
5234
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
5235
+ if (!oldFirst && !oldLast) return null;
5236
+
5237
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
5238
+ // Get the spans that 'stick out' on both sides
5239
+ var first = markedSpansBefore(oldFirst, startCh, isInsert);
5240
+ var last = markedSpansAfter(oldLast, endCh, isInsert);
5241
+
5242
+ // Next, merge those two ends
5243
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
5244
+ if (first) {
5245
+ // Fix up .to properties of first
5246
+ for (var i = 0; i < first.length; ++i) {
5247
+ var span = first[i];
5248
+ if (span.to == null) {
5249
+ var found = getMarkedSpanFor(last, span.marker);
5250
+ if (!found) span.to = startCh;
5251
+ else if (sameLine) span.to = found.to == null ? null : found.to + offset;
5252
+ }
5253
+ }
5254
+ }
5255
+ if (last) {
5256
+ // Fix up .from in last (or move them into first in case of sameLine)
5257
+ for (var i = 0; i < last.length; ++i) {
5258
+ var span = last[i];
5259
+ if (span.to != null) span.to += offset;
5260
+ if (span.from == null) {
5261
+ var found = getMarkedSpanFor(first, span.marker);
5262
+ if (!found) {
5263
+ span.from = offset;
5264
+ if (sameLine) (first || (first = [])).push(span);
5265
+ }
5266
+ } else {
5267
+ span.from += offset;
5268
+ if (sameLine) (first || (first = [])).push(span);
5269
+ }
5270
+ }
5271
+ }
5272
+ // Make sure we didn't create any zero-length spans
5273
+ if (first) first = clearEmptySpans(first);
5274
+ if (last && last != first) last = clearEmptySpans(last);
5275
+
5276
+ var newMarkers = [first];
5277
+ if (!sameLine) {
5278
+ // Fill gap with whole-line-spans
5279
+ var gap = change.text.length - 2, gapMarkers;
5280
+ if (gap > 0 && first)
5281
+ for (var i = 0; i < first.length; ++i)
5282
+ if (first[i].to == null)
5283
+ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
5284
+ for (var i = 0; i < gap; ++i)
5285
+ newMarkers.push(gapMarkers);
5286
+ newMarkers.push(last);
5287
+ }
5288
+ return newMarkers;
5289
+ }
5290
+
5291
+ // Remove spans that are empty and don't have a clearWhenEmpty
5292
+ // option of false.
5293
+ function clearEmptySpans(spans) {
5294
+ for (var i = 0; i < spans.length; ++i) {
5295
+ var span = spans[i];
5296
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
5297
+ spans.splice(i--, 1);
5298
+ }
5299
+ if (!spans.length) return null;
5300
+ return spans;
5301
+ }
5302
+
5303
+ // Used for un/re-doing changes from the history. Combines the
5304
+ // result of computing the existing spans with the set of spans that
5305
+ // existed in the history (so that deleting around a span and then
5306
+ // undoing brings back the span).
5307
+ function mergeOldSpans(doc, change) {
5308
+ var old = getOldSpans(doc, change);
5309
+ var stretched = stretchSpansOverChange(doc, change);
5310
+ if (!old) return stretched;
5311
+ if (!stretched) return old;
5312
+
5313
+ for (var i = 0; i < old.length; ++i) {
5314
+ var oldCur = old[i], stretchCur = stretched[i];
5315
+ if (oldCur && stretchCur) {
5316
+ spans: for (var j = 0; j < stretchCur.length; ++j) {
5317
+ var span = stretchCur[j];
5318
+ for (var k = 0; k < oldCur.length; ++k)
5319
+ if (oldCur[k].marker == span.marker) continue spans;
5320
+ oldCur.push(span);
5321
+ }
5322
+ } else if (stretchCur) {
5323
+ old[i] = stretchCur;
5324
+ }
5325
+ }
5326
+ return old;
5327
+ }
5328
+
5329
+ // Used to 'clip' out readOnly ranges when making a change.
5330
+ function removeReadOnlyRanges(doc, from, to) {
5331
+ var markers = null;
5332
+ doc.iter(from.line, to.line + 1, function(line) {
5333
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
5334
+ var mark = line.markedSpans[i].marker;
5335
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
5336
+ (markers || (markers = [])).push(mark);
5337
+ }
5338
+ });
5339
+ if (!markers) return null;
5340
+ var parts = [{from: from, to: to}];
5341
+ for (var i = 0; i < markers.length; ++i) {
5342
+ var mk = markers[i], m = mk.find(0);
5343
+ for (var j = 0; j < parts.length; ++j) {
5344
+ var p = parts[j];
5345
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
5346
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
5347
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
5348
+ newParts.push({from: p.from, to: m.from});
5349
+ if (dto > 0 || !mk.inclusiveRight && !dto)
5350
+ newParts.push({from: m.to, to: p.to});
5351
+ parts.splice.apply(parts, newParts);
5352
+ j += newParts.length - 1;
5353
+ }
5354
+ }
5355
+ return parts;
5356
+ }
5357
+
5358
+ // Connect or disconnect spans from a line.
5359
+ function detachMarkedSpans(line) {
5360
+ var spans = line.markedSpans;
5361
+ if (!spans) return;
5362
+ for (var i = 0; i < spans.length; ++i)
5363
+ spans[i].marker.detachLine(line);
5364
+ line.markedSpans = null;
5365
+ }
5366
+ function attachMarkedSpans(line, spans) {
5367
+ if (!spans) return;
5368
+ for (var i = 0; i < spans.length; ++i)
5369
+ spans[i].marker.attachLine(line);
5370
+ line.markedSpans = spans;
5371
+ }
5372
+
5373
+ // Helpers used when computing which overlapping collapsed span
5374
+ // counts as the larger one.
5375
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
5376
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
5377
+
5378
+ // Returns a number indicating which of two overlapping collapsed
5379
+ // spans is larger (and thus includes the other). Falls back to
5380
+ // comparing ids when the spans cover exactly the same range.
5381
+ function compareCollapsedMarkers(a, b) {
5382
+ var lenDiff = a.lines.length - b.lines.length;
5383
+ if (lenDiff != 0) return lenDiff;
5384
+ var aPos = a.find(), bPos = b.find();
5385
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
5386
+ if (fromCmp) return -fromCmp;
5387
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
5388
+ if (toCmp) return toCmp;
5389
+ return b.id - a.id;
5390
+ }
5391
+
5392
+ // Find out whether a line ends or starts in a collapsed span. If
5393
+ // so, return the marker for that span.
5394
+ function collapsedSpanAtSide(line, start) {
5395
+ var sps = sawCollapsedSpans && line.markedSpans, found;
5396
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
5397
+ sp = sps[i];
5398
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
5399
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
5400
+ found = sp.marker;
5401
+ }
5402
+ return found;
5403
+ }
5404
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
5405
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
5406
+
5407
+ // Test whether there exists a collapsed span that partially
5408
+ // overlaps (covers the start or end, but not both) of a new span.
5409
+ // Such overlap is not allowed.
5410
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
5411
+ var line = getLine(doc, lineNo);
5412
+ var sps = sawCollapsedSpans && line.markedSpans;
5413
+ if (sps) for (var i = 0; i < sps.length; ++i) {
5414
+ var sp = sps[i];
5415
+ if (!sp.marker.collapsed) continue;
5416
+ var found = sp.marker.find(0);
5417
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
5418
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
5419
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
5420
+ if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
5421
+ fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
5422
+ return true;
5423
+ }
5424
+ }
5425
+
5426
+ // A visual line is a line as drawn on the screen. Folding, for
5427
+ // example, can cause multiple logical lines to appear on the same
5428
+ // visual line. This finds the start of the visual line that the
5429
+ // given line is part of (usually that is the line itself).
5430
+ function visualLine(line) {
5431
+ var merged;
5432
+ while (merged = collapsedSpanAtStart(line))
5433
+ line = merged.find(-1, true).line;
5434
+ return line;
5435
+ }
5436
+
5437
+ // Returns an array of logical lines that continue the visual line
5438
+ // started by the argument, or undefined if there are no such lines.
5439
+ function visualLineContinued(line) {
5440
+ var merged, lines;
5441
+ while (merged = collapsedSpanAtEnd(line)) {
5442
+ line = merged.find(1, true).line;
5443
+ (lines || (lines = [])).push(line);
5444
+ }
5445
+ return lines;
5446
+ }
5447
+
5448
+ // Get the line number of the start of the visual line that the
5449
+ // given line number is part of.
5450
+ function visualLineNo(doc, lineN) {
5451
+ var line = getLine(doc, lineN), vis = visualLine(line);
5452
+ if (line == vis) return lineN;
5453
+ return lineNo(vis);
5454
+ }
5455
+ // Get the line number of the start of the next visual line after
5456
+ // the given line.
5457
+ function visualLineEndNo(doc, lineN) {
5458
+ if (lineN > doc.lastLine()) return lineN;
5459
+ var line = getLine(doc, lineN), merged;
5460
+ if (!lineIsHidden(doc, line)) return lineN;
5461
+ while (merged = collapsedSpanAtEnd(line))
5462
+ line = merged.find(1, true).line;
5463
+ return lineNo(line) + 1;
5464
+ }
5465
+
5466
+ // Compute whether a line is hidden. Lines count as hidden when they
5467
+ // are part of a visual line that starts with another line, or when
5468
+ // they are entirely covered by collapsed, non-widget span.
5469
+ function lineIsHidden(doc, line) {
5470
+ var sps = sawCollapsedSpans && line.markedSpans;
5471
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
5472
+ sp = sps[i];
5473
+ if (!sp.marker.collapsed) continue;
5474
+ if (sp.from == null) return true;
5475
+ if (sp.marker.widgetNode) continue;
5476
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
5477
+ return true;
5478
+ }
5479
+ }
5480
+ function lineIsHiddenInner(doc, line, span) {
5481
+ if (span.to == null) {
5482
+ var end = span.marker.find(1, true);
5483
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
5484
+ }
5485
+ if (span.marker.inclusiveRight && span.to == line.text.length)
5486
+ return true;
5487
+ for (var sp, i = 0; i < line.markedSpans.length; ++i) {
5488
+ sp = line.markedSpans[i];
5489
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
5490
+ (sp.to == null || sp.to != span.from) &&
5491
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
5492
+ lineIsHiddenInner(doc, line, sp)) return true;
5493
+ }
5494
+ }
5495
+
5496
+ // LINE WIDGETS
5497
+
5498
+ // Line widgets are block elements displayed above or below a line.
5499
+
5500
+ var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
5501
+ if (options) for (var opt in options) if (options.hasOwnProperty(opt))
5502
+ this[opt] = options[opt];
5503
+ this.cm = cm;
5504
+ this.node = node;
5505
+ };
5506
+ eventMixin(LineWidget);
5507
+
5508
+ function adjustScrollWhenAboveVisible(cm, line, diff) {
5509
+ if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
5510
+ addToScrollPos(cm, null, diff);
5511
+ }
5512
+
5513
+ LineWidget.prototype.clear = function() {
5514
+ var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
5515
+ if (no == null || !ws) return;
5516
+ for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
5517
+ if (!ws.length) line.widgets = null;
5518
+ var height = widgetHeight(this);
5519
+ runInOp(cm, function() {
5520
+ adjustScrollWhenAboveVisible(cm, line, -height);
5521
+ regLineChange(cm, no, "widget");
5522
+ updateLineHeight(line, Math.max(0, line.height - height));
5523
+ });
5524
+ };
5525
+ LineWidget.prototype.changed = function() {
5526
+ var oldH = this.height, cm = this.cm, line = this.line;
5527
+ this.height = null;
5528
+ var diff = widgetHeight(this) - oldH;
5529
+ if (!diff) return;
5530
+ runInOp(cm, function() {
5531
+ cm.curOp.forceUpdate = true;
5532
+ adjustScrollWhenAboveVisible(cm, line, diff);
5533
+ updateLineHeight(line, line.height + diff);
5534
+ });
5535
+ };
5536
+
5537
+ function widgetHeight(widget) {
5538
+ if (widget.height != null) return widget.height;
5539
+ if (!contains(document.body, widget.node))
5540
+ removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
5541
+ return widget.height = widget.node.offsetHeight;
5542
+ }
5543
+
5544
+ function addLineWidget(cm, handle, node, options) {
5545
+ var widget = new LineWidget(cm, node, options);
5546
+ if (widget.noHScroll) cm.display.alignWidgets = true;
5547
+ changeLine(cm, handle, "widget", function(line) {
5548
+ var widgets = line.widgets || (line.widgets = []);
5549
+ if (widget.insertAt == null) widgets.push(widget);
5550
+ else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
5551
+ widget.line = line;
5552
+ if (!lineIsHidden(cm.doc, line)) {
5553
+ var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;
5554
+ updateLineHeight(line, line.height + widgetHeight(widget));
5555
+ if (aboveVisible) addToScrollPos(cm, null, widget.height);
5556
+ cm.curOp.forceUpdate = true;
5557
+ }
5558
+ return true;
5559
+ });
5560
+ return widget;
5561
+ }
5562
+
5563
+ // LINE DATA STRUCTURE
5564
+
5565
+ // Line objects. These hold state related to a line, including
5566
+ // highlighting info (the styles array).
5567
+ var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
5568
+ this.text = text;
5569
+ attachMarkedSpans(this, markedSpans);
5570
+ this.height = estimateHeight ? estimateHeight(this) : 1;
5571
+ };
5572
+ eventMixin(Line);
5573
+ Line.prototype.lineNo = function() { return lineNo(this); };
5574
+
5575
+ // Change the content (text, markers) of a line. Automatically
5576
+ // invalidates cached information and tries to re-estimate the
5577
+ // line's height.
5578
+ function updateLine(line, text, markedSpans, estimateHeight) {
5579
+ line.text = text;
5580
+ if (line.stateAfter) line.stateAfter = null;
5581
+ if (line.styles) line.styles = null;
5582
+ if (line.order != null) line.order = null;
5583
+ detachMarkedSpans(line);
5584
+ attachMarkedSpans(line, markedSpans);
5585
+ var estHeight = estimateHeight ? estimateHeight(line) : 1;
5586
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
5587
+ }
5588
+
5589
+ // Detach a line from the document tree and its markers.
5590
+ function cleanUpLine(line) {
5591
+ line.parent = null;
5592
+ detachMarkedSpans(line);
5593
+ }
5594
+
5595
+ function extractLineClasses(type, output) {
5596
+ if (type) for (;;) {
5597
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
5598
+ if (!lineClass) break;
5599
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
5600
+ var prop = lineClass[1] ? "bgClass" : "textClass";
5601
+ if (output[prop] == null)
5602
+ output[prop] = lineClass[2];
5603
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
5604
+ output[prop] += " " + lineClass[2];
5605
+ }
5606
+ return type;
5607
+ }
5608
+
5609
+ function callBlankLine(mode, state) {
5610
+ if (mode.blankLine) return mode.blankLine(state);
5611
+ if (!mode.innerMode) return;
5612
+ var inner = CodeMirror.innerMode(mode, state);
5613
+ if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
5614
+ }
5615
+
5616
+ function readToken(mode, stream, state) {
5617
+ for (var i = 0; i < 10; i++) {
5618
+ var style = mode.token(stream, state);
5619
+ if (stream.pos > stream.start) return style;
5620
+ }
5621
+ throw new Error("Mode " + mode.name + " failed to advance stream.");
5622
+ }
5623
+
5624
+ // Run the given mode's parser over a line, calling f for each token.
5625
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
5626
+ var flattenSpans = mode.flattenSpans;
5627
+ if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
5628
+ var curStart = 0, curStyle = null;
5629
+ var stream = new StringStream(text, cm.options.tabSize), style;
5630
+ if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
5631
+ while (!stream.eol()) {
5632
+ if (stream.pos > cm.options.maxHighlightLength) {
5633
+ flattenSpans = false;
5634
+ if (forceToEnd) processLine(cm, text, state, stream.pos);
5635
+ stream.pos = text.length;
5636
+ style = null;
5637
+ } else {
5638
+ style = extractLineClasses(readToken(mode, stream, state), lineClasses);
5639
+ }
5640
+ if (cm.options.addModeClass) {
5641
+ var mName = CodeMirror.innerMode(mode, state).mode.name;
5642
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
5643
+ }
5644
+ if (!flattenSpans || curStyle != style) {
5645
+ if (curStart < stream.start) f(stream.start, curStyle);
5646
+ curStart = stream.start; curStyle = style;
5647
+ }
5648
+ stream.start = stream.pos;
5649
+ }
5650
+ while (curStart < stream.pos) {
5651
+ // Webkit seems to refuse to render text nodes longer than 57444 characters
5652
+ var pos = Math.min(stream.pos, curStart + 50000);
5653
+ f(pos, curStyle);
5654
+ curStart = pos;
5655
+ }
5656
+ }
5657
+
5658
+ // Compute a style array (an array starting with a mode generation
5659
+ // -- for invalidation -- followed by pairs of end positions and
5660
+ // style strings), which is used to highlight the tokens on the
5661
+ // line.
5662
+ function highlightLine(cm, line, state, forceToEnd) {
5663
+ // A styles array always starts with a number identifying the
5664
+ // mode/overlays that it is based on (for easy invalidation).
5665
+ var st = [cm.state.modeGen], lineClasses = {};
5666
+ // Compute the base array of styles
5667
+ runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
5668
+ st.push(end, style);
5669
+ }, lineClasses, forceToEnd);
5670
+
5671
+ // Run overlays, adjust style array.
5672
+ for (var o = 0; o < cm.state.overlays.length; ++o) {
5673
+ var overlay = cm.state.overlays[o], i = 1, at = 0;
5674
+ runMode(cm, line.text, overlay.mode, true, function(end, style) {
5675
+ var start = i;
5676
+ // Ensure there's a token end at the current position, and that i points at it
5677
+ while (at < end) {
5678
+ var i_end = st[i];
5679
+ if (i_end > end)
5680
+ st.splice(i, 1, end, st[i+1], i_end);
5681
+ i += 2;
5682
+ at = Math.min(end, i_end);
5683
+ }
5684
+ if (!style) return;
5685
+ if (overlay.opaque) {
5686
+ st.splice(start, i - start, end, "cm-overlay " + style);
5687
+ i = start + 2;
5688
+ } else {
5689
+ for (; start < i; start += 2) {
5690
+ var cur = st[start+1];
5691
+ st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
5692
+ }
5693
+ }
5694
+ }, lineClasses);
5695
+ }
5696
+
5697
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
5698
+ }
5699
+
5700
+ function getLineStyles(cm, line) {
5701
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
5702
+ var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
5703
+ line.styles = result.styles;
5704
+ if (result.classes) line.styleClasses = result.classes;
5705
+ else if (line.styleClasses) line.styleClasses = null;
5706
+ }
5707
+ return line.styles;
5708
+ }
5709
+
5710
+ // Lightweight form of highlight -- proceed over this line and
5711
+ // update state, but don't save a style array. Used for lines that
5712
+ // aren't currently visible.
5713
+ function processLine(cm, text, state, startAt) {
5714
+ var mode = cm.doc.mode;
5715
+ var stream = new StringStream(text, cm.options.tabSize);
5716
+ stream.start = stream.pos = startAt || 0;
5717
+ if (text == "") callBlankLine(mode, state);
5718
+ while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
5719
+ readToken(mode, stream, state);
5720
+ stream.start = stream.pos;
5721
+ }
5722
+ }
5723
+
5724
+ // Convert a style as returned by a mode (either null, or a string
5725
+ // containing one or more styles) to a CSS style. This is cached,
5726
+ // and also looks for line-wide styles.
5727
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
5728
+ function interpretTokenStyle(style, options) {
5729
+ if (!style || /^\s*$/.test(style)) return null;
5730
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
5731
+ return cache[style] ||
5732
+ (cache[style] = style.replace(/\S+/g, "cm-$&"));
5733
+ }
5734
+
5735
+ // Render the DOM representation of the text of a line. Also builds
5736
+ // up a 'line map', which points at the DOM nodes that represent
5737
+ // specific stretches of text, and is used by the measuring code.
5738
+ // The returned object contains the DOM node, this map, and
5739
+ // information about line-wide styles that were set by the mode.
5740
+ function buildLineContent(cm, lineView) {
5741
+ // The padding-right forces the element to have a 'border', which
5742
+ // is needed on Webkit to be able to get line-level bounding
5743
+ // rectangles for it (in measureChar).
5744
+ var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
5745
+ var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm};
5746
+ lineView.measure = {};
5747
+
5748
+ // Iterate over the logical lines that make up this visual line.
5749
+ for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
5750
+ var line = i ? lineView.rest[i - 1] : lineView.line, order;
5751
+ builder.pos = 0;
5752
+ builder.addToken = buildToken;
5753
+ // Optionally wire in some hacks into the token-rendering
5754
+ // algorithm, to deal with browser quirks.
5755
+ if ((ie || webkit) && cm.getOption("lineWrapping"))
5756
+ builder.addToken = buildTokenSplitSpaces(builder.addToken);
5757
+ if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
5758
+ builder.addToken = buildTokenBadBidi(builder.addToken, order);
5759
+ builder.map = [];
5760
+ insertLineContent(line, builder, getLineStyles(cm, line));
5761
+ if (line.styleClasses) {
5762
+ if (line.styleClasses.bgClass)
5763
+ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
5764
+ if (line.styleClasses.textClass)
5765
+ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
5766
+ }
5767
+
5768
+ // Ensure at least a single node is present, for measuring.
5769
+ if (builder.map.length == 0)
5770
+ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
5771
+
5772
+ // Store the map and a cache object for the current logical line
5773
+ if (i == 0) {
5774
+ lineView.measure.map = builder.map;
5775
+ lineView.measure.cache = {};
5776
+ } else {
5777
+ (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
5778
+ (lineView.measure.caches || (lineView.measure.caches = [])).push({});
5779
+ }
5780
+ }
5781
+
5782
+ signal(cm, "renderLine", cm, lineView.line, builder.pre);
5783
+ if (builder.pre.className)
5784
+ builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
5785
+ return builder;
5786
+ }
5787
+
5788
+ function defaultSpecialCharPlaceholder(ch) {
5789
+ var token = elt("span", "\u2022", "cm-invalidchar");
5790
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
5791
+ return token;
5792
+ }
5793
+
5794
+ // Build up the DOM representation for a single token, and add it to
5795
+ // the line map. Takes care to render special characters separately.
5796
+ function buildToken(builder, text, style, startStyle, endStyle, title) {
5797
+ if (!text) return;
5798
+ var special = builder.cm.options.specialChars, mustWrap = false;
5799
+ if (!special.test(text)) {
5800
+ builder.col += text.length;
5801
+ var content = document.createTextNode(text);
5802
+ builder.map.push(builder.pos, builder.pos + text.length, content);
5803
+ if (ie_upto8) mustWrap = true;
5804
+ builder.pos += text.length;
5805
+ } else {
5806
+ var content = document.createDocumentFragment(), pos = 0;
5807
+ while (true) {
5808
+ special.lastIndex = pos;
5809
+ var m = special.exec(text);
5810
+ var skipped = m ? m.index - pos : text.length - pos;
5811
+ if (skipped) {
5812
+ var txt = document.createTextNode(text.slice(pos, pos + skipped));
5813
+ if (ie_upto8) content.appendChild(elt("span", [txt]));
5814
+ else content.appendChild(txt);
5815
+ builder.map.push(builder.pos, builder.pos + skipped, txt);
5816
+ builder.col += skipped;
5817
+ builder.pos += skipped;
5818
+ }
5819
+ if (!m) break;
5820
+ pos += skipped + 1;
5821
+ if (m[0] == "\t") {
5822
+ var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
5823
+ var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
5824
+ builder.col += tabWidth;
5825
+ } else {
5826
+ var txt = builder.cm.options.specialCharPlaceholder(m[0]);
5827
+ if (ie_upto8) content.appendChild(elt("span", [txt]));
5828
+ else content.appendChild(txt);
5829
+ builder.col += 1;
5830
+ }
5831
+ builder.map.push(builder.pos, builder.pos + 1, txt);
5832
+ builder.pos++;
5833
+ }
5834
+ }
5835
+ if (style || startStyle || endStyle || mustWrap) {
5836
+ var fullStyle = style || "";
5837
+ if (startStyle) fullStyle += startStyle;
5838
+ if (endStyle) fullStyle += endStyle;
5839
+ var token = elt("span", [content], fullStyle);
5840
+ if (title) token.title = title;
5841
+ return builder.content.appendChild(token);
5842
+ }
5843
+ builder.content.appendChild(content);
5844
+ }
5845
+
5846
+ function buildTokenSplitSpaces(inner) {
5847
+ function split(old) {
5848
+ var out = " ";
5849
+ for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
5850
+ out += " ";
5851
+ return out;
5852
+ }
5853
+ return function(builder, text, style, startStyle, endStyle, title) {
5854
+ inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
5855
+ };
5856
+ }
5857
+
5858
+ // Work around nonsense dimensions being reported for stretches of
5859
+ // right-to-left text.
5860
+ function buildTokenBadBidi(inner, order) {
5861
+ return function(builder, text, style, startStyle, endStyle, title) {
5862
+ style = style ? style + " cm-force-border" : "cm-force-border";
5863
+ var start = builder.pos, end = start + text.length;
5864
+ for (;;) {
5865
+ // Find the part that overlaps with the start of this text
5866
+ for (var i = 0; i < order.length; i++) {
5867
+ var part = order[i];
5868
+ if (part.to > start && part.from <= start) break;
5869
+ }
5870
+ if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title);
5871
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);
5872
+ startStyle = null;
5873
+ text = text.slice(part.to - start);
5874
+ start = part.to;
5875
+ }
5876
+ };
5877
+ }
5878
+
5879
+ function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
5880
+ var widget = !ignoreWidget && marker.widgetNode;
5881
+ if (widget) {
5882
+ builder.map.push(builder.pos, builder.pos + size, widget);
5883
+ builder.content.appendChild(widget);
5884
+ }
5885
+ builder.pos += size;
5886
+ }
5887
+
5888
+ // Outputs a number of spans to make up a line, taking highlighting
5889
+ // and marked text into account.
5890
+ function insertLineContent(line, builder, styles) {
5891
+ var spans = line.markedSpans, allText = line.text, at = 0;
5892
+ if (!spans) {
5893
+ for (var i = 1; i < styles.length; i+=2)
5894
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
5895
+ return;
5896
+ }
5897
+
5898
+ var len = allText.length, pos = 0, i = 1, text = "", style;
5899
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
5900
+ for (;;) {
5901
+ if (nextChange == pos) { // Update current marker set
5902
+ spanStyle = spanEndStyle = spanStartStyle = title = "";
5903
+ collapsed = null; nextChange = Infinity;
5904
+ var foundBookmarks = [];
5905
+ for (var j = 0; j < spans.length; ++j) {
5906
+ var sp = spans[j], m = sp.marker;
5907
+ if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
5908
+ if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
5909
+ if (m.className) spanStyle += " " + m.className;
5910
+ if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
5911
+ if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
5912
+ if (m.title && !title) title = m.title;
5913
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
5914
+ collapsed = sp;
5915
+ } else if (sp.from > pos && nextChange > sp.from) {
5916
+ nextChange = sp.from;
5917
+ }
5918
+ if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);
5919
+ }
5920
+ if (collapsed && (collapsed.from || 0) == pos) {
5921
+ buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
5922
+ collapsed.marker, collapsed.from == null);
5923
+ if (collapsed.to == null) return;
5924
+ }
5925
+ if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
5926
+ buildCollapsedSpan(builder, 0, foundBookmarks[j]);
5927
+ }
5928
+ if (pos >= len) break;
5929
+
5930
+ var upto = Math.min(len, nextChange);
5931
+ while (true) {
5932
+ if (text) {
5933
+ var end = pos + text.length;
5934
+ if (!collapsed) {
5935
+ var tokenText = end > upto ? text.slice(0, upto - pos) : text;
5936
+ builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
5937
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
5938
+ }
5939
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
5940
+ pos = end;
5941
+ spanStartStyle = "";
5942
+ }
5943
+ text = allText.slice(at, at = styles[i++]);
5944
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
5945
+ }
5946
+ }
5947
+ }
5948
+
5949
+ // DOCUMENT DATA STRUCTURE
5950
+
5951
+ // By default, updates that start and end at the beginning of a line
5952
+ // are treated specially, in order to make the association of line
5953
+ // widgets and marker elements with the text behave more intuitive.
5954
+ function isWholeLineUpdate(doc, change) {
5955
+ return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
5956
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
5957
+ }
5958
+
5959
+ // Perform a change on the document data structure.
5960
+ function updateDoc(doc, change, markedSpans, estimateHeight) {
5961
+ function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
5962
+ function update(line, text, spans) {
5963
+ updateLine(line, text, spans, estimateHeight);
5964
+ signalLater(line, "change", line, change);
5965
+ }
5966
+
5967
+ var from = change.from, to = change.to, text = change.text;
5968
+ var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
5969
+ var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
5970
+
5971
+ // Adjust the line structure
5972
+ if (isWholeLineUpdate(doc, change)) {
5973
+ // This is a whole-line replace. Treated specially to make
5974
+ // sure line objects move the way they are supposed to.
5975
+ for (var i = 0, added = []; i < text.length - 1; ++i)
5976
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
5977
+ update(lastLine, lastLine.text, lastSpans);
5978
+ if (nlines) doc.remove(from.line, nlines);
5979
+ if (added.length) doc.insert(from.line, added);
5980
+ } else if (firstLine == lastLine) {
5981
+ if (text.length == 1) {
5982
+ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
5983
+ } else {
5984
+ for (var added = [], i = 1; i < text.length - 1; ++i)
5985
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
5986
+ added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
5987
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
5988
+ doc.insert(from.line + 1, added);
5989
+ }
5990
+ } else if (text.length == 1) {
5991
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
5992
+ doc.remove(from.line + 1, nlines);
5993
+ } else {
5994
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
5995
+ update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
5996
+ for (var i = 1, added = []; i < text.length - 1; ++i)
5997
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
5998
+ if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
5999
+ doc.insert(from.line + 1, added);
6000
+ }
6001
+
6002
+ signalLater(doc, "change", doc, change);
6003
+ }
6004
+
6005
+ // The document is represented as a BTree consisting of leaves, with
6006
+ // chunk of lines in them, and branches, with up to ten leaves or
6007
+ // other branch nodes below them. The top node is always a branch
6008
+ // node, and is the document object itself (meaning it has
6009
+ // additional methods and properties).
6010
+ //
6011
+ // All nodes have parent links. The tree is used both to go from
6012
+ // line numbers to line objects, and to go from objects to numbers.
6013
+ // It also indexes by height, and is used to convert between height
6014
+ // and line object, and to find the total height of the document.
6015
+ //
6016
+ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
6017
+
6018
+ function LeafChunk(lines) {
6019
+ this.lines = lines;
6020
+ this.parent = null;
6021
+ for (var i = 0, height = 0; i < lines.length; ++i) {
6022
+ lines[i].parent = this;
6023
+ height += lines[i].height;
6024
+ }
6025
+ this.height = height;
6026
+ }
6027
+
6028
+ LeafChunk.prototype = {
6029
+ chunkSize: function() { return this.lines.length; },
6030
+ // Remove the n lines at offset 'at'.
6031
+ removeInner: function(at, n) {
6032
+ for (var i = at, e = at + n; i < e; ++i) {
6033
+ var line = this.lines[i];
6034
+ this.height -= line.height;
6035
+ cleanUpLine(line);
6036
+ signalLater(line, "delete");
6037
+ }
6038
+ this.lines.splice(at, n);
6039
+ },
6040
+ // Helper used to collapse a small branch into a single leaf.
6041
+ collapse: function(lines) {
6042
+ lines.push.apply(lines, this.lines);
6043
+ },
6044
+ // Insert the given array of lines at offset 'at', count them as
6045
+ // having the given height.
6046
+ insertInner: function(at, lines, height) {
6047
+ this.height += height;
6048
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
6049
+ for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
6050
+ },
6051
+ // Used to iterate over a part of the tree.
6052
+ iterN: function(at, n, op) {
6053
+ for (var e = at + n; at < e; ++at)
6054
+ if (op(this.lines[at])) return true;
6055
+ }
6056
+ };
6057
+
6058
+ function BranchChunk(children) {
6059
+ this.children = children;
6060
+ var size = 0, height = 0;
6061
+ for (var i = 0; i < children.length; ++i) {
6062
+ var ch = children[i];
6063
+ size += ch.chunkSize(); height += ch.height;
6064
+ ch.parent = this;
6065
+ }
6066
+ this.size = size;
6067
+ this.height = height;
6068
+ this.parent = null;
6069
+ }
6070
+
6071
+ BranchChunk.prototype = {
6072
+ chunkSize: function() { return this.size; },
6073
+ removeInner: function(at, n) {
6074
+ this.size -= n;
6075
+ for (var i = 0; i < this.children.length; ++i) {
6076
+ var child = this.children[i], sz = child.chunkSize();
6077
+ if (at < sz) {
6078
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
6079
+ child.removeInner(at, rm);
6080
+ this.height -= oldHeight - child.height;
6081
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
6082
+ if ((n -= rm) == 0) break;
6083
+ at = 0;
6084
+ } else at -= sz;
6085
+ }
6086
+ // If the result is smaller than 25 lines, ensure that it is a
6087
+ // single leaf node.
6088
+ if (this.size - n < 25 &&
6089
+ (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
6090
+ var lines = [];
6091
+ this.collapse(lines);
6092
+ this.children = [new LeafChunk(lines)];
6093
+ this.children[0].parent = this;
6094
+ }
6095
+ },
6096
+ collapse: function(lines) {
6097
+ for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
6098
+ },
6099
+ insertInner: function(at, lines, height) {
6100
+ this.size += lines.length;
6101
+ this.height += height;
6102
+ for (var i = 0; i < this.children.length; ++i) {
6103
+ var child = this.children[i], sz = child.chunkSize();
6104
+ if (at <= sz) {
6105
+ child.insertInner(at, lines, height);
6106
+ if (child.lines && child.lines.length > 50) {
6107
+ while (child.lines.length > 50) {
6108
+ var spilled = child.lines.splice(child.lines.length - 25, 25);
6109
+ var newleaf = new LeafChunk(spilled);
6110
+ child.height -= newleaf.height;
6111
+ this.children.splice(i + 1, 0, newleaf);
6112
+ newleaf.parent = this;
6113
+ }
6114
+ this.maybeSpill();
6115
+ }
6116
+ break;
6117
+ }
6118
+ at -= sz;
6119
+ }
6120
+ },
6121
+ // When a node has grown, check whether it should be split.
6122
+ maybeSpill: function() {
6123
+ if (this.children.length <= 10) return;
6124
+ var me = this;
6125
+ do {
6126
+ var spilled = me.children.splice(me.children.length - 5, 5);
6127
+ var sibling = new BranchChunk(spilled);
6128
+ if (!me.parent) { // Become the parent node
6129
+ var copy = new BranchChunk(me.children);
6130
+ copy.parent = me;
6131
+ me.children = [copy, sibling];
6132
+ me = copy;
6133
+ } else {
6134
+ me.size -= sibling.size;
6135
+ me.height -= sibling.height;
6136
+ var myIndex = indexOf(me.parent.children, me);
6137
+ me.parent.children.splice(myIndex + 1, 0, sibling);
6138
+ }
6139
+ sibling.parent = me.parent;
6140
+ } while (me.children.length > 10);
6141
+ me.parent.maybeSpill();
6142
+ },
6143
+ iterN: function(at, n, op) {
6144
+ for (var i = 0; i < this.children.length; ++i) {
6145
+ var child = this.children[i], sz = child.chunkSize();
6146
+ if (at < sz) {
6147
+ var used = Math.min(n, sz - at);
6148
+ if (child.iterN(at, used, op)) return true;
6149
+ if ((n -= used) == 0) break;
6150
+ at = 0;
6151
+ } else at -= sz;
6152
+ }
6153
+ }
6154
+ };
6155
+
6156
+ var nextDocId = 0;
6157
+ var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
6158
+ if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
6159
+ if (firstLine == null) firstLine = 0;
6160
+
6161
+ BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
6162
+ this.first = firstLine;
6163
+ this.scrollTop = this.scrollLeft = 0;
6164
+ this.cantEdit = false;
6165
+ this.cleanGeneration = 1;
6166
+ this.frontier = firstLine;
6167
+ var start = Pos(firstLine, 0);
6168
+ this.sel = simpleSelection(start);
6169
+ this.history = new History(null);
6170
+ this.id = ++nextDocId;
6171
+ this.modeOption = mode;
6172
+
6173
+ if (typeof text == "string") text = splitLines(text);
6174
+ updateDoc(this, {from: start, to: start, text: text});
6175
+ setSelection(this, simpleSelection(start), sel_dontScroll);
6176
+ };
6177
+
6178
+ Doc.prototype = createObj(BranchChunk.prototype, {
6179
+ constructor: Doc,
6180
+ // Iterate over the document. Supports two forms -- with only one
6181
+ // argument, it calls that for each line in the document. With
6182
+ // three, it iterates over the range given by the first two (with
6183
+ // the second being non-inclusive).
6184
+ iter: function(from, to, op) {
6185
+ if (op) this.iterN(from - this.first, to - from, op);
6186
+ else this.iterN(this.first, this.first + this.size, from);
6187
+ },
6188
+
6189
+ // Non-public interface for adding and removing lines.
6190
+ insert: function(at, lines) {
6191
+ var height = 0;
6192
+ for (var i = 0; i < lines.length; ++i) height += lines[i].height;
6193
+ this.insertInner(at - this.first, lines, height);
6194
+ },
6195
+ remove: function(at, n) { this.removeInner(at - this.first, n); },
6196
+
6197
+ // From here, the methods are part of the public interface. Most
6198
+ // are also available from CodeMirror (editor) instances.
6199
+
6200
+ getValue: function(lineSep) {
6201
+ var lines = getLines(this, this.first, this.first + this.size);
6202
+ if (lineSep === false) return lines;
6203
+ return lines.join(lineSep || "\n");
6204
+ },
6205
+ setValue: docMethodOp(function(code) {
6206
+ var top = Pos(this.first, 0), last = this.first + this.size - 1;
6207
+ makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
6208
+ text: splitLines(code), origin: "setValue"}, true);
6209
+ setSelection(this, simpleSelection(top));
6210
+ }),
6211
+ replaceRange: function(code, from, to, origin) {
6212
+ from = clipPos(this, from);
6213
+ to = to ? clipPos(this, to) : from;
6214
+ replaceRange(this, code, from, to, origin);
6215
+ },
6216
+ getRange: function(from, to, lineSep) {
6217
+ var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
6218
+ if (lineSep === false) return lines;
6219
+ return lines.join(lineSep || "\n");
6220
+ },
6221
+
6222
+ getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
6223
+
6224
+ getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
6225
+ getLineNumber: function(line) {return lineNo(line);},
6226
+
6227
+ getLineHandleVisualStart: function(line) {
6228
+ if (typeof line == "number") line = getLine(this, line);
6229
+ return visualLine(line);
6230
+ },
6231
+
6232
+ lineCount: function() {return this.size;},
6233
+ firstLine: function() {return this.first;},
6234
+ lastLine: function() {return this.first + this.size - 1;},
6235
+
6236
+ clipPos: function(pos) {return clipPos(this, pos);},
6237
+
6238
+ getCursor: function(start) {
6239
+ var range = this.sel.primary(), pos;
6240
+ if (start == null || start == "head") pos = range.head;
6241
+ else if (start == "anchor") pos = range.anchor;
6242
+ else if (start == "end" || start == "to" || start === false) pos = range.to();
6243
+ else pos = range.from();
6244
+ return pos;
6245
+ },
6246
+ listSelections: function() { return this.sel.ranges; },
6247
+ somethingSelected: function() {return this.sel.somethingSelected();},
6248
+
6249
+ setCursor: docMethodOp(function(line, ch, options) {
6250
+ setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
6251
+ }),
6252
+ setSelection: docMethodOp(function(anchor, head, options) {
6253
+ setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
6254
+ }),
6255
+ extendSelection: docMethodOp(function(head, other, options) {
6256
+ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
6257
+ }),
6258
+ extendSelections: docMethodOp(function(heads, options) {
6259
+ extendSelections(this, clipPosArray(this, heads, options));
6260
+ }),
6261
+ extendSelectionsBy: docMethodOp(function(f, options) {
6262
+ extendSelections(this, map(this.sel.ranges, f), options);
6263
+ }),
6264
+ setSelections: docMethodOp(function(ranges, primary, options) {
6265
+ if (!ranges.length) return;
6266
+ for (var i = 0, out = []; i < ranges.length; i++)
6267
+ out[i] = new Range(clipPos(this, ranges[i].anchor),
6268
+ clipPos(this, ranges[i].head));
6269
+ if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
6270
+ setSelection(this, normalizeSelection(out, primary), options);
6271
+ }),
6272
+ addSelection: docMethodOp(function(anchor, head, options) {
6273
+ var ranges = this.sel.ranges.slice(0);
6274
+ ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
6275
+ setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
6276
+ }),
6277
+
6278
+ getSelection: function(lineSep) {
6279
+ var ranges = this.sel.ranges, lines;
6280
+ for (var i = 0; i < ranges.length; i++) {
6281
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
6282
+ lines = lines ? lines.concat(sel) : sel;
6283
+ }
6284
+ if (lineSep === false) return lines;
6285
+ else return lines.join(lineSep || "\n");
6286
+ },
6287
+ getSelections: function(lineSep) {
6288
+ var parts = [], ranges = this.sel.ranges;
6289
+ for (var i = 0; i < ranges.length; i++) {
6290
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
6291
+ if (lineSep !== false) sel = sel.join(lineSep || "\n");
6292
+ parts[i] = sel;
6293
+ }
6294
+ return parts;
6295
+ },
6296
+ replaceSelection: function(code, collapse, origin) {
6297
+ var dup = [];
6298
+ for (var i = 0; i < this.sel.ranges.length; i++)
6299
+ dup[i] = code;
6300
+ this.replaceSelections(dup, collapse, origin || "+input");
6301
+ },
6302
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
6303
+ var changes = [], sel = this.sel;
6304
+ for (var i = 0; i < sel.ranges.length; i++) {
6305
+ var range = sel.ranges[i];
6306
+ changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
6307
+ }
6308
+ var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
6309
+ for (var i = changes.length - 1; i >= 0; i--)
6310
+ makeChange(this, changes[i]);
6311
+ if (newSel) setSelectionReplaceHistory(this, newSel);
6312
+ else if (this.cm) ensureCursorVisible(this.cm);
6313
+ }),
6314
+ undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
6315
+ redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
6316
+ undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
6317
+ redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
6318
+
6319
+ setExtending: function(val) {this.extend = val;},
6320
+ getExtending: function() {return this.extend;},
6321
+
6322
+ historySize: function() {
6323
+ var hist = this.history, done = 0, undone = 0;
6324
+ for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
6325
+ for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
6326
+ return {undo: done, redo: undone};
6327
+ },
6328
+ clearHistory: function() {this.history = new History(this.history.maxGeneration);},
6329
+
6330
+ markClean: function() {
6331
+ this.cleanGeneration = this.changeGeneration(true);
6332
+ },
6333
+ changeGeneration: function(forceSplit) {
6334
+ if (forceSplit)
6335
+ this.history.lastOp = this.history.lastOrigin = null;
6336
+ return this.history.generation;
6337
+ },
6338
+ isClean: function (gen) {
6339
+ return this.history.generation == (gen || this.cleanGeneration);
6340
+ },
6341
+
6342
+ getHistory: function() {
6343
+ return {done: copyHistoryArray(this.history.done),
6344
+ undone: copyHistoryArray(this.history.undone)};
6345
+ },
6346
+ setHistory: function(histData) {
6347
+ var hist = this.history = new History(this.history.maxGeneration);
6348
+ hist.done = copyHistoryArray(histData.done.slice(0), null, true);
6349
+ hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
6350
+ },
6351
+
6352
+ markText: function(from, to, options) {
6353
+ return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
6354
+ },
6355
+ setBookmark: function(pos, options) {
6356
+ var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
6357
+ insertLeft: options && options.insertLeft,
6358
+ clearWhenEmpty: false, shared: options && options.shared};
6359
+ pos = clipPos(this, pos);
6360
+ return markText(this, pos, pos, realOpts, "bookmark");
6361
+ },
6362
+ findMarksAt: function(pos) {
6363
+ pos = clipPos(this, pos);
6364
+ var markers = [], spans = getLine(this, pos.line).markedSpans;
6365
+ if (spans) for (var i = 0; i < spans.length; ++i) {
6366
+ var span = spans[i];
6367
+ if ((span.from == null || span.from <= pos.ch) &&
6368
+ (span.to == null || span.to >= pos.ch))
6369
+ markers.push(span.marker.parent || span.marker);
6370
+ }
6371
+ return markers;
6372
+ },
6373
+ findMarks: function(from, to, filter) {
6374
+ from = clipPos(this, from); to = clipPos(this, to);
6375
+ var found = [], lineNo = from.line;
6376
+ this.iter(from.line, to.line + 1, function(line) {
6377
+ var spans = line.markedSpans;
6378
+ if (spans) for (var i = 0; i < spans.length; i++) {
6379
+ var span = spans[i];
6380
+ if (!(lineNo == from.line && from.ch > span.to ||
6381
+ span.from == null && lineNo != from.line||
6382
+ lineNo == to.line && span.from > to.ch) &&
6383
+ (!filter || filter(span.marker)))
6384
+ found.push(span.marker.parent || span.marker);
6385
+ }
6386
+ ++lineNo;
6387
+ });
6388
+ return found;
6389
+ },
6390
+ getAllMarks: function() {
6391
+ var markers = [];
6392
+ this.iter(function(line) {
6393
+ var sps = line.markedSpans;
6394
+ if (sps) for (var i = 0; i < sps.length; ++i)
6395
+ if (sps[i].from != null) markers.push(sps[i].marker);
6396
+ });
6397
+ return markers;
6398
+ },
6399
+
6400
+ posFromIndex: function(off) {
6401
+ var ch, lineNo = this.first;
6402
+ this.iter(function(line) {
6403
+ var sz = line.text.length + 1;
6404
+ if (sz > off) { ch = off; return true; }
6405
+ off -= sz;
6406
+ ++lineNo;
6407
+ });
6408
+ return clipPos(this, Pos(lineNo, ch));
6409
+ },
6410
+ indexFromPos: function (coords) {
6411
+ coords = clipPos(this, coords);
6412
+ var index = coords.ch;
6413
+ if (coords.line < this.first || coords.ch < 0) return 0;
6414
+ this.iter(this.first, coords.line, function (line) {
6415
+ index += line.text.length + 1;
6416
+ });
6417
+ return index;
6418
+ },
6419
+
6420
+ copy: function(copyHistory) {
6421
+ var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
6422
+ doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
6423
+ doc.sel = this.sel;
6424
+ doc.extend = false;
6425
+ if (copyHistory) {
6426
+ doc.history.undoDepth = this.history.undoDepth;
6427
+ doc.setHistory(this.getHistory());
6428
+ }
6429
+ return doc;
6430
+ },
6431
+
6432
+ linkedDoc: function(options) {
6433
+ if (!options) options = {};
6434
+ var from = this.first, to = this.first + this.size;
6435
+ if (options.from != null && options.from > from) from = options.from;
6436
+ if (options.to != null && options.to < to) to = options.to;
6437
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
6438
+ if (options.sharedHist) copy.history = this.history;
6439
+ (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
6440
+ copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
6441
+ copySharedMarkers(copy, findSharedMarkers(this));
6442
+ return copy;
6443
+ },
6444
+ unlinkDoc: function(other) {
6445
+ if (other instanceof CodeMirror) other = other.doc;
6446
+ if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
6447
+ var link = this.linked[i];
6448
+ if (link.doc != other) continue;
6449
+ this.linked.splice(i, 1);
6450
+ other.unlinkDoc(this);
6451
+ detachSharedMarkers(findSharedMarkers(this));
6452
+ break;
6453
+ }
6454
+ // If the histories were shared, split them again
6455
+ if (other.history == this.history) {
6456
+ var splitIds = [other.id];
6457
+ linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
6458
+ other.history = new History(null);
6459
+ other.history.done = copyHistoryArray(this.history.done, splitIds);
6460
+ other.history.undone = copyHistoryArray(this.history.undone, splitIds);
6461
+ }
6462
+ },
6463
+ iterLinkedDocs: function(f) {linkedDocs(this, f);},
6464
+
6465
+ getMode: function() {return this.mode;},
6466
+ getEditor: function() {return this.cm;}
6467
+ });
6468
+
6469
+ // Public alias.
6470
+ Doc.prototype.eachLine = Doc.prototype.iter;
6471
+
6472
+ // Set up methods on CodeMirror's prototype to redirect to the editor's document.
6473
+ var dontDelegate = "iter insert remove copy getEditor".split(" ");
6474
+ for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
6475
+ CodeMirror.prototype[prop] = (function(method) {
6476
+ return function() {return method.apply(this.doc, arguments);};
6477
+ })(Doc.prototype[prop]);
6478
+
6479
+ eventMixin(Doc);
6480
+
6481
+ // Call f for all linked documents.
6482
+ function linkedDocs(doc, f, sharedHistOnly) {
6483
+ function propagate(doc, skip, sharedHist) {
6484
+ if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
6485
+ var rel = doc.linked[i];
6486
+ if (rel.doc == skip) continue;
6487
+ var shared = sharedHist && rel.sharedHist;
6488
+ if (sharedHistOnly && !shared) continue;
6489
+ f(rel.doc, shared);
6490
+ propagate(rel.doc, doc, shared);
6491
+ }
6492
+ }
6493
+ propagate(doc, null, true);
6494
+ }
6495
+
6496
+ // Attach a document to an editor.
6497
+ function attachDoc(cm, doc) {
6498
+ if (doc.cm) throw new Error("This document is already in use.");
6499
+ cm.doc = doc;
6500
+ doc.cm = cm;
6501
+ estimateLineHeights(cm);
6502
+ loadMode(cm);
6503
+ if (!cm.options.lineWrapping) findMaxLine(cm);
6504
+ cm.options.mode = doc.modeOption;
6505
+ regChange(cm);
6506
+ }
6507
+
6508
+ // LINE UTILITIES
6509
+
6510
+ // Find the line object corresponding to the given line number.
6511
+ function getLine(doc, n) {
6512
+ n -= doc.first;
6513
+ if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
6514
+ for (var chunk = doc; !chunk.lines;) {
6515
+ for (var i = 0;; ++i) {
6516
+ var child = chunk.children[i], sz = child.chunkSize();
6517
+ if (n < sz) { chunk = child; break; }
6518
+ n -= sz;
6519
+ }
6520
+ }
6521
+ return chunk.lines[n];
6522
+ }
6523
+
6524
+ // Get the part of a document between two positions, as an array of
6525
+ // strings.
6526
+ function getBetween(doc, start, end) {
6527
+ var out = [], n = start.line;
6528
+ doc.iter(start.line, end.line + 1, function(line) {
6529
+ var text = line.text;
6530
+ if (n == end.line) text = text.slice(0, end.ch);
6531
+ if (n == start.line) text = text.slice(start.ch);
6532
+ out.push(text);
6533
+ ++n;
6534
+ });
6535
+ return out;
6536
+ }
6537
+ // Get the lines between from and to, as array of strings.
6538
+ function getLines(doc, from, to) {
6539
+ var out = [];
6540
+ doc.iter(from, to, function(line) { out.push(line.text); });
6541
+ return out;
6542
+ }
6543
+
6544
+ // Update the height of a line, propagating the height change
6545
+ // upwards to parent nodes.
6546
+ function updateLineHeight(line, height) {
6547
+ var diff = height - line.height;
6548
+ if (diff) for (var n = line; n; n = n.parent) n.height += diff;
6549
+ }
6550
+
6551
+ // Given a line object, find its line number by walking up through
6552
+ // its parent links.
6553
+ function lineNo(line) {
6554
+ if (line.parent == null) return null;
6555
+ var cur = line.parent, no = indexOf(cur.lines, line);
6556
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
6557
+ for (var i = 0;; ++i) {
6558
+ if (chunk.children[i] == cur) break;
6559
+ no += chunk.children[i].chunkSize();
6560
+ }
6561
+ }
6562
+ return no + cur.first;
6563
+ }
6564
+
6565
+ // Find the line at the given vertical position, using the height
6566
+ // information in the document tree.
6567
+ function lineAtHeight(chunk, h) {
6568
+ var n = chunk.first;
6569
+ outer: do {
6570
+ for (var i = 0; i < chunk.children.length; ++i) {
6571
+ var child = chunk.children[i], ch = child.height;
6572
+ if (h < ch) { chunk = child; continue outer; }
6573
+ h -= ch;
6574
+ n += child.chunkSize();
6575
+ }
6576
+ return n;
6577
+ } while (!chunk.lines);
6578
+ for (var i = 0; i < chunk.lines.length; ++i) {
6579
+ var line = chunk.lines[i], lh = line.height;
6580
+ if (h < lh) break;
6581
+ h -= lh;
6582
+ }
6583
+ return n + i;
6584
+ }
6585
+
6586
+
6587
+ // Find the height above the given line.
6588
+ function heightAtLine(lineObj) {
6589
+ lineObj = visualLine(lineObj);
6590
+
6591
+ var h = 0, chunk = lineObj.parent;
6592
+ for (var i = 0; i < chunk.lines.length; ++i) {
6593
+ var line = chunk.lines[i];
6594
+ if (line == lineObj) break;
6595
+ else h += line.height;
6596
+ }
6597
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
6598
+ for (var i = 0; i < p.children.length; ++i) {
6599
+ var cur = p.children[i];
6600
+ if (cur == chunk) break;
6601
+ else h += cur.height;
6602
+ }
6603
+ }
6604
+ return h;
6605
+ }
6606
+
6607
+ // Get the bidi ordering for the given line (and cache it). Returns
6608
+ // false for lines that are fully left-to-right, and an array of
6609
+ // BidiSpan objects otherwise.
6610
+ function getOrder(line) {
6611
+ var order = line.order;
6612
+ if (order == null) order = line.order = bidiOrdering(line.text);
6613
+ return order;
6614
+ }
6615
+
6616
+ // HISTORY
6617
+
6618
+ function History(startGen) {
6619
+ // Arrays of change events and selections. Doing something adds an
6620
+ // event to done and clears undo. Undoing moves events from done
6621
+ // to undone, redoing moves them in the other direction.
6622
+ this.done = []; this.undone = [];
6623
+ this.undoDepth = Infinity;
6624
+ // Used to track when changes can be merged into a single undo
6625
+ // event
6626
+ this.lastModTime = this.lastSelTime = 0;
6627
+ this.lastOp = null;
6628
+ this.lastOrigin = this.lastSelOrigin = null;
6629
+ // Used by the isClean() method
6630
+ this.generation = this.maxGeneration = startGen || 1;
6631
+ }
6632
+
6633
+ // Create a history change event from an updateDoc-style change
6634
+ // object.
6635
+ function historyChangeFromChange(doc, change) {
6636
+ var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
6637
+ attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
6638
+ linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
6639
+ return histChange;
6640
+ }
6641
+
6642
+ // Pop all selection events off the end of a history array. Stop at
6643
+ // a change event.
6644
+ function clearSelectionEvents(array) {
6645
+ while (array.length) {
6646
+ var last = lst(array);
6647
+ if (last.ranges) array.pop();
6648
+ else break;
6649
+ }
6650
+ }
6651
+
6652
+ // Find the top change event in the history. Pop off selection
6653
+ // events that are in the way.
6654
+ function lastChangeEvent(hist, force) {
6655
+ if (force) {
6656
+ clearSelectionEvents(hist.done);
6657
+ return lst(hist.done);
6658
+ } else if (hist.done.length && !lst(hist.done).ranges) {
6659
+ return lst(hist.done);
6660
+ } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
6661
+ hist.done.pop();
6662
+ return lst(hist.done);
6663
+ }
6664
+ }
6665
+
6666
+ // Register a change in the history. Merges changes that are within
6667
+ // a single operation, ore are close together with an origin that
6668
+ // allows merging (starting with "+") into a single event.
6669
+ function addChangeToHistory(doc, change, selAfter, opId) {
6670
+ var hist = doc.history;
6671
+ hist.undone.length = 0;
6672
+ var time = +new Date, cur;
6673
+
6674
+ if ((hist.lastOp == opId ||
6675
+ hist.lastOrigin == change.origin && change.origin &&
6676
+ ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
6677
+ change.origin.charAt(0) == "*")) &&
6678
+ (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
6679
+ // Merge this change into the last event
6680
+ var last = lst(cur.changes);
6681
+ if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
6682
+ // Optimized case for simple insertion -- don't want to add
6683
+ // new changesets for every character typed
6684
+ last.to = changeEnd(change);
6685
+ } else {
6686
+ // Add new sub-event
6687
+ cur.changes.push(historyChangeFromChange(doc, change));
6688
+ }
6689
+ } else {
6690
+ // Can not be merged, start a new event.
6691
+ var before = lst(hist.done);
6692
+ if (!before || !before.ranges)
6693
+ pushSelectionToHistory(doc.sel, hist.done);
6694
+ cur = {changes: [historyChangeFromChange(doc, change)],
6695
+ generation: hist.generation};
6696
+ hist.done.push(cur);
6697
+ while (hist.done.length > hist.undoDepth) {
6698
+ hist.done.shift();
6699
+ if (!hist.done[0].ranges) hist.done.shift();
6700
+ }
6701
+ }
6702
+ hist.done.push(selAfter);
6703
+ hist.generation = ++hist.maxGeneration;
6704
+ hist.lastModTime = hist.lastSelTime = time;
6705
+ hist.lastOp = opId;
6706
+ hist.lastOrigin = hist.lastSelOrigin = change.origin;
6707
+
6708
+ if (!last) signal(doc, "historyAdded");
6709
+ }
6710
+
6711
+ function selectionEventCanBeMerged(doc, origin, prev, sel) {
6712
+ var ch = origin.charAt(0);
6713
+ return ch == "*" ||
6714
+ ch == "+" &&
6715
+ prev.ranges.length == sel.ranges.length &&
6716
+ prev.somethingSelected() == sel.somethingSelected() &&
6717
+ new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
6718
+ }
6719
+
6720
+ // Called whenever the selection changes, sets the new selection as
6721
+ // the pending selection in the history, and pushes the old pending
6722
+ // selection into the 'done' array when it was significantly
6723
+ // different (in number of selected ranges, emptiness, or time).
6724
+ function addSelectionToHistory(doc, sel, opId, options) {
6725
+ var hist = doc.history, origin = options && options.origin;
6726
+
6727
+ // A new event is started when the previous origin does not match
6728
+ // the current, or the origins don't allow matching. Origins
6729
+ // starting with * are always merged, those starting with + are
6730
+ // merged when similar and close together in time.
6731
+ if (opId == hist.lastOp ||
6732
+ (origin && hist.lastSelOrigin == origin &&
6733
+ (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
6734
+ selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
6735
+ hist.done[hist.done.length - 1] = sel;
6736
+ else
6737
+ pushSelectionToHistory(sel, hist.done);
6738
+
6739
+ hist.lastSelTime = +new Date;
6740
+ hist.lastSelOrigin = origin;
6741
+ hist.lastOp = opId;
6742
+ if (options && options.clearRedo !== false)
6743
+ clearSelectionEvents(hist.undone);
6744
+ }
6745
+
6746
+ function pushSelectionToHistory(sel, dest) {
6747
+ var top = lst(dest);
6748
+ if (!(top && top.ranges && top.equals(sel)))
6749
+ dest.push(sel);
6750
+ }
6751
+
6752
+ // Used to store marked span information in the history.
6753
+ function attachLocalSpans(doc, change, from, to) {
6754
+ var existing = change["spans_" + doc.id], n = 0;
6755
+ doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
6756
+ if (line.markedSpans)
6757
+ (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
6758
+ ++n;
6759
+ });
6760
+ }
6761
+
6762
+ // When un/re-doing restores text containing marked spans, those
6763
+ // that have been explicitly cleared should not be restored.
6764
+ function removeClearedSpans(spans) {
6765
+ if (!spans) return null;
6766
+ for (var i = 0, out; i < spans.length; ++i) {
6767
+ if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
6768
+ else if (out) out.push(spans[i]);
6769
+ }
6770
+ return !out ? spans : out.length ? out : null;
6771
+ }
6772
+
6773
+ // Retrieve and filter the old marked spans stored in a change event.
6774
+ function getOldSpans(doc, change) {
6775
+ var found = change["spans_" + doc.id];
6776
+ if (!found) return null;
6777
+ for (var i = 0, nw = []; i < change.text.length; ++i)
6778
+ nw.push(removeClearedSpans(found[i]));
6779
+ return nw;
6780
+ }
6781
+
6782
+ // Used both to provide a JSON-safe object in .getHistory, and, when
6783
+ // detaching a document, to split the history in two
6784
+ function copyHistoryArray(events, newGroup, instantiateSel) {
6785
+ for (var i = 0, copy = []; i < events.length; ++i) {
6786
+ var event = events[i];
6787
+ if (event.ranges) {
6788
+ copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
6789
+ continue;
6790
+ }
6791
+ var changes = event.changes, newChanges = [];
6792
+ copy.push({changes: newChanges});
6793
+ for (var j = 0; j < changes.length; ++j) {
6794
+ var change = changes[j], m;
6795
+ newChanges.push({from: change.from, to: change.to, text: change.text});
6796
+ if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
6797
+ if (indexOf(newGroup, Number(m[1])) > -1) {
6798
+ lst(newChanges)[prop] = change[prop];
6799
+ delete change[prop];
6800
+ }
6801
+ }
6802
+ }
6803
+ }
6804
+ return copy;
6805
+ }
6806
+
6807
+ // Rebasing/resetting history to deal with externally-sourced changes
6808
+
6809
+ function rebaseHistSelSingle(pos, from, to, diff) {
6810
+ if (to < pos.line) {
6811
+ pos.line += diff;
6812
+ } else if (from < pos.line) {
6813
+ pos.line = from;
6814
+ pos.ch = 0;
6815
+ }
6816
+ }
6817
+
6818
+ // Tries to rebase an array of history events given a change in the
6819
+ // document. If the change touches the same lines as the event, the
6820
+ // event, and everything 'behind' it, is discarded. If the change is
6821
+ // before the event, the event's positions are updated. Uses a
6822
+ // copy-on-write scheme for the positions, to avoid having to
6823
+ // reallocate them all on every rebase, but also avoid problems with
6824
+ // shared position objects being unsafely updated.
6825
+ function rebaseHistArray(array, from, to, diff) {
6826
+ for (var i = 0; i < array.length; ++i) {
6827
+ var sub = array[i], ok = true;
6828
+ if (sub.ranges) {
6829
+ if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
6830
+ for (var j = 0; j < sub.ranges.length; j++) {
6831
+ rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
6832
+ rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
6833
+ }
6834
+ continue;
6835
+ }
6836
+ for (var j = 0; j < sub.changes.length; ++j) {
6837
+ var cur = sub.changes[j];
6838
+ if (to < cur.from.line) {
6839
+ cur.from = Pos(cur.from.line + diff, cur.from.ch);
6840
+ cur.to = Pos(cur.to.line + diff, cur.to.ch);
6841
+ } else if (from <= cur.to.line) {
6842
+ ok = false;
6843
+ break;
6844
+ }
6845
+ }
6846
+ if (!ok) {
6847
+ array.splice(0, i + 1);
6848
+ i = 0;
6849
+ }
6850
+ }
6851
+ }
6852
+
6853
+ function rebaseHist(hist, change) {
6854
+ var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
6855
+ rebaseHistArray(hist.done, from, to, diff);
6856
+ rebaseHistArray(hist.undone, from, to, diff);
6857
+ }
6858
+
6859
+ // EVENT UTILITIES
6860
+
6861
+ // Due to the fact that we still support jurassic IE versions, some
6862
+ // compatibility wrappers are needed.
6863
+
6864
+ var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
6865
+ if (e.preventDefault) e.preventDefault();
6866
+ else e.returnValue = false;
6867
+ };
6868
+ var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
6869
+ if (e.stopPropagation) e.stopPropagation();
6870
+ else e.cancelBubble = true;
6871
+ };
6872
+ function e_defaultPrevented(e) {
6873
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
6874
+ }
6875
+ var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
6876
+
6877
+ function e_target(e) {return e.target || e.srcElement;}
6878
+ function e_button(e) {
6879
+ var b = e.which;
6880
+ if (b == null) {
6881
+ if (e.button & 1) b = 1;
6882
+ else if (e.button & 2) b = 3;
6883
+ else if (e.button & 4) b = 2;
6884
+ }
6885
+ if (mac && e.ctrlKey && b == 1) b = 3;
6886
+ return b;
6887
+ }
6888
+
6889
+ // EVENT HANDLING
6890
+
6891
+ // Lightweight event framework. on/off also work on DOM nodes,
6892
+ // registering native DOM handlers.
6893
+
6894
+ var on = CodeMirror.on = function(emitter, type, f) {
6895
+ if (emitter.addEventListener)
6896
+ emitter.addEventListener(type, f, false);
6897
+ else if (emitter.attachEvent)
6898
+ emitter.attachEvent("on" + type, f);
6899
+ else {
6900
+ var map = emitter._handlers || (emitter._handlers = {});
6901
+ var arr = map[type] || (map[type] = []);
6902
+ arr.push(f);
6903
+ }
6904
+ };
6905
+
6906
+ var off = CodeMirror.off = function(emitter, type, f) {
6907
+ if (emitter.removeEventListener)
6908
+ emitter.removeEventListener(type, f, false);
6909
+ else if (emitter.detachEvent)
6910
+ emitter.detachEvent("on" + type, f);
6911
+ else {
6912
+ var arr = emitter._handlers && emitter._handlers[type];
6913
+ if (!arr) return;
6914
+ for (var i = 0; i < arr.length; ++i)
6915
+ if (arr[i] == f) { arr.splice(i, 1); break; }
6916
+ }
6917
+ };
6918
+
6919
+ var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
6920
+ var arr = emitter._handlers && emitter._handlers[type];
6921
+ if (!arr) return;
6922
+ var args = Array.prototype.slice.call(arguments, 2);
6923
+ for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
6924
+ };
6925
+
6926
+ // Often, we want to signal events at a point where we are in the
6927
+ // middle of some work, but don't want the handler to start calling
6928
+ // other methods on the editor, which might be in an inconsistent
6929
+ // state or simply not expect any other events to happen.
6930
+ // signalLater looks whether there are any handlers, and schedules
6931
+ // them to be executed when the last operation ends, or, if no
6932
+ // operation is active, when a timeout fires.
6933
+ var delayedCallbacks, delayedCallbackDepth = 0;
6934
+ function signalLater(emitter, type /*, values...*/) {
6935
+ var arr = emitter._handlers && emitter._handlers[type];
6936
+ if (!arr) return;
6937
+ var args = Array.prototype.slice.call(arguments, 2);
6938
+ if (!delayedCallbacks) {
6939
+ ++delayedCallbackDepth;
6940
+ delayedCallbacks = [];
6941
+ setTimeout(fireDelayed, 0);
6942
+ }
6943
+ function bnd(f) {return function(){f.apply(null, args);};};
6944
+ for (var i = 0; i < arr.length; ++i)
6945
+ delayedCallbacks.push(bnd(arr[i]));
6946
+ }
6947
+
6948
+ function fireDelayed() {
6949
+ --delayedCallbackDepth;
6950
+ var delayed = delayedCallbacks;
6951
+ delayedCallbacks = null;
6952
+ for (var i = 0; i < delayed.length; ++i) delayed[i]();
6953
+ }
6954
+
6955
+ // The DOM events that CodeMirror handles can be overridden by
6956
+ // registering a (non-DOM) handler on the editor for the event name,
6957
+ // and preventDefault-ing the event in that handler.
6958
+ function signalDOMEvent(cm, e, override) {
6959
+ signal(cm, override || e.type, cm, e);
6960
+ return e_defaultPrevented(e) || e.codemirrorIgnore;
6961
+ }
6962
+
6963
+ function signalCursorActivity(cm) {
6964
+ var arr = cm._handlers && cm._handlers.cursorActivity;
6965
+ if (!arr) return;
6966
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
6967
+ for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
6968
+ set.push(arr[i]);
6969
+ }
6970
+
6971
+ function hasHandler(emitter, type) {
6972
+ var arr = emitter._handlers && emitter._handlers[type];
6973
+ return arr && arr.length > 0;
6974
+ }
6975
+
6976
+ // Add on and off methods to a constructor's prototype, to make
6977
+ // registering events on such objects more convenient.
6978
+ function eventMixin(ctor) {
6979
+ ctor.prototype.on = function(type, f) {on(this, type, f);};
6980
+ ctor.prototype.off = function(type, f) {off(this, type, f);};
6981
+ }
6982
+
6983
+ // MISC UTILITIES
6984
+
6985
+ // Number of pixels added to scroller and sizer to hide scrollbar
6986
+ var scrollerCutOff = 30;
6987
+
6988
+ // Returned or thrown by various protocols to signal 'I'm not
6989
+ // handling this'.
6990
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
6991
+
6992
+ // Reused option objects for setSelection & friends
6993
+ var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
6994
+
6995
+ function Delayed() {this.id = null;}
6996
+ Delayed.prototype.set = function(ms, f) {
6997
+ clearTimeout(this.id);
6998
+ this.id = setTimeout(f, ms);
6999
+ };
7000
+
7001
+ // Counts the column offset in a string, taking tabs into account.
7002
+ // Used mostly to find indentation.
7003
+ var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
7004
+ if (end == null) {
7005
+ end = string.search(/[^\s\u00a0]/);
7006
+ if (end == -1) end = string.length;
7007
+ }
7008
+ for (var i = startIndex || 0, n = startValue || 0;;) {
7009
+ var nextTab = string.indexOf("\t", i);
7010
+ if (nextTab < 0 || nextTab >= end)
7011
+ return n + (end - i);
7012
+ n += nextTab - i;
7013
+ n += tabSize - (n % tabSize);
7014
+ i = nextTab + 1;
7015
+ }
7016
+ };
7017
+
7018
+ // The inverse of countColumn -- find the offset that corresponds to
7019
+ // a particular column.
7020
+ function findColumn(string, goal, tabSize) {
7021
+ for (var pos = 0, col = 0;;) {
7022
+ var nextTab = string.indexOf("\t", pos);
7023
+ if (nextTab == -1) nextTab = string.length;
7024
+ var skipped = nextTab - pos;
7025
+ if (nextTab == string.length || col + skipped >= goal)
7026
+ return pos + Math.min(skipped, goal - col);
7027
+ col += nextTab - pos;
7028
+ col += tabSize - (col % tabSize);
7029
+ pos = nextTab + 1;
7030
+ if (col >= goal) return pos;
7031
+ }
7032
+ }
7033
+
7034
+ var spaceStrs = [""];
7035
+ function spaceStr(n) {
7036
+ while (spaceStrs.length <= n)
7037
+ spaceStrs.push(lst(spaceStrs) + " ");
7038
+ return spaceStrs[n];
7039
+ }
7040
+
7041
+ function lst(arr) { return arr[arr.length-1]; }
7042
+
7043
+ var selectInput = function(node) { node.select(); };
7044
+ if (ios) // Mobile Safari apparently has a bug where select() is broken.
7045
+ selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
7046
+ else if (ie) // Suppress mysterious IE10 errors
7047
+ selectInput = function(node) { try { node.select(); } catch(_e) {} };
7048
+
7049
+ function indexOf(array, elt) {
7050
+ for (var i = 0; i < array.length; ++i)
7051
+ if (array[i] == elt) return i;
7052
+ return -1;
7053
+ }
7054
+ if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); };
7055
+ function map(array, f) {
7056
+ var out = [];
7057
+ for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
7058
+ return out;
7059
+ }
7060
+ if ([].map) map = function(array, f) { return array.map(f); };
7061
+
7062
+ function createObj(base, props) {
7063
+ var inst;
7064
+ if (Object.create) {
7065
+ inst = Object.create(base);
7066
+ } else {
7067
+ var ctor = function() {};
7068
+ ctor.prototype = base;
7069
+ inst = new ctor();
7070
+ }
7071
+ if (props) copyObj(props, inst);
7072
+ return inst;
7073
+ };
7074
+
7075
+ function copyObj(obj, target, overwrite) {
7076
+ if (!target) target = {};
7077
+ for (var prop in obj)
7078
+ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
7079
+ target[prop] = obj[prop];
7080
+ return target;
7081
+ }
7082
+
7083
+ function bind(f) {
7084
+ var args = Array.prototype.slice.call(arguments, 1);
7085
+ return function(){return f.apply(null, args);};
7086
+ }
7087
+
7088
+ var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
7089
+ var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
7090
+ return /\w/.test(ch) || ch > "\x80" &&
7091
+ (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
7092
+ };
7093
+ function isWordChar(ch, helper) {
7094
+ if (!helper) return isWordCharBasic(ch);
7095
+ if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
7096
+ return helper.test(ch);
7097
+ }
7098
+
7099
+ function isEmpty(obj) {
7100
+ for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
7101
+ return true;
7102
+ }
7103
+
7104
+ // Extending unicode characters. A series of a non-extending char +
7105
+ // any number of extending chars is treated as a single unit as far
7106
+ // as editing and measuring is concerned. This is not fully correct,
7107
+ // since some scripts/fonts/browsers also treat other configurations
7108
+ // of code points as a group.
7109
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
7110
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
7111
+
7112
+ // DOM UTILITIES
7113
+
7114
+ function elt(tag, content, className, style) {
7115
+ var e = document.createElement(tag);
7116
+ if (className) e.className = className;
7117
+ if (style) e.style.cssText = style;
7118
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
7119
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
7120
+ return e;
7121
+ }
7122
+
7123
+ var range;
7124
+ if (document.createRange) range = function(node, start, end) {
7125
+ var r = document.createRange();
7126
+ r.setEnd(node, end);
7127
+ r.setStart(node, start);
7128
+ return r;
7129
+ };
7130
+ else range = function(node, start, end) {
7131
+ var r = document.body.createTextRange();
7132
+ r.moveToElementText(node.parentNode);
7133
+ r.collapse(true);
7134
+ r.moveEnd("character", end);
7135
+ r.moveStart("character", start);
7136
+ return r;
7137
+ };
7138
+
7139
+ function removeChildren(e) {
7140
+ for (var count = e.childNodes.length; count > 0; --count)
7141
+ e.removeChild(e.firstChild);
7142
+ return e;
7143
+ }
7144
+
7145
+ function removeChildrenAndAdd(parent, e) {
7146
+ return removeChildren(parent).appendChild(e);
7147
+ }
7148
+
7149
+ function contains(parent, child) {
7150
+ if (parent.contains)
7151
+ return parent.contains(child);
7152
+ while (child = child.parentNode)
7153
+ if (child == parent) return true;
7154
+ }
7155
+
7156
+ function activeElt() { return document.activeElement; }
7157
+ // Older versions of IE throws unspecified error when touching
7158
+ // document.activeElement in some cases (during loading, in iframe)
7159
+ if (ie_upto10) activeElt = function() {
7160
+ try { return document.activeElement; }
7161
+ catch(e) { return document.body; }
7162
+ };
7163
+
7164
+ function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
7165
+ function rmClass(node, cls) {
7166
+ var test = classTest(cls);
7167
+ if (test.test(node.className)) node.className = node.className.replace(test, "");
7168
+ }
7169
+ function addClass(node, cls) {
7170
+ if (!classTest(cls).test(node.className)) node.className += " " + cls;
7171
+ }
7172
+ function joinClasses(a, b) {
7173
+ var as = a.split(" ");
7174
+ for (var i = 0; i < as.length; i++)
7175
+ if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
7176
+ return b;
7177
+ }
7178
+
7179
+ // WINDOW-WIDE EVENTS
7180
+
7181
+ // These must be handled carefully, because naively registering a
7182
+ // handler for each editor will cause the editors to never be
7183
+ // garbage collected.
7184
+
7185
+ function forEachCodeMirror(f) {
7186
+ if (!document.body.getElementsByClassName) return;
7187
+ var byClass = document.body.getElementsByClassName("CodeMirror");
7188
+ for (var i = 0; i < byClass.length; i++) {
7189
+ var cm = byClass[i].CodeMirror;
7190
+ if (cm) f(cm);
7191
+ }
7192
+ }
7193
+
7194
+ var globalsRegistered = false;
7195
+ function ensureGlobalHandlers() {
7196
+ if (globalsRegistered) return;
7197
+ registerGlobalHandlers();
7198
+ globalsRegistered = true;
7199
+ }
7200
+ function registerGlobalHandlers() {
7201
+ // When the window resizes, we need to refresh active editors.
7202
+ var resizeTimer;
7203
+ on(window, "resize", function() {
7204
+ if (resizeTimer == null) resizeTimer = setTimeout(function() {
7205
+ resizeTimer = null;
7206
+ knownScrollbarWidth = null;
7207
+ forEachCodeMirror(onResize);
7208
+ }, 100);
7209
+ });
7210
+ // When the window loses focus, we want to show the editor as blurred
7211
+ on(window, "blur", function() {
7212
+ forEachCodeMirror(onBlur);
7213
+ });
7214
+ }
7215
+
7216
+ // FEATURE DETECTION
7217
+
7218
+ // Detect drag-and-drop
7219
+ var dragAndDrop = function() {
7220
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
7221
+ // couldn't get it to work yet.
7222
+ if (ie_upto8) return false;
7223
+ var div = elt('div');
7224
+ return "draggable" in div || "dragDrop" in div;
7225
+ }();
7226
+
7227
+ var knownScrollbarWidth;
7228
+ function scrollbarWidth(measure) {
7229
+ if (knownScrollbarWidth != null) return knownScrollbarWidth;
7230
+ var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
7231
+ removeChildrenAndAdd(measure, test);
7232
+ if (test.offsetWidth)
7233
+ knownScrollbarWidth = test.offsetHeight - test.clientHeight;
7234
+ return knownScrollbarWidth || 0;
7235
+ }
7236
+
7237
+ var zwspSupported;
7238
+ function zeroWidthElement(measure) {
7239
+ if (zwspSupported == null) {
7240
+ var test = elt("span", "\u200b");
7241
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
7242
+ if (measure.firstChild.offsetHeight != 0)
7243
+ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_upto7;
7244
+ }
7245
+ if (zwspSupported) return elt("span", "\u200b");
7246
+ else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
7247
+ }
7248
+
7249
+ // Feature-detect IE's crummy client rect reporting for bidi text
7250
+ var badBidiRects;
7251
+ function hasBadBidiRects(measure) {
7252
+ if (badBidiRects != null) return badBidiRects;
7253
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
7254
+ var r0 = range(txt, 0, 1).getBoundingClientRect();
7255
+ if (r0.left == r0.right) return false;
7256
+ var r1 = range(txt, 1, 2).getBoundingClientRect();
7257
+ return badBidiRects = (r1.right - r0.right < 3);
7258
+ }
7259
+
7260
+ // See if "".split is the broken IE version, if so, provide an
7261
+ // alternative way to split lines.
7262
+ var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
7263
+ var pos = 0, result = [], l = string.length;
7264
+ while (pos <= l) {
7265
+ var nl = string.indexOf("\n", pos);
7266
+ if (nl == -1) nl = string.length;
7267
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
7268
+ var rt = line.indexOf("\r");
7269
+ if (rt != -1) {
7270
+ result.push(line.slice(0, rt));
7271
+ pos += rt + 1;
7272
+ } else {
7273
+ result.push(line);
7274
+ pos = nl + 1;
7275
+ }
7276
+ }
7277
+ return result;
7278
+ } : function(string){return string.split(/\r\n?|\n/);};
7279
+
7280
+ var hasSelection = window.getSelection ? function(te) {
7281
+ try { return te.selectionStart != te.selectionEnd; }
7282
+ catch(e) { return false; }
7283
+ } : function(te) {
7284
+ try {var range = te.ownerDocument.selection.createRange();}
7285
+ catch(e) {}
7286
+ if (!range || range.parentElement() != te) return false;
7287
+ return range.compareEndPoints("StartToEnd", range) != 0;
7288
+ };
7289
+
7290
+ var hasCopyEvent = (function() {
7291
+ var e = elt("div");
7292
+ if ("oncopy" in e) return true;
7293
+ e.setAttribute("oncopy", "return;");
7294
+ return typeof e.oncopy == "function";
7295
+ })();
7296
+
7297
+ // KEY NAMES
7298
+
7299
+ var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
7300
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
7301
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
7302
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
7303
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
7304
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
7305
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
7306
+ CodeMirror.keyNames = keyNames;
7307
+ (function() {
7308
+ // Number keys
7309
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
7310
+ // Alphabetic keys
7311
+ for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
7312
+ // Function keys
7313
+ for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
7314
+ })();
7315
+
7316
+ // BIDI HELPERS
7317
+
7318
+ function iterateBidiSections(order, from, to, f) {
7319
+ if (!order) return f(from, to, "ltr");
7320
+ var found = false;
7321
+ for (var i = 0; i < order.length; ++i) {
7322
+ var part = order[i];
7323
+ if (part.from < to && part.to > from || from == to && part.to == from) {
7324
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
7325
+ found = true;
7326
+ }
7327
+ }
7328
+ if (!found) f(from, to, "ltr");
7329
+ }
7330
+
7331
+ function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
7332
+ function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
7333
+
7334
+ function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
7335
+ function lineRight(line) {
7336
+ var order = getOrder(line);
7337
+ if (!order) return line.text.length;
7338
+ return bidiRight(lst(order));
7339
+ }
7340
+
7341
+ function lineStart(cm, lineN) {
7342
+ var line = getLine(cm.doc, lineN);
7343
+ var visual = visualLine(line);
7344
+ if (visual != line) lineN = lineNo(visual);
7345
+ var order = getOrder(visual);
7346
+ var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
7347
+ return Pos(lineN, ch);
7348
+ }
7349
+ function lineEnd(cm, lineN) {
7350
+ var merged, line = getLine(cm.doc, lineN);
7351
+ while (merged = collapsedSpanAtEnd(line)) {
7352
+ line = merged.find(1, true).line;
7353
+ lineN = null;
7354
+ }
7355
+ var order = getOrder(line);
7356
+ var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
7357
+ return Pos(lineN == null ? lineNo(line) : lineN, ch);
7358
+ }
7359
+
7360
+ function compareBidiLevel(order, a, b) {
7361
+ var linedir = order[0].level;
7362
+ if (a == linedir) return true;
7363
+ if (b == linedir) return false;
7364
+ return a < b;
7365
+ }
7366
+ var bidiOther;
7367
+ function getBidiPartAt(order, pos) {
7368
+ bidiOther = null;
7369
+ for (var i = 0, found; i < order.length; ++i) {
7370
+ var cur = order[i];
7371
+ if (cur.from < pos && cur.to > pos) return i;
7372
+ if ((cur.from == pos || cur.to == pos)) {
7373
+ if (found == null) {
7374
+ found = i;
7375
+ } else if (compareBidiLevel(order, cur.level, order[found].level)) {
7376
+ if (cur.from != cur.to) bidiOther = found;
7377
+ return i;
7378
+ } else {
7379
+ if (cur.from != cur.to) bidiOther = i;
7380
+ return found;
7381
+ }
7382
+ }
7383
+ }
7384
+ return found;
7385
+ }
7386
+
7387
+ function moveInLine(line, pos, dir, byUnit) {
7388
+ if (!byUnit) return pos + dir;
7389
+ do pos += dir;
7390
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
7391
+ return pos;
7392
+ }
7393
+
7394
+ // This is needed in order to move 'visually' through bi-directional
7395
+ // text -- i.e., pressing left should make the cursor go left, even
7396
+ // when in RTL text. The tricky part is the 'jumps', where RTL and
7397
+ // LTR text touch each other. This often requires the cursor offset
7398
+ // to move more than one unit, in order to visually move one unit.
7399
+ function moveVisually(line, start, dir, byUnit) {
7400
+ var bidi = getOrder(line);
7401
+ if (!bidi) return moveLogically(line, start, dir, byUnit);
7402
+ var pos = getBidiPartAt(bidi, start), part = bidi[pos];
7403
+ var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
7404
+
7405
+ for (;;) {
7406
+ if (target > part.from && target < part.to) return target;
7407
+ if (target == part.from || target == part.to) {
7408
+ if (getBidiPartAt(bidi, target) == pos) return target;
7409
+ part = bidi[pos += dir];
7410
+ return (dir > 0) == part.level % 2 ? part.to : part.from;
7411
+ } else {
7412
+ part = bidi[pos += dir];
7413
+ if (!part) return null;
7414
+ if ((dir > 0) == part.level % 2)
7415
+ target = moveInLine(line, part.to, -1, byUnit);
7416
+ else
7417
+ target = moveInLine(line, part.from, 1, byUnit);
7418
+ }
7419
+ }
7420
+ }
7421
+
7422
+ function moveLogically(line, start, dir, byUnit) {
7423
+ var target = start + dir;
7424
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
7425
+ return target < 0 || target > line.text.length ? null : target;
7426
+ }
7427
+
7428
+ // Bidirectional ordering algorithm
7429
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
7430
+ // that this (partially) implements.
7431
+
7432
+ // One-char codes used for character types:
7433
+ // L (L): Left-to-Right
7434
+ // R (R): Right-to-Left
7435
+ // r (AL): Right-to-Left Arabic
7436
+ // 1 (EN): European Number
7437
+ // + (ES): European Number Separator
7438
+ // % (ET): European Number Terminator
7439
+ // n (AN): Arabic Number
7440
+ // , (CS): Common Number Separator
7441
+ // m (NSM): Non-Spacing Mark
7442
+ // b (BN): Boundary Neutral
7443
+ // s (B): Paragraph Separator
7444
+ // t (S): Segment Separator
7445
+ // w (WS): Whitespace
7446
+ // N (ON): Other Neutrals
7447
+
7448
+ // Returns null if characters are ordered as they appear
7449
+ // (left-to-right), or an array of sections ({from, to, level}
7450
+ // objects) in the order in which they occur visually.
7451
+ var bidiOrdering = (function() {
7452
+ // Character types for codepoints 0 to 0xff
7453
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
7454
+ // Character types for codepoints 0x600 to 0x6ff
7455
+ var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
7456
+ function charType(code) {
7457
+ if (code <= 0xf7) return lowTypes.charAt(code);
7458
+ else if (0x590 <= code && code <= 0x5f4) return "R";
7459
+ else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
7460
+ else if (0x6ee <= code && code <= 0x8ac) return "r";
7461
+ else if (0x2000 <= code && code <= 0x200b) return "w";
7462
+ else if (code == 0x200c) return "b";
7463
+ else return "L";
7464
+ }
7465
+
7466
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
7467
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
7468
+ // Browsers seem to always treat the boundaries of block elements as being L.
7469
+ var outerType = "L";
7470
+
7471
+ function BidiSpan(level, from, to) {
7472
+ this.level = level;
7473
+ this.from = from; this.to = to;
7474
+ }
7475
+
7476
+ return function(str) {
7477
+ if (!bidiRE.test(str)) return false;
7478
+ var len = str.length, types = [];
7479
+ for (var i = 0, type; i < len; ++i)
7480
+ types.push(type = charType(str.charCodeAt(i)));
7481
+
7482
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
7483
+ // change the type of the NSM to the type of the previous
7484
+ // character. If the NSM is at the start of the level run, it will
7485
+ // get the type of sor.
7486
+ for (var i = 0, prev = outerType; i < len; ++i) {
7487
+ var type = types[i];
7488
+ if (type == "m") types[i] = prev;
7489
+ else prev = type;
7490
+ }
7491
+
7492
+ // W2. Search backwards from each instance of a European number
7493
+ // until the first strong type (R, L, AL, or sor) is found. If an
7494
+ // AL is found, change the type of the European number to Arabic
7495
+ // number.
7496
+ // W3. Change all ALs to R.
7497
+ for (var i = 0, cur = outerType; i < len; ++i) {
7498
+ var type = types[i];
7499
+ if (type == "1" && cur == "r") types[i] = "n";
7500
+ else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
7501
+ }
7502
+
7503
+ // W4. A single European separator between two European numbers
7504
+ // changes to a European number. A single common separator between
7505
+ // two numbers of the same type changes to that type.
7506
+ for (var i = 1, prev = types[0]; i < len - 1; ++i) {
7507
+ var type = types[i];
7508
+ if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
7509
+ else if (type == "," && prev == types[i+1] &&
7510
+ (prev == "1" || prev == "n")) types[i] = prev;
7511
+ prev = type;
7512
+ }
7513
+
7514
+ // W5. A sequence of European terminators adjacent to European
7515
+ // numbers changes to all European numbers.
7516
+ // W6. Otherwise, separators and terminators change to Other
7517
+ // Neutral.
7518
+ for (var i = 0; i < len; ++i) {
7519
+ var type = types[i];
7520
+ if (type == ",") types[i] = "N";
7521
+ else if (type == "%") {
7522
+ for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
7523
+ var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
7524
+ for (var j = i; j < end; ++j) types[j] = replace;
7525
+ i = end - 1;
7526
+ }
7527
+ }
7528
+
7529
+ // W7. Search backwards from each instance of a European number
7530
+ // until the first strong type (R, L, or sor) is found. If an L is
7531
+ // found, then change the type of the European number to L.
7532
+ for (var i = 0, cur = outerType; i < len; ++i) {
7533
+ var type = types[i];
7534
+ if (cur == "L" && type == "1") types[i] = "L";
7535
+ else if (isStrong.test(type)) cur = type;
7536
+ }
7537
+
7538
+ // N1. A sequence of neutrals takes the direction of the
7539
+ // surrounding strong text if the text on both sides has the same
7540
+ // direction. European and Arabic numbers act as if they were R in
7541
+ // terms of their influence on neutrals. Start-of-level-run (sor)
7542
+ // and end-of-level-run (eor) are used at level run boundaries.
7543
+ // N2. Any remaining neutrals take the embedding direction.
7544
+ for (var i = 0; i < len; ++i) {
7545
+ if (isNeutral.test(types[i])) {
7546
+ for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
7547
+ var before = (i ? types[i-1] : outerType) == "L";
7548
+ var after = (end < len ? types[end] : outerType) == "L";
7549
+ var replace = before || after ? "L" : "R";
7550
+ for (var j = i; j < end; ++j) types[j] = replace;
7551
+ i = end - 1;
7552
+ }
7553
+ }
7554
+
7555
+ // Here we depart from the documented algorithm, in order to avoid
7556
+ // building up an actual levels array. Since there are only three
7557
+ // levels (0, 1, 2) in an implementation that doesn't take
7558
+ // explicit embedding into account, we can build up the order on
7559
+ // the fly, without following the level-based algorithm.
7560
+ var order = [], m;
7561
+ for (var i = 0; i < len;) {
7562
+ if (countsAsLeft.test(types[i])) {
7563
+ var start = i;
7564
+ for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
7565
+ order.push(new BidiSpan(0, start, i));
7566
+ } else {
7567
+ var pos = i, at = order.length;
7568
+ for (++i; i < len && types[i] != "L"; ++i) {}
7569
+ for (var j = pos; j < i;) {
7570
+ if (countsAsNum.test(types[j])) {
7571
+ if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
7572
+ var nstart = j;
7573
+ for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
7574
+ order.splice(at, 0, new BidiSpan(2, nstart, j));
7575
+ pos = j;
7576
+ } else ++j;
7577
+ }
7578
+ if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
7579
+ }
7580
+ }
7581
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
7582
+ order[0].from = m[0].length;
7583
+ order.unshift(new BidiSpan(0, 0, m[0].length));
7584
+ }
7585
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
7586
+ lst(order).to -= m[0].length;
7587
+ order.push(new BidiSpan(0, len - m[0].length, len));
7588
+ }
7589
+ if (order[0].level != lst(order).level)
7590
+ order.push(new BidiSpan(order[0].level, len, len));
7591
+
7592
+ return order;
7593
+ };
7594
+ })();
7595
+
7596
+ // THE END
7597
+
7598
+ CodeMirror.version = "4.2.0";
7599
+
7600
+ return CodeMirror;
7601
+ });
resources/js/codemirror/mode/clike/clike.js ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("clike", function(config, parserConfig) {
15
+ var indentUnit = config.indentUnit,
16
+ statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
17
+ dontAlignCalls = parserConfig.dontAlignCalls,
18
+ keywords = parserConfig.keywords || {},
19
+ builtin = parserConfig.builtin || {},
20
+ blockKeywords = parserConfig.blockKeywords || {},
21
+ atoms = parserConfig.atoms || {},
22
+ hooks = parserConfig.hooks || {},
23
+ multiLineStrings = parserConfig.multiLineStrings;
24
+ var isOperatorChar = /[+\-*&%=<>!?|\/]/;
25
+
26
+ var curPunc;
27
+
28
+ function tokenBase(stream, state) {
29
+ var ch = stream.next();
30
+ if (hooks[ch]) {
31
+ var result = hooks[ch](stream, state);
32
+ if (result !== false) return result;
33
+ }
34
+ if (ch == '"' || ch == "'") {
35
+ state.tokenize = tokenString(ch);
36
+ return state.tokenize(stream, state);
37
+ }
38
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
39
+ curPunc = ch;
40
+ return null;
41
+ }
42
+ if (/\d/.test(ch)) {
43
+ stream.eatWhile(/[\w\.]/);
44
+ return "number";
45
+ }
46
+ if (ch == "/") {
47
+ if (stream.eat("*")) {
48
+ state.tokenize = tokenComment;
49
+ return tokenComment(stream, state);
50
+ }
51
+ if (stream.eat("/")) {
52
+ stream.skipToEnd();
53
+ return "comment";
54
+ }
55
+ }
56
+ if (isOperatorChar.test(ch)) {
57
+ stream.eatWhile(isOperatorChar);
58
+ return "operator";
59
+ }
60
+ stream.eatWhile(/[\w\$_]/);
61
+ var cur = stream.current();
62
+ if (keywords.propertyIsEnumerable(cur)) {
63
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
64
+ return "keyword";
65
+ }
66
+ if (builtin.propertyIsEnumerable(cur)) {
67
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
68
+ return "builtin";
69
+ }
70
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
71
+ return "variable";
72
+ }
73
+
74
+ function tokenString(quote) {
75
+ return function(stream, state) {
76
+ var escaped = false, next, end = false;
77
+ while ((next = stream.next()) != null) {
78
+ if (next == quote && !escaped) {end = true; break;}
79
+ escaped = !escaped && next == "\\";
80
+ }
81
+ if (end || !(escaped || multiLineStrings))
82
+ state.tokenize = null;
83
+ return "string";
84
+ };
85
+ }
86
+
87
+ function tokenComment(stream, state) {
88
+ var maybeEnd = false, ch;
89
+ while (ch = stream.next()) {
90
+ if (ch == "/" && maybeEnd) {
91
+ state.tokenize = null;
92
+ break;
93
+ }
94
+ maybeEnd = (ch == "*");
95
+ }
96
+ return "comment";
97
+ }
98
+
99
+ function Context(indented, column, type, align, prev) {
100
+ this.indented = indented;
101
+ this.column = column;
102
+ this.type = type;
103
+ this.align = align;
104
+ this.prev = prev;
105
+ }
106
+ function pushContext(state, col, type) {
107
+ var indent = state.indented;
108
+ if (state.context && state.context.type == "statement")
109
+ indent = state.context.indented;
110
+ return state.context = new Context(indent, col, type, null, state.context);
111
+ }
112
+ function popContext(state) {
113
+ var t = state.context.type;
114
+ if (t == ")" || t == "]" || t == "}")
115
+ state.indented = state.context.indented;
116
+ return state.context = state.context.prev;
117
+ }
118
+
119
+ // Interface
120
+
121
+ return {
122
+ startState: function(basecolumn) {
123
+ return {
124
+ tokenize: null,
125
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
126
+ indented: 0,
127
+ startOfLine: true
128
+ };
129
+ },
130
+
131
+ token: function(stream, state) {
132
+ var ctx = state.context;
133
+ if (stream.sol()) {
134
+ if (ctx.align == null) ctx.align = false;
135
+ state.indented = stream.indentation();
136
+ state.startOfLine = true;
137
+ }
138
+ if (stream.eatSpace()) return null;
139
+ curPunc = null;
140
+ var style = (state.tokenize || tokenBase)(stream, state);
141
+ if (style == "comment" || style == "meta") return style;
142
+ if (ctx.align == null) ctx.align = true;
143
+
144
+ if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
145
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
146
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
147
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
148
+ else if (curPunc == "}") {
149
+ while (ctx.type == "statement") ctx = popContext(state);
150
+ if (ctx.type == "}") ctx = popContext(state);
151
+ while (ctx.type == "statement") ctx = popContext(state);
152
+ }
153
+ else if (curPunc == ctx.type) popContext(state);
154
+ else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
155
+ pushContext(state, stream.column(), "statement");
156
+ state.startOfLine = false;
157
+ return style;
158
+ },
159
+
160
+ indent: function(state, textAfter) {
161
+ if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
162
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
163
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
164
+ var closing = firstChar == ctx.type;
165
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
166
+ else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1);
167
+ else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
168
+ else return ctx.indented + (closing ? 0 : indentUnit);
169
+ },
170
+
171
+ electricChars: "{}",
172
+ blockCommentStart: "/*",
173
+ blockCommentEnd: "*/",
174
+ lineComment: "//",
175
+ fold: "brace"
176
+ };
177
+ });
178
+
179
+ function words(str) {
180
+ var obj = {}, words = str.split(" ");
181
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
182
+ return obj;
183
+ }
184
+ var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
185
+ "double static else struct entry switch extern typedef float union for unsigned " +
186
+ "goto while enum void const signed volatile";
187
+
188
+ function cppHook(stream, state) {
189
+ if (!state.startOfLine) return false;
190
+ for (;;) {
191
+ if (stream.skipTo("\\")) {
192
+ stream.next();
193
+ if (stream.eol()) {
194
+ state.tokenize = cppHook;
195
+ break;
196
+ }
197
+ } else {
198
+ stream.skipToEnd();
199
+ state.tokenize = null;
200
+ break;
201
+ }
202
+ }
203
+ return "meta";
204
+ }
205
+
206
+ function cpp11StringHook(stream, state) {
207
+ stream.backUp(1);
208
+ // Raw strings.
209
+ if (stream.match(/(R|u8R|uR|UR|LR)/)) {
210
+ var match = stream.match(/"(.{0,16})\(/);
211
+ if (!match) {
212
+ return false;
213
+ }
214
+ state.cpp11RawStringDelim = match[1];
215
+ state.tokenize = tokenRawString;
216
+ return tokenRawString(stream, state);
217
+ }
218
+ // Unicode strings/chars.
219
+ if (stream.match(/(u8|u|U|L)/)) {
220
+ if (stream.match(/["']/, /* eat */ false)) {
221
+ return "string";
222
+ }
223
+ return false;
224
+ }
225
+ // Ignore this hook.
226
+ stream.next();
227
+ return false;
228
+ }
229
+
230
+ // C#-style strings where "" escapes a quote.
231
+ function tokenAtString(stream, state) {
232
+ var next;
233
+ while ((next = stream.next()) != null) {
234
+ if (next == '"' && !stream.eat('"')) {
235
+ state.tokenize = null;
236
+ break;
237
+ }
238
+ }
239
+ return "string";
240
+ }
241
+
242
+ // C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
243
+ // <delim> can be a string up to 16 characters long.
244
+ function tokenRawString(stream, state) {
245
+ var closingSequence = new RegExp(".*?\\)" + state.cpp11RawStringDelim + '"');
246
+ var match = stream.match(closingSequence);
247
+ if (match) {
248
+ state.tokenize = null;
249
+ } else {
250
+ stream.skipToEnd();
251
+ }
252
+ return "string";
253
+ }
254
+
255
+ function def(mimes, mode) {
256
+ if (typeof mimes == "string") mimes = [mimes];
257
+ var words = [];
258
+ function add(obj) {
259
+ if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
260
+ words.push(prop);
261
+ }
262
+ add(mode.keywords);
263
+ add(mode.builtin);
264
+ add(mode.atoms);
265
+ if (words.length) {
266
+ mode.helperType = mimes[0];
267
+ CodeMirror.registerHelper("hintWords", mimes[0], words);
268
+ }
269
+
270
+ for (var i = 0; i < mimes.length; ++i)
271
+ CodeMirror.defineMIME(mimes[i], mode);
272
+ }
273
+
274
+ def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
275
+ name: "clike",
276
+ keywords: words(cKeywords),
277
+ blockKeywords: words("case do else for if switch while struct"),
278
+ atoms: words("null"),
279
+ hooks: {"#": cppHook},
280
+ modeProps: {fold: ["brace", "include"]}
281
+ });
282
+
283
+ def(["text/x-c++src", "text/x-c++hdr"], {
284
+ name: "clike",
285
+ keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
286
+ "static_cast typeid catch operator template typename class friend private " +
287
+ "this using const_cast inline public throw virtual delete mutable protected " +
288
+ "wchar_t alignas alignof constexpr decltype nullptr noexcept thread_local final " +
289
+ "static_assert override"),
290
+ blockKeywords: words("catch class do else finally for if struct switch try while"),
291
+ atoms: words("true false null"),
292
+ hooks: {
293
+ "#": cppHook,
294
+ "u": cpp11StringHook,
295
+ "U": cpp11StringHook,
296
+ "L": cpp11StringHook,
297
+ "R": cpp11StringHook
298
+ },
299
+ modeProps: {fold: ["brace", "include"]}
300
+ });
301
+ def("text/x-java", {
302
+ name: "clike",
303
+ keywords: words("abstract assert boolean break byte case catch char class const continue default " +
304
+ "do double else enum extends final finally float for goto if implements import " +
305
+ "instanceof int interface long native new package private protected public " +
306
+ "return short static strictfp super switch synchronized this throw throws transient " +
307
+ "try void volatile while"),
308
+ blockKeywords: words("catch class do else finally for if switch try while"),
309
+ atoms: words("true false null"),
310
+ hooks: {
311
+ "@": function(stream) {
312
+ stream.eatWhile(/[\w\$_]/);
313
+ return "meta";
314
+ }
315
+ },
316
+ modeProps: {fold: ["brace", "import"]}
317
+ });
318
+ def("text/x-csharp", {
319
+ name: "clike",
320
+ keywords: words("abstract as base break case catch checked class const continue" +
321
+ " default delegate do else enum event explicit extern finally fixed for" +
322
+ " foreach goto if implicit in interface internal is lock namespace new" +
323
+ " operator out override params private protected public readonly ref return sealed" +
324
+ " sizeof stackalloc static struct switch this throw try typeof unchecked" +
325
+ " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
326
+ " global group into join let orderby partial remove select set value var yield"),
327
+ blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
328
+ builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
329
+ " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
330
+ " UInt64 bool byte char decimal double short int long object" +
331
+ " sbyte float string ushort uint ulong"),
332
+ atoms: words("true false null"),
333
+ hooks: {
334
+ "@": function(stream, state) {
335
+ if (stream.eat('"')) {
336
+ state.tokenize = tokenAtString;
337
+ return tokenAtString(stream, state);
338
+ }
339
+ stream.eatWhile(/[\w\$_]/);
340
+ return "meta";
341
+ }
342
+ }
343
+ });
344
+ def("text/x-scala", {
345
+ name: "clike",
346
+ keywords: words(
347
+
348
+ /* scala */
349
+ "abstract case catch class def do else extends false final finally for forSome if " +
350
+ "implicit import lazy match new null object override package private protected return " +
351
+ "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
352
+ "<% >: # @ " +
353
+
354
+ /* package scala */
355
+ "assert assume require print println printf readLine readBoolean readByte readShort " +
356
+ "readChar readInt readLong readFloat readDouble " +
357
+
358
+ "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
359
+ "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
360
+ "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
361
+ "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
362
+ "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
363
+
364
+ /* package java.lang */
365
+ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
366
+ "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
367
+ "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
368
+ "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
369
+
370
+
371
+ ),
372
+ blockKeywords: words("catch class do else finally for forSome if match switch try while"),
373
+ atoms: words("true false null"),
374
+ hooks: {
375
+ "@": function(stream) {
376
+ stream.eatWhile(/[\w\$_]/);
377
+ return "meta";
378
+ }
379
+ }
380
+ });
381
+ def(["x-shader/x-vertex", "x-shader/x-fragment"], {
382
+ name: "clike",
383
+ keywords: words("float int bool void " +
384
+ "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
385
+ "mat2 mat3 mat4 " +
386
+ "sampler1D sampler2D sampler3D samplerCube " +
387
+ "sampler1DShadow sampler2DShadow" +
388
+ "const attribute uniform varying " +
389
+ "break continue discard return " +
390
+ "for while do if else struct " +
391
+ "in out inout"),
392
+ blockKeywords: words("for while do if else struct"),
393
+ builtin: words("radians degrees sin cos tan asin acos atan " +
394
+ "pow exp log exp2 sqrt inversesqrt " +
395
+ "abs sign floor ceil fract mod min max clamp mix step smootstep " +
396
+ "length distance dot cross normalize ftransform faceforward " +
397
+ "reflect refract matrixCompMult " +
398
+ "lessThan lessThanEqual greaterThan greaterThanEqual " +
399
+ "equal notEqual any all not " +
400
+ "texture1D texture1DProj texture1DLod texture1DProjLod " +
401
+ "texture2D texture2DProj texture2DLod texture2DProjLod " +
402
+ "texture3D texture3DProj texture3DLod texture3DProjLod " +
403
+ "textureCube textureCubeLod " +
404
+ "shadow1D shadow2D shadow1DProj shadow2DProj " +
405
+ "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
406
+ "dFdx dFdy fwidth " +
407
+ "noise1 noise2 noise3 noise4"),
408
+ atoms: words("true false " +
409
+ "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
410
+ "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
411
+ "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
412
+ "gl_FogCoord " +
413
+ "gl_Position gl_PointSize gl_ClipVertex " +
414
+ "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
415
+ "gl_TexCoord gl_FogFragCoord " +
416
+ "gl_FragCoord gl_FrontFacing " +
417
+ "gl_FragColor gl_FragData gl_FragDepth " +
418
+ "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
419
+ "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
420
+ "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
421
+ "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
422
+ "gl_ProjectionMatrixInverseTranspose " +
423
+ "gl_ModelViewProjectionMatrixInverseTranspose " +
424
+ "gl_TextureMatrixInverseTranspose " +
425
+ "gl_NormalScale gl_DepthRange gl_ClipPlane " +
426
+ "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
427
+ "gl_FrontLightModelProduct gl_BackLightModelProduct " +
428
+ "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
429
+ "gl_FogParameters " +
430
+ "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
431
+ "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
432
+ "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
433
+ "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
434
+ "gl_MaxDrawBuffers"),
435
+ hooks: {"#": cppHook},
436
+ modeProps: {fold: ["brace", "include"]}
437
+ });
438
+
439
+ });
resources/js/codemirror/mode/css/css.js ADDED
@@ -0,0 +1,717 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("css", function(config, parserConfig) {
15
+ if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
16
+
17
+ var indentUnit = config.indentUnit,
18
+ tokenHooks = parserConfig.tokenHooks,
19
+ mediaTypes = parserConfig.mediaTypes || {},
20
+ mediaFeatures = parserConfig.mediaFeatures || {},
21
+ propertyKeywords = parserConfig.propertyKeywords || {},
22
+ nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
23
+ colorKeywords = parserConfig.colorKeywords || {},
24
+ valueKeywords = parserConfig.valueKeywords || {},
25
+ fontProperties = parserConfig.fontProperties || {},
26
+ allowNested = parserConfig.allowNested;
27
+
28
+ var type, override;
29
+ function ret(style, tp) { type = tp; return style; }
30
+
31
+ // Tokenizers
32
+
33
+ function tokenBase(stream, state) {
34
+ var ch = stream.next();
35
+ if (tokenHooks[ch]) {
36
+ var result = tokenHooks[ch](stream, state);
37
+ if (result !== false) return result;
38
+ }
39
+ if (ch == "@") {
40
+ stream.eatWhile(/[\w\\\-]/);
41
+ return ret("def", stream.current());
42
+ } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
43
+ return ret(null, "compare");
44
+ } else if (ch == "\"" || ch == "'") {
45
+ state.tokenize = tokenString(ch);
46
+ return state.tokenize(stream, state);
47
+ } else if (ch == "#") {
48
+ stream.eatWhile(/[\w\\\-]/);
49
+ return ret("atom", "hash");
50
+ } else if (ch == "!") {
51
+ stream.match(/^\s*\w*/);
52
+ return ret("keyword", "important");
53
+ } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
54
+ stream.eatWhile(/[\w.%]/);
55
+ return ret("number", "unit");
56
+ } else if (ch === "-") {
57
+ if (/[\d.]/.test(stream.peek())) {
58
+ stream.eatWhile(/[\w.%]/);
59
+ return ret("number", "unit");
60
+ } else if (stream.match(/^\w+-/)) {
61
+ return ret("meta", "meta");
62
+ }
63
+ } else if (/[,+>*\/]/.test(ch)) {
64
+ return ret(null, "select-op");
65
+ } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
66
+ return ret("qualifier", "qualifier");
67
+ } else if (/[:;{}\[\]\(\)]/.test(ch)) {
68
+ return ret(null, ch);
69
+ } else if (ch == "u" && stream.match("rl(")) {
70
+ stream.backUp(1);
71
+ state.tokenize = tokenParenthesized;
72
+ return ret("property", "word");
73
+ } else if (/[\w\\\-]/.test(ch)) {
74
+ stream.eatWhile(/[\w\\\-]/);
75
+ return ret("property", "word");
76
+ } else {
77
+ return ret(null, null);
78
+ }
79
+ }
80
+
81
+ function tokenString(quote) {
82
+ return function(stream, state) {
83
+ var escaped = false, ch;
84
+ while ((ch = stream.next()) != null) {
85
+ if (ch == quote && !escaped) {
86
+ if (quote == ")") stream.backUp(1);
87
+ break;
88
+ }
89
+ escaped = !escaped && ch == "\\";
90
+ }
91
+ if (ch == quote || !escaped && quote != ")") state.tokenize = null;
92
+ return ret("string", "string");
93
+ };
94
+ }
95
+
96
+ function tokenParenthesized(stream, state) {
97
+ stream.next(); // Must be '('
98
+ if (!stream.match(/\s*[\"\')]/, false))
99
+ state.tokenize = tokenString(")");
100
+ else
101
+ state.tokenize = null;
102
+ return ret(null, "(");
103
+ }
104
+
105
+ // Context management
106
+
107
+ function Context(type, indent, prev) {
108
+ this.type = type;
109
+ this.indent = indent;
110
+ this.prev = prev;
111
+ }
112
+
113
+ function pushContext(state, stream, type) {
114
+ state.context = new Context(type, stream.indentation() + indentUnit, state.context);
115
+ return type;
116
+ }
117
+
118
+ function popContext(state) {
119
+ state.context = state.context.prev;
120
+ return state.context.type;
121
+ }
122
+
123
+ function pass(type, stream, state) {
124
+ return states[state.context.type](type, stream, state);
125
+ }
126
+ function popAndPass(type, stream, state, n) {
127
+ for (var i = n || 1; i > 0; i--)
128
+ state.context = state.context.prev;
129
+ return pass(type, stream, state);
130
+ }
131
+
132
+ // Parser
133
+
134
+ function wordAsValue(stream) {
135
+ var word = stream.current().toLowerCase();
136
+ if (valueKeywords.hasOwnProperty(word))
137
+ override = "atom";
138
+ else if (colorKeywords.hasOwnProperty(word))
139
+ override = "keyword";
140
+ else
141
+ override = "variable";
142
+ }
143
+
144
+ var states = {};
145
+
146
+ states.top = function(type, stream, state) {
147
+ if (type == "{") {
148
+ return pushContext(state, stream, "block");
149
+ } else if (type == "}" && state.context.prev) {
150
+ return popContext(state);
151
+ } else if (type == "@media") {
152
+ return pushContext(state, stream, "media");
153
+ } else if (type == "@font-face") {
154
+ return "font_face_before";
155
+ } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
156
+ return "keyframes";
157
+ } else if (type && type.charAt(0) == "@") {
158
+ return pushContext(state, stream, "at");
159
+ } else if (type == "hash") {
160
+ override = "builtin";
161
+ } else if (type == "word") {
162
+ override = "tag";
163
+ } else if (type == "variable-definition") {
164
+ return "maybeprop";
165
+ } else if (type == "interpolation") {
166
+ return pushContext(state, stream, "interpolation");
167
+ } else if (type == ":") {
168
+ return "pseudo";
169
+ } else if (allowNested && type == "(") {
170
+ return pushContext(state, stream, "parens");
171
+ }
172
+ return state.context.type;
173
+ };
174
+
175
+ states.block = function(type, stream, state) {
176
+ if (type == "word") {
177
+ var word = stream.current().toLowerCase();
178
+ if (propertyKeywords.hasOwnProperty(word)) {
179
+ override = "property";
180
+ return "maybeprop";
181
+ } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
182
+ override = "string-2";
183
+ return "maybeprop";
184
+ } else if (allowNested) {
185
+ override = stream.match(/^\s*:/, false) ? "property" : "tag";
186
+ return "block";
187
+ } else {
188
+ override += " error";
189
+ return "maybeprop";
190
+ }
191
+ } else if (type == "meta") {
192
+ return "block";
193
+ } else if (!allowNested && (type == "hash" || type == "qualifier")) {
194
+ override = "error";
195
+ return "block";
196
+ } else {
197
+ return states.top(type, stream, state);
198
+ }
199
+ };
200
+
201
+ states.maybeprop = function(type, stream, state) {
202
+ if (type == ":") return pushContext(state, stream, "prop");
203
+ return pass(type, stream, state);
204
+ };
205
+
206
+ states.prop = function(type, stream, state) {
207
+ if (type == ";") return popContext(state);
208
+ if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
209
+ if (type == "}" || type == "{") return popAndPass(type, stream, state);
210
+ if (type == "(") return pushContext(state, stream, "parens");
211
+
212
+ if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
213
+ override += " error";
214
+ } else if (type == "word") {
215
+ wordAsValue(stream);
216
+ } else if (type == "interpolation") {
217
+ return pushContext(state, stream, "interpolation");
218
+ }
219
+ return "prop";
220
+ };
221
+
222
+ states.propBlock = function(type, _stream, state) {
223
+ if (type == "}") return popContext(state);
224
+ if (type == "word") { override = "property"; return "maybeprop"; }
225
+ return state.context.type;
226
+ };
227
+
228
+ states.parens = function(type, stream, state) {
229
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
230
+ if (type == ")") return popContext(state);
231
+ if (type == "(") return pushContext(state, stream, "parens");
232
+ if (type == "word") wordAsValue(stream);
233
+ return "parens";
234
+ };
235
+
236
+ states.pseudo = function(type, stream, state) {
237
+ if (type == "word") {
238
+ override = "variable-3";
239
+ return state.context.type;
240
+ }
241
+ return pass(type, stream, state);
242
+ };
243
+
244
+ states.media = function(type, stream, state) {
245
+ if (type == "(") return pushContext(state, stream, "media_parens");
246
+ if (type == "}") return popAndPass(type, stream, state);
247
+ if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
248
+
249
+ if (type == "word") {
250
+ var word = stream.current().toLowerCase();
251
+ if (word == "only" || word == "not" || word == "and")
252
+ override = "keyword";
253
+ else if (mediaTypes.hasOwnProperty(word))
254
+ override = "attribute";
255
+ else if (mediaFeatures.hasOwnProperty(word))
256
+ override = "property";
257
+ else
258
+ override = "error";
259
+ }
260
+ return state.context.type;
261
+ };
262
+
263
+ states.media_parens = function(type, stream, state) {
264
+ if (type == ")") return popContext(state);
265
+ if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
266
+ return states.media(type, stream, state);
267
+ };
268
+
269
+ states.font_face_before = function(type, stream, state) {
270
+ if (type == "{")
271
+ return pushContext(state, stream, "font_face");
272
+ return pass(type, stream, state);
273
+ };
274
+
275
+ states.font_face = function(type, stream, state) {
276
+ if (type == "}") return popContext(state);
277
+ if (type == "word") {
278
+ if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
279
+ override = "error";
280
+ else
281
+ override = "property";
282
+ return "maybeprop";
283
+ }
284
+ return "font_face";
285
+ };
286
+
287
+ states.keyframes = function(type, stream, state) {
288
+ if (type == "word") { override = "variable"; return "keyframes"; }
289
+ if (type == "{") return pushContext(state, stream, "top");
290
+ return pass(type, stream, state);
291
+ };
292
+
293
+ states.at = function(type, stream, state) {
294
+ if (type == ";") return popContext(state);
295
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
296
+ if (type == "word") override = "tag";
297
+ else if (type == "hash") override = "builtin";
298
+ return "at";
299
+ };
300
+
301
+ states.interpolation = function(type, stream, state) {
302
+ if (type == "}") return popContext(state);
303
+ if (type == "{" || type == ";") return popAndPass(type, stream, state);
304
+ if (type != "variable") override = "error";
305
+ return "interpolation";
306
+ };
307
+
308
+ return {
309
+ startState: function(base) {
310
+ return {tokenize: null,
311
+ state: "top",
312
+ context: new Context("top", base || 0, null)};
313
+ },
314
+
315
+ token: function(stream, state) {
316
+ if (!state.tokenize && stream.eatSpace()) return null;
317
+ var style = (state.tokenize || tokenBase)(stream, state);
318
+ if (style && typeof style == "object") {
319
+ type = style[1];
320
+ style = style[0];
321
+ }
322
+ override = style;
323
+ state.state = states[state.state](type, stream, state);
324
+ return override;
325
+ },
326
+
327
+ indent: function(state, textAfter) {
328
+ var cx = state.context, ch = textAfter && textAfter.charAt(0);
329
+ var indent = cx.indent;
330
+ if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
331
+ if (cx.prev &&
332
+ (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
333
+ ch == ")" && (cx.type == "parens" || cx.type == "media_parens") ||
334
+ ch == "{" && (cx.type == "at" || cx.type == "media"))) {
335
+ indent = cx.indent - indentUnit;
336
+ cx = cx.prev;
337
+ }
338
+ return indent;
339
+ },
340
+
341
+ electricChars: "}",
342
+ blockCommentStart: "/*",
343
+ blockCommentEnd: "*/",
344
+ fold: "brace"
345
+ };
346
+ });
347
+
348
+ function keySet(array) {
349
+ var keys = {};
350
+ for (var i = 0; i < array.length; ++i) {
351
+ keys[array[i]] = true;
352
+ }
353
+ return keys;
354
+ }
355
+
356
+ var mediaTypes_ = [
357
+ "all", "aural", "braille", "handheld", "print", "projection", "screen",
358
+ "tty", "tv", "embossed"
359
+ ], mediaTypes = keySet(mediaTypes_);
360
+
361
+ var mediaFeatures_ = [
362
+ "width", "min-width", "max-width", "height", "min-height", "max-height",
363
+ "device-width", "min-device-width", "max-device-width", "device-height",
364
+ "min-device-height", "max-device-height", "aspect-ratio",
365
+ "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
366
+ "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
367
+ "max-color", "color-index", "min-color-index", "max-color-index",
368
+ "monochrome", "min-monochrome", "max-monochrome", "resolution",
369
+ "min-resolution", "max-resolution", "scan", "grid"
370
+ ], mediaFeatures = keySet(mediaFeatures_);
371
+
372
+ var propertyKeywords_ = [
373
+ "align-content", "align-items", "align-self", "alignment-adjust",
374
+ "alignment-baseline", "anchor-point", "animation", "animation-delay",
375
+ "animation-direction", "animation-duration", "animation-fill-mode",
376
+ "animation-iteration-count", "animation-name", "animation-play-state",
377
+ "animation-timing-function", "appearance", "azimuth", "backface-visibility",
378
+ "background", "background-attachment", "background-clip", "background-color",
379
+ "background-image", "background-origin", "background-position",
380
+ "background-repeat", "background-size", "baseline-shift", "binding",
381
+ "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
382
+ "bookmark-target", "border", "border-bottom", "border-bottom-color",
383
+ "border-bottom-left-radius", "border-bottom-right-radius",
384
+ "border-bottom-style", "border-bottom-width", "border-collapse",
385
+ "border-color", "border-image", "border-image-outset",
386
+ "border-image-repeat", "border-image-slice", "border-image-source",
387
+ "border-image-width", "border-left", "border-left-color",
388
+ "border-left-style", "border-left-width", "border-radius", "border-right",
389
+ "border-right-color", "border-right-style", "border-right-width",
390
+ "border-spacing", "border-style", "border-top", "border-top-color",
391
+ "border-top-left-radius", "border-top-right-radius", "border-top-style",
392
+ "border-top-width", "border-width", "bottom", "box-decoration-break",
393
+ "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
394
+ "caption-side", "clear", "clip", "color", "color-profile", "column-count",
395
+ "column-fill", "column-gap", "column-rule", "column-rule-color",
396
+ "column-rule-style", "column-rule-width", "column-span", "column-width",
397
+ "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
398
+ "cue-after", "cue-before", "cursor", "direction", "display",
399
+ "dominant-baseline", "drop-initial-after-adjust",
400
+ "drop-initial-after-align", "drop-initial-before-adjust",
401
+ "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
402
+ "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
403
+ "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
404
+ "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
405
+ "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
406
+ "font-stretch", "font-style", "font-synthesis", "font-variant",
407
+ "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
408
+ "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
409
+ "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
410
+ "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
411
+ "grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
412
+ "grid-template", "grid-template-areas", "grid-template-columns",
413
+ "grid-template-rows", "hanging-punctuation", "height", "hyphens",
414
+ "icon", "image-orientation", "image-rendering", "image-resolution",
415
+ "inline-box-align", "justify-content", "left", "letter-spacing",
416
+ "line-break", "line-height", "line-stacking", "line-stacking-ruby",
417
+ "line-stacking-shift", "line-stacking-strategy", "list-style",
418
+ "list-style-image", "list-style-position", "list-style-type", "margin",
419
+ "margin-bottom", "margin-left", "margin-right", "margin-top",
420
+ "marker-offset", "marks", "marquee-direction", "marquee-loop",
421
+ "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
422
+ "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
423
+ "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
424
+ "opacity", "order", "orphans", "outline",
425
+ "outline-color", "outline-offset", "outline-style", "outline-width",
426
+ "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
427
+ "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
428
+ "page", "page-break-after", "page-break-before", "page-break-inside",
429
+ "page-policy", "pause", "pause-after", "pause-before", "perspective",
430
+ "perspective-origin", "pitch", "pitch-range", "play-during", "position",
431
+ "presentation-level", "punctuation-trim", "quotes", "region-break-after",
432
+ "region-break-before", "region-break-inside", "region-fragment",
433
+ "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
434
+ "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
435
+ "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
436
+ "shape-outside", "size", "speak", "speak-as", "speak-header",
437
+ "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
438
+ "tab-size", "table-layout", "target", "target-name", "target-new",
439
+ "target-position", "text-align", "text-align-last", "text-decoration",
440
+ "text-decoration-color", "text-decoration-line", "text-decoration-skip",
441
+ "text-decoration-style", "text-emphasis", "text-emphasis-color",
442
+ "text-emphasis-position", "text-emphasis-style", "text-height",
443
+ "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
444
+ "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
445
+ "text-wrap", "top", "transform", "transform-origin", "transform-style",
446
+ "transition", "transition-delay", "transition-duration",
447
+ "transition-property", "transition-timing-function", "unicode-bidi",
448
+ "vertical-align", "visibility", "voice-balance", "voice-duration",
449
+ "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
450
+ "voice-volume", "volume", "white-space", "widows", "width", "word-break",
451
+ "word-spacing", "word-wrap", "z-index",
452
+ // SVG-specific
453
+ "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
454
+ "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
455
+ "color-interpolation", "color-interpolation-filters",
456
+ "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
457
+ "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
458
+ "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
459
+ "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
460
+ "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
461
+ "glyph-orientation-vertical", "text-anchor", "writing-mode"
462
+ ], propertyKeywords = keySet(propertyKeywords_);
463
+
464
+ var nonStandardPropertyKeywords = [
465
+ "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
466
+ "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
467
+ "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
468
+ "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
469
+ "searchfield-results-decoration", "zoom"
470
+ ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords);
471
+
472
+ var colorKeywords_ = [
473
+ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
474
+ "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
475
+ "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
476
+ "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
477
+ "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
478
+ "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
479
+ "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
480
+ "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
481
+ "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
482
+ "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
483
+ "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
484
+ "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
485
+ "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
486
+ "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
487
+ "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
488
+ "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
489
+ "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
490
+ "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
491
+ "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
492
+ "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
493
+ "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
494
+ "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
495
+ "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
496
+ "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
497
+ "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
498
+ "whitesmoke", "yellow", "yellowgreen"
499
+ ], colorKeywords = keySet(colorKeywords_);
500
+
501
+ var valueKeywords_ = [
502
+ "above", "absolute", "activeborder", "activecaption", "afar",
503
+ "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
504
+ "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
505
+ "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
506
+ "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
507
+ "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
508
+ "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
509
+ "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
510
+ "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
511
+ "cell", "center", "checkbox", "circle", "cjk-earthly-branch",
512
+ "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
513
+ "col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
514
+ "content-box", "context-menu", "continuous", "copy", "cover", "crop",
515
+ "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
516
+ "decimal-leading-zero", "default", "default-button", "destination-atop",
517
+ "destination-in", "destination-out", "destination-over", "devanagari",
518
+ "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
519
+ "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
520
+ "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
521
+ "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
522
+ "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
523
+ "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
524
+ "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
525
+ "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
526
+ "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
527
+ "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
528
+ "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
529
+ "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
530
+ "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
531
+ "help", "hidden", "hide", "higher", "highlight", "highlighttext",
532
+ "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
533
+ "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
534
+ "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
535
+ "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
536
+ "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
537
+ "landscape", "lao", "large", "larger", "left", "level", "lighter",
538
+ "line-through", "linear", "lines", "list-item", "listbox", "listitem",
539
+ "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
540
+ "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
541
+ "lower-roman", "lowercase", "ltr", "malayalam", "match",
542
+ "media-controls-background", "media-current-time-display",
543
+ "media-fullscreen-button", "media-mute-button", "media-play-button",
544
+ "media-return-to-realtime-button", "media-rewind-button",
545
+ "media-seek-back-button", "media-seek-forward-button", "media-slider",
546
+ "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
547
+ "media-volume-slider-container", "media-volume-sliderthumb", "medium",
548
+ "menu", "menulist", "menulist-button", "menulist-text",
549
+ "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
550
+ "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
551
+ "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
552
+ "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
553
+ "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
554
+ "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
555
+ "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
556
+ "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
557
+ "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
558
+ "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
559
+ "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
560
+ "ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
561
+ "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
562
+ "searchfield-cancel-button", "searchfield-decoration",
563
+ "searchfield-results-button", "searchfield-results-decoration",
564
+ "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
565
+ "single", "skip-white-space", "slide", "slider-horizontal",
566
+ "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
567
+ "small", "small-caps", "small-caption", "smaller", "solid", "somali",
568
+ "source-atop", "source-in", "source-out", "source-over", "space", "square",
569
+ "square-button", "start", "static", "status-bar", "stretch", "stroke",
570
+ "sub", "subpixel-antialiased", "super", "sw-resize", "table",
571
+ "table-caption", "table-cell", "table-column", "table-column-group",
572
+ "table-footer-group", "table-header-group", "table-row", "table-row-group",
573
+ "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
574
+ "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
575
+ "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
576
+ "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
577
+ "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
578
+ "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
579
+ "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
580
+ "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
581
+ "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
582
+ "window", "windowframe", "windowtext", "x-large", "x-small", "xor",
583
+ "xx-large", "xx-small"
584
+ ], valueKeywords = keySet(valueKeywords_);
585
+
586
+ var fontProperties_ = [
587
+ "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
588
+ "font-stretch", "font-weight", "font-style"
589
+ ], fontProperties = keySet(fontProperties_);
590
+
591
+ var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_)
592
+ .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_);
593
+ CodeMirror.registerHelper("hintWords", "css", allWords);
594
+
595
+ function tokenCComment(stream, state) {
596
+ var maybeEnd = false, ch;
597
+ while ((ch = stream.next()) != null) {
598
+ if (maybeEnd && ch == "/") {
599
+ state.tokenize = null;
600
+ break;
601
+ }
602
+ maybeEnd = (ch == "*");
603
+ }
604
+ return ["comment", "comment"];
605
+ }
606
+
607
+ function tokenSGMLComment(stream, state) {
608
+ if (stream.skipTo("-->")) {
609
+ stream.match("-->");
610
+ state.tokenize = null;
611
+ } else {
612
+ stream.skipToEnd();
613
+ }
614
+ return ["comment", "comment"];
615
+ }
616
+
617
+ CodeMirror.defineMIME("text/css", {
618
+ mediaTypes: mediaTypes,
619
+ mediaFeatures: mediaFeatures,
620
+ propertyKeywords: propertyKeywords,
621
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords,
622
+ colorKeywords: colorKeywords,
623
+ valueKeywords: valueKeywords,
624
+ fontProperties: fontProperties,
625
+ tokenHooks: {
626
+ "<": function(stream, state) {
627
+ if (!stream.match("!--")) return false;
628
+ state.tokenize = tokenSGMLComment;
629
+ return tokenSGMLComment(stream, state);
630
+ },
631
+ "/": function(stream, state) {
632
+ if (!stream.eat("*")) return false;
633
+ state.tokenize = tokenCComment;
634
+ return tokenCComment(stream, state);
635
+ }
636
+ },
637
+ name: "css"
638
+ });
639
+
640
+ CodeMirror.defineMIME("text/x-scss", {
641
+ mediaTypes: mediaTypes,
642
+ mediaFeatures: mediaFeatures,
643
+ propertyKeywords: propertyKeywords,
644
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords,
645
+ colorKeywords: colorKeywords,
646
+ valueKeywords: valueKeywords,
647
+ fontProperties: fontProperties,
648
+ allowNested: true,
649
+ tokenHooks: {
650
+ "/": function(stream, state) {
651
+ if (stream.eat("/")) {
652
+ stream.skipToEnd();
653
+ return ["comment", "comment"];
654
+ } else if (stream.eat("*")) {
655
+ state.tokenize = tokenCComment;
656
+ return tokenCComment(stream, state);
657
+ } else {
658
+ return ["operator", "operator"];
659
+ }
660
+ },
661
+ ":": function(stream) {
662
+ if (stream.match(/\s*{/))
663
+ return [null, "{"];
664
+ return false;
665
+ },
666
+ "$": function(stream) {
667
+ stream.match(/^[\w-]+/);
668
+ if (stream.match(/^\s*:/, false))
669
+ return ["variable-2", "variable-definition"];
670
+ return ["variable-2", "variable"];
671
+ },
672
+ "#": function(stream) {
673
+ if (!stream.eat("{")) return false;
674
+ return [null, "interpolation"];
675
+ }
676
+ },
677
+ name: "css",
678
+ helperType: "scss"
679
+ });
680
+
681
+ CodeMirror.defineMIME("text/x-less", {
682
+ mediaTypes: mediaTypes,
683
+ mediaFeatures: mediaFeatures,
684
+ propertyKeywords: propertyKeywords,
685
+ nonStandardPropertyKeywords: nonStandardPropertyKeywords,
686
+ colorKeywords: colorKeywords,
687
+ valueKeywords: valueKeywords,
688
+ fontProperties: fontProperties,
689
+ allowNested: true,
690
+ tokenHooks: {
691
+ "/": function(stream, state) {
692
+ if (stream.eat("/")) {
693
+ stream.skipToEnd();
694
+ return ["comment", "comment"];
695
+ } else if (stream.eat("*")) {
696
+ state.tokenize = tokenCComment;
697
+ return tokenCComment(stream, state);
698
+ } else {
699
+ return ["operator", "operator"];
700
+ }
701
+ },
702
+ "@": function(stream) {
703
+ if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
704
+ stream.eatWhile(/[\w\\\-]/);
705
+ if (stream.match(/^\s*:/, false))
706
+ return ["variable-2", "variable-definition"];
707
+ return ["variable-2", "variable"];
708
+ },
709
+ "&": function() {
710
+ return ["atom", "atom"];
711
+ }
712
+ },
713
+ name: "css",
714
+ helperType: "less"
715
+ });
716
+
717
+ });
resources/js/codemirror/mode/htmlembedded/htmlembedded.js ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../htmlmixed/htmlmixed"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
15
+
16
+ //config settings
17
+ var scriptStartRegex = parserConfig.scriptStartRegex || /^<%/i,
18
+ scriptEndRegex = parserConfig.scriptEndRegex || /^%>/i;
19
+
20
+ //inner modes
21
+ var scriptingMode, htmlMixedMode;
22
+
23
+ //tokenizer when in html mode
24
+ function htmlDispatch(stream, state) {
25
+ if (stream.match(scriptStartRegex, false)) {
26
+ state.token=scriptingDispatch;
27
+ return scriptingMode.token(stream, state.scriptState);
28
+ }
29
+ else
30
+ return htmlMixedMode.token(stream, state.htmlState);
31
+ }
32
+
33
+ //tokenizer when in scripting mode
34
+ function scriptingDispatch(stream, state) {
35
+ if (stream.match(scriptEndRegex, false)) {
36
+ state.token=htmlDispatch;
37
+ return htmlMixedMode.token(stream, state.htmlState);
38
+ }
39
+ else
40
+ return scriptingMode.token(stream, state.scriptState);
41
+ }
42
+
43
+
44
+ return {
45
+ startState: function() {
46
+ scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec);
47
+ htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed");
48
+ return {
49
+ token : parserConfig.startOpen ? scriptingDispatch : htmlDispatch,
50
+ htmlState : CodeMirror.startState(htmlMixedMode),
51
+ scriptState : CodeMirror.startState(scriptingMode)
52
+ };
53
+ },
54
+
55
+ token: function(stream, state) {
56
+ return state.token(stream, state);
57
+ },
58
+
59
+ indent: function(state, textAfter) {
60
+ if (state.token == htmlDispatch)
61
+ return htmlMixedMode.indent(state.htmlState, textAfter);
62
+ else if (scriptingMode.indent)
63
+ return scriptingMode.indent(state.scriptState, textAfter);
64
+ },
65
+
66
+ copyState: function(state) {
67
+ return {
68
+ token : state.token,
69
+ htmlState : CodeMirror.copyState(htmlMixedMode, state.htmlState),
70
+ scriptState : CodeMirror.copyState(scriptingMode, state.scriptState)
71
+ };
72
+ },
73
+
74
+ innerMode: function(state) {
75
+ if (state.token == scriptingDispatch) return {state: state.scriptState, mode: scriptingMode};
76
+ else return {state: state.htmlState, mode: htmlMixedMode};
77
+ }
78
+ };
79
+ }, "htmlmixed");
80
+
81
+ CodeMirror.defineMIME("application/x-ejs", { name: "htmlembedded", scriptingModeSpec:"javascript"});
82
+ CodeMirror.defineMIME("application/x-aspx", { name: "htmlembedded", scriptingModeSpec:"text/x-csharp"});
83
+ CodeMirror.defineMIME("application/x-jsp", { name: "htmlembedded", scriptingModeSpec:"text/x-java"});
84
+ CodeMirror.defineMIME("application/x-erb", { name: "htmlembedded", scriptingModeSpec:"ruby"});
85
+
86
+ });
resources/js/codemirror/mode/htmlmixed/htmlmixed.js ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
15
+ var htmlMode = CodeMirror.getMode(config, {name: "xml",
16
+ htmlMode: true,
17
+ multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
18
+ multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
19
+ var cssMode = CodeMirror.getMode(config, "css");
20
+
21
+ var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
22
+ scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
23
+ mode: CodeMirror.getMode(config, "javascript")});
24
+ if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
25
+ var conf = scriptTypesConf[i];
26
+ scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
27
+ }
28
+ scriptTypes.push({matches: /./,
29
+ mode: CodeMirror.getMode(config, "text/plain")});
30
+
31
+ function html(stream, state) {
32
+ var tagName = state.htmlState.tagName;
33
+ var style = htmlMode.token(stream, state.htmlState);
34
+ if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
35
+ // Script block: mode to change to depends on type attribute
36
+ var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
37
+ scriptType = scriptType ? scriptType[1] : "";
38
+ if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
39
+ for (var i = 0; i < scriptTypes.length; ++i) {
40
+ var tp = scriptTypes[i];
41
+ if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
42
+ if (tp.mode) {
43
+ state.token = script;
44
+ state.localMode = tp.mode;
45
+ state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
46
+ }
47
+ break;
48
+ }
49
+ }
50
+ } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
51
+ state.token = css;
52
+ state.localMode = cssMode;
53
+ state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
54
+ }
55
+ return style;
56
+ }
57
+ function maybeBackup(stream, pat, style) {
58
+ var cur = stream.current();
59
+ var close = cur.search(pat), m;
60
+ if (close > -1) stream.backUp(cur.length - close);
61
+ else if (m = cur.match(/<\/?$/)) {
62
+ stream.backUp(cur.length);
63
+ if (!stream.match(pat, false)) stream.match(cur);
64
+ }
65
+ return style;
66
+ }
67
+ function script(stream, state) {
68
+ if (stream.match(/^<\/\s*script\s*>/i, false)) {
69
+ state.token = html;
70
+ state.localState = state.localMode = null;
71
+ return html(stream, state);
72
+ }
73
+ return maybeBackup(stream, /<\/\s*script\s*>/,
74
+ state.localMode.token(stream, state.localState));
75
+ }
76
+ function css(stream, state) {
77
+ if (stream.match(/^<\/\s*style\s*>/i, false)) {
78
+ state.token = html;
79
+ state.localState = state.localMode = null;
80
+ return html(stream, state);
81
+ }
82
+ return maybeBackup(stream, /<\/\s*style\s*>/,
83
+ cssMode.token(stream, state.localState));
84
+ }
85
+
86
+ return {
87
+ startState: function() {
88
+ var state = htmlMode.startState();
89
+ return {token: html, localMode: null, localState: null, htmlState: state};
90
+ },
91
+
92
+ copyState: function(state) {
93
+ if (state.localState)
94
+ var local = CodeMirror.copyState(state.localMode, state.localState);
95
+ return {token: state.token, localMode: state.localMode, localState: local,
96
+ htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
97
+ },
98
+
99
+ token: function(stream, state) {
100
+ return state.token(stream, state);
101
+ },
102
+
103
+ indent: function(state, textAfter) {
104
+ if (!state.localMode || /^\s*<\//.test(textAfter))
105
+ return htmlMode.indent(state.htmlState, textAfter);
106
+ else if (state.localMode.indent)
107
+ return state.localMode.indent(state.localState, textAfter);
108
+ else
109
+ return CodeMirror.Pass;
110
+ },
111
+
112
+ innerMode: function(state) {
113
+ return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
114
+ }
115
+ };
116
+ }, "xml", "javascript", "css");
117
+
118
+ CodeMirror.defineMIME("text/html", "htmlmixed");
119
+
120
+ });
resources/js/codemirror/mode/javascript/javascript.js ADDED
@@ -0,0 +1,663 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // TODO actually recognize syntax of TypeScript constructs
5
+
6
+ (function(mod) {
7
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
8
+ mod(require("../../lib/codemirror"));
9
+ else if (typeof define == "function" && define.amd) // AMD
10
+ define(["../../lib/codemirror"], mod);
11
+ else // Plain browser env
12
+ mod(CodeMirror);
13
+ })(function(CodeMirror) {
14
+ "use strict";
15
+
16
+ CodeMirror.defineMode("javascript", function(config, parserConfig) {
17
+ var indentUnit = config.indentUnit;
18
+ var statementIndent = parserConfig.statementIndent;
19
+ var jsonldMode = parserConfig.jsonld;
20
+ var jsonMode = parserConfig.json || jsonldMode;
21
+ var isTS = parserConfig.typescript;
22
+
23
+ // Tokenizer
24
+
25
+ var keywords = function(){
26
+ function kw(type) {return {type: type, style: "keyword"};}
27
+ var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
28
+ var operator = kw("operator"), atom = {type: "atom", style: "atom"};
29
+
30
+ var jsKeywords = {
31
+ "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
32
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
33
+ "var": kw("var"), "const": kw("var"), "let": kw("var"),
34
+ "function": kw("function"), "catch": kw("catch"),
35
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
36
+ "in": operator, "typeof": operator, "instanceof": operator,
37
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
38
+ "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
39
+ "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
40
+ };
41
+
42
+ // Extend the 'normal' keywords with the TypeScript language extensions
43
+ if (isTS) {
44
+ var type = {type: "variable", style: "variable-3"};
45
+ var tsKeywords = {
46
+ // object-like things
47
+ "interface": kw("interface"),
48
+ "extends": kw("extends"),
49
+ "constructor": kw("constructor"),
50
+
51
+ // scope modifiers
52
+ "public": kw("public"),
53
+ "private": kw("private"),
54
+ "protected": kw("protected"),
55
+ "static": kw("static"),
56
+
57
+ // types
58
+ "string": type, "number": type, "bool": type, "any": type
59
+ };
60
+
61
+ for (var attr in tsKeywords) {
62
+ jsKeywords[attr] = tsKeywords[attr];
63
+ }
64
+ }
65
+
66
+ return jsKeywords;
67
+ }();
68
+
69
+ var isOperatorChar = /[+\-*&%=<>!?|~^]/;
70
+ var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
71
+
72
+ function readRegexp(stream) {
73
+ var escaped = false, next, inSet = false;
74
+ while ((next = stream.next()) != null) {
75
+ if (!escaped) {
76
+ if (next == "/" && !inSet) return;
77
+ if (next == "[") inSet = true;
78
+ else if (inSet && next == "]") inSet = false;
79
+ }
80
+ escaped = !escaped && next == "\\";
81
+ }
82
+ }
83
+
84
+ // Used as scratch variables to communicate multiple values without
85
+ // consing up tons of objects.
86
+ var type, content;
87
+ function ret(tp, style, cont) {
88
+ type = tp; content = cont;
89
+ return style;
90
+ }
91
+ function tokenBase(stream, state) {
92
+ var ch = stream.next();
93
+ if (ch == '"' || ch == "'") {
94
+ state.tokenize = tokenString(ch);
95
+ return state.tokenize(stream, state);
96
+ } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
97
+ return ret("number", "number");
98
+ } else if (ch == "." && stream.match("..")) {
99
+ return ret("spread", "meta");
100
+ } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
101
+ return ret(ch);
102
+ } else if (ch == "=" && stream.eat(">")) {
103
+ return ret("=>", "operator");
104
+ } else if (ch == "0" && stream.eat(/x/i)) {
105
+ stream.eatWhile(/[\da-f]/i);
106
+ return ret("number", "number");
107
+ } else if (/\d/.test(ch)) {
108
+ stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
109
+ return ret("number", "number");
110
+ } else if (ch == "/") {
111
+ if (stream.eat("*")) {
112
+ state.tokenize = tokenComment;
113
+ return tokenComment(stream, state);
114
+ } else if (stream.eat("/")) {
115
+ stream.skipToEnd();
116
+ return ret("comment", "comment");
117
+ } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
118
+ state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
119
+ readRegexp(stream);
120
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
121
+ return ret("regexp", "string-2");
122
+ } else {
123
+ stream.eatWhile(isOperatorChar);
124
+ return ret("operator", "operator", stream.current());
125
+ }
126
+ } else if (ch == "`") {
127
+ state.tokenize = tokenQuasi;
128
+ return tokenQuasi(stream, state);
129
+ } else if (ch == "#") {
130
+ stream.skipToEnd();
131
+ return ret("error", "error");
132
+ } else if (isOperatorChar.test(ch)) {
133
+ stream.eatWhile(isOperatorChar);
134
+ return ret("operator", "operator", stream.current());
135
+ } else {
136
+ stream.eatWhile(/[\w\$_]/);
137
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
138
+ return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
139
+ ret("variable", "variable", word);
140
+ }
141
+ }
142
+
143
+ function tokenString(quote) {
144
+ return function(stream, state) {
145
+ var escaped = false, next;
146
+ if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
147
+ state.tokenize = tokenBase;
148
+ return ret("jsonld-keyword", "meta");
149
+ }
150
+ while ((next = stream.next()) != null) {
151
+ if (next == quote && !escaped) break;
152
+ escaped = !escaped && next == "\\";
153
+ }
154
+ if (!escaped) state.tokenize = tokenBase;
155
+ return ret("string", "string");
156
+ };
157
+ }
158
+
159
+ function tokenComment(stream, state) {
160
+ var maybeEnd = false, ch;
161
+ while (ch = stream.next()) {
162
+ if (ch == "/" && maybeEnd) {
163
+ state.tokenize = tokenBase;
164
+ break;
165
+ }
166
+ maybeEnd = (ch == "*");
167
+ }
168
+ return ret("comment", "comment");
169
+ }
170
+
171
+ function tokenQuasi(stream, state) {
172
+ var escaped = false, next;
173
+ while ((next = stream.next()) != null) {
174
+ if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
175
+ state.tokenize = tokenBase;
176
+ break;
177
+ }
178
+ escaped = !escaped && next == "\\";
179
+ }
180
+ return ret("quasi", "string-2", stream.current());
181
+ }
182
+
183
+ var brackets = "([{}])";
184
+ // This is a crude lookahead trick to try and notice that we're
185
+ // parsing the argument patterns for a fat-arrow function before we
186
+ // actually hit the arrow token. It only works if the arrow is on
187
+ // the same line as the arguments and there's no strange noise
188
+ // (comments) in between. Fallback is to only notice when we hit the
189
+ // arrow, and not declare the arguments as locals for the arrow
190
+ // body.
191
+ function findFatArrow(stream, state) {
192
+ if (state.fatArrowAt) state.fatArrowAt = null;
193
+ var arrow = stream.string.indexOf("=>", stream.start);
194
+ if (arrow < 0) return;
195
+
196
+ var depth = 0, sawSomething = false;
197
+ for (var pos = arrow - 1; pos >= 0; --pos) {
198
+ var ch = stream.string.charAt(pos);
199
+ var bracket = brackets.indexOf(ch);
200
+ if (bracket >= 0 && bracket < 3) {
201
+ if (!depth) { ++pos; break; }
202
+ if (--depth == 0) break;
203
+ } else if (bracket >= 3 && bracket < 6) {
204
+ ++depth;
205
+ } else if (/[$\w]/.test(ch)) {
206
+ sawSomething = true;
207
+ } else if (sawSomething && !depth) {
208
+ ++pos;
209
+ break;
210
+ }
211
+ }
212
+ if (sawSomething && !depth) state.fatArrowAt = pos;
213
+ }
214
+
215
+ // Parser
216
+
217
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
218
+
219
+ function JSLexical(indented, column, type, align, prev, info) {
220
+ this.indented = indented;
221
+ this.column = column;
222
+ this.type = type;
223
+ this.prev = prev;
224
+ this.info = info;
225
+ if (align != null) this.align = align;
226
+ }
227
+
228
+ function inScope(state, varname) {
229
+ for (var v = state.localVars; v; v = v.next)
230
+ if (v.name == varname) return true;
231
+ for (var cx = state.context; cx; cx = cx.prev) {
232
+ for (var v = cx.vars; v; v = v.next)
233
+ if (v.name == varname) return true;
234
+ }
235
+ }
236
+
237
+ function parseJS(state, style, type, content, stream) {
238
+ var cc = state.cc;
239
+ // Communicate our context to the combinators.
240
+ // (Less wasteful than consing up a hundred closures on every call.)
241
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
242
+
243
+ if (!state.lexical.hasOwnProperty("align"))
244
+ state.lexical.align = true;
245
+
246
+ while(true) {
247
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
248
+ if (combinator(type, content)) {
249
+ while(cc.length && cc[cc.length - 1].lex)
250
+ cc.pop()();
251
+ if (cx.marked) return cx.marked;
252
+ if (type == "variable" && inScope(state, content)) return "variable-2";
253
+ return style;
254
+ }
255
+ }
256
+ }
257
+
258
+ // Combinator utils
259
+
260
+ var cx = {state: null, column: null, marked: null, cc: null};
261
+ function pass() {
262
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
263
+ }
264
+ function cont() {
265
+ pass.apply(null, arguments);
266
+ return true;
267
+ }
268
+ function register(varname) {
269
+ function inList(list) {
270
+ for (var v = list; v; v = v.next)
271
+ if (v.name == varname) return true;
272
+ return false;
273
+ }
274
+ var state = cx.state;
275
+ if (state.context) {
276
+ cx.marked = "def";
277
+ if (inList(state.localVars)) return;
278
+ state.localVars = {name: varname, next: state.localVars};
279
+ } else {
280
+ if (inList(state.globalVars)) return;
281
+ if (parserConfig.globalVars)
282
+ state.globalVars = {name: varname, next: state.globalVars};
283
+ }
284
+ }
285
+
286
+ // Combinators
287
+
288
+ var defaultVars = {name: "this", next: {name: "arguments"}};
289
+ function pushcontext() {
290
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
291
+ cx.state.localVars = defaultVars;
292
+ }
293
+ function popcontext() {
294
+ cx.state.localVars = cx.state.context.vars;
295
+ cx.state.context = cx.state.context.prev;
296
+ }
297
+ function pushlex(type, info) {
298
+ var result = function() {
299
+ var state = cx.state, indent = state.indented;
300
+ if (state.lexical.type == "stat") indent = state.lexical.indented;
301
+ state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
302
+ };
303
+ result.lex = true;
304
+ return result;
305
+ }
306
+ function poplex() {
307
+ var state = cx.state;
308
+ if (state.lexical.prev) {
309
+ if (state.lexical.type == ")")
310
+ state.indented = state.lexical.indented;
311
+ state.lexical = state.lexical.prev;
312
+ }
313
+ }
314
+ poplex.lex = true;
315
+
316
+ function expect(wanted) {
317
+ function exp(type) {
318
+ if (type == wanted) return cont();
319
+ else if (wanted == ";") return pass();
320
+ else return cont(exp);
321
+ };
322
+ return exp;
323
+ }
324
+
325
+ function statement(type, value) {
326
+ if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
327
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
328
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
329
+ if (type == "{") return cont(pushlex("}"), block, poplex);
330
+ if (type == ";") return cont();
331
+ if (type == "if") {
332
+ if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
333
+ cx.state.cc.pop()();
334
+ return cont(pushlex("form"), expression, statement, poplex, maybeelse);
335
+ }
336
+ if (type == "function") return cont(functiondef);
337
+ if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
338
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
339
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
340
+ block, poplex, poplex);
341
+ if (type == "case") return cont(expression, expect(":"));
342
+ if (type == "default") return cont(expect(":"));
343
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
344
+ statement, poplex, popcontext);
345
+ if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
346
+ if (type == "class") return cont(pushlex("form"), className, objlit, poplex);
347
+ if (type == "export") return cont(pushlex("form"), afterExport, poplex);
348
+ if (type == "import") return cont(pushlex("form"), afterImport, poplex);
349
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
350
+ }
351
+ function expression(type) {
352
+ return expressionInner(type, false);
353
+ }
354
+ function expressionNoComma(type) {
355
+ return expressionInner(type, true);
356
+ }
357
+ function expressionInner(type, noComma) {
358
+ if (cx.state.fatArrowAt == cx.stream.start) {
359
+ var body = noComma ? arrowBodyNoComma : arrowBody;
360
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
361
+ else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
362
+ }
363
+
364
+ var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
365
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
366
+ if (type == "function") return cont(functiondef, maybeop);
367
+ if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
368
+ if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
369
+ if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
370
+ if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
371
+ if (type == "{") return contCommasep(objprop, "}", null, maybeop);
372
+ if (type == "quasi") { return pass(quasi, maybeop); }
373
+ return cont();
374
+ }
375
+ function maybeexpression(type) {
376
+ if (type.match(/[;\}\)\],]/)) return pass();
377
+ return pass(expression);
378
+ }
379
+ function maybeexpressionNoComma(type) {
380
+ if (type.match(/[;\}\)\],]/)) return pass();
381
+ return pass(expressionNoComma);
382
+ }
383
+
384
+ function maybeoperatorComma(type, value) {
385
+ if (type == ",") return cont(expression);
386
+ return maybeoperatorNoComma(type, value, false);
387
+ }
388
+ function maybeoperatorNoComma(type, value, noComma) {
389
+ var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
390
+ var expr = noComma == false ? expression : expressionNoComma;
391
+ if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
392
+ if (type == "operator") {
393
+ if (/\+\+|--/.test(value)) return cont(me);
394
+ if (value == "?") return cont(expression, expect(":"), expr);
395
+ return cont(expr);
396
+ }
397
+ if (type == "quasi") { return pass(quasi, me); }
398
+ if (type == ";") return;
399
+ if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
400
+ if (type == ".") return cont(property, me);
401
+ if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
402
+ }
403
+ function quasi(type, value) {
404
+ if (type != "quasi") return pass();
405
+ if (value.slice(value.length - 2) != "${") return cont(quasi);
406
+ return cont(expression, continueQuasi);
407
+ }
408
+ function continueQuasi(type) {
409
+ if (type == "}") {
410
+ cx.marked = "string-2";
411
+ cx.state.tokenize = tokenQuasi;
412
+ return cont(quasi);
413
+ }
414
+ }
415
+ function arrowBody(type) {
416
+ findFatArrow(cx.stream, cx.state);
417
+ if (type == "{") return pass(statement);
418
+ return pass(expression);
419
+ }
420
+ function arrowBodyNoComma(type) {
421
+ findFatArrow(cx.stream, cx.state);
422
+ if (type == "{") return pass(statement);
423
+ return pass(expressionNoComma);
424
+ }
425
+ function maybelabel(type) {
426
+ if (type == ":") return cont(poplex, statement);
427
+ return pass(maybeoperatorComma, expect(";"), poplex);
428
+ }
429
+ function property(type) {
430
+ if (type == "variable") {cx.marked = "property"; return cont();}
431
+ }
432
+ function objprop(type, value) {
433
+ if (type == "variable") {
434
+ cx.marked = "property";
435
+ if (value == "get" || value == "set") return cont(getterSetter);
436
+ } else if (type == "number" || type == "string") {
437
+ cx.marked = jsonldMode ? "property" : (type + " property");
438
+ } else if (type == "[") {
439
+ return cont(expression, expect("]"), afterprop);
440
+ }
441
+ if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
442
+ }
443
+ function getterSetter(type) {
444
+ if (type != "variable") return pass(afterprop);
445
+ cx.marked = "property";
446
+ return cont(functiondef);
447
+ }
448
+ function afterprop(type) {
449
+ if (type == ":") return cont(expressionNoComma);
450
+ if (type == "(") return pass(functiondef);
451
+ }
452
+ function commasep(what, end) {
453
+ function proceed(type) {
454
+ if (type == ",") {
455
+ var lex = cx.state.lexical;
456
+ if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
457
+ return cont(what, proceed);
458
+ }
459
+ if (type == end) return cont();
460
+ return cont(expect(end));
461
+ }
462
+ return function(type) {
463
+ if (type == end) return cont();
464
+ return pass(what, proceed);
465
+ };
466
+ }
467
+ function contCommasep(what, end, info) {
468
+ for (var i = 3; i < arguments.length; i++)
469
+ cx.cc.push(arguments[i]);
470
+ return cont(pushlex(end, info), commasep(what, end), poplex);
471
+ }
472
+ function block(type) {
473
+ if (type == "}") return cont();
474
+ return pass(statement, block);
475
+ }
476
+ function maybetype(type) {
477
+ if (isTS && type == ":") return cont(typedef);
478
+ }
479
+ function typedef(type) {
480
+ if (type == "variable"){cx.marked = "variable-3"; return cont();}
481
+ }
482
+ function vardef() {
483
+ return pass(pattern, maybetype, maybeAssign, vardefCont);
484
+ }
485
+ function pattern(type, value) {
486
+ if (type == "variable") { register(value); return cont(); }
487
+ if (type == "[") return contCommasep(pattern, "]");
488
+ if (type == "{") return contCommasep(proppattern, "}");
489
+ }
490
+ function proppattern(type, value) {
491
+ if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
492
+ register(value);
493
+ return cont(maybeAssign);
494
+ }
495
+ if (type == "variable") cx.marked = "property";
496
+ return cont(expect(":"), pattern, maybeAssign);
497
+ }
498
+ function maybeAssign(_type, value) {
499
+ if (value == "=") return cont(expressionNoComma);
500
+ }
501
+ function vardefCont(type) {
502
+ if (type == ",") return cont(vardef);
503
+ }
504
+ function maybeelse(type, value) {
505
+ if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
506
+ }
507
+ function forspec(type) {
508
+ if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
509
+ }
510
+ function forspec1(type) {
511
+ if (type == "var") return cont(vardef, expect(";"), forspec2);
512
+ if (type == ";") return cont(forspec2);
513
+ if (type == "variable") return cont(formaybeinof);
514
+ return pass(expression, expect(";"), forspec2);
515
+ }
516
+ function formaybeinof(_type, value) {
517
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
518
+ return cont(maybeoperatorComma, forspec2);
519
+ }
520
+ function forspec2(type, value) {
521
+ if (type == ";") return cont(forspec3);
522
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
523
+ return pass(expression, expect(";"), forspec3);
524
+ }
525
+ function forspec3(type) {
526
+ if (type != ")") cont(expression);
527
+ }
528
+ function functiondef(type, value) {
529
+ if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
530
+ if (type == "variable") {register(value); return cont(functiondef);}
531
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
532
+ }
533
+ function funarg(type) {
534
+ if (type == "spread") return cont(funarg);
535
+ return pass(pattern, maybetype);
536
+ }
537
+ function className(type, value) {
538
+ if (type == "variable") {register(value); return cont(classNameAfter);}
539
+ }
540
+ function classNameAfter(_type, value) {
541
+ if (value == "extends") return cont(expression);
542
+ }
543
+ function objlit(type) {
544
+ if (type == "{") return contCommasep(objprop, "}");
545
+ }
546
+ function afterModule(type, value) {
547
+ if (type == "string") return cont(statement);
548
+ if (type == "variable") { register(value); return cont(maybeFrom); }
549
+ }
550
+ function afterExport(_type, value) {
551
+ if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
552
+ if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
553
+ return pass(statement);
554
+ }
555
+ function afterImport(type) {
556
+ if (type == "string") return cont();
557
+ return pass(importSpec, maybeFrom);
558
+ }
559
+ function importSpec(type, value) {
560
+ if (type == "{") return contCommasep(importSpec, "}");
561
+ if (type == "variable") register(value);
562
+ return cont();
563
+ }
564
+ function maybeFrom(_type, value) {
565
+ if (value == "from") { cx.marked = "keyword"; return cont(expression); }
566
+ }
567
+ function arrayLiteral(type) {
568
+ if (type == "]") return cont();
569
+ return pass(expressionNoComma, maybeArrayComprehension);
570
+ }
571
+ function maybeArrayComprehension(type) {
572
+ if (type == "for") return pass(comprehension, expect("]"));
573
+ if (type == ",") return cont(commasep(expressionNoComma, "]"));
574
+ return pass(commasep(expressionNoComma, "]"));
575
+ }
576
+ function comprehension(type) {
577
+ if (type == "for") return cont(forspec, comprehension);
578
+ if (type == "if") return cont(expression, comprehension);
579
+ }
580
+
581
+ // Interface
582
+
583
+ return {
584
+ startState: function(basecolumn) {
585
+ var state = {
586
+ tokenize: tokenBase,
587
+ lastType: "sof",
588
+ cc: [],
589
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
590
+ localVars: parserConfig.localVars,
591
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
592
+ indented: 0
593
+ };
594
+ if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
595
+ state.globalVars = parserConfig.globalVars;
596
+ return state;
597
+ },
598
+
599
+ token: function(stream, state) {
600
+ if (stream.sol()) {
601
+ if (!state.lexical.hasOwnProperty("align"))
602
+ state.lexical.align = false;
603
+ state.indented = stream.indentation();
604
+ findFatArrow(stream, state);
605
+ }
606
+ if (state.tokenize != tokenComment && stream.eatSpace()) return null;
607
+ var style = state.tokenize(stream, state);
608
+ if (type == "comment") return style;
609
+ state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
610
+ return parseJS(state, style, type, content, stream);
611
+ },
612
+
613
+ indent: function(state, textAfter) {
614
+ if (state.tokenize == tokenComment) return CodeMirror.Pass;
615
+ if (state.tokenize != tokenBase) return 0;
616
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
617
+ // Kludge to prevent 'maybelse' from blocking lexical scope pops
618
+ if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
619
+ var c = state.cc[i];
620
+ if (c == poplex) lexical = lexical.prev;
621
+ else if (c != maybeelse) break;
622
+ }
623
+ if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
624
+ if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
625
+ lexical = lexical.prev;
626
+ var type = lexical.type, closing = firstChar == type;
627
+
628
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
629
+ else if (type == "form" && firstChar == "{") return lexical.indented;
630
+ else if (type == "form") return lexical.indented + indentUnit;
631
+ else if (type == "stat")
632
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
633
+ else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
634
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
635
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
636
+ else return lexical.indented + (closing ? 0 : indentUnit);
637
+ },
638
+
639
+ electricChars: ":{}",
640
+ blockCommentStart: jsonMode ? null : "/*",
641
+ blockCommentEnd: jsonMode ? null : "*/",
642
+ lineComment: jsonMode ? null : "//",
643
+ fold: "brace",
644
+
645
+ helperType: jsonMode ? "json" : "javascript",
646
+ jsonldMode: jsonldMode,
647
+ jsonMode: jsonMode
648
+ };
649
+ });
650
+
651
+ CodeMirror.registerHelper("wordChars", "javascript", /[\\w$]/);
652
+
653
+ CodeMirror.defineMIME("text/javascript", "javascript");
654
+ CodeMirror.defineMIME("text/ecmascript", "javascript");
655
+ CodeMirror.defineMIME("application/javascript", "javascript");
656
+ CodeMirror.defineMIME("application/ecmascript", "javascript");
657
+ CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
658
+ CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
659
+ CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
660
+ CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
661
+ CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
662
+
663
+ });
resources/js/codemirror/mode/php/php.js ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ function keywords(str) {
15
+ var obj = {}, words = str.split(" ");
16
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
17
+ return obj;
18
+ }
19
+ function heredoc(delim) {
20
+ return function(stream, state) {
21
+ if (stream.match(delim)) state.tokenize = null;
22
+ else stream.skipToEnd();
23
+ return "string";
24
+ };
25
+ }
26
+
27
+ // Helper for stringWithEscapes
28
+ function matchSequence(list) {
29
+ if (list.length == 0) return stringWithEscapes;
30
+ return function (stream, state) {
31
+ var patterns = list[0];
32
+ for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) {
33
+ state.tokenize = matchSequence(list.slice(1));
34
+ return patterns[i][1];
35
+ }
36
+ state.tokenize = stringWithEscapes;
37
+ return "string";
38
+ };
39
+ }
40
+ function stringWithEscapes(stream, state) {
41
+ var escaped = false, next, end = false;
42
+
43
+ if (stream.current() == '"') return "string";
44
+
45
+ // "Complex" syntax
46
+ if (stream.match("${", false) || stream.match("{$", false)) {
47
+ state.tokenize = null;
48
+ return "string";
49
+ }
50
+
51
+ // Simple syntax
52
+ if (stream.match(/\$[a-zA-Z_][a-zA-Z0-9_]*/)) {
53
+ // After the variable name there may appear array or object operator.
54
+ if (stream.match("[", false)) {
55
+ // Match array operator
56
+ state.tokenize = matchSequence([
57
+ [["[", null]],
58
+ [[/\d[\w\.]*/, "number"],
59
+ [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"],
60
+ [/[\w\$]+/, "variable"]],
61
+ [["]", null]]
62
+ ]);
63
+ }
64
+ if (stream.match(/\-\>\w/, false)) {
65
+ // Match object operator
66
+ state.tokenize = matchSequence([
67
+ [["->", null]],
68
+ [[/[\w]+/, "variable"]]
69
+ ]);
70
+ }
71
+ return "variable-2";
72
+ }
73
+
74
+ // Normal string
75
+ while (
76
+ !stream.eol() &&
77
+ (!stream.match("{$", false)) &&
78
+ (!stream.match(/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false) || escaped)
79
+ ) {
80
+ next = stream.next();
81
+ if (!escaped && next == '"') { end = true; break; }
82
+ escaped = !escaped && next == "\\";
83
+ }
84
+ if (end) {
85
+ state.tokenize = null;
86
+ state.phpEncapsStack.pop();
87
+ }
88
+ return "string";
89
+ }
90
+
91
+ var phpKeywords = "abstract and array as break case catch class clone const continue declare default " +
92
+ "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " +
93
+ "for foreach function global goto if implements interface instanceof namespace " +
94
+ "new or private protected public static switch throw trait try use var while xor " +
95
+ "die echo empty exit eval include include_once isset list require require_once return " +
96
+ "print unset __halt_compiler self static parent yield insteadof finally";
97
+ var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__";
98
+ var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once";
99
+ CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" "));
100
+ CodeMirror.registerHelper("wordChars", "php", /[\\w$]/);
101
+
102
+ var phpConfig = {
103
+ name: "clike",
104
+ helperType: "php",
105
+ keywords: keywords(phpKeywords),
106
+ blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"),
107
+ atoms: keywords(phpAtoms),
108
+ builtin: keywords(phpBuiltin),
109
+ multiLineStrings: true,
110
+ hooks: {
111
+ "$": function(stream) {
112
+ stream.eatWhile(/[\w\$_]/);
113
+ return "variable-2";
114
+ },
115
+ "<": function(stream, state) {
116
+ if (stream.match(/<</)) {
117
+ stream.eatWhile(/[\w\.]/);
118
+ state.tokenize = heredoc(stream.current().slice(3));
119
+ return state.tokenize(stream, state);
120
+ }
121
+ return false;
122
+ },
123
+ "#": function(stream) {
124
+ while (!stream.eol() && !stream.match("?>", false)) stream.next();
125
+ return "comment";
126
+ },
127
+ "/": function(stream) {
128
+ if (stream.eat("/")) {
129
+ while (!stream.eol() && !stream.match("?>", false)) stream.next();
130
+ return "comment";
131
+ }
132
+ return false;
133
+ },
134
+ '"': function(stream, state) {
135
+ if (!state.phpEncapsStack)
136
+ state.phpEncapsStack = [];
137
+ state.phpEncapsStack.push(0);
138
+ state.tokenize = stringWithEscapes;
139
+ return state.tokenize(stream, state);
140
+ },
141
+ "{": function(_stream, state) {
142
+ if (state.phpEncapsStack && state.phpEncapsStack.length > 0)
143
+ state.phpEncapsStack[state.phpEncapsStack.length - 1]++;
144
+ return false;
145
+ },
146
+ "}": function(_stream, state) {
147
+ if (state.phpEncapsStack && state.phpEncapsStack.length > 0)
148
+ if (--state.phpEncapsStack[state.phpEncapsStack.length - 1] == 0)
149
+ state.tokenize = stringWithEscapes;
150
+ return false;
151
+ }
152
+ }
153
+ };
154
+
155
+ CodeMirror.defineMode("php", function(config, parserConfig) {
156
+ var htmlMode = CodeMirror.getMode(config, "text/html");
157
+ var phpMode = CodeMirror.getMode(config, phpConfig);
158
+
159
+ function dispatch(stream, state) {
160
+ var isPHP = state.curMode == phpMode;
161
+ if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null;
162
+ if (!isPHP) {
163
+ if (stream.match(/^<\?\w*/)) {
164
+ state.curMode = phpMode;
165
+ state.curState = state.php;
166
+ return "meta";
167
+ }
168
+ if (state.pending == '"' || state.pending == "'") {
169
+ while (!stream.eol() && stream.next() != state.pending) {}
170
+ var style = "string";
171
+ } else if (state.pending && stream.pos < state.pending.end) {
172
+ stream.pos = state.pending.end;
173
+ var style = state.pending.style;
174
+ } else {
175
+ var style = htmlMode.token(stream, state.curState);
176
+ }
177
+ if (state.pending) state.pending = null;
178
+ var cur = stream.current(), openPHP = cur.search(/<\?/), m;
179
+ if (openPHP != -1) {
180
+ if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0];
181
+ else state.pending = {end: stream.pos, style: style};
182
+ stream.backUp(cur.length - openPHP);
183
+ }
184
+ return style;
185
+ } else if (isPHP && state.php.tokenize == null && stream.match("?>")) {
186
+ state.curMode = htmlMode;
187
+ state.curState = state.html;
188
+ return "meta";
189
+ } else {
190
+ return phpMode.token(stream, state.curState);
191
+ }
192
+ }
193
+
194
+ return {
195
+ startState: function() {
196
+ var html = CodeMirror.startState(htmlMode), php = CodeMirror.startState(phpMode);
197
+ return {html: html,
198
+ php: php,
199
+ curMode: parserConfig.startOpen ? phpMode : htmlMode,
200
+ curState: parserConfig.startOpen ? php : html,
201
+ pending: null};
202
+ },
203
+
204
+ copyState: function(state) {
205
+ var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
206
+ php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
207
+ if (state.curMode == htmlMode) cur = htmlNew;
208
+ else cur = phpNew;
209
+ return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur,
210
+ pending: state.pending};
211
+ },
212
+
213
+ token: dispatch,
214
+
215
+ indent: function(state, textAfter) {
216
+ if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
217
+ (state.curMode == phpMode && /^\?>/.test(textAfter)))
218
+ return htmlMode.indent(state.html, textAfter);
219
+ return state.curMode.indent(state.curState, textAfter);
220
+ },
221
+
222
+ blockCommentStart: "/*",
223
+ blockCommentEnd: "*/",
224
+ lineComment: "//",
225
+
226
+ innerMode: function(state) { return {state: state.curState, mode: state.curMode}; }
227
+ };
228
+ }, "htmlmixed", "clike");
229
+
230
+ CodeMirror.defineMIME("application/x-httpd-php", "php");
231
+ CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true});
232
+ CodeMirror.defineMIME("text/x-php", phpConfig);
233
+ });
resources/js/codemirror/mode/xml/xml.js ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("xml", function(config, parserConfig) {
15
+ var indentUnit = config.indentUnit;
16
+ var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
17
+ var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
18
+ if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
19
+
20
+ var Kludges = parserConfig.htmlMode ? {
21
+ autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
22
+ 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
23
+ 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
24
+ 'track': true, 'wbr': true},
25
+ implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
26
+ 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
27
+ 'th': true, 'tr': true},
28
+ contextGrabbers: {
29
+ 'dd': {'dd': true, 'dt': true},
30
+ 'dt': {'dd': true, 'dt': true},
31
+ 'li': {'li': true},
32
+ 'option': {'option': true, 'optgroup': true},
33
+ 'optgroup': {'optgroup': true},
34
+ 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
35
+ 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
36
+ 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
37
+ 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
38
+ 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
39
+ 'rp': {'rp': true, 'rt': true},
40
+ 'rt': {'rp': true, 'rt': true},
41
+ 'tbody': {'tbody': true, 'tfoot': true},
42
+ 'td': {'td': true, 'th': true},
43
+ 'tfoot': {'tbody': true},
44
+ 'th': {'td': true, 'th': true},
45
+ 'thead': {'tbody': true, 'tfoot': true},
46
+ 'tr': {'tr': true}
47
+ },
48
+ doNotIndent: {"pre": true},
49
+ allowUnquoted: true,
50
+ allowMissing: true,
51
+ caseFold: true
52
+ } : {
53
+ autoSelfClosers: {},
54
+ implicitlyClosed: {},
55
+ contextGrabbers: {},
56
+ doNotIndent: {},
57
+ allowUnquoted: false,
58
+ allowMissing: false,
59
+ caseFold: false
60
+ };
61
+ var alignCDATA = parserConfig.alignCDATA;
62
+
63
+ // Return variables for tokenizers
64
+ var type, setStyle;
65
+
66
+ function inText(stream, state) {
67
+ function chain(parser) {
68
+ state.tokenize = parser;
69
+ return parser(stream, state);
70
+ }
71
+
72
+ var ch = stream.next();
73
+ if (ch == "<") {
74
+ if (stream.eat("!")) {
75
+ if (stream.eat("[")) {
76
+ if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
77
+ else return null;
78
+ } else if (stream.match("--")) {
79
+ return chain(inBlock("comment", "-->"));
80
+ } else if (stream.match("DOCTYPE", true, true)) {
81
+ stream.eatWhile(/[\w\._\-]/);
82
+ return chain(doctype(1));
83
+ } else {
84
+ return null;
85
+ }
86
+ } else if (stream.eat("?")) {
87
+ stream.eatWhile(/[\w\._\-]/);
88
+ state.tokenize = inBlock("meta", "?>");
89
+ return "meta";
90
+ } else {
91
+ type = stream.eat("/") ? "closeTag" : "openTag";
92
+ state.tokenize = inTag;
93
+ return "tag bracket";
94
+ }
95
+ } else if (ch == "&") {
96
+ var ok;
97
+ if (stream.eat("#")) {
98
+ if (stream.eat("x")) {
99
+ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
100
+ } else {
101
+ ok = stream.eatWhile(/[\d]/) && stream.eat(";");
102
+ }
103
+ } else {
104
+ ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
105
+ }
106
+ return ok ? "atom" : "error";
107
+ } else {
108
+ stream.eatWhile(/[^&<]/);
109
+ return null;
110
+ }
111
+ }
112
+
113
+ function inTag(stream, state) {
114
+ var ch = stream.next();
115
+ if (ch == ">" || (ch == "/" && stream.eat(">"))) {
116
+ state.tokenize = inText;
117
+ type = ch == ">" ? "endTag" : "selfcloseTag";
118
+ return "tag bracket";
119
+ } else if (ch == "=") {
120
+ type = "equals";
121
+ return null;
122
+ } else if (ch == "<") {
123
+ state.tokenize = inText;
124
+ state.state = baseState;
125
+ state.tagName = state.tagStart = null;
126
+ var next = state.tokenize(stream, state);
127
+ return next ? next + " tag error" : "tag error";
128
+ } else if (/[\'\"]/.test(ch)) {
129
+ state.tokenize = inAttribute(ch);
130
+ state.stringStartCol = stream.column();
131
+ return state.tokenize(stream, state);
132
+ } else {
133
+ stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
134
+ return "word";
135
+ }
136
+ }
137
+
138
+ function inAttribute(quote) {
139
+ var closure = function(stream, state) {
140
+ while (!stream.eol()) {
141
+ if (stream.next() == quote) {
142
+ state.tokenize = inTag;
143
+ break;
144
+ }
145
+ }
146
+ return "string";
147
+ };
148
+ closure.isInAttribute = true;
149
+ return closure;
150
+ }
151
+
152
+ function inBlock(style, terminator) {
153
+ return function(stream, state) {
154
+ while (!stream.eol()) {
155
+ if (stream.match(terminator)) {
156
+ state.tokenize = inText;
157
+ break;
158
+ }
159
+ stream.next();
160
+ }
161
+ return style;
162
+ };
163
+ }
164
+ function doctype(depth) {
165
+ return function(stream, state) {
166
+ var ch;
167
+ while ((ch = stream.next()) != null) {
168
+ if (ch == "<") {
169
+ state.tokenize = doctype(depth + 1);
170
+ return state.tokenize(stream, state);
171
+ } else if (ch == ">") {
172
+ if (depth == 1) {
173
+ state.tokenize = inText;
174
+ break;
175
+ } else {
176
+ state.tokenize = doctype(depth - 1);
177
+ return state.tokenize(stream, state);
178
+ }
179
+ }
180
+ }
181
+ return "meta";
182
+ };
183
+ }
184
+
185
+ function Context(state, tagName, startOfLine) {
186
+ this.prev = state.context;
187
+ this.tagName = tagName;
188
+ this.indent = state.indented;
189
+ this.startOfLine = startOfLine;
190
+ if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
191
+ this.noIndent = true;
192
+ }
193
+ function popContext(state) {
194
+ if (state.context) state.context = state.context.prev;
195
+ }
196
+ function maybePopContext(state, nextTagName) {
197
+ var parentTagName;
198
+ while (true) {
199
+ if (!state.context) {
200
+ return;
201
+ }
202
+ parentTagName = state.context.tagName;
203
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
204
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
205
+ return;
206
+ }
207
+ popContext(state);
208
+ }
209
+ }
210
+
211
+ function baseState(type, stream, state) {
212
+ if (type == "openTag") {
213
+ state.tagStart = stream.column();
214
+ return tagNameState;
215
+ } else if (type == "closeTag") {
216
+ return closeTagNameState;
217
+ } else {
218
+ return baseState;
219
+ }
220
+ }
221
+ function tagNameState(type, stream, state) {
222
+ if (type == "word") {
223
+ state.tagName = stream.current();
224
+ setStyle = "tag";
225
+ return attrState;
226
+ } else {
227
+ setStyle = "error";
228
+ return tagNameState;
229
+ }
230
+ }
231
+ function closeTagNameState(type, stream, state) {
232
+ if (type == "word") {
233
+ var tagName = stream.current();
234
+ if (state.context && state.context.tagName != tagName &&
235
+ Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
236
+ popContext(state);
237
+ if (state.context && state.context.tagName == tagName) {
238
+ setStyle = "tag";
239
+ return closeState;
240
+ } else {
241
+ setStyle = "tag error";
242
+ return closeStateErr;
243
+ }
244
+ } else {
245
+ setStyle = "error";
246
+ return closeStateErr;
247
+ }
248
+ }
249
+
250
+ function closeState(type, _stream, state) {
251
+ if (type != "endTag") {
252
+ setStyle = "error";
253
+ return closeState;
254
+ }
255
+ popContext(state);
256
+ return baseState;
257
+ }
258
+ function closeStateErr(type, stream, state) {
259
+ setStyle = "error";
260
+ return closeState(type, stream, state);
261
+ }
262
+
263
+ function attrState(type, _stream, state) {
264
+ if (type == "word") {
265
+ setStyle = "attribute";
266
+ return attrEqState;
267
+ } else if (type == "endTag" || type == "selfcloseTag") {
268
+ var tagName = state.tagName, tagStart = state.tagStart;
269
+ state.tagName = state.tagStart = null;
270
+ if (type == "selfcloseTag" ||
271
+ Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
272
+ maybePopContext(state, tagName);
273
+ } else {
274
+ maybePopContext(state, tagName);
275
+ state.context = new Context(state, tagName, tagStart == state.indented);
276
+ }
277
+ return baseState;
278
+ }
279
+ setStyle = "error";
280
+ return attrState;
281
+ }
282
+ function attrEqState(type, stream, state) {
283
+ if (type == "equals") return attrValueState;
284
+ if (!Kludges.allowMissing) setStyle = "error";
285
+ return attrState(type, stream, state);
286
+ }
287
+ function attrValueState(type, stream, state) {
288
+ if (type == "string") return attrContinuedState;
289
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
290
+ setStyle = "error";
291
+ return attrState(type, stream, state);
292
+ }
293
+ function attrContinuedState(type, stream, state) {
294
+ if (type == "string") return attrContinuedState;
295
+ return attrState(type, stream, state);
296
+ }
297
+
298
+ return {
299
+ startState: function() {
300
+ return {tokenize: inText,
301
+ state: baseState,
302
+ indented: 0,
303
+ tagName: null, tagStart: null,
304
+ context: null};
305
+ },
306
+
307
+ token: function(stream, state) {
308
+ if (!state.tagName && stream.sol())
309
+ state.indented = stream.indentation();
310
+
311
+ if (stream.eatSpace()) return null;
312
+ type = null;
313
+ var style = state.tokenize(stream, state);
314
+ if ((style || type) && style != "comment") {
315
+ setStyle = null;
316
+ state.state = state.state(type || style, stream, state);
317
+ if (setStyle)
318
+ style = setStyle == "error" ? style + " error" : setStyle;
319
+ }
320
+ return style;
321
+ },
322
+
323
+ indent: function(state, textAfter, fullLine) {
324
+ var context = state.context;
325
+ // Indent multi-line strings (e.g. css).
326
+ if (state.tokenize.isInAttribute) {
327
+ if (state.tagStart == state.indented)
328
+ return state.stringStartCol + 1;
329
+ else
330
+ return state.indented + indentUnit;
331
+ }
332
+ if (context && context.noIndent) return CodeMirror.Pass;
333
+ if (state.tokenize != inTag && state.tokenize != inText)
334
+ return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
335
+ // Indent the starts of attribute names.
336
+ if (state.tagName) {
337
+ if (multilineTagIndentPastTag)
338
+ return state.tagStart + state.tagName.length + 2;
339
+ else
340
+ return state.tagStart + indentUnit * multilineTagIndentFactor;
341
+ }
342
+ if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
343
+ var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
344
+ if (tagAfter && tagAfter[1]) { // Closing tag spotted
345
+ while (context) {
346
+ if (context.tagName == tagAfter[2]) {
347
+ context = context.prev;
348
+ break;
349
+ } else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
350
+ context = context.prev;
351
+ } else {
352
+ break;
353
+ }
354
+ }
355
+ } else if (tagAfter) { // Opening tag spotted
356
+ while (context) {
357
+ var grabbers = Kludges.contextGrabbers[context.tagName];
358
+ if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
359
+ context = context.prev;
360
+ else
361
+ break;
362
+ }
363
+ }
364
+ while (context && !context.startOfLine)
365
+ context = context.prev;
366
+ if (context) return context.indent + indentUnit;
367
+ else return 0;
368
+ },
369
+
370
+ electricInput: /<\/[\s\w:]+>$/,
371
+ blockCommentStart: "<!--",
372
+ blockCommentEnd: "-->",
373
+
374
+ configuration: parserConfig.htmlMode ? "html" : "xml",
375
+ helperType: parserConfig.htmlMode ? "html" : "xml"
376
+ };
377
+ });
378
+
379
+ CodeMirror.defineMIME("text/xml", "xml");
380
+ CodeMirror.defineMIME("application/xml", "xml");
381
+ if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
382
+ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
383
+
384
+ });
resources/js/string-locator-search.js ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function ($) {
2
+ var string_locator_search_active = false;
3
+
4
+ var add_notice = function( title, message, format ) {
5
+ $(".notices").append( '<div class="notice notice-' + format + ' is-dismissible"><p><strong>' + title + '</strong><br />' + message + '</p></div>' );
6
+ };
7
+
8
+ var throw_error = function( title, message ) {
9
+ string_locator_search_active = false;
10
+ $(".string-locator-feedback").hide();
11
+ add_notice( title, message, 'error' );
12
+ };
13
+
14
+ var finalize_string_locator_search = function() {
15
+ string_locator_search_active = false;
16
+
17
+ $("#string-locator-feedback-text").text('');
18
+
19
+ var search_finalized = {
20
+ action : 'string-locator-clean',
21
+ nonce : string_locator.search_nonce
22
+ };
23
+
24
+ $.post(
25
+ string_locator.ajax_url,
26
+ search_finalized,
27
+ function( response ) {
28
+ $(".string-locator-feedback").hide();
29
+ if ( $("tbody", ".tools_page_string-locator").is(":empty") ) {
30
+ $("tbody", ".tools_page_string-locator").html( '<tr><td colspan="3">' + string_locator.search_no_results + '</td></tr>' );
31
+ }
32
+ }
33
+ ).fail(function(xhr, textStatus, errorThrown) {
34
+ throw_error( errorThrown, string_locator.search_error );
35
+ });
36
+ };
37
+
38
+ var clear_string_locator_result_area = function() {
39
+ $(".notices").html('');
40
+ $("#string-locator-search-progress").removeAttr( 'value' );
41
+ $("tbody", ".tools_page_string-locator").html('');
42
+ };
43
+
44
+ var perform_string_locator_single_search = function( maxCount, thisCount ) {
45
+ if ( thisCount >= maxCount || ! string_locator_search_active ) {
46
+ $("#string-locator-feedback-text").html( string_locator.saving_results_string );
47
+ finalize_string_locator_search();
48
+ return false;
49
+ }
50
+
51
+ var search_request = {
52
+ action : 'string-locator-search',
53
+ filenum : thisCount,
54
+ nonce : string_locator.search_nonce
55
+ };
56
+
57
+ $.post(
58
+ string_locator.ajax_url,
59
+ search_request,
60
+ function ( response ) {
61
+ if ( ! response.success ) {
62
+ add_notice( string_locator.warning_title, response.data, 'warning' );
63
+ }
64
+
65
+ if ( undefined !== response.data.search ) {
66
+ $("#string-locator-search-progress").val( response.data.filenum );
67
+ $("#string-locator-feedback-text").html( response.data.next_file );
68
+
69
+ string_locator_append_result( response.data.search );
70
+ }
71
+ var nextCount = response.data.filenum + 1;
72
+ perform_string_locator_single_search( maxCount, nextCount );
73
+ },
74
+ 'json'
75
+ ).fail(function(xhr, textStatus, errorThrown) {
76
+ throw_error( errorThrown, string_locator.search_error );
77
+ });
78
+ };
79
+
80
+ var string_locator_append_result = function( total_entries ) {
81
+ if ( $(".no-items", ".tools_page_string-locator").is(':visible') ) {
82
+ $(".no-items", ".tools_page_string-locator").hide();
83
+ }
84
+
85
+ total_entries.forEach( function ( entries ) {
86
+ for (var i = 0, amount = entries.length; i < amount; i++) {
87
+
88
+ var entry = entries[i];
89
+
90
+ if (undefined !== entry.stringresult) {
91
+ var builtHTML = '<tr>' +
92
+ '<td>' + entry.stringresult + '<div class="row-actions"><span class="edit"><a href="' + entry.editurl + '" aria-label="Edit">Edit</a></span></div></td>' +
93
+ '<td>' + entry.filename + '</td>' +
94
+ '<td>' + entry.linenum + '</td>' +
95
+ '</tr>';
96
+
97
+ $("tbody", ".tools_page_string-locator").append(builtHTML);
98
+ }
99
+ }
100
+ } );
101
+ };
102
+
103
+
104
+ $("#string-locator-search-form").on( 'submit', function (e) {
105
+ e.preventDefault();
106
+ $("#string-locator-feedback-text").text( string_locator.search_preparing );
107
+ $(".string-locator-feedback").show();
108
+ string_locator_search_active = true;
109
+ clear_string_locator_result_area();
110
+
111
+ var directory_request = {
112
+ action : 'string-locator-get-directory-structure',
113
+ directory : $("#string-locator-search").val(),
114
+ search : $("#string-locator-string").val(),
115
+ nonce : string_locator.search_nonce
116
+ };
117
+
118
+ $("table.tools_page_string-locator").show();
119
+
120
+ $.post(
121
+ string_locator.ajax_url,
122
+ directory_request,
123
+ function ( response ) {
124
+ if ( ! response.success ) {
125
+ add_notice( response.data, 'alert' );
126
+ return;
127
+ }
128
+ $("#string-locator-search-progress").attr( 'max', response.data.total ).val( response.data.current );
129
+ $("#string-locator-feedback-text").text( string_locator.search_started );
130
+ perform_string_locator_single_search( response.data.total, 0 );
131
+ },
132
+ 'json'
133
+ ).fail(function(xhr, textStatus, errorThrown) {
134
+ throw_error( errorThrown, string_locator.search_error );
135
+ });
136
+ });
137
+ });
resources/js/string-locator.js ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var theEditor = document.getElementById( 'code-editor');
2
+
3
+ if ( theEditor != null ) {
4
+ var editLine = theEditor.getAttribute( 'data-editor-goto-line'),
5
+ editorLanguage = theEditor.getAttribute( 'data-editor-language');
6
+
7
+ function resizeEditor( editor ) {
8
+ var setEditorSize = ( Math.max( document.documentElement.clientHeight, window.innerHeight || 0 ) - 177 );
9
+ editor.setSize( null, parseInt( setEditorSize ) );
10
+ }
11
+
12
+ var editor = CodeMirror.fromTextArea( document.getElementById( 'code-editor' ), {
13
+ lineNumbers: true,
14
+ mode: editorLanguage,
15
+ styleActiveLine : true,
16
+ matchBrackets : true,
17
+ indentWithTabs : true,
18
+ indentUnit : 4,
19
+ theme : 'twilight'
20
+ } );
21
+
22
+ editor.scrollIntoView( parseInt( editLine ) );
23
+ editor.setCursor( parseInt( editLine - 1 ), 0 );
24
+ resizeEditor( editor );
25
+ }
26
+
27
+ var gotoClick = document.getElementsByClassName( 'string-locator-edit-goto' );
28
+ for( var i = 0; i < gotoClick.length; i++ ) {
29
+ var click = gotoClick[i];
30
+ click.onclick = function() {
31
+ editor.scrollIntoView( parseInt( this.getAttribute( 'data-goto-line' ) ) );
32
+ editor.setCursor( parseInt( this.getAttribute( 'data-goto-line' ) - 1 ), 0 );
33
+ }
34
+ }
string-locator.php ADDED
@@ -0,0 +1,1363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: String Locator
4
+ * Plugin URI: http://www.clorith.net/wordpress-string-locator/
5
+ * Description: Scan through theme and plugin files looking for text strings
6
+ * Version: 2.0.3
7
+ * Author: Clorith
8
+ * Author URI: http://www.clorith.net
9
+ * Text Domain: string-locator
10
+ * License: GPL2
11
+ *
12
+ * Copyright 2013 Marius Jensen (email : marius@clorith.net)
13
+ *
14
+ * This program is free software; you can redistribute it and/or modify
15
+ * it under the terms of the GNU General Public License, version 2, as
16
+ * published by the Free Software Foundation.
17
+ *
18
+ * This program is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License
24
+ * along with this program; if not, write to the Free Software
25
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
+ */
27
+
28
+ /**
29
+ * The primary plugin class.
30
+ *
31
+ * The String_Locator class contains the functions required to search, edit, and safeguard edits within the plugin.
32
+ *
33
+ * @since 1.0.0
34
+ */
35
+ class String_Locator
36
+ {
37
+ /**
38
+ * The code language used for the editing page.
39
+ *
40
+ * @access public
41
+ *
42
+ * @since 1.2.0
43
+ *
44
+ * @var string $string_locator_language
45
+ */
46
+ public $string_locator_language = '';
47
+
48
+ /**
49
+ * String Locator version number.
50
+ *
51
+ * @access public
52
+ *
53
+ * @since 1.2.0
54
+ *
55
+ * @var string $version
56
+ */
57
+ public $version = '2.0.3';
58
+
59
+ /**
60
+ * An array containing all notices to display.
61
+ *
62
+ * @access public
63
+ *
64
+ * @since 1.2.0
65
+ *
66
+ * @var array $notice
67
+ */
68
+ public $notice = array();
69
+
70
+ /**
71
+ * Has there been a failed edit.
72
+ *
73
+ * @access public
74
+ *
75
+ * @since 1.2.0
76
+ *
77
+ * @var bool $failed_edit
78
+ */
79
+ public $failed_edit = false;
80
+
81
+ /**
82
+ * The URL to the plugins directory.
83
+ *
84
+ * @access private
85
+ *
86
+ * @since 1.2.0
87
+ *
88
+ * @var string $plugin_url
89
+ */
90
+ private $plugin_url = '';
91
+
92
+ /**
93
+ * Holds the path to the plugins pages within wp-admin based on the site setup.
94
+ *
95
+ * @access private
96
+ *
97
+ * @since 1.5.0
98
+ *
99
+ * @var string
100
+ */
101
+ private $path_to_use = '';
102
+
103
+ /**
104
+ * An array of HTTP codes considered to have "broken" a website.
105
+ *
106
+ * @access private
107
+ *
108
+ * @since 1.6.0
109
+ *
110
+ * @var array
111
+ */
112
+ private $bad_http_codes = array( '500' );
113
+
114
+ /**
115
+ * The length of an excerpt from a file matching our search.
116
+ *
117
+ * @access private
118
+ *
119
+ * @since 1.7.0
120
+ *
121
+ * @var int
122
+ */
123
+ private $excerpt_length = 25;
124
+
125
+ /**
126
+ * The maximum execution time of PHP.
127
+ *
128
+ * @access private
129
+ *
130
+ * @since 1.9.0
131
+ *
132
+ * @var int
133
+ */
134
+ private $max_execution_time = 0;
135
+
136
+ /**
137
+ * The current time when execution began.
138
+ *
139
+ * @access private
140
+ *
141
+ * @since 1.9.0
142
+ *
143
+ * @var int
144
+ */
145
+ private $start_execution_timer = 0;
146
+
147
+ /**
148
+ * The maximum amount of memory available to PHP.
149
+ *
150
+ * @access private
151
+ *
152
+ * @since 2.0.0
153
+ *
154
+ * @var int
155
+ */
156
+ private $max_memory_consumption = 0;
157
+
158
+ /**
159
+ * Construct the plugin
160
+ */
161
+ function __construct()
162
+ {
163
+ /*
164
+ * Set up execution limitations
165
+ */
166
+ $this->set_max_execution_time();
167
+ $this->set_memory_limit();
168
+
169
+ /*
170
+ * Define class variables requiring expressions
171
+ */
172
+ $this->plugin_url = plugin_dir_url( __FILE__ );
173
+ $this->path_to_use = ( is_multisite() ? 'network/admin.php' : 'tools.php' );
174
+ $this->excerpt_length = apply_filters( 'string_locator_excerpt_length', 25 );
175
+
176
+ $this->start_execution_timer = microtime( true );
177
+
178
+ add_action( 'admin_menu', array( $this, 'populate_menu' ) );
179
+ add_action( 'network_admin_menu', array( $this, 'populate_network_menu' ) );
180
+
181
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 11 );
182
+
183
+ add_action( 'plugins_loaded', array( $this, 'load_i18n' ) );
184
+
185
+ add_action( 'admin_init', array( $this, 'editor_save' ) );
186
+ add_action( 'admin_notices', array( $this, 'admin_notice' ) );
187
+
188
+ add_action( 'wp_ajax_string-locator-get-directory-structure', array( $this, 'ajax_get_directory_structure' ) );
189
+ add_action( 'wp_ajax_string-locator-search', array( $this, 'ajax_file_search' ) );
190
+ add_action( 'wp_ajax_string-locator-clean', array( $this, 'ajax_clean_search' ) );
191
+ }
192
+
193
+ /**
194
+ * Check what system PHP runs as.
195
+ *
196
+ * Currently this is only used to check if HHVM is being used, but may need ot be expanded in the future
197
+ * as new systems pop up that require quirks for proper behavior.
198
+ *
199
+ * @since 2.0.3
200
+ *
201
+ * @param string $system The system being used.
202
+ *
203
+ * @return bool
204
+ */
205
+ function is_specific_system( $system ) {
206
+ if ( 'HHVM' == $system ) {
207
+ return defined( 'HHVM_VERSION' );
208
+ }
209
+
210
+ return false;
211
+ }
212
+
213
+ /**
214
+ * Sets up the memory limit variables
215
+ *
216
+ * @uses String_Locator::is_valid_location()
217
+ * @uses apply_filters()
218
+ * @uses absint()
219
+ *
220
+ * @since 2.0.0
221
+ *
222
+ * @return void
223
+ */
224
+ function set_memory_limit() {
225
+ $memory_limit = ini_get( 'memory_limit' );
226
+
227
+ if ( empty( $memory_limit ) && $this->is_specific_system( 'HHVM' ) ) {
228
+ /*
229
+ * Some versions of HHVM have a ini_get bug which returns a blank value.
230
+ *
231
+ * This check is in place to set the HHVM default value if this is the case.
232
+ *
233
+ * As of https://github.com/facebook/hhvm/commit/91cf450b8ec25b849274fe19e1e66dd5380e4ea6 the default
234
+ * value was set to 1GiB, so this is what we'll base our selves off
235
+ *
236
+ * The filter allows for this value to be overridden by a mu-plugin or similar for those who know the
237
+ * value in use by their system until HHVM allows for a more exact config reading.
238
+ */
239
+ $memory_limit = apply_filters( 'string-locator-hhvm-memory-limit', '1G');
240
+ }
241
+
242
+ $this->max_memory_consumption = absint( $memory_limit );
243
+
244
+ if ( strstr( $memory_limit, 'k' ) ) {
245
+ $this->max_memory_consumption = ( str_replace( 'k', '', $memory_limit ) * 1000 );
246
+ }
247
+ if ( strstr( $memory_limit, 'M' ) ) {
248
+ $this->max_memory_consumption = ( str_replace( 'M', '', $memory_limit ) * 1000000 );
249
+ }
250
+ if ( strstr( $memory_limit, 'G' ) ) {
251
+ $this->max_memory_consumption = ( str_replace( 'G', '', $memory_limit ) * 1000000000 );
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Sets up the max execution time variables
257
+ *
258
+ * @since 2.0.3
259
+ *
260
+ * @return void
261
+ */
262
+ function set_max_execution_time() {
263
+ $this->max_execution_time = ini_get( 'max_execution_time' );
264
+ }
265
+
266
+ /**
267
+ * Create a set of drop-down options for picking one of the available themes
268
+ *
269
+ * @uses esc_html()
270
+ * @uses __()
271
+ * @uses wp_get_themes()
272
+ * @uses wp_get_theme()
273
+ *
274
+ * @param string $current The current selection option to match against
275
+ *
276
+ * @return string
277
+ */
278
+ function get_themes_options( $current = null ) {
279
+ $options = sprintf(
280
+ '<option value="%s" %s>&mdash; %s &mdash;</option>',
281
+ 't--',
282
+ ( $current == 't--' ? 'selected="selected"' : '' ),
283
+ esc_html( __( 'All themes', 'string-locator' ) )
284
+ );
285
+
286
+ $string_locate_themes = wp_get_themes();
287
+
288
+ foreach( $string_locate_themes AS $string_locate_theme_slug => $string_locate_theme ) {
289
+ $string_locate_theme_data = wp_get_theme( $string_locate_theme_slug );
290
+ $string_locate_value = 't-' . $string_locate_theme_slug;
291
+
292
+ $options .= sprintf(
293
+ '<option value="%s" %s>%s</option>',
294
+ $string_locate_value,
295
+ ( $current == $string_locate_value ? 'selected="selected"' : '' ),
296
+ $string_locate_theme_data->Name
297
+ );
298
+ }
299
+
300
+ return $options;
301
+ }
302
+
303
+ /**
304
+ * Create a set of drop-down options for picking one of the available plugins
305
+ *
306
+ * @uses esc_html()
307
+ * @uses __()
308
+ *
309
+ * @param string $current The current selection option to match against
310
+ *
311
+ * @return string
312
+ */
313
+ function get_plugins_options( $current = null ) {
314
+ $options = sprintf(
315
+ '<option value="%s" %s>&mdash; %s &mdash;</option>',
316
+ 'p--',
317
+ ( $current == 'p--' ? 'selected="selected"' : '' ),
318
+ esc_html( __( 'All plugins', 'string-locator' ) )
319
+ );
320
+
321
+ $string_locate_plugins = get_plugins();
322
+
323
+ foreach( $string_locate_plugins AS $string_locate_plugin_path => $string_locate_plugin )
324
+ {
325
+ $string_locate_value = 'p-' . $string_locate_plugin_path;
326
+
327
+ $options .= sprintf(
328
+ '<option value="%s" %s>%s</option>',
329
+ $string_locate_value,
330
+ ( $current == $string_locate_value ? 'selected="selected"' : '' ),
331
+ $string_locate_plugin['Name']
332
+ );
333
+ }
334
+
335
+ return $options;
336
+ }
337
+
338
+ /**
339
+ * Handles the AJAX request to prepare the search hierarchy
340
+ *
341
+ * @uses check_ajax_referer()
342
+ * @uses wp_send_json_error()
343
+ * @uses String_Locator::prepare_scan_path()
344
+ * @uses String_Locator::ajax_scan_path()
345
+ * @uses wp_unslash()
346
+ * @uses update_option()
347
+ * @uses wp_send_json_success()
348
+ *
349
+ * @return object
350
+ */
351
+ function ajax_get_directory_structure() {
352
+ if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) { wp_send_json_error( __( 'Authentication failed', 'string-locator' ) ); }
353
+
354
+ $scan_path = $this->prepare_scan_path( $_POST['directory'] );
355
+ if ( is_file( $scan_path->path ) ) {
356
+ $files = array( $scan_path->path );
357
+ }
358
+ else {
359
+ $files = $this->ajax_scan_path( $scan_path->path );
360
+ }
361
+
362
+ /*
363
+ * Make sure each chunk of file arrays never exceeds 500 files
364
+ * This is to prevent the SQL string from being too large and crashing everything
365
+ */
366
+ $file_chunks = array_chunk( $files, apply_filters( 'string-locator-files-per-array', 500 ), true );
367
+
368
+ $store = (object) array(
369
+ 'scan_path' => $scan_path,
370
+ 'search' => wp_unslash( $_POST['search'] ),
371
+ 'directory' => $_POST['directory'],
372
+ 'chunks' => count( $file_chunks )
373
+ );
374
+
375
+ $response = array(
376
+ 'total' => count( $files ),
377
+ 'current' => 0,
378
+ 'directory' => $scan_path,
379
+ 'chunks' => count( $file_chunks )
380
+ );
381
+
382
+ update_option( 'string-locator-search-overview', serialize( $store ), true );
383
+ update_option( 'string-locator-search-history', serialize( array() ) );
384
+
385
+ foreach( $file_chunks AS $count => $file_chunk ) {
386
+ update_option( 'string-locator-search-files-' . $count, serialize( $file_chunk ) );
387
+ }
388
+
389
+ wp_send_json_success( $response );
390
+ }
391
+
392
+ /**
393
+ * Check if the script is about to exceed the max execution time.
394
+ *
395
+ * @uses apply_filters()
396
+ *
397
+ * @since 1.9.0
398
+ *
399
+ * @return bool
400
+ */
401
+ function nearing_execution_limit() {
402
+ $built_in_delay = apply_filters( 'string-locator-extra-search-delay', 2 );
403
+ $execution_time = ( microtime( true ) - $this->start_execution_timer + $built_in_delay );
404
+
405
+ if ( $execution_time >= $this->max_execution_time ) {
406
+ return $execution_time;
407
+ }
408
+ return false;
409
+ }
410
+
411
+ /**
412
+ * Check if the script is about to exceed the server memory limit.
413
+ *
414
+ * @uses apply_filters()
415
+ *
416
+ * @since 2.0.0
417
+ *
418
+ * @return bool
419
+ */
420
+ function nearing_memory_limit() {
421
+ // We give our selves a 256k memory buffer, as we need to close off the script properly as well
422
+ $built_in_buffer = apply_filters( 'string-locator-extra-memory-buffer', 256000 );
423
+ $memory_use = ( memory_get_usage( true ) + $built_in_buffer );
424
+
425
+ if ( $memory_use >= $this->max_memory_consumption ) {
426
+ return $memory_use;
427
+ }
428
+ return false;
429
+ }
430
+
431
+ /**
432
+ * Search an individual file supplied via AJAX
433
+ *
434
+ * @uses check_ajax_referer()
435
+ * @uses wp_send_json_error()
436
+ * @uses apply_filters()
437
+ * @uses absint()
438
+ * @uses get_option()
439
+ * @uses maybe_unserialize()
440
+ * @uses update_option()
441
+ * @uses wp_send_json_success()
442
+ *
443
+ * @since 1.9.0
444
+ *
445
+ * @return void
446
+ */
447
+ function ajax_file_search() {
448
+ if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) { wp_send_json_error( __( 'Authentication failed', 'string-locator' ) ); }
449
+
450
+ $files_per_chunk = apply_filters( 'string-locator-files-per-array', 500 );
451
+ $response = array(
452
+ 'search' => array(),
453
+ 'filenum' => absint( $_POST['filenum'] )
454
+ );
455
+
456
+ $filenum = absint( $_POST['filenum'] );
457
+ $next_file = $filenum + 1;
458
+
459
+ $next_chunk = ( ceil( ( $next_file ) / $files_per_chunk ) - 1 );
460
+ $chunk = ( ceil( $filenum / $files_per_chunk ) - 1 );
461
+ if ( $chunk < 0 ) {
462
+ $chunk = 0;
463
+ }
464
+ if ( $next_chunk < 0 ) {
465
+ $next_chunk = 0;
466
+ }
467
+
468
+ $scan_data = unserialize( get_option( 'string-locator-search-overview' ) );
469
+ $file_data = unserialize( get_option( 'string-locator-search-files-' . $chunk ) );
470
+
471
+ if ( ! isset( $file_data[ $filenum ] ) ) {
472
+ wp_send_json_error( sprintf( __( 'The file-number, %d, that was sent could not be found.', 'string-locator' ), $filenum ) );
473
+ }
474
+
475
+ if ( $this->nearing_execution_limit() ) {
476
+ wp_send_json_error( sprintf( __( 'The maximum time your server allows a script to run is too low for the plugin to run as intended, at startup %d seconds have passed', 'string-locator' ), $this->nearing_execution_limit() ) );
477
+ }
478
+ if ( $this->nearing_memory_limit() ) {
479
+ wp_send_json_error( sprintf( __( 'The memory limit is about to be exceeded before the search has started, this could be an early indicator that your site may soon struggle as well, unfortunately this means the plugin is unable to perform any searches. Current memory consumption: %d bytes', 'string-locator' ), $this->nearing_memory_limit() ) );
480
+ }
481
+
482
+ while ( ! $this->nearing_execution_limit() && ! $this->nearing_memory_limit() && isset( $file_data[ $filenum ]) ) {
483
+ $filenum = absint( $_POST['filenum'] );
484
+ $next_file = $filenum + 1;
485
+
486
+ $next_chunk = ( ceil( ( $next_file ) / $files_per_chunk ) - 1 );
487
+ $chunk = ( ceil( $filenum / $files_per_chunk ) - 1 );
488
+ if ( $chunk < 0 ) {
489
+ $chunk = 0;
490
+ }
491
+ if ( $next_chunk < 0 ) {
492
+ $next_chunk = 0;
493
+ }
494
+
495
+ if ( ! isset( $file_data[ $filenum ] ) ) {
496
+ $chunk ++;
497
+ $file_data = unserialize( get_option( 'string-locator-search-files-' . $chunk ) );
498
+ }
499
+
500
+ $file_name = explode( "/", $file_data[ $filenum ] );
501
+ $file_name = end( $file_name );
502
+
503
+ $search_results = $this->scan_file( $file_data[ $filenum ], $scan_data->search, $file_data[ $filenum ], $scan_data->scan_path->type, '' );
504
+
505
+ $response['last_file'] = $file_data[ $filenum ];
506
+ $response['filenum'] = $filenum;
507
+ $response['filename'] = $file_name;
508
+ $response['search'][] = $search_results;
509
+
510
+ if ( $next_chunk != $chunk ) {
511
+ $file_data = unserialize( get_option( 'string-locator-search-files-' . $next_chunk ) );
512
+ }
513
+
514
+ $response['next_file'] = ( isset( $file_data[ $next_file ] ) ? $file_data[ $next_file ] : '' );
515
+
516
+ if ( ! empty( $search_results ) ) {
517
+ $history = maybe_unserialize( get_option( 'string-locator-search-history', array() ) );
518
+ $history = array_merge( $history, $search_results );
519
+ update_option( 'string-locator-search-history', serialize( $history ), false );
520
+ }
521
+
522
+ $_POST['filenum']++;
523
+ }
524
+
525
+ wp_send_json_success( $response );
526
+ }
527
+
528
+ /**
529
+ * Clean up our options used to help during the search
530
+ *
531
+ * @uses check_ajax_referer()
532
+ * @uses wp_send_json_error()
533
+ * @uses get_option()
534
+ * @uses delete_option()
535
+ * @uses wp_send_json_success()
536
+ *
537
+ * @return void
538
+ */
539
+ function ajax_clean_search() {
540
+ if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) { wp_send_json_error( __( 'Authentication failed', 'string-locator' ) ); }
541
+
542
+ $scan_data = unserialize( get_option( 'string-locator-search-overview' ) );
543
+ for( $i = 0; $i < $scan_data->chunks; $i++ ) {
544
+ delete_option( 'string-locator-search-files-' . $i );
545
+ }
546
+
547
+ wp_send_json_success( true );
548
+ }
549
+
550
+ /**
551
+ * Create a table row for insertion into the search results list
552
+ *
553
+ * @uses esc_url()
554
+ * @uses esc_html()
555
+ *
556
+ * @param array|object $item The table row item
557
+ *
558
+ * @return string
559
+ */
560
+ function prepare_table_row( $item ) {
561
+ if ( ! is_object( $item ) ) {
562
+ $item = (object) $item;
563
+ }
564
+
565
+ return sprintf(
566
+ '<tr>
567
+ <td>%1$s<div class="row-actions"><span class="edit"><a href="%2$s" aria-label="Edit">Edit</a></span></div></td>
568
+ <td><a href="%2$s">%3$s</a></td>
569
+ <td>%4$d</td>
570
+ </tr>',
571
+ $item->stringresult,
572
+ esc_url( $item->editurl ),
573
+ esc_html( $item->filename_raw ),
574
+ esc_html( $item->linenum )
575
+ );
576
+ }
577
+
578
+ /**
579
+ * Create a full table populated with the supplied items
580
+ *
581
+ * @uses esc_html()
582
+ * @uses __()
583
+ *
584
+ * @param array $items An array of table rows
585
+ * @param array $table_class An array of items to append to the table class along with the defaults
586
+ *
587
+ * @return string
588
+ */
589
+ function prepare_full_table( $items, $table_class = array() ) {
590
+ $table_class = array_merge( $table_class, array(
591
+ 'wp-list-table',
592
+ 'widefat',
593
+ 'fixed',
594
+ 'striped',
595
+ 'tools_page_string-locator'
596
+ ) );
597
+
598
+ $table_columns = sprintf(
599
+ '<tr>
600
+ <th scope="col" class="manage-column column-stringresult column-primary">%s</th>
601
+ <th scope="col" class="manage-column column-filename">%s</th>
602
+ <th scope="col" class="manage-column column-linenum">%s</th>
603
+ </tr>',
604
+ esc_html( __( 'String', 'string-locator' ) ),
605
+ esc_html( __( 'File', 'string-locator' ) ),
606
+ esc_html( __( 'Line number', 'string-locator' ) )
607
+ );
608
+
609
+ $table_rows = array();
610
+ foreach( $items AS $item ) {
611
+ $table_rows[] = $this->prepare_table_row( $item );
612
+ }
613
+
614
+ $table = sprintf(
615
+ '<div class="tablenav top"><br class="clear"></div><table class="%s"><thead>%s</thead><tbody>%s</tbody><tfoot>%s</tfoot></table>',
616
+ implode( ' ', $table_class ),
617
+ $table_columns,
618
+ implode( "\n", $table_rows ),
619
+ $table_columns
620
+ );
621
+
622
+ return $table;
623
+ }
624
+
625
+ /**
626
+ * Create an admin edit link for the supplied path
627
+ *
628
+ * @uses absint()
629
+ * @uses admin_url()
630
+ *
631
+ * @param string $path
632
+ * @param int $line
633
+ *
634
+ * @return string
635
+ */
636
+ function create_edit_link( $path, $line = 0 ) {
637
+ $file_type = 'core';
638
+ $file_slug = '';
639
+ $content_path = str_replace( '\\', '/', WP_CONTENT_DIR );
640
+
641
+ $path = str_replace( '\\', '/', $path );
642
+ $paths = explode( '/', $path );
643
+
644
+ $url_args = array(
645
+ 'page=string-locator',
646
+ 'edit-file=' . end( $paths )
647
+ );
648
+
649
+ switch ( true ) {
650
+ case ( in_array( 'wp-content', $paths ) && in_array( 'plugins', $paths ) ) :
651
+ $file_type = 'plugin';
652
+ $content_path .= '/plugins/';
653
+ break;
654
+ case ( in_array( 'wp-content', $paths ) && in_array( 'themes', $paths ) ) :
655
+ $file_type = 'theme';
656
+ $content_path .= '/themes/';
657
+ break;
658
+ }
659
+
660
+ $rel_path = str_replace( $content_path, '', $path );
661
+ $rel_paths = explode( '/', $rel_path );
662
+
663
+ if ( 'core' != $file_type ) {
664
+ $file_slug = $rel_paths[0];
665
+ }
666
+
667
+ $url_args[] = 'file-reference=' . $file_slug;
668
+ $url_args[] = 'file-type=' . $file_type;
669
+ $url_args[] = 'string-locator-line=' . absint( $line );
670
+ $url_args[] = 'string-locator-path=' . urlencode( str_replace( '/', DIRECTORY_SEPARATOR, $path ) );
671
+
672
+ $url = admin_url( $this->path_to_use . '?' . implode( '&', $url_args ) );
673
+
674
+ return $url;
675
+ }
676
+
677
+ /**
678
+ * Parse the search option to determine what kind of search we are performing and what directory to start in
679
+ *
680
+ * @param $option
681
+ *
682
+ * @return bool|object
683
+ */
684
+ function prepare_scan_path( $option ) {
685
+ $data = array(
686
+ 'path' => '',
687
+ 'type' => '',
688
+ 'slug' => ''
689
+ );
690
+
691
+ switch ( true ) {
692
+ case ( 't--' == $option ):
693
+ $data['path'] = WP_CONTENT_DIR . '/themes/';
694
+ $data['type'] = 'theme';
695
+ break;
696
+ case ( strlen( $option ) > 3 && 't-' == substr( $option, 0, 2 ) ):
697
+ $data['path'] = WP_CONTENT_DIR . '/themes/' . substr( $option, 2 );
698
+ $data['type'] = 'theme';
699
+ $data['slug'] = substr( $option, 2 );
700
+ break;
701
+ case ( 'p--' == $option ):
702
+ $data['path'] = WP_CONTENT_DIR . '/plugins/';
703
+ $data['type'] = 'plugin';
704
+ break;
705
+ case ( strlen( $option ) > 3 && 'p-' == substr( $option, 0, 2 ) ):
706
+ $slug = explode( '/', substr( $option, 2 ) );
707
+
708
+ $data['path'] = WP_CONTENT_DIR . '/plugins/' . $slug[0];
709
+ $data['type'] = 'plugin';
710
+ $data['slug'] = $slug[0];
711
+ break;
712
+ case ( 'core' == $option ):
713
+ $data['path'] = ABSPATH;
714
+ $data['type'] = 'core';
715
+ break;
716
+ case ( 'wp-content' == $option ):
717
+ $data['path'] = WP_CONTENT_DIR;
718
+ $data['type'] = 'core';
719
+ break;
720
+ }
721
+
722
+ if ( empty( $data['path'] ) ) {
723
+ return false;
724
+ }
725
+
726
+ return (object) $data;
727
+ }
728
+
729
+ /**
730
+ * Check if a file path is valid for editing
731
+ *
732
+ * @param string $path Path to file
733
+ * @return bool
734
+ */
735
+ function is_valid_location( $path ) {
736
+ $valid = true;
737
+ $path = str_replace( array( '/' ), array( DIRECTORY_SEPARATOR ), stripslashes( $path ) );
738
+ $abspath = str_replace( array( '/' ), array( DIRECTORY_SEPARATOR ), ABSPATH );
739
+
740
+ if ( empty( $path ) ) {
741
+ $valid = false;
742
+ }
743
+ if ( stristr( $path, '..' ) ) {
744
+ $valid = false;
745
+ }
746
+ if ( ! stristr( $path, $abspath ) ) {
747
+ $valid = false;
748
+ }
749
+
750
+ return $valid;
751
+ }
752
+
753
+ /**
754
+ * Set the text domain for translated plugin content
755
+ *
756
+ * @uses load_plugin_textdomain()
757
+ *
758
+ * @return void
759
+ */
760
+ function load_i18n() {
761
+ $i18n_dir = 'string-locator/languages/';
762
+ load_plugin_textdomain( 'string-locator', false, $i18n_dir );
763
+ }
764
+
765
+ /**
766
+ * Load up JavaScript and CSS for our plugin on the appropriate admin pages
767
+ *
768
+ * @uses wp_register_style()
769
+ * @uses plugin_dir_url()
770
+ * @uses wp_register_script()
771
+ * @uses admin_url()
772
+ * @uses wp_create_nonce()
773
+ * @uses wp_enqueue_style()
774
+ * @uses wp_enqueue_script()
775
+ * @uses wp_localize_script()
776
+ *
777
+ * @return void
778
+ */
779
+ function admin_enqueue_scripts( $hook ) {
780
+ // Break out early if we are not on a String Locator page
781
+ if ( 'tools_page_string-locator' != $hook && 'toplevel_page_string-locator' != $hook ) {
782
+ return;
783
+ }
784
+
785
+ /**
786
+ * String Locator Styles
787
+ */
788
+ wp_register_style( 'string-locator', plugin_dir_url( __FILE__ ) . '/resources/css/string-locator.css', array(), $this->version );
789
+
790
+ /**
791
+ * String Locator Scripts
792
+ */
793
+ wp_register_script( 'string-locator-search', plugin_dir_url( __FILE__ ) . '/resources/js/string-locator-search.js', array( 'jquery' ), $this->version );
794
+
795
+ if ( isset( $_GET['edit-file'] )) {
796
+ $filename = explode( '.', $_GET['edit-file'] );
797
+ $filext = end( $filename );
798
+ switch( $filext ) {
799
+ case 'js':
800
+ $this->string_locator_language = 'javascript';
801
+ break;
802
+ case 'php':
803
+ $this->string_locator_language = 'application/x-httpd-php';
804
+ break;
805
+ case 'css':
806
+ $this->string_locator_language = 'css';
807
+ break;
808
+ default:
809
+ $this->string_locator_language = 'htmlmixed';
810
+ }
811
+
812
+ /**
813
+ * CodeMirror Styles
814
+ */
815
+ wp_register_style( 'codemirror', plugin_dir_url( __FILE__ ) . '/resources/css/codemirror.css', array( 'codemirror-lint' ), $this->version );
816
+ wp_register_style( 'codemirror-twilight', plugin_dir_url( __FILE__ ) . '/resources/css/codemirror/twilight.css', array( 'codemirror' ), $this->version );
817
+ wp_register_style( 'codemirror-lint', plugin_dir_url( __FILE__ ) . '/resources/js/codemirror/addon/lint/lint.css', array(), $this->version );
818
+
819
+ /**
820
+ * CodeMirror Scripts
821
+ */
822
+ wp_register_script( 'codemirror-addon-edit-closebrackets', $this->plugin_url . '/resources/js/codemirror/addon/edit/closebrackets.js', array( 'codemirror' ), $this->version, true );
823
+ wp_register_script( 'codemirror-addon-edit-matchbrackets', $this->plugin_url . '/resources/js/codemirror/addon/edit/matchbrackets.js', array( 'codemirror' ), $this->version, true );
824
+ wp_register_script( 'codemirror-addon-selection-active-line', $this->plugin_url . '/resources/js/codemirror/addon/selection/active-line.js', array( 'codemirror' ), $this->version, true );
825
+
826
+ wp_register_script( 'codemirror-addon-lint-css', $this->plugin_url . '/resources/js/codemirror/addon/lint/lint.js', array( 'codemirror' ), $this->version, true );
827
+
828
+ wp_register_script( 'codemirror-mode-javascript', $this->plugin_url . '/resources/js/codemirror/mode/javascript/javascript.js', array( 'codemirror' ), $this->version, true );
829
+ wp_register_script( 'codemirror-mode-htmlmixed', $this->plugin_url . '/resources/js/codemirror/mode/htmlmixed/htmlmixed.js', array( 'codemirror' ), $this->version, true );
830
+ wp_register_script( 'codemirror-mode-clike', $this->plugin_url . '/resources/js/codemirror/mode/clike/clike.js', array( 'codemirror' ), $this->version, true );
831
+ wp_register_script( 'codemirror-mode-xml', $this->plugin_url . '/resources/js/codemirror/mode/xml/xml.js', array( 'codemirror' ), $this->version, true );
832
+ wp_register_script( 'codemirror-mode-css', $this->plugin_url . '/resources/js/codemirror/mode/css/css.js', array( 'codemirror' ), $this->version, true );
833
+ wp_register_script( 'codemirror-mode-php', $this->plugin_url . '/resources/js/codemirror/mode/php/php.js', array( 'codemirror' ), $this->version, true );
834
+ wp_register_script( 'codemirror', $this->plugin_url . '/resources/js/codemirror/lib/codemirror.js', array(), $this->version, true );
835
+
836
+ /**
837
+ * String Locator Scripts
838
+ */
839
+ wp_register_script( 'string-locator-editor', $this->plugin_url . '/resources/js/string-locator.js', array( 'codemirror' ), $this->version, true );
840
+
841
+ /**
842
+ * CodeMirror Enqueue
843
+ */
844
+ wp_enqueue_style( 'codemirror-twilight' );
845
+
846
+ wp_enqueue_script( 'codemirror-addon-edit-closebrackets' );
847
+ wp_enqueue_script( 'codemirror-addon-edit-matchbrackets' );
848
+ wp_enqueue_script( 'codemirror-addon-selection-active-line' );
849
+ wp_enqueue_script( 'codemirror-addon-lint' );
850
+
851
+ wp_enqueue_script( 'codemirror-mode-javascript' );
852
+ wp_enqueue_script( 'codemirror-mode-htmlmixed' );
853
+ wp_enqueue_script( 'codemirror-mode-clike' );
854
+ wp_enqueue_script( 'codemirror-mode-xml' );
855
+ wp_enqueue_script( 'codemirror-mode-css' );
856
+ wp_enqueue_script( 'codemirror-mode-php' );
857
+
858
+ /**
859
+ * String Locator Enqueue
860
+ */
861
+ wp_enqueue_script( 'string-locator-editor' );
862
+ }
863
+
864
+ /**
865
+ * String Locator Enqueue
866
+ */
867
+ wp_enqueue_style( 'string-locator' );
868
+
869
+ wp_enqueue_script( 'string-locator-search' );
870
+ wp_localize_script( 'string-locator-search', 'string_locator', array(
871
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
872
+ 'search_nonce' => wp_create_nonce( 'string-locator-search' ),
873
+ 'saving_results_string' => __( 'Saving search results&hellip;', 'string-locator' ),
874
+ 'search_preparing' => __( 'Preparing search&hellip;', 'string-locator' ),
875
+ 'search_started' => __( 'Preparations completed, search started&hellip;', 'string-locator' ),
876
+ 'search_error' => __( 'The above error was returned by your server, for more details please consult your servers error logs.', 'string-locator' ),
877
+ 'search_no_results' => __( 'Your search was completed, but no results were found..', 'string-locator' ),
878
+ 'warning_title' => __( 'Warning', 'string-locator' )
879
+ ) );
880
+ }
881
+
882
+ /**
883
+ * Add our plugin to the 'Tools' menu.
884
+ *
885
+ * @uses is_multisite()
886
+ * @uses __()
887
+ * @uses add_submenu_page()
888
+ *
889
+ * @return void
890
+ */
891
+ function populate_menu()
892
+ {
893
+ if ( is_multisite() ) {
894
+ return;
895
+ }
896
+ $page_title = __( 'String Locator', 'string-locator' );
897
+ $menu_title = __( 'String Locator', 'string-locator' );
898
+ $capability = 'edit_themes';
899
+ $parent_slug = 'tools.php';
900
+ $menu_slug = 'string-locator';
901
+ $function = array( $this, 'options_page' );
902
+
903
+ add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
904
+ }
905
+
906
+ /**
907
+ * Add our plugin to the top level menu in multisite.
908
+ *
909
+ * @uses __()
910
+ * @uses add_menu_page()
911
+ *
912
+ * @return void
913
+ */
914
+ function populate_network_menu()
915
+ {
916
+ $page_title = __( 'String Locator', 'string-locator' );
917
+ $menu_title = __( 'String Locator', 'string-locator' );
918
+ $capability = 'edit_themes';
919
+ $menu_slug = 'string-locator';
920
+ $function = array( $this, 'options_page' );
921
+
922
+ add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, 'dashicons-edit' );
923
+ }
924
+
925
+ /**
926
+ * Function for including the actual plugin Admin UI page.
927
+ *
928
+ * @uses current_user_can()
929
+ * @uses String_Locator::is_valid_location()
930
+ *
931
+ * @return void
932
+ */
933
+ function options_page()
934
+ {
935
+ /*
936
+ * Don't load anything if the user can't edit themes any way
937
+ */
938
+ if ( ! current_user_can( 'edit_themes' ) ) {
939
+ return;
940
+ }
941
+
942
+ /*
943
+ * Show the edit page if;
944
+ * - The edit file path query var is set
945
+ * - The edit file path query var isn't empty
946
+ * - The edit file path query var does not contains double dots (used to traverse directories)
947
+ */
948
+ if ( isset( $_GET['string-locator-path'] ) && $this->is_valid_location( $_GET['string-locator-path'] ) ) {
949
+ include_once( dirname( __FILE__ ) . '/editor.php' );
950
+ }
951
+ else {
952
+ include_once( dirname( __FILE__ ) . '/options.php' );
953
+ }
954
+ }
955
+
956
+ /**
957
+ * Check for mismatching start and end parameters (such as opening and closing parenthesis).
958
+ *
959
+ * @param string $start Start delimited
960
+ * @param string $end End delimiter
961
+ * @param string $string The string to scan
962
+ *
963
+ * @return array
964
+ */
965
+ function SmartScan( $start, $end, $string ) {
966
+ $opened = array();
967
+
968
+ $lines = explode( "\n", $string );
969
+ for ( $i = 0; $i < count( $lines ); $i++ ) {
970
+ if ( stristr( $lines[$i], $start ) ) {
971
+ $opened[] = $i;
972
+ }
973
+ if ( stristr( $lines[$i], $end ) ) {
974
+ array_pop( $opened );
975
+ }
976
+ }
977
+
978
+ return $opened;
979
+ }
980
+
981
+ /**
982
+ * Handler for storing the content of the code editor.
983
+ * This is also when we invoke the Smart-Scan if enabled.
984
+ *
985
+ * @uses check_admin_referer()
986
+ * @uses current_user_can()
987
+ * @uses String_Locator::SmartScan()
988
+ * @uses __()
989
+ * @uses String_Locator::write_file()
990
+ * @uses wp_remote_head()
991
+ *
992
+ * @return void
993
+ */
994
+ function editor_save() {
995
+ if ( isset( $_POST['string-locator-editor-content'] ) && check_admin_referer( 'string-locator-edit_' . $_GET['edit-file'] ) && current_user_can( 'edit_themes' ) ) {
996
+
997
+ if ( $this->is_valid_location( $_GET['string-locator-path'] ) ) {
998
+ $path = urldecode( $_GET['string-locator-path'] );
999
+ $content = stripslashes( $_POST['string-locator-editor-content'] );
1000
+
1001
+ /*
1002
+ * Send an error notice if the file isn't writable
1003
+ */
1004
+ if ( ! is_writeable( $path ) ) {
1005
+ $this->notice[] = array(
1006
+ 'type' => 'error',
1007
+ 'message' => __( 'The file could not be written to, please check file permissions or edit it manually.', 'string-locator' )
1008
+ );
1009
+ $this->failed_edit = true;
1010
+ return;
1011
+ }
1012
+
1013
+ /*
1014
+ * If enabled, run the Smart-Scan on the content before saving it
1015
+ */
1016
+ if ( isset( $_POST['string-locator-smart-edit'] ) ) {
1017
+ $open_brace = substr_count( $content, '{' );
1018
+ $close_brace = substr_count( $content, '}' );
1019
+ if ( $open_brace != $close_brace ) {
1020
+ $this->failed_edit = true;
1021
+
1022
+ $opened = $this->SmartScan( '{', '}', $content );
1023
+
1024
+ foreach( $opened AS $line ) {
1025
+ $this->notice[] = array(
1026
+ 'type' => 'error',
1027
+ 'message' => sprintf(
1028
+ __( 'There is an inconsistency in the opening and closing braces, { and }, of your file on line %s', 'string-locator' ),
1029
+ '<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
1030
+ )
1031
+ );
1032
+ }
1033
+ }
1034
+
1035
+ $open_bracket = substr_count( $content, '[' );
1036
+ $close_bracket = substr_count( $content, ']' );
1037
+ if ( $open_bracket != $close_bracket ) {
1038
+ $this->failed_edit = true;
1039
+
1040
+ $opened = $this->SmartScan( '[', ']', $content );
1041
+
1042
+ foreach( $opened AS $line ) {
1043
+ $this->notice[] = array(
1044
+ 'type' => 'error',
1045
+ 'message' => sprintf(
1046
+ __( 'There is an inconsistency in the opening and closing braces, [ and ], of your file on line %s', 'string-locator' ),
1047
+ '<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
1048
+ )
1049
+ );
1050
+ }
1051
+ }
1052
+
1053
+ $open_parenthesis = substr_count( $content, '(' );
1054
+ $close_parenthesis = substr_count( $content, ')' );
1055
+ if ( $open_parenthesis != $close_parenthesis ) {
1056
+ $this->failed_edit = true;
1057
+
1058
+ $opened = $this->SmartScan( '(', ')', $content );
1059
+
1060
+ foreach( $opened AS $line ) {
1061
+ $this->notice[] = array(
1062
+ 'type' => 'error',
1063
+ 'message' => sprintf(
1064
+ __( 'There is an inconsistency in the opening and closing braces, ( and ), of your file on line %s', 'string-locator' ),
1065
+ '<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
1066
+ )
1067
+ );
1068
+ }
1069
+ }
1070
+
1071
+ if ( $this->failed_edit ) {
1072
+ return;
1073
+ }
1074
+ }
1075
+
1076
+ $original = file_get_contents( $path );
1077
+
1078
+ if ( isset( $_POST['string-locator-make-child-theme'] ) ) {
1079
+ $child_theme = $this->create_child_theme( $_GET['file-reference'] );
1080
+ }
1081
+
1082
+ $this->write_file( $path, $content );
1083
+
1084
+ /*
1085
+ * Check the status of the site after making our edits.
1086
+ * If the site fails, revert the changes to return the sites to its original state
1087
+ */
1088
+ $header = wp_remote_head( site_url() );
1089
+ if ( 301 == $header['response']['code'] ) {
1090
+ $header = wp_remote_head( $header['headers']['location'] );
1091
+ }
1092
+
1093
+ if ( in_array( $header['response']['code'], $this->bad_http_codes ) ) {
1094
+ $this->failed_edit = true;
1095
+ $this->write_file( $path, $original );
1096
+
1097
+ $this->notice[] = array(
1098
+ 'type' => 'error',
1099
+ 'message' => __( 'A 500 server error was detected on your site after updating your file. We have restored the previous version of the file for you.', 'string-locator' )
1100
+ );
1101
+ }
1102
+ else {
1103
+ $this->notice[] = array(
1104
+ 'type' => 'updated',
1105
+ 'message' => __( 'The file has been saved', 'string-locator' )
1106
+ );
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ private function create_child_theme( $theme ) {
1113
+ $child_theme = sprintf( '%s/%s-child', get_theme_root(), $theme );
1114
+ mkdir( $child_theme );
1115
+
1116
+ touch( $child_theme . '/functions.php' );
1117
+ touch( $child_theme . '/style.css' );
1118
+
1119
+ return $child_theme;
1120
+ }
1121
+
1122
+ /**
1123
+ * When editing a file, this is where we write all the new content.
1124
+ *
1125
+ * We will break early if the user isn't allowed to edit files
1126
+ *
1127
+ * @uses current_user_can()
1128
+ * @uses apply_filters()
1129
+ * @uses __()
1130
+ *
1131
+ * @param string $path - The path to the file
1132
+ * @param string $content - The content to write to the file
1133
+ *
1134
+ * @return void
1135
+ */
1136
+ private function write_file( $path, $content ) {
1137
+ if ( ! current_user_can( 'edit_themes' ) ) {
1138
+ return;
1139
+ }
1140
+
1141
+ if ( apply_filters( 'string-locator-filter-closing-php-tags', true ) ) {
1142
+ $content = preg_replace( "/\?>$/si", '', trim( $content ), -1, $replaced_strings );
1143
+
1144
+ if ( $replaced_strings >= 1 ) {
1145
+ $this->notice[] = array(
1146
+ 'type' => 'error',
1147
+ 'message' => __( 'We detected a PHP code tag ending, this has been automatically stripped out to help prevent errors in your code.', 'string-locator' )
1148
+ );
1149
+ }
1150
+ }
1151
+
1152
+ $file = fopen( $path, "w" );
1153
+ $lines = explode( "\n", str_replace( array( "\r\n", "\r" ), "\n", $content ) );
1154
+ $total_lines = count( $lines );
1155
+
1156
+ for( $i = 0; $i < $total_lines; $i++ ) {
1157
+ $write_line = $lines[ $i ];
1158
+
1159
+ if ( ( $i + 1 ) < $total_lines ) {
1160
+ $write_line .= PHP_EOL;
1161
+ }
1162
+
1163
+ fwrite( $file, $write_line );
1164
+ }
1165
+
1166
+ fclose( $file );
1167
+ }
1168
+
1169
+ /**
1170
+ * Hook the admin notices and loop over any notices we've registered in the plugin.
1171
+ *
1172
+ * @uses esc_attr()
1173
+ * @uses esc_html()
1174
+ *
1175
+ * @return void
1176
+ */
1177
+ function admin_notice() {
1178
+ if ( ! empty( $this->notice ) ) {
1179
+ foreach( $this->notice AS $note ) {
1180
+ printf(
1181
+ '<div class="%s"><p>%s</p></div>',
1182
+ esc_attr( $note['type'] ),
1183
+ esc_html( $note['message'] )
1184
+ );
1185
+ }
1186
+ }
1187
+ }
1188
+
1189
+ /**
1190
+ * Scan through an individual file to look for occurrences of £string
1191
+ *
1192
+ * @uses esc_url()
1193
+ * @uses esc_html()
1194
+ * @uses String_Locator::create_edit_link()
1195
+ *
1196
+ * @param string $filename - The path to the file
1197
+ * @param string $string - The search string
1198
+ * @param mixed $location - The file location object/string
1199
+ * @param string $type - File type
1200
+ * @param string $slug - The plugin/theme slug of the file
1201
+ *
1202
+ * @return string
1203
+ */
1204
+ function scan_file( $filename, $string, $location, $type, $slug ) {
1205
+ if ( empty( $string ) || ! is_file( $filename ) ) {
1206
+ return false;
1207
+ }
1208
+ $output = array();
1209
+ $linenum = 0;
1210
+ $match_count = 0;
1211
+
1212
+ if ( ! is_object( $location ) ) {
1213
+ $path = $location;
1214
+ $location = explode( DIRECTORY_SEPARATOR, $location );
1215
+ $file = end( $location );
1216
+ }
1217
+ else {
1218
+ $path = $location->getPathname();
1219
+ $file = $location->getFilename();
1220
+ }
1221
+
1222
+ /*
1223
+ * Check if the filename matches our search pattern
1224
+ */
1225
+ if ( stristr( $file, $string ) ) {
1226
+ $relativepath = str_replace( array( ABSPATH, '\\', '/' ), array( '', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR ), $path );
1227
+ $match_count++;
1228
+
1229
+ $editurl = $this->create_edit_link( $path, $linenum );
1230
+
1231
+ $path_string = sprintf(
1232
+ '<a href="%s">%s</a>',
1233
+ esc_url( $editurl ),
1234
+ esc_html( $relativepath )
1235
+ );
1236
+
1237
+ $output[] = array(
1238
+ 'ID' => $match_count,
1239
+ 'linenum' => 0,
1240
+ 'path' => $path,
1241
+ 'filename' => $path_string,
1242
+ 'filename_raw' => $relativepath,
1243
+ 'editurl' => $editurl,
1244
+ 'stringresult' => $file
1245
+ );
1246
+ }
1247
+
1248
+ $readfile = @fopen( $filename, "r" );
1249
+ if ( $readfile )
1250
+ {
1251
+ while ( ( $readline = fgets( $readfile ) ) !== false )
1252
+ {
1253
+ $string_preview_is_cut = false;
1254
+ $linenum++;
1255
+
1256
+ /*
1257
+ * If our string is found in this line, output the line number and other data
1258
+ */
1259
+ if ( stristr( $readline, $string ) )
1260
+ {
1261
+ /*
1262
+ * Prepare the visual path for the end user
1263
+ * Removes path leading up to WordPress root and ensures consistent directory separators
1264
+ */
1265
+ $relativepath = str_replace( array( ABSPATH, '\\', '/' ), array( '', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR ), $path );
1266
+ $match_count++;
1267
+
1268
+ /*
1269
+ * Create the URL to take the user to the editor
1270
+ */
1271
+ $editurl = $this->create_edit_link( $path, $linenum );
1272
+
1273
+ $string_preview = $readline;
1274
+ if ( strlen( $string_preview ) > 100 ) {
1275
+ $string_location = strpos( $string_preview, $string );
1276
+
1277
+ $string_location_start = $string_location - $this->excerpt_length;
1278
+ if ( $string_location_start < 0 ) {
1279
+ $string_location_start = 0;
1280
+ }
1281
+
1282
+ $string_location_end = $string_location + strlen( $string ) + $this->excerpt_length;
1283
+ if ( $string_location_end > strlen( $string_preview ) ) {
1284
+ $string_location_end = strlen( $string_preview );
1285
+ }
1286
+
1287
+ $string_preview = substr( $string_preview, $string_location_start, $string_location_end );
1288
+ $string_preview_is_cut = true;
1289
+ }
1290
+
1291
+ $string_preview = str_ireplace( $string, '<strong>' . $string . '</strong>', esc_html( $string_preview ) );
1292
+ if ( $string_preview_is_cut ) {
1293
+ $string_preview = sprintf(
1294
+ '&hellip;%s&hellip;',
1295
+ $string_preview
1296
+ );
1297
+ }
1298
+
1299
+ $path_string = sprintf(
1300
+ '<a href="%s">%s</a>',
1301
+ esc_url( $editurl ),
1302
+ esc_html( $relativepath )
1303
+ );
1304
+
1305
+ $output[] = array(
1306
+ 'ID' => $match_count,
1307
+ 'linenum' => $linenum,
1308
+ 'path' => $path,
1309
+ 'filename' => $path_string,
1310
+ 'filename_raw' => $relativepath,
1311
+ 'editurl' => $editurl,
1312
+ 'stringresult' => $string_preview
1313
+ );
1314
+ }
1315
+ }
1316
+
1317
+ fclose( $readfile );
1318
+ }
1319
+ else {
1320
+ /*
1321
+ * The file was unreadable, give the user a friendly notification
1322
+ */
1323
+ $output[] = array(
1324
+ 'linenum' => '#',
1325
+ 'filename' => esc_html( sprintf( __( 'Could not read file: %s', 'string-locator' ), $filename ) ),
1326
+ 'stringresult' => ''
1327
+ );
1328
+ }
1329
+
1330
+ return $output;
1331
+ }
1332
+
1333
+ /**
1334
+ * Get a list of files inside a path.
1335
+ *
1336
+ * @param string $path
1337
+ *
1338
+ * @return array
1339
+ */
1340
+ function ajax_scan_path( $path ) {
1341
+ $files = array();
1342
+
1343
+ $paths = new RecursiveIteratorIterator(
1344
+ new RecursiveDirectoryIterator( $path ),
1345
+ RecursiveIteratorIterator::SELF_FIRST
1346
+ );
1347
+
1348
+ foreach ( $paths AS $name => $location ) {
1349
+ if ( is_dir( $location->getPathname() ) ) {
1350
+ continue;
1351
+ }
1352
+
1353
+ $files[] = $location->getPathname();
1354
+ }
1355
+
1356
+ return $files;
1357
+ }
1358
+ }
1359
+
1360
+ /**
1361
+ * Instantiate the plugin
1362
+ */
1363
+ $string_locator = new string_locator();
uninstall.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ //if uninstall not called from WordPress exit
3
+ if ( !defined( 'WP_UNINSTALL_PLUGIN' ) )
4
+ exit();
5
+
6
+ delete_option( 'string-locator-results' );