Version Description
- Added support for HHVM
- Improved inline documentation
Download this release
Release Info
Developer | Clorith |
Plugin | String locator |
Version | 2.0.3 |
Comparing to | |
See all releases |
Version 2.0.3
- LICENSE +339 -0
- changelog.txt +75 -0
- editor.php +197 -0
- languages/string-locator-de_DE.mo +0 -0
- languages/string-locator-de_DE.po +198 -0
- languages/string-locator-es.ES.mo +0 -0
- languages/string-locator-es.ES.po +182 -0
- languages/string-locator-nb_NO.mo +0 -0
- languages/string-locator-nb_NO.po +188 -0
- languages/string-locator-sr_RS.mo +0 -0
- languages/string-locator-sr_RS.po +182 -0
- languages/string-locator.pot +158 -0
- options.php +69 -0
- readme.txt +75 -0
- resources/css/codemirror.css +272 -0
- resources/css/codemirror/3024-day.css +34 -0
- resources/css/codemirror/3024-night.css +34 -0
- resources/css/codemirror/ambiance-mobile.css +5 -0
- resources/css/codemirror/ambiance.css +74 -0
- resources/css/codemirror/base16-dark.css +34 -0
- resources/css/codemirror/base16-light.css +34 -0
- resources/css/codemirror/blackboard.css +28 -0
- resources/css/codemirror/cobalt.css +21 -0
- resources/css/codemirror/eclipse.css +23 -0
- resources/css/codemirror/elegant.css +13 -0
- resources/css/codemirror/erlang-dark.css +30 -0
- resources/css/codemirror/lesser-dark.css +43 -0
- resources/css/codemirror/mbo.css +37 -0
- resources/css/codemirror/mdn-like.css +44 -0
- resources/css/codemirror/midnight.css +43 -0
- resources/css/codemirror/monokai.css +29 -0
- resources/css/codemirror/neat.css +12 -0
- resources/css/codemirror/neo.css +40 -0
- resources/css/codemirror/night.css +24 -0
- resources/css/codemirror/paraiso-dark.css +34 -0
- resources/css/codemirror/paraiso-light.css +34 -0
- resources/css/codemirror/pastel-on-dark.css +48 -0
- resources/css/codemirror/rubyblue.css +21 -0
- resources/css/codemirror/solarized.css +167 -0
- resources/css/codemirror/the-matrix.css +26 -0
- resources/css/codemirror/tomorrow-night-eighties.css +34 -0
- resources/css/codemirror/twilight.css +28 -0
- resources/css/codemirror/vibrant-ink.css +30 -0
- resources/css/codemirror/xq-dark.css +49 -0
- resources/css/codemirror/xq-light.css +43 -0
- resources/css/string-locator.css +87 -0
- resources/js/codemirror/addon/comment/comment.js +172 -0
- resources/js/codemirror/addon/comment/continuecomment.js +85 -0
- resources/js/codemirror/addon/dialog/dialog.css +32 -0
- resources/js/codemirror/addon/dialog/dialog.js +133 -0
- resources/js/codemirror/addon/display/fullscreen.css +6 -0
- resources/js/codemirror/addon/display/fullscreen.js +41 -0
- resources/js/codemirror/addon/display/placeholder.js +58 -0
- resources/js/codemirror/addon/display/rulers.js +64 -0
- resources/js/codemirror/addon/edit/closebrackets.js +143 -0
- resources/js/codemirror/addon/edit/closetag.js +141 -0
- resources/js/codemirror/addon/edit/continuelist.js +38 -0
- resources/js/codemirror/addon/edit/matchbrackets.js +120 -0
- resources/js/codemirror/addon/edit/matchtags.js +66 -0
- resources/js/codemirror/addon/edit/trailingspace.js +27 -0
- resources/js/codemirror/addon/fold/brace-fold.js +105 -0
- resources/js/codemirror/addon/fold/comment-fold.js +57 -0
- resources/js/codemirror/addon/fold/foldcode.js +145 -0
- resources/js/codemirror/addon/fold/foldgutter.css +21 -0
- resources/js/codemirror/addon/fold/foldgutter.js +134 -0
- resources/js/codemirror/addon/fold/indent-fold.js +44 -0
- resources/js/codemirror/addon/fold/markdown-fold.js +49 -0
- resources/js/codemirror/addon/fold/xml-fold.js +181 -0
- resources/js/codemirror/addon/hint/anyword-hint.js +42 -0
- resources/js/codemirror/addon/hint/css-hint.js +56 -0
- resources/js/codemirror/addon/hint/html-hint.js +348 -0
- resources/js/codemirror/addon/hint/javascript-hint.js +141 -0
- resources/js/codemirror/addon/hint/python-hint.js +102 -0
- resources/js/codemirror/addon/hint/show-hint.css +38 -0
- resources/js/codemirror/addon/hint/show-hint.js +389 -0
- resources/js/codemirror/addon/hint/sql-hint.js +164 -0
- resources/js/codemirror/addon/hint/xml-hint.js +96 -0
- resources/js/codemirror/addon/lint/coffeescript-lint.js +41 -0
- resources/js/codemirror/addon/lint/css-lint.js +35 -0
- resources/js/codemirror/addon/lint/javascript-lint.js +136 -0
- resources/js/codemirror/addon/lint/json-lint.js +31 -0
- resources/js/codemirror/addon/lint/lint.css +73 -0
- resources/js/codemirror/addon/lint/lint.js +210 -0
- resources/js/codemirror/addon/lint/yaml-lint.js +28 -0
- resources/js/codemirror/addon/merge/merge.css +92 -0
- resources/js/codemirror/addon/merge/merge.js +513 -0
- resources/js/codemirror/addon/mode/loadmode.js +61 -0
- resources/js/codemirror/addon/mode/multiplex.js +118 -0
- resources/js/codemirror/addon/mode/multiplex_test.js +33 -0
- resources/js/codemirror/addon/mode/overlay.js +85 -0
- resources/js/codemirror/addon/runmode/colorize.js +40 -0
- resources/js/codemirror/addon/runmode/runmode-standalone.js +153 -0
- resources/js/codemirror/addon/runmode/runmode.js +72 -0
- resources/js/codemirror/addon/runmode/runmode.node.js +122 -0
- resources/js/codemirror/addon/scroll/scrollpastend.js +46 -0
- resources/js/codemirror/addon/search/match-highlighter.js +104 -0
- resources/js/codemirror/addon/search/search.js +158 -0
- resources/js/codemirror/addon/search/searchcursor.js +189 -0
- resources/js/codemirror/addon/selection/active-line.js +69 -0
- resources/js/codemirror/addon/selection/mark-selection.js +118 -0
- resources/js/codemirror/addon/tern/tern.css +86 -0
- resources/js/codemirror/addon/tern/tern.js +667 -0
- resources/js/codemirror/addon/tern/worker.js +44 -0
- resources/js/codemirror/addon/wrap/hardwrap.js +139 -0
- resources/js/codemirror/lib/codemirror.js +7601 -0
- resources/js/codemirror/mode/clike/clike.js +439 -0
- resources/js/codemirror/mode/css/css.js +717 -0
- resources/js/codemirror/mode/htmlembedded/htmlembedded.js +86 -0
- resources/js/codemirror/mode/htmlmixed/htmlmixed.js +120 -0
- resources/js/codemirror/mode/javascript/javascript.js +663 -0
- resources/js/codemirror/mode/php/php.js +233 -0
- resources/js/codemirror/mode/xml/xml.js +384 -0
- resources/js/string-locator-search.js +137 -0
- resources/js/string-locator.js +34 -0
- string-locator.php +1363 -0
- 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…', '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 \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>— %s —</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>— %s —</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…', 'string-locator' ),
|
874 |
+
'search_preparing' => __( 'Preparing search…', 'string-locator' ),
|
875 |
+
'search_started' => __( 'Preparations completed, search started…', '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 |
+
'…%s…',
|
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' );
|