├── .gitignore
├── LICENSE
├── README.md
├── app
├── css
│ ├── base16-ocean-dark.css
│ ├── codemirror.css
│ ├── dialog.css
│ ├── fonts.css
│ ├── simple-hint.css
│ ├── simplescrollbars.css
│ └── style.css
├── editor.js
├── fileMenu.js
├── helpMenu.js
├── index.html
├── js
│ ├── closetag.js
│ ├── codemirror.js
│ ├── css.js
│ ├── dialog.js
│ ├── foldcode.js
│ ├── formatting.js
│ ├── htmlmixed.js
│ ├── javascript-hint.js
│ ├── javascript.js
│ ├── jquery-3.1.1.min.js
│ ├── loadmode.js
│ ├── match-highlighter.js
│ ├── meta.js
│ ├── overlay.js
│ ├── runmode.js
│ ├── search.js
│ ├── searchcursor.js
│ ├── simple-hint.js
│ ├── simplescrollbars.js
│ └── xml.js
├── lib
│ ├── animate.css
│ ├── anime.min.js
│ ├── bootstrap.min.css
│ ├── bootstrap.min.js
│ ├── font-awesome.min.css
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── fontawesome-webfont.woff2
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ ├── jquery-3.1.1.min.js
│ ├── materialize.js
│ ├── materialize.min.css
│ ├── p5.min.js
│ └── three.min.js
├── main.js
├── package.json
├── scripts.js
├── shortcuts.js
├── styles.js
├── viewMenu.js
└── windowControl.js
├── build
├── icon.icns
├── icon.ico
└── icons
│ ├── 128x128.png
│ ├── 512x512.png
│ └── CB.svg
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | Thumbs.db
4 | *.log
5 | *.autogenerated
6 | /dist
7 | .vscode
8 | /lib
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Abhishek Warokar, Jay Shah
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CodePad
5 | An Offline Front-End Development Playground
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | > **NEW: Save your snippets!**
16 |
17 | __CodePad__ instantly previews your code so you don't have to run back and forth between an editor and a browser. You can also add your favorite icon fonts, libraries and frameworks such as Font Awesome, anime.js and Bootstrap with a click. And the best of it all, everything works offline.
18 |
19 | ## Screenshot 🖼️
20 |
21 | [
](https://thecodepad.github.io)
22 |
23 |
24 | ## Installation 💻
25 |
26 | Download CodePad for Windows [here](https://github.com/Jay9596/CodePad/releases/download/v1.1-beta/CodePad.rar). Extract and run CodePad.exe. Coming Soon for Ubuntu and macOS.
27 |
28 | ## Run From Source 🎩
29 |
30 | You can run the app via command line by following these steps:
31 |
32 | ```
33 | $ git clone https://github.com/thecodepad/codepad.git
34 | $ cd codepad
35 | $ npm install
36 | $ npm start
37 | ```
38 |
39 | > Please note that 'Save' will not work here.
40 |
41 | ## Dev To-Do List 🌈
42 |
43 | - [x] Save the code snippet
44 | - [ ] Resizeable editor
45 | - [ ] Editor themes/appearance settings
46 | - [ ] Preprocessor support
47 | - [ ] Import custom libs
48 | - [ ] View output in fullscreen/browser
49 |
50 | ## Credits 👨
51 |
52 | Designed and developed by: [@apollonian11](https://www.github.com/apollonian11) and [@jay9596](https://www.github.com/jay9596)
53 |
--------------------------------------------------------------------------------
/app/css/base16-ocean-dark.css:
--------------------------------------------------------------------------------
1 | .cm-s-base16-ocean-dark.CodeMirror {background: #2b303b; color: #dfe1e8;}
2 | .cm-s-base16-ocean-dark div.CodeMirror-selected {background: #343d46 !important;}
3 | .cm-s-base16-ocean-dark .CodeMirror-gutters {background: #2b303b; border-right: 0px;}
4 | .cm-s-base16-ocean-dark .CodeMirror-linenumber {color: #65737e;}
5 | .cm-s-base16-ocean-dark .CodeMirror-cursor {border-left: 2px solid #a7adba !important;}
6 |
7 | .cm-s-base16-ocean-dark span.cm-comment {color: #ab7967;}
8 | .cm-s-base16-ocean-dark span.cm-atom {color: #b48ead;}
9 | .cm-s-base16-ocean-dark span.cm-number {color: #b48ead;}
10 |
11 | .cm-s-base16-ocean-dark span.cm-property, .cm-s-base16-ocean-dark span.cm-attribute {color: #a3be8c;}
12 | .cm-s-base16-ocean-dark span.cm-keyword {color: #bf616a;}
13 | .cm-s-base16-ocean-dark span.cm-string {color: #ebcb8b;}
14 |
15 | .cm-s-base16-ocean-dark span.cm-variable {color: #a3be8c;}
16 | .cm-s-base16-ocean-dark span.cm-variable-2 {color: #8fa1b3;}
17 | .cm-s-base16-ocean-dark span.cm-def {color: #d08770;}
18 | .cm-s-base16-ocean-dark span.cm-error {background: rgba(191, 97, 106, 0.3); color: #a7adba;}
19 | .cm-s-base16-ocean-dark span.cm-bracket {color: #dfe1e8;}
20 | .cm-s-base16-ocean-dark span.cm-tag {color: #bf616a;}
21 | .cm-s-base16-ocean-dark span.cm-link {color: #b48ead;}
22 |
23 | .cm-s-base16-ocean-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
--------------------------------------------------------------------------------
/app/css/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | height: 320px;
6 | color: black;
7 | font-size: 14px;
8 | line-height: 24px;
9 | font-family: 'Source Code Pro', 'Roboto Mono', 'Courier New', 'Courier', monospace;
10 | font-weight: 400;
11 | }
12 |
13 |
14 | /* PADDING */
15 |
16 | .CodeMirror-lines {
17 | padding: 4px 0;
18 | /* Vertical padding around content */
19 | }
20 |
21 | .CodeMirror pre {
22 | padding: 0 4px;
23 | /* Horizontal padding of content */
24 | }
25 |
26 | .CodeMirror-scrollbar-filler,
27 | .CodeMirror-gutter-filler {
28 | background-color: white;
29 | /* The little square between H and V scrollbars */
30 | }
31 |
32 |
33 | /* GUTTER */
34 |
35 | .CodeMirror-gutters {
36 | border-right: 1px solid #ddd;
37 | background-color: #f7f7f7;
38 | white-space: nowrap;
39 | }
40 |
41 | .CodeMirror-linenumbers {}
42 |
43 | .CodeMirror-linenumber {
44 | padding: 0 10px 0 10px;
45 | min-width: 20px;
46 | text-align: right;
47 | color: #999;
48 | white-space: nowrap;
49 | }
50 |
51 | .CodeMirror-guttermarker {
52 | color: black;
53 | }
54 |
55 | .CodeMirror-guttermarker-subtle {
56 | color: #999;
57 | }
58 |
59 |
60 | /* CURSOR */
61 |
62 | .CodeMirror-cursor {
63 | border-left: 1px solid black;
64 | border-right: none;
65 | width: 0;
66 | }
67 |
68 |
69 | /* Shown when moving in bi-directional text */
70 |
71 | .CodeMirror div.CodeMirror-secondarycursor {
72 | border-left: 1px solid silver;
73 | }
74 |
75 | .cm-fat-cursor .CodeMirror-cursor {
76 | width: auto;
77 | border: 0 !important;
78 | background: #7e7;
79 | }
80 |
81 | .cm-fat-cursor div.CodeMirror-cursors {
82 | z-index: 1;
83 | }
84 |
85 | .cm-animate-fat-cursor {
86 | width: auto;
87 | border: 0;
88 | -webkit-animation: blink 1.06s steps(1) infinite;
89 | -moz-animation: blink 1.06s steps(1) infinite;
90 | animation: blink 1.06s steps(1) infinite;
91 | background-color: #7e7;
92 | }
93 |
94 | @-moz-keyframes blink {
95 | 0% {}
96 | 50% {
97 | background-color: transparent;
98 | }
99 | 100% {}
100 | }
101 |
102 | @-webkit-keyframes blink {
103 | 0% {}
104 | 50% {
105 | background-color: transparent;
106 | }
107 | 100% {}
108 | }
109 |
110 | @keyframes blink {
111 | 0% {}
112 | 50% {
113 | background-color: transparent;
114 | }
115 | 100% {}
116 | }
117 |
118 |
119 | /* Can style cursor different in overwrite (non-insert) mode */
120 |
121 | .CodeMirror-overwrite .CodeMirror-cursor {}
122 |
123 | .cm-tab {
124 | display: inline-block;
125 | text-decoration: inherit;
126 | }
127 |
128 | .CodeMirror-rulers {
129 | position: absolute;
130 | left: 0;
131 | right: 0;
132 | top: -50px;
133 | bottom: -20px;
134 | overflow: hidden;
135 | }
136 |
137 | .CodeMirror-ruler {
138 | border-left: 1px solid #ccc;
139 | top: 0;
140 | bottom: 0;
141 | position: absolute;
142 | }
143 |
144 |
145 | /* DEFAULT THEME */
146 |
147 | .cm-s-default .cm-header {
148 | color: blue;
149 | }
150 |
151 | .cm-s-default .cm-quote {
152 | color: #090;
153 | }
154 |
155 | .cm-negative {
156 | color: #d44;
157 | }
158 |
159 | .cm-positive {
160 | color: #292;
161 | }
162 |
163 | .cm-header,
164 | .cm-strong {
165 | font-weight: bold;
166 | }
167 |
168 | .cm-em {
169 | font-style: italic;
170 | }
171 |
172 | .cm-link {
173 | text-decoration: underline;
174 | }
175 |
176 | .cm-strikethrough {
177 | text-decoration: line-through;
178 | }
179 |
180 | .cm-s-default .cm-keyword {
181 | color: #708;
182 | }
183 |
184 | .cm-s-default .cm-atom {
185 | color: #219;
186 | }
187 |
188 | .cm-s-default .cm-number {
189 | color: #164;
190 | }
191 |
192 | .cm-s-default .cm-def {
193 | color: #00f;
194 | }
195 |
196 | .cm-s-default .cm-variable,
197 | .cm-s-default .cm-punctuation,
198 | .cm-s-default .cm-property,
199 | .cm-s-default .cm-operator {}
200 |
201 | .cm-s-default .cm-variable-2 {
202 | color: #05a;
203 | }
204 |
205 | .cm-s-default .cm-variable-3 {
206 | color: #085;
207 | }
208 |
209 | .cm-s-default .cm-comment {
210 | color: #a50;
211 | }
212 |
213 | .cm-s-default .cm-string {
214 | color: #a11;
215 | }
216 |
217 | .cm-s-default .cm-string-2 {
218 | color: #f50;
219 | }
220 |
221 | .cm-s-default .cm-meta {
222 | color: #555;
223 | }
224 |
225 | .cm-s-default .cm-qualifier {
226 | color: #555;
227 | }
228 |
229 | .cm-s-default .cm-builtin {
230 | color: #30a;
231 | }
232 |
233 | .cm-s-default .cm-bracket {
234 | color: #997;
235 | }
236 |
237 | .cm-s-default .cm-tag {
238 | color: #170;
239 | }
240 |
241 | .cm-s-default .cm-attribute {
242 | color: #00c;
243 | }
244 |
245 | .cm-s-default .cm-hr {
246 | color: #999;
247 | }
248 |
249 | .cm-s-default .cm-link {
250 | color: #00c;
251 | }
252 |
253 | .cm-s-default .cm-error {
254 | color: #f00;
255 | }
256 |
257 | .cm-invalidchar {
258 | color: #f00;
259 | }
260 |
261 | .CodeMirror-composing {
262 | border-bottom: 2px solid;
263 | }
264 |
265 |
266 | /* Default styles for common addons */
267 |
268 | div.CodeMirror span.CodeMirror-matchingbracket {
269 | color: #0f0;
270 | }
271 |
272 | div.CodeMirror span.CodeMirror-nonmatchingbracket {
273 | color: #f22;
274 | }
275 |
276 | .CodeMirror-matchingtag {
277 | background: rgba(255, 150, 0, .3);
278 | }
279 |
280 | .CodeMirror-activeline-background {
281 | background: #e8f2ff;
282 | }
283 |
284 |
285 | /* STOP */
286 |
287 |
288 | /* The rest of this file contains styles related to the mechanics of
289 | the editor. You probably shouldn't touch them. */
290 |
291 | .CodeMirror {
292 | position: relative;
293 | overflow: hidden;
294 | background: white;
295 | }
296 |
297 | .CodeMirror-scroll {
298 | overflow: scroll !important;
299 | /* Things will break if this is overridden */
300 | /* 30px is the magic margin used to hide the element's real scrollbars */
301 | /* See overflow: hidden in .CodeMirror */
302 | margin-bottom: -30px;
303 | margin-right: -30px;
304 | padding-bottom: 30px;
305 | height: 100%;
306 | outline: none;
307 | /* Prevent dragging from highlighting the element */
308 | position: relative;
309 | }
310 |
311 |
312 | /*.CodeMirror-scroll {
313 | height: auto;
314 | overflow-y: hidden;
315 | overflow-x: auto;
316 | }*/
317 |
318 | .CodeMirror-sizer {
319 | position: relative;
320 | border-right: 30px solid transparent;
321 | }
322 |
323 |
324 | /* The fake, visible scrollbars. Used to force redraw during scrolling
325 | before actual scrolling happens, thus preventing shaking and
326 | flickering artifacts. */
327 |
328 | .CodeMirror-vscrollbar,
329 | .CodeMirror-hscrollbar,
330 | .CodeMirror-scrollbar-filler,
331 | .CodeMirror-gutter-filler {
332 | position: absolute;
333 | z-index: 6;
334 | display: none;
335 | }
336 |
337 | .CodeMirror-vscrollbar {
338 | right: 0;
339 | top: 0;
340 | overflow-x: hidden;
341 | overflow-y: scroll;
342 | }
343 |
344 | .CodeMirror-hscrollbar {
345 | bottom: 0;
346 | left: 0;
347 | overflow-y: hidden;
348 | overflow-x: scroll;
349 | }
350 |
351 | .CodeMirror-scrollbar-filler {
352 | right: 0;
353 | bottom: 0;
354 | }
355 |
356 | .CodeMirror-gutter-filler {
357 | left: 0;
358 | bottom: 0;
359 | }
360 |
361 | .CodeMirror-gutters {
362 | position: absolute;
363 | left: 0;
364 | top: 0;
365 | min-height: 100%;
366 | z-index: 3;
367 | }
368 |
369 | .CodeMirror-gutter {
370 | white-space: normal;
371 | height: 100%;
372 | display: inline-block;
373 | vertical-align: top;
374 | margin-bottom: -30px;
375 | }
376 |
377 | .CodeMirror-gutter-wrapper {
378 | position: absolute;
379 | z-index: 4;
380 | background: none !important;
381 | border: none !important;
382 | }
383 |
384 | .CodeMirror-gutter-background {
385 | position: absolute;
386 | top: 0;
387 | bottom: 0;
388 | z-index: 4;
389 | }
390 |
391 | .CodeMirror-gutter-elt {
392 | position: absolute;
393 | cursor: default;
394 | z-index: 4;
395 | }
396 |
397 | .CodeMirror-gutter-wrapper {
398 | -webkit-user-select: none;
399 | -moz-user-select: none;
400 | user-select: none;
401 | }
402 |
403 | .CodeMirror-lines {
404 | cursor: text;
405 | min-height: 1px;
406 | /* prevents collapsing before first draw */
407 | }
408 |
409 | .CodeMirror pre {
410 | /* Reset some styles that the rest of the page might have set */
411 | -moz-border-radius: 0;
412 | -webkit-border-radius: 0;
413 | border-radius: 0;
414 | border-width: 0;
415 | background: transparent;
416 | font-family: inherit;
417 | font-size: inherit;
418 | margin: 0;
419 | white-space: pre;
420 | word-wrap: normal;
421 | line-height: inherit;
422 | color: inherit;
423 | z-index: 2;
424 | position: relative;
425 | overflow: visible;
426 | -webkit-tap-highlight-color: transparent;
427 | -webkit-font-variant-ligatures: contextual;
428 | font-variant-ligatures: contextual;
429 | }
430 |
431 | .CodeMirror-wrap pre {
432 | word-wrap: break-word;
433 | white-space: pre-wrap;
434 | word-break: normal;
435 | }
436 |
437 | .CodeMirror-linebackground {
438 | position: absolute;
439 | left: 0;
440 | right: 0;
441 | top: 0;
442 | bottom: 0;
443 | z-index: 0;
444 | }
445 |
446 | .CodeMirror-linewidget {
447 | position: relative;
448 | z-index: 2;
449 | overflow: auto;
450 | }
451 |
452 | .CodeMirror-widget {}
453 |
454 | .CodeMirror-code {
455 | outline: none;
456 | }
457 |
458 |
459 | /* Force content-box sizing for the elements where we expect it */
460 |
461 | .CodeMirror-scroll,
462 | .CodeMirror-sizer,
463 | .CodeMirror-gutter,
464 | .CodeMirror-gutters,
465 | .CodeMirror-linenumber {
466 | -moz-box-sizing: content-box;
467 | box-sizing: content-box;
468 | }
469 |
470 | .CodeMirror-measure {
471 | position: absolute;
472 | width: 100%;
473 | height: 0;
474 | overflow: hidden;
475 | visibility: hidden;
476 | }
477 |
478 | .CodeMirror-cursor {
479 | position: absolute;
480 | pointer-events: none;
481 | }
482 |
483 | .CodeMirror-measure pre {
484 | position: static;
485 | }
486 |
487 | div.CodeMirror-cursors {
488 | visibility: hidden;
489 | position: relative;
490 | z-index: 3;
491 | }
492 |
493 | div.CodeMirror-dragcursors {
494 | visibility: visible;
495 | }
496 |
497 | .CodeMirror-focused div.CodeMirror-cursors {
498 | visibility: visible;
499 | }
500 |
501 | .CodeMirror-selected {
502 | background: #d9d9d9;
503 | }
504 |
505 | .CodeMirror-focused .CodeMirror-selected {
506 | background: #d7d4f0;
507 | }
508 |
509 | .CodeMirror-crosshair {
510 | cursor: crosshair;
511 | }
512 |
513 | .CodeMirror-line::selection,
514 | .CodeMirror-line>span::selection,
515 | .CodeMirror-line>span>span::selection {
516 | background: #d7d4f0;
517 | }
518 |
519 | .CodeMirror-line::-moz-selection,
520 | .CodeMirror-line>span::-moz-selection,
521 | .CodeMirror-line>span>span::-moz-selection {
522 | background: #d7d4f0;
523 | }
524 |
525 | .cm-searching {
526 | background: #ffa;
527 | background: rgba(255, 255, 0, .4);
528 | }
529 |
530 |
531 | /* Used to force a border model for a node */
532 |
533 | .cm-force-border {
534 | padding-right: .1px;
535 | }
536 |
537 | @media print {
538 | /* Hide the cursor when printing */
539 | .CodeMirror div.CodeMirror-cursors {
540 | visibility: hidden;
541 | }
542 | }
543 |
544 |
545 | /* See issue #2901 */
546 |
547 | .cm-tab-wrap-hack:after {
548 | content: '';
549 | }
550 |
551 |
552 | /* Help users use markselection to safely style text background */
553 |
554 | span.CodeMirror-selectedtext {
555 | background: none;
556 | }
--------------------------------------------------------------------------------
/app/css/dialog.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-dialog {
2 | position: relative;
3 | }
4 |
5 | .CodeMirror-dialog > div {
6 | position: absolute;
7 | top: 0; left: 0; right: 0;
8 | background: white;
9 | border-bottom: 1px solid #eee;
10 | z-index: 15;
11 | padding: .1em .8em;
12 | overflow: hidden;
13 | color: #333;
14 | }
15 |
16 | .CodeMirror-dialog input {
17 | border: none;
18 | outline: none;
19 | background: transparent;
20 | width: 20em;
21 | color: inherit;
22 | font-family: monospace;
23 | }
24 |
--------------------------------------------------------------------------------
/app/css/fonts.css:
--------------------------------------------------------------------------------
1 | /* latin-ext */
2 |
3 | @font-face {
4 | font-family: 'Source Code Pro';
5 | font-style: normal;
6 | font-weight: 400;
7 | src: local('Source Code Pro'), local('SourceCodePro-Regular'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/mrl8jkM18OlOQN8JLgasDy2Q8seG17bfDXYR_jUsrzg.woff2) format('woff2');
8 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
9 | }
10 |
11 |
12 | /* latin */
13 |
14 | @font-face {
15 | font-family: 'Source Code Pro';
16 | font-style: normal;
17 | font-weight: 400;
18 | src: local('Source Code Pro'), local('SourceCodePro-Regular'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/mrl8jkM18OlOQN8JLgasD9V_2ngZ8dMf8fLgjYEouxg.woff2) format('woff2');
19 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
20 | }
21 |
22 |
23 | /* latin-ext */
24 |
25 | @font-face {
26 | font-family: 'Source Code Pro';
27 | font-style: normal;
28 | font-weight: 500;
29 | src: local('Source Code Pro Medium'), local('SourceCodePro-Medium'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqWPwYXaUNREbAUyQ5RuiVI0.woff2) format('woff2');
30 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
31 | }
32 |
33 |
34 | /* latin */
35 |
36 | @font-face {
37 | font-family: 'Source Code Pro';
38 | font-style: normal;
39 | font-weight: 500;
40 | src: local('Source Code Pro Medium'), local('SourceCodePro-Medium'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqUHj7CJK1I4bLnYZkMY-kd4.woff2) format('woff2');
41 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
42 | }
43 |
44 |
45 | /* latin-ext */
46 |
47 | @font-face {
48 | font-family: 'Source Code Pro';
49 | font-style: normal;
50 | font-weight: 600;
51 | src: local('Source Code Pro Semibold'), local('SourceCodePro-Semibold'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqVKFh1TDTPrUZWzVp6FtpG8.woff2) format('woff2');
52 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
53 | }
54 |
55 |
56 | /* latin */
57 |
58 | @font-face {
59 | font-family: 'Source Code Pro';
60 | font-style: normal;
61 | font-weight: 600;
62 | src: local('Source Code Pro Semibold'), local('SourceCodePro-Semibold'), url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqSOFnW3Jk0f09zW_Yln67Ac.woff2) format('woff2');
63 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
64 | }
--------------------------------------------------------------------------------
/app/css/simple-hint.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-completions {
2 | position: absolute;
3 | z-index: 10;
4 | overflow: hidden;
5 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
6 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
7 | box-shadow: 2px 3px 5px rgba(0,0,0,.2);
8 | }
9 | .CodeMirror-completions select {
10 | background: #fafafa;
11 | outline: none;
12 | border: none;
13 | padding: 0;
14 | margin: 0;
15 | font-family: monospace;
16 | }
17 |
--------------------------------------------------------------------------------
/app/css/simplescrollbars.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div {
2 | position: absolute;
3 | background: #ccc;
4 | -moz-box-sizing: border-box;
5 | box-sizing: border-box;
6 | border: 1px solid #bbb;
7 | border-radius: 2px;
8 | }
9 |
10 | .CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical {
11 | position: absolute;
12 | z-index: 6;
13 | background: #eee;
14 | }
15 |
16 | .CodeMirror-simplescroll-horizontal {
17 | bottom: 0; left: 0;
18 | height: 8px;
19 | }
20 | .CodeMirror-simplescroll-horizontal div {
21 | bottom: 0;
22 | height: 100%;
23 | }
24 |
25 | .CodeMirror-simplescroll-vertical {
26 | right: 0; top: 0;
27 | width: 8px;
28 | }
29 | .CodeMirror-simplescroll-vertical div {
30 | right: 0;
31 | width: 100%;
32 | }
33 |
34 |
35 | .CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler {
36 | display: none;
37 | }
38 |
39 | .CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
40 | position: absolute;
41 | background: #bcd;
42 | border-radius: 3px;
43 | }
44 |
45 | .CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {
46 | position: absolute;
47 | z-index: 6;
48 | }
49 |
50 | .CodeMirror-overlayscroll-horizontal {
51 | bottom: 0; left: 0;
52 | height: 6px;
53 | }
54 | .CodeMirror-overlayscroll-horizontal div {
55 | bottom: 0;
56 | height: 100%;
57 | }
58 |
59 | .CodeMirror-overlayscroll-vertical {
60 | right: 0; top: 0;
61 | width: 6px;
62 | }
63 | .CodeMirror-overlayscroll-vertical div {
64 | right: 0;
65 | width: 100%;
66 | }
67 |
--------------------------------------------------------------------------------
/app/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | border: 0;
3 | font-size: 14px;
4 | height: 100vh;
5 | margin: 0;
6 | overflow: hidden;
7 | padding: 0;
8 | }
9 |
10 |
11 | /*Menubar styles begin here*/
12 |
13 | #menu-bar {
14 | -webkit-app-region: drag;
15 | background-color: #101216;
16 | height: 32px;
17 | }
18 |
19 | #menu-bar a::selection {
20 | background: transparent;
21 | }
22 |
23 | #menu-items ul {
24 | -webkit-app-region: no-drag;
25 | float: left;
26 | list-style: none;
27 | margin: 0;
28 | padding: 0;
29 | z-index: 9999;
30 | }
31 |
32 | a.menu-item {
33 | color: #C0C5CE;
34 | }
35 |
36 | a.menu-item:hover {
37 | cursor: default;
38 | }
39 |
40 | #menu-items ul a {
41 | display: block;
42 | font-family: 'Segoe UI Semibold', Tahoma, Geneva, Verdana, sans-serif;
43 | font-size: 12px;
44 | line-height: 32px;
45 | outline: none;
46 | padding: 0 12px;
47 | text-decoration: none;
48 | }
49 |
50 | #menu-items ul li:hover {
51 | background: #EEEEEE;
52 | }
53 |
54 | ul {
55 | list-style-type: none;
56 | margin: 0;
57 | padding: 0;
58 | overflow: hidden;
59 | }
60 |
61 | ul:hover {
62 | cursor: default;
63 | }
64 |
65 | li a,
66 | .menu-item {
67 | display: inline-block;
68 | color: white;
69 | text-align: center;
70 | padding: 14px 16px;
71 | text-decoration: none;
72 | }
73 |
74 | li a:hover,
75 | .dropdown:hover .menu-item {
76 | background-color: #303238;
77 | }
78 |
79 | li.dropdown {
80 | display: inline-block;
81 | z-index: 9999;
82 | }
83 |
84 | .dropdown-content {
85 | z-index: 9999;
86 | display: none;
87 | position: absolute;
88 | background-color: #FDFDFD;
89 | border-radius: 0 0 2px 2px;
90 | min-width: 200px;
91 | box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
92 | }
93 |
94 | .dropdown-content a {
95 | color: black;
96 | padding: 12px 16px;
97 | text-decoration: none;
98 | display: block;
99 | text-align: left;
100 | }
101 |
102 | .dropdown-content a:hover {
103 | background-color: #F1F1F1;
104 | }
105 |
106 | .dropdown:hover .dropdown-content {
107 | display: block;
108 | }
109 |
110 | .disabled {
111 | opacity: 0.4;
112 | }
113 |
114 | .shortcut {
115 | float: right;
116 | opacity: 0.5;
117 | }
118 |
119 | .status {
120 | border-radius: 200px;
121 | background: linear-gradient(#00D89F, #09E17B);
122 | opacity: 0;
123 | float: right;
124 | height: 10px;
125 | margin: 11px 2px;
126 | width: 10px;
127 | }
128 |
129 | .status-active {
130 | opacity: 1
131 | }
132 |
133 | #codepad-center {
134 | position: absolute;
135 | color: #EAEAEA;
136 | font-size: 12px;
137 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
138 | line-height: 32px;
139 | left: 50%;
140 | margin-right: -50%;
141 | transform: translateX(-50%);
142 | }
143 |
144 | #codepad-center::selection {
145 | background: transparent;
146 | }
147 |
148 | #window-control {
149 | float: right;
150 | height: 32px;
151 | margin-right: 10px;
152 | }
153 |
154 | #window-control::selection {
155 | background: transparent;
156 | }
157 |
158 | .buttons {
159 | -webkit-app-region: no-drag;
160 | border-radius: 200px;
161 | display: inline-block;
162 | height: 12px;
163 | margin: 10px 2px;
164 | transition: 0.08s ease-out;
165 | width: 12px;
166 | }
167 |
168 | .buttons:hover {
169 | border-radius: 200px;
170 | cursor: pointer;
171 | height: 16px;
172 | margin: 8px 0px;
173 | width: 16px;
174 | }
175 |
176 | #max-button {
177 | background: linear-gradient(#00D89F, #09E17B);
178 | }
179 |
180 | #min-button {
181 | background: linear-gradient(#FFE066, #F0C808);
182 | }
183 |
184 | #close-button {
185 | background: linear-gradient(#F88734, #FD6A51);
186 | }
187 |
188 |
189 | /* Menubar style ends */
190 |
191 |
192 | /* editor: The container holding HTML/CSS/JS editors */
193 |
194 | #editor {
195 | display: flex;
196 | left: 0;
197 | top: 0;
198 | width: 100%;
199 | border-bottom: 2px solid #121418;
200 | }
201 |
202 | .editor-item {
203 | border-right: 2px solid #121418;
204 | height: 50%;
205 | min-width: 33.28%;
206 | width: auto;
207 | }
208 |
209 |
210 | /* No border-right for JS editor*/
211 |
212 | .editor-item:last-child {
213 | border-right: 0;
214 | }
215 |
216 | .editor-label {
217 | background-color: #232831;
218 | color: #EAEAEA;
219 | font-family: 'Segoe UI Semibold', Tahoma, Geneva, Verdana, sans-serif;
220 | height: 32px;
221 | line-height: 32px;
222 | text-align: center;
223 | /*padding-right: 5px;*/
224 | }
225 |
226 | .editor-focus {
227 | box-shadow: inset 0 2px 0 0 #8A99BB;
228 | }
229 |
230 | .editor-label:hover {
231 | cursor: default;
232 | }
233 |
234 | .editor-label::selection {
235 | background: transparent;
236 | }
237 |
238 | .editor-item:hover {
239 | cursor: text;
240 | }
241 |
242 |
243 | /* result-viewport: The container holding iframe element */
244 |
245 | #result-viewport {
246 | height: calc(100% - 384px);
247 | border: 0;
248 | margin: 0;
249 | background: white;
250 | width: 100%;
251 | top: 0;
252 | left: 0;
253 | z-index: 1;
254 | }
255 |
256 |
257 | /* output: iframe element*/
258 |
259 | #output {
260 | border: 0;
261 | height: 100%;
262 | margin: 0;
263 | padding: 0;
264 | width: 100%;
265 | }
--------------------------------------------------------------------------------
/app/editor.js:
--------------------------------------------------------------------------------
1 | // 1. Declarations and Node Modules Import
2 | const electron = require('electron')
3 | const path = require('path')
4 | const shell = electron.shell
5 | const remote = electron.remote
6 | const fs = require('fs')
7 | const {
8 | dialog,
9 | Menu,
10 | MenuItem
11 | } = remote
12 | const VIEW = require('./viewMenu')
13 | const HELP = require('./helpMenu')
14 | const SHORTCUT = require('./shortcuts')
15 | const WINDOW = require('./windowControl')
16 | const JSMenu = require('./scripts')
17 | const CSSMenu = require('./styles')
18 | const FILE = require('./fileMenu')
19 |
20 | var scripts = ''
21 | var styles = ''
22 | var currentEditor
23 | var editor = []
24 | var output, html, css, js, editorLabels
25 | var saveFlag = false
26 | var styFlags = [0, 0, 0]
27 | var scrFlags = [0, 0, 0, 0, 0]
28 |
29 | var cssLib = [
30 | ['animate.css', ""],
31 | ['bootstrap.min.css', ""],
32 | ['font-awesome.min.css', ""]
33 | ]
34 |
35 | var jsLib = [
36 | ['jquery-3.1.1.min.js', ""],
37 | ['anime.min.js', ""],
38 | ['bootstrap.min.js', ""],
39 | ['p5.min.js', ""],
40 | ['three.min.js', ""]
41 | ]
42 |
43 | // 3. Main Functions for Electron
44 | onload = function () {
45 | WINDOW.initContextMenu()
46 | WINDOW.windowClicks()
47 |
48 | editor[0] = CodeMirror(
49 | document.getElementById('html-editor'), {
50 | mode: {
51 | name: 'htmlmixed'
52 | },
53 | lineNumbers: true,
54 | lineWrapping: true,
55 | autofocus: true,
56 | indentWithTabs: false,
57 | indentUnit: 2,
58 | smartIndent: true,
59 | scrollbarStyle: 'overlay',
60 | theme: 'base16-ocean-dark'
61 | })
62 |
63 | editor[1] = CodeMirror(
64 | document.getElementById('css-editor'), {
65 | mode: {
66 | name: 'css'
67 | },
68 | lineNumbers: true,
69 | lineWrapping: true,
70 | indentWithTabs: false,
71 | indentUnit: 2,
72 | smartIndent: true,
73 | scrollbarStyle: 'overlay',
74 | theme: 'base16-ocean-dark'
75 | })
76 |
77 | editor[2] = CodeMirror(
78 | document.getElementById('js-editor'), {
79 | mode: {
80 | name: 'javascript',
81 | json: true
82 | },
83 | lineNumbers: true,
84 | lineWrapping: true,
85 | indentWithTabs: false,
86 | indentUnit: 2,
87 | smartIndent: true,
88 | scrollbarStyle: 'overlay',
89 | theme: 'base16-ocean-dark'
90 | })
91 |
92 | html = editor[0]
93 | css = editor[1]
94 | js = editor[2]
95 |
96 | // Output refresh and editor focus
97 | output = document.getElementById('output')
98 | editorLabels = document.getElementsByClassName('editor-label')
99 |
100 | for (var k = 0; k < 3; k++) {
101 | editor[k].on('change', function (change) {
102 | paint()
103 | })
104 | }
105 |
106 | html.on('focus', changeEditor)
107 | css.on('focus', changeEditor)
108 | js.on('focus', changeEditor)
109 |
110 | FILE.fileMenu()
111 | VIEW.viewMenu()
112 | HELP.helpMenu()
113 | JSMenu.addScript()
114 | CSSMenu.addStyle()
115 | SHORTCUT.shortcuts()
116 | FILE.newFile()
117 | onresize()
118 | }
119 |
120 | // 5. Editor Functions
121 | const getScr = () => scripts
122 | const getSty = () => styles
123 | const getCurrenEditor = () => {
124 | return currentEditor
125 | }
126 |
127 | function toggleEditors(editorI) {
128 | if (editorI === html) {
129 | css.focus()
130 | }
131 | if (editorI === css) {
132 | js.focus()
133 | }
134 | if (editorI === js) {
135 | html.focus()
136 | }
137 | }
138 |
139 | function removeFocus(editor) {
140 | for (var i = 0; i < editor.length; i++) {
141 | editor[i].classList.remove('editor-focus')
142 | }
143 | }
144 | // 6. Save the snippet functions
145 | function toggleStatus(i, span) {
146 | if (span[i].classList.contains('status-active')) {
147 | span[i].classList.remove('status-active')
148 | } else {
149 | span[i].classList.add('status-active')
150 | }
151 | }
152 |
153 | // Refresh on resize
154 | onresize = function () {
155 | for (var i = 0; i < 3; i++) {
156 | editor[i].refresh()
157 | }
158 | }
159 |
160 | function paint() {
161 | output.srcdoc = '' + '' + getSty() + '' + '' + '' + html.getValue() + getScr() + '' + '' + ''
162 | }
163 |
164 | function changeEditor(editor){
165 | removeFocus(editorLabels)
166 | if(editor == html)
167 | {
168 | editorLabels[0].classList.add('editor-focus')
169 | currentEditor = html
170 | }
171 | if(editor == css)
172 | {
173 | editorLabels[1].classList.add('editor-focus')
174 | currentEditor = css
175 | }
176 | if(editor == js)
177 | {
178 | editorLabels[2].classList.add('editor-focus')
179 | currentEditor = js
180 | }
181 | }
--------------------------------------------------------------------------------
/app/fileMenu.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | fileMenu,
3 | newFile,
4 | handleNew,
5 | handleSave,
6 | handleSaveAs
7 | }
8 | let saveFlag
9 | const getSavePath = () => savePath
10 | const setSavePath = (path) => {
11 | savePath = path
12 | }
13 |
14 | function fileMenu () {
15 | document.getElementById('save').addEventListener('click', handleSave)
16 | document.getElementById('save-as').addEventListener('click', handleSaveAs)
17 | document.getElementById('new').addEventListener('click', handleNew)
18 | document.getElementById('close-window').addEventListener('click', function (e) {
19 | window.close()
20 | })
21 | }
22 |
23 | function handleNew (i) {
24 | if (false) {
25 | newFile()
26 | editor[i].setValue('')
27 | } else {
28 | window.open(path.join('file://', __dirname, '/index.html'))
29 | }
30 | }
31 |
32 | function handleSaveAs () {
33 | var path = dialog.showOpenDialog({
34 | properties: ['openDirectory']
35 | })
36 | if (path !== undefined) {
37 | saveFlag = true
38 | setSavePath(path)
39 | handleSave()
40 | }
41 | }
42 |
43 | function handleSave () {
44 | if (saveFlag === true) {
45 | var path = getSavePath()
46 | // console.log('save path: ' + path)
47 | var htmlString = '\n' + '\n' + 'CodePad Save\n' + CSSMenu.getCssLibs() + '\n\n' + '\n' + '\n' + html.getValue() + JSMenu.getJsLibs() + '\n\n' + '\n' + ''
48 | // Write HTML
49 | fs.writeFile(path + '\\index.html', htmlString, (err) => {
50 | if (err) {
51 | console.error(err)
52 | }
53 | // console.log('success HTML')
54 | })
55 | // Write CSS
56 | fs.writeFile(path + '\\style.css', css.getValue(), (err) => {
57 | if (err) {
58 | console.error(err)
59 | }
60 | // console.log('success CSS')
61 | })
62 | // Write JS
63 | fs.writeFile(path + '\\script.js', js.getValue(), (err) => {
64 | if (err) {
65 | console.error(err)
66 | }
67 | // console.log('success JS')
68 | })
69 | for (var j = 0; j < styFlags.length; j++) {
70 | if (styFlags[j] === 1) {
71 | fs.createReadStream('resources/app.asar/app/lib/' + cssLib[j][0]).pipe(fs.createWriteStream(path + '/' + cssLib[j][0]))
72 | if (j === 1) {
73 | fs.createReadStream('resources/app.asar/app/lib/glyphicons-halflings-regular.eot').pipe(fs.createWriteStream(path + '/glyphicons-halflings-regular.eot'))
74 | fs.createReadStream('resources/app.asar/app/lib/glyphicons-halflings-regular.ttf').pipe(fs.createWriteStream(path + '/glyphicons-halflings-regular.tff'))
75 | fs.createReadStream('resources/app.asar/app/lib/glyphicons-halflings-regular.woff').pipe(fs.createWriteStream(path + '/glyphicons-halflings-regular.woff'))
76 | fs.createReadStream('resources/app.asar/app/lib/glyphicons-halflings-regular.woff2').pipe(fs.createWriteStream(path + '/glyphicons-halflings-regular.woff2'))
77 | }
78 | if (j === 2) {
79 | fs.createReadStream('resources/app.asar/app/lib/fontawesome-webfont.ttf').pipe(fs.createWriteStream(path + '/fontawesome-webfont.ttf'))
80 | fs.createReadStream('resources/app.asar/app/lib/fontawesome-webfont.woff').pipe(fs.createWriteStream(path + '/fontawesome-webfont.woff'))
81 | fs.createReadStream('resources/app.asar/app/lib/fontawesome-webfont.woff2').pipe(fs.createWriteStream(path + '/fontawesome-webfont.woff2'))
82 | }
83 | }
84 | }
85 | for (var i = 0; i < scrFlags.length; i++) {
86 | if (scrFlags[i] === 1) {
87 | fs.createReadStream('resources/app.asar/app/lib/' + jsLib[i][0]).pipe(fs.createWriteStream(path + '/' + jsLib[i][0]))
88 | }
89 | }
90 | dialog.showMessageBox({
91 | message: 'Saved to ' + path + '\\',
92 | buttons: ['OK']
93 | })
94 | } else {
95 | handleSaveAs()
96 | }
97 | }
98 |
99 | function newFile () {
100 | fileEntry = null
101 | hasWriteAccess = false
102 | }
103 |
--------------------------------------------------------------------------------
/app/helpMenu.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | helpMenu
3 | }
4 |
5 | function helpMenu () {
6 | // Open links in the 'Help' menu in the default browser
7 | var helpa = document.getElementById('help-menu').getElementsByTagName('a')
8 | for (var i = 0; i < helpa.length; i++) {
9 | helpa[i].addEventListener('click', function (e) {
10 | e.preventDefault()
11 | shell.openExternal(this.href)
12 | })
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CodePad
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
89 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/js/closetag.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tag-closer extension for CodeMirror.
3 | *
4 | * This extension adds a "closeTag" utility function that can be used with key bindings to
5 | * insert a matching end tag after the ">" character of a start tag has been typed. It can
6 | * also complete "" if a matching start tag is found. It will correctly ignore signal
7 | * characters for empty tags, comments, CDATA, etc.
8 | *
9 | * The function depends on internal parser state to identify tags. It is compatible with the
10 | * following CodeMirror modes and will ignore all others:
11 | * - htmlmixed
12 | * - xml
13 | *
14 | * See demos/closetag.html for a usage example.
15 | *
16 | * @author Nathan Williams
17 | * Contributed under the same license terms as CodeMirror.
18 | */
19 | (function() {
20 | /** Option that allows tag closing behavior to be toggled. Default is true. */
21 | CodeMirror.defaults['closeTagEnabled'] = true;
22 |
23 | /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
24 | CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul'];
25 |
26 | /**
27 | * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
28 | * - cm: The editor instance.
29 | * - ch: The character being processed.
30 | * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
31 | * Pass false to disable indentation. Pass an array to override the default list of tag names.
32 | */
33 | CodeMirror.defineExtension("closeTag", function(cm, ch, indent) {
34 | if (!cm.getOption('closeTagEnabled')) {
35 | throw CodeMirror.Pass;
36 | }
37 |
38 | var mode = cm.getOption('mode');
39 |
40 | if (mode == 'text/html') {
41 |
42 | /*
43 | * Relevant structure of token:
44 | *
45 | * htmlmixed
46 | * className
47 | * state
48 | * htmlState
49 | * type
50 | * context
51 | * tagName
52 | * mode
53 | *
54 | * xml
55 | * className
56 | * state
57 | * tagName
58 | * type
59 | */
60 |
61 | var pos = cm.getCursor();
62 | var tok = cm.getTokenAt(pos);
63 | var state = tok.state;
64 |
65 | if (state.mode && state.mode != 'html') {
66 | throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
67 | }
68 |
69 | if (ch == '>') {
70 | var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
71 |
72 | if (tok.className == 'tag' && type == 'closeTag') {
73 | throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
74 | }
75 |
76 | cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
77 | pos = {line: pos.line, ch: pos.ch + 1};
78 | cm.setCursor(pos);
79 |
80 | tok = cm.getTokenAt(cm.getCursor());
81 | state = tok.state;
82 | type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
83 |
84 | if (tok.className == 'tag' && type != 'selfcloseTag') {
85 | var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml
86 | if (tagName.length > 0) {
87 | insertEndTag(cm, indent, pos, tagName);
88 | }
89 | return;
90 | }
91 |
92 | // Undo the '>' insert and allow cm to handle the key instead.
93 | cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
94 | cm.replaceSelection("");
95 |
96 | } else if (ch == '/') {
97 | if (tok.className == 'tag' && tok.string == '<') {
98 | var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for '' edge case
99 | if (tagName.length > 0) {
100 | completeEndTag(cm, pos, tagName);
101 | return;
102 | }
103 | }
104 | }
105 |
106 | }
107 |
108 | throw CodeMirror.Pass; // Bubble if not handled
109 | });
110 |
111 | function insertEndTag(cm, indent, pos, tagName) {
112 | if (shouldIndent(cm, indent, tagName)) {
113 | cm.replaceSelection('\n\n' + tagName + '>', 'end');
114 | cm.indentLine(pos.line + 1);
115 | cm.indentLine(pos.line + 2);
116 | cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
117 | } else {
118 | cm.replaceSelection('' + tagName + '>');
119 | cm.setCursor(pos);
120 | }
121 | }
122 |
123 | function shouldIndent(cm, indent, tagName) {
124 | if (typeof indent == 'undefined' || indent == null || indent == true) {
125 | indent = cm.getOption('closeTagIndent');
126 | }
127 | if (!indent) {
128 | indent = [];
129 | }
130 | return indexOf(indent, tagName.toLowerCase()) != -1;
131 | }
132 |
133 | // C&P from codemirror.js...would be nice if this were visible to utilities.
134 | function indexOf(collection, elt) {
135 | if (collection.indexOf) return collection.indexOf(elt);
136 | for (var i = 0, e = collection.length; i < e; ++i)
137 | if (collection[i] == elt) return i;
138 | return -1;
139 | }
140 |
141 | function completeEndTag(cm, pos, tagName) {
142 | cm.replaceSelection('/' + tagName + '>');
143 | cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
144 | }
145 |
146 | })();
147 |
--------------------------------------------------------------------------------
/app/js/dialog.js:
--------------------------------------------------------------------------------
1 | // Open simple dialogs on top of an editor. Relies on dialog.css.
2 |
3 | (function() {
4 | function dialogDiv(cm, template) {
5 | var wrap = cm.getWrapperElement();
6 | var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
7 | dialog.className = "CodeMirror-dialog";
8 | dialog.innerHTML = '' + template + '
';
9 | return dialog;
10 | }
11 |
12 | CodeMirror.defineExtension("openDialog", function(template, callback) {
13 | var dialog = dialogDiv(this, template);
14 | var closed = false, me = this;
15 | function close() {
16 | if (closed) return;
17 | closed = true;
18 | dialog.parentNode.removeChild(dialog);
19 | }
20 | var inp = dialog.getElementsByTagName("input")[0];
21 | if (inp) {
22 | CodeMirror.connect(inp, "keydown", function(e) {
23 | if (e.keyCode == 13 || e.keyCode == 27) {
24 | CodeMirror.e_stop(e);
25 | close();
26 | me.focus();
27 | if (e.keyCode == 13) callback(inp.value);
28 | }
29 | });
30 | inp.focus();
31 | CodeMirror.connect(inp, "blur", close);
32 | }
33 | return close;
34 | });
35 |
36 | CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
37 | var dialog = dialogDiv(this, template);
38 | var buttons = dialog.getElementsByTagName("button");
39 | var closed = false, me = this, blurring = 1;
40 | function close() {
41 | if (closed) return;
42 | closed = true;
43 | dialog.parentNode.removeChild(dialog);
44 | me.focus();
45 | }
46 | buttons[0].focus();
47 | for (var i = 0; i < buttons.length; ++i) {
48 | var b = buttons[i];
49 | (function(callback) {
50 | CodeMirror.connect(b, "click", function(e) {
51 | CodeMirror.e_preventDefault(e);
52 | close();
53 | if (callback) callback(me);
54 | });
55 | })(callbacks[i]);
56 | CodeMirror.connect(b, "blur", function() {
57 | --blurring;
58 | setTimeout(function() { if (blurring <= 0) close(); }, 200);
59 | });
60 | CodeMirror.connect(b, "focus", function() { ++blurring; });
61 | }
62 | });
63 | })();
64 |
--------------------------------------------------------------------------------
/app/js/foldcode.js:
--------------------------------------------------------------------------------
1 | // the tagRangeFinder function is
2 | // Copyright (C) 2011 by Daniel Glazman
3 | // released under the MIT license (../../LICENSE) like the rest of CodeMirror
4 | CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
5 | 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";
6 | var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
7 | var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
8 |
9 | var lineText = cm.getLine(line);
10 | var found = false;
11 | var tag = null;
12 | var pos = 0;
13 | while (!found) {
14 | pos = lineText.indexOf("<", pos);
15 | if (-1 == pos) // no tag on line
16 | return;
17 | if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
18 | pos++;
19 | continue;
20 | }
21 | // ok we weem to have a start tag
22 | if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
23 | pos++;
24 | continue;
25 | }
26 | var gtPos = lineText.indexOf(">", pos + 1);
27 | if (-1 == gtPos) { // end of start tag not in line
28 | var l = line + 1;
29 | var foundGt = false;
30 | var lastLine = cm.lineCount();
31 | while (l < lastLine && !foundGt) {
32 | var lt = cm.getLine(l);
33 | var gt = lt.indexOf(">");
34 | if (-1 != gt) { // found a >
35 | foundGt = true;
36 | var slash = lt.lastIndexOf("/", gt);
37 | if (-1 != slash && slash < gt) {
38 | var str = lineText.substr(slash, gt - slash + 1);
39 | if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
40 | if (hideEnd === true) l++;
41 | return l;
42 | }
43 | }
44 | }
45 | l++;
46 | }
47 | found = true;
48 | }
49 | else {
50 | var slashPos = lineText.lastIndexOf("/", gtPos);
51 | if (-1 == slashPos) { // cannot be empty tag
52 | found = true;
53 | // don't continue
54 | }
55 | else { // empty tag?
56 | // check if really empty tag
57 | var str = lineText.substr(slashPos, gtPos - slashPos + 1);
58 | if (!str.match( /\/\s*\>/ )) { // finally not empty
59 | found = true;
60 | // don't continue
61 | }
62 | }
63 | }
64 | if (found) {
65 | var subLine = lineText.substr(pos + 1);
66 | tag = subLine.match(xmlNAMERegExp);
67 | if (tag) {
68 | // we have an element name, wooohooo !
69 | tag = tag[0];
70 | // do we have the close tag on same line ???
71 | if (-1 != lineText.indexOf("" + tag + ">", pos)) // yep
72 | {
73 | found = false;
74 | }
75 | // we don't, so we have a candidate...
76 | }
77 | else
78 | found = false;
79 | }
80 | if (!found)
81 | pos++;
82 | }
83 |
84 | if (found) {
85 | var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
86 | var startTagRegExp = new RegExp(startTag, "g");
87 | var endTag = "" + tag + ">";
88 | var depth = 1;
89 | var l = line + 1;
90 | var lastLine = cm.lineCount();
91 | while (l < lastLine) {
92 | lineText = cm.getLine(l);
93 | var match = lineText.match(startTagRegExp);
94 | if (match) {
95 | for (var i = 0; i < match.length; i++) {
96 | if (match[i] == endTag)
97 | depth--;
98 | else
99 | depth++;
100 | if (!depth) {
101 | if (hideEnd === true) l++;
102 | return l;
103 | }
104 | }
105 | }
106 | l++;
107 | }
108 | return;
109 | }
110 | };
111 |
112 | CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
113 | var lineText = cm.getLine(line);
114 | var startChar = lineText.lastIndexOf("{");
115 | if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return;
116 | var tokenType = cm.getTokenAt({line: line, ch: startChar}).className;
117 | var count = 1, lastLine = cm.lineCount(), end;
118 | outer: for (var i = line + 1; i < lastLine; ++i) {
119 | var text = cm.getLine(i), pos = 0;
120 | for (;;) {
121 | var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
122 | if (nextOpen < 0) nextOpen = text.length;
123 | if (nextClose < 0) nextClose = text.length;
124 | pos = Math.min(nextOpen, nextClose);
125 | if (pos == text.length) break;
126 | if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
127 | if (pos == nextOpen) ++count;
128 | else if (!--count) { end = i; break outer; }
129 | }
130 | ++pos;
131 | }
132 | }
133 | if (end == null || end == line + 1) return;
134 | if (hideEnd === true) end++;
135 | return end;
136 | };
137 |
138 | CodeMirror.indentRangeFinder = function(cm, line) {
139 | var tabSize = cm.getOption("tabSize");
140 | var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
141 | for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
142 | var handle = cm.getLineHandle(i);
143 | if (!/^\s*$/.test(handle.text)) {
144 | if (handle.indentation(tabSize) <= myIndent) break;
145 | last = i;
146 | }
147 | }
148 | if (!last) return null;
149 | return last + 1;
150 | };
151 |
152 | CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
153 | var folded = [];
154 | if (markText == null) markText = '▼
%N%';
155 |
156 | function isFolded(cm, n) {
157 | for (var i = 0; i < folded.length; ++i) {
158 | var start = cm.lineInfo(folded[i].start);
159 | if (!start) folded.splice(i--, 1);
160 | else if (start.line == n) return {pos: i, region: folded[i]};
161 | }
162 | }
163 |
164 | function expand(cm, region) {
165 | cm.clearMarker(region.start);
166 | for (var i = 0; i < region.hidden.length; ++i)
167 | cm.showLine(region.hidden[i]);
168 | }
169 |
170 | return function(cm, line) {
171 | cm.operation(function() {
172 | var known = isFolded(cm, line);
173 | if (known) {
174 | folded.splice(known.pos, 1);
175 | expand(cm, known.region);
176 | } else {
177 | var end = rangeFinder(cm, line, hideEnd);
178 | if (end == null) return;
179 | var hidden = [];
180 | for (var i = line + 1; i < end; ++i) {
181 | var handle = cm.hideLine(i);
182 | if (handle) hidden.push(handle);
183 | }
184 | var first = cm.setMarker(line, markText);
185 | var region = {start: first, hidden: hidden};
186 | cm.onDeleteLine(first, function() { expand(cm, region); });
187 | folded.push(region);
188 | }
189 | });
190 | };
191 | };
192 |
--------------------------------------------------------------------------------
/app/js/formatting.js:
--------------------------------------------------------------------------------
1 | // ============== Formatting extensions ============================
2 | // A common storage for all mode-specific formatting features
3 | if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
4 |
5 | // Returns the extension of the editor's current mode
6 | CodeMirror.defineExtension("getModeExt", function () {
7 | var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
8 | var ext = CodeMirror.modeExtensions[mname];
9 | if (!ext) throw new Error("No extensions found for mode " + mname);
10 | return ext;
11 | });
12 |
13 | // If the current mode is 'htmlmixed', returns the extension of a mode located at
14 | // the specified position (can be htmlmixed, css or javascript). Otherwise, simply
15 | // returns the extension of the editor's current mode.
16 | CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
17 | var token = this.getTokenAt(pos);
18 | if (token && token.state && token.state.mode)
19 | return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
20 | else
21 | return this.getModeExt();
22 | });
23 |
24 | // Comment/uncomment the specified range
25 | CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
26 | var curMode = this.getModeExtAtPos(this.getCursor());
27 | if (isComment) { // Comment range
28 | var commentedText = this.getRange(from, to);
29 | this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
30 | , from, to);
31 | if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
32 | this.setCursor(from.line, from.ch + curMode.commentStart.length);
33 | }
34 | }
35 | else { // Uncomment range
36 | var selText = this.getRange(from, to);
37 | var startIndex = selText.indexOf(curMode.commentStart);
38 | var endIndex = selText.lastIndexOf(curMode.commentEnd);
39 | if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
40 | // Take string till comment start
41 | selText = selText.substr(0, startIndex)
42 | // From comment start till comment end
43 | + selText.substring(startIndex + curMode.commentStart.length, endIndex)
44 | // From comment end till string end
45 | + selText.substr(endIndex + curMode.commentEnd.length);
46 | }
47 | this.replaceRange(selText, from, to);
48 | }
49 | });
50 |
51 | // Applies automatic mode-aware indentation to the specified range
52 | CodeMirror.defineExtension("autoIndentRange", function (from, to) {
53 | var cmInstance = this;
54 | this.operation(function () {
55 | for (var i = from.line; i <= to.line; i++) {
56 | cmInstance.indentLine(i, "smart");
57 | }
58 | });
59 | });
60 |
61 | // Applies automatic formatting to the specified range
62 | CodeMirror.defineExtension("autoFormatRange", function (from, to) {
63 | var absStart = this.indexFromPos(from);
64 | var absEnd = this.indexFromPos(to);
65 | // Insert additional line breaks where necessary according to the
66 | // mode's syntax
67 | var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
68 | var cmInstance = this;
69 |
70 | // Replace and auto-indent the range
71 | this.operation(function () {
72 | cmInstance.replaceRange(res, from, to);
73 | var startLine = cmInstance.posFromIndex(absStart).line;
74 | var endLine = cmInstance.posFromIndex(absStart + res.length).line;
75 | for (var i = startLine; i <= endLine; i++) {
76 | cmInstance.indentLine(i, "smart");
77 | }
78 | });
79 | });
80 |
81 | // Define extensions for a few modes
82 |
83 | CodeMirror.modeExtensions["css"] = {
84 | commentStart: "/*",
85 | commentEnd: "*/",
86 | wordWrapChars: [";", "\\{", "\\}"],
87 | autoFormatLineBreaks: function (text) {
88 | return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
89 | }
90 | };
91 |
92 | CodeMirror.modeExtensions["javascript"] = {
93 | commentStart: "/*",
94 | commentEnd: "*/",
95 | wordWrapChars: [";", "\\{", "\\}"],
96 |
97 | getNonBreakableBlocks: function (text) {
98 | var nonBreakableRegexes = [
99 | new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
100 | new RegExp("'([\\s\\S]*?)('|$)"),
101 | new RegExp("\"([\\s\\S]*?)(\"|$)"),
102 | new RegExp("//.*([\r\n]|$)")
103 | ];
104 | var nonBreakableBlocks = new Array();
105 | for (var i = 0; i < nonBreakableRegexes.length; i++) {
106 | var curPos = 0;
107 | while (curPos < text.length) {
108 | var m = text.substr(curPos).match(nonBreakableRegexes[i]);
109 | if (m != null) {
110 | nonBreakableBlocks.push({
111 | start: curPos + m.index,
112 | end: curPos + m.index + m[0].length
113 | });
114 | curPos += m.index + Math.max(1, m[0].length);
115 | }
116 | else { // No more matches
117 | break;
118 | }
119 | }
120 | }
121 | nonBreakableBlocks.sort(function (a, b) {
122 | return a.start - b.start;
123 | });
124 |
125 | return nonBreakableBlocks;
126 | },
127 |
128 | autoFormatLineBreaks: function (text) {
129 | var curPos = 0;
130 | var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
131 | var nonBreakableBlocks = this.getNonBreakableBlocks(text);
132 | if (nonBreakableBlocks != null) {
133 | var res = "";
134 | for (var i = 0; i < nonBreakableBlocks.length; i++) {
135 | if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
136 | res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
137 | curPos = nonBreakableBlocks[i].start;
138 | }
139 | if (nonBreakableBlocks[i].start <= curPos
140 | && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
141 | res += text.substring(curPos, nonBreakableBlocks[i].end);
142 | curPos = nonBreakableBlocks[i].end;
143 | }
144 | }
145 | if (curPos < text.length - 1) {
146 | res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
147 | }
148 | return res;
149 | }
150 | else {
151 | return text.replace(reLinesSplitter, "$1\n$2");
152 | }
153 | }
154 | };
155 |
156 | CodeMirror.modeExtensions["xml"] = {
157 | commentStart: "",
159 | wordWrapChars: [">"],
160 |
161 | autoFormatLineBreaks: function (text) {
162 | var lines = text.split("\n");
163 | var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
164 | var reOpenBrackets = new RegExp("<", "g");
165 | var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
166 | for (var i = 0; i < lines.length; i++) {
167 | var mToProcess = lines[i].match(reProcessedPortion);
168 | if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
169 | lines[i] = mToProcess[1]
170 | + mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
171 | + mToProcess[3];
172 | continue;
173 | }
174 | }
175 |
176 | return lines.join("\n");
177 | }
178 | };
179 |
180 | CodeMirror.modeExtensions["htmlmixed"] = {
181 | commentStart: "",
183 | wordWrapChars: [">", ";", "\\{", "\\}"],
184 |
185 | getModeInfos: function (text, absPos) {
186 | var modeInfos = new Array();
187 | modeInfos[0] =
188 | {
189 | pos: 0,
190 | modeExt: CodeMirror.modeExtensions["xml"],
191 | modeName: "xml"
192 | };
193 |
194 | var modeMatchers = new Array();
195 | modeMatchers[0] =
196 | {
197 | regex: new RegExp("]*>|$)", "i"),
198 | modeExt: CodeMirror.modeExtensions["css"],
199 | modeName: "css"
200 | };
201 | modeMatchers[1] =
202 | {
203 | regex: new RegExp("]*>|$)", "i"),
204 | modeExt: CodeMirror.modeExtensions["javascript"],
205 | modeName: "javascript"
206 | };
207 |
208 | var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
209 | // Detect modes for the entire text
210 | for (var i = 0; i < modeMatchers.length; i++) {
211 | var curPos = 0;
212 | while (curPos <= lastCharPos) {
213 | var m = text.substr(curPos).match(modeMatchers[i].regex);
214 | if (m != null) {
215 | if (m.length > 1 && m[1].length > 0) {
216 | // Push block begin pos
217 | var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
218 | modeInfos.push(
219 | {
220 | pos: blockBegin,
221 | modeExt: modeMatchers[i].modeExt,
222 | modeName: modeMatchers[i].modeName
223 | });
224 | // Push block end pos
225 | modeInfos.push(
226 | {
227 | pos: blockBegin + m[1].length,
228 | modeExt: modeInfos[0].modeExt,
229 | modeName: modeInfos[0].modeName
230 | });
231 | curPos += m.index + m[0].length;
232 | continue;
233 | }
234 | else {
235 | curPos += m.index + Math.max(m[0].length, 1);
236 | }
237 | }
238 | else { // No more matches
239 | break;
240 | }
241 | }
242 | }
243 | // Sort mode infos
244 | modeInfos.sort(function sortModeInfo(a, b) {
245 | return a.pos - b.pos;
246 | });
247 |
248 | return modeInfos;
249 | },
250 |
251 | autoFormatLineBreaks: function (text, startPos, endPos) {
252 | var modeInfos = this.getModeInfos(text);
253 | var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
254 | var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
255 | var res = "";
256 | // Use modes info to break lines correspondingly
257 | if (modeInfos.length > 1) { // Deal with multi-mode text
258 | for (var i = 1; i <= modeInfos.length; i++) {
259 | var selStart = modeInfos[i - 1].pos;
260 | var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
261 |
262 | if (selStart >= endPos) { // The block starts later than the needed fragment
263 | break;
264 | }
265 | if (selStart < startPos) {
266 | if (selEnd <= startPos) { // The block starts earlier than the needed fragment
267 | continue;
268 | }
269 | selStart = startPos;
270 | }
271 | if (selEnd > endPos) {
272 | selEnd = endPos;
273 | }
274 | var textPortion = text.substring(selStart, selEnd);
275 | if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
276 | if (!reBlockStartsWithNewline.test(textPortion)
277 | && selStart > 0) { // The block does not start with a line break
278 | textPortion = "\n" + textPortion;
279 | }
280 | if (!reBlockEndsWithNewline.test(textPortion)
281 | && selEnd < text.length - 1) { // The block does not end with a line break
282 | textPortion += "\n";
283 | }
284 | }
285 | res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
286 | }
287 | }
288 | else { // Single-mode text
289 | res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
290 | }
291 |
292 | return res;
293 | }
294 | };
295 |
--------------------------------------------------------------------------------
/app/js/htmlmixed.js:
--------------------------------------------------------------------------------
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 | var defaultTags = {
15 | script: [
16 | ["lang", /(javascript|babel)/i, "javascript"],
17 | ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"],
18 | ["type", /./, "text/plain"],
19 | [null, null, "javascript"]
20 | ],
21 | style: [
22 | ["lang", /^css$/i, "css"],
23 | ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
24 | ["type", /./, "text/plain"],
25 | [null, null, "css"]
26 | ]
27 | };
28 |
29 | function maybeBackup(stream, pat, style) {
30 | var cur = stream.current(), close = cur.search(pat);
31 | if (close > -1) {
32 | stream.backUp(cur.length - close);
33 | } else if (cur.match(/<\/?$/)) {
34 | stream.backUp(cur.length);
35 | if (!stream.match(pat, false)) stream.match(cur);
36 | }
37 | return style;
38 | }
39 |
40 | var attrRegexpCache = {};
41 | function getAttrRegexp(attr) {
42 | var regexp = attrRegexpCache[attr];
43 | if (regexp) return regexp;
44 | return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
45 | }
46 |
47 | function getAttrValue(text, attr) {
48 | var match = text.match(getAttrRegexp(attr))
49 | return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
50 | }
51 |
52 | function getTagRegexp(tagName, anchored) {
53 | return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
54 | }
55 |
56 | function addTags(from, to) {
57 | for (var tag in from) {
58 | var dest = to[tag] || (to[tag] = []);
59 | var source = from[tag];
60 | for (var i = source.length - 1; i >= 0; i--)
61 | dest.unshift(source[i])
62 | }
63 | }
64 |
65 | function findMatchingMode(tagInfo, tagText) {
66 | for (var i = 0; i < tagInfo.length; i++) {
67 | var spec = tagInfo[i];
68 | if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
69 | }
70 | }
71 |
72 | CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
73 | var htmlMode = CodeMirror.getMode(config, {
74 | name: "xml",
75 | htmlMode: true,
76 | multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
77 | multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
78 | });
79 |
80 | var tags = {};
81 | var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
82 | addTags(defaultTags, tags);
83 | if (configTags) addTags(configTags, tags);
84 | if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
85 | tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
86 |
87 | function html(stream, state) {
88 | var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
89 | if (tag && !/[<>\s\/]/.test(stream.current()) &&
90 | (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
91 | tags.hasOwnProperty(tagName)) {
92 | state.inTag = tagName + " "
93 | } else if (state.inTag && tag && />$/.test(stream.current())) {
94 | var inTag = /^([\S]+) (.*)/.exec(state.inTag)
95 | state.inTag = null
96 | var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
97 | var mode = CodeMirror.getMode(config, modeSpec)
98 | var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
99 | state.token = function (stream, state) {
100 | if (stream.match(endTagA, false)) {
101 | state.token = html;
102 | state.localState = state.localMode = null;
103 | return null;
104 | }
105 | return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
106 | };
107 | state.localMode = mode;
108 | state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
109 | } else if (state.inTag) {
110 | state.inTag += stream.current()
111 | if (stream.eol()) state.inTag += " "
112 | }
113 | return style;
114 | };
115 |
116 | return {
117 | startState: function () {
118 | var state = CodeMirror.startState(htmlMode);
119 | return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
120 | },
121 |
122 | copyState: function (state) {
123 | var local;
124 | if (state.localState) {
125 | local = CodeMirror.copyState(state.localMode, state.localState);
126 | }
127 | return {token: state.token, inTag: state.inTag,
128 | localMode: state.localMode, localState: local,
129 | htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
130 | },
131 |
132 | token: function (stream, state) {
133 | return state.token(stream, state);
134 | },
135 |
136 | indent: function (state, textAfter) {
137 | if (!state.localMode || /^\s*<\//.test(textAfter))
138 | return htmlMode.indent(state.htmlState, textAfter);
139 | else if (state.localMode.indent)
140 | return state.localMode.indent(state.localState, textAfter);
141 | else
142 | return CodeMirror.Pass;
143 | },
144 |
145 | innerMode: function (state) {
146 | return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
147 | }
148 | };
149 | }, "xml", "javascript", "css");
150 |
151 | CodeMirror.defineMIME("text/html", "htmlmixed");
152 | });
153 |
--------------------------------------------------------------------------------
/app/js/javascript-hint.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | function forEach(arr, f) {
3 | for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
4 | }
5 |
6 | function arrayContains(arr, item) {
7 | if (!Array.prototype.indexOf) {
8 | var i = arr.length;
9 | while (i--) {
10 | if (arr[i] === item) {
11 | return true;
12 | }
13 | }
14 | return false;
15 | }
16 | return arr.indexOf(item) != -1;
17 | }
18 |
19 | function scriptHint(editor, keywords, getToken) {
20 | // Find the token at the cursor
21 | var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
22 | // If it's not a 'word-style' token, ignore the token.
23 | if (!/^[\w$_]*$/.test(token.string)) {
24 | token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
25 | className: token.string == "." ? "property" : null};
26 | }
27 | // If it is a property, find out what it is a property of.
28 | while (tprop.className == "property") {
29 | tprop = getToken(editor, {line: cur.line, ch: tprop.start});
30 | if (tprop.string != ".") return;
31 | tprop = getToken(editor, {line: cur.line, ch: tprop.start});
32 | if (tprop.string == ')') {
33 | var level = 1;
34 | do {
35 | tprop = getToken(editor, {line: cur.line, ch: tprop.start});
36 | switch (tprop.string) {
37 | case ')': level++; break;
38 | case '(': level--; break;
39 | default: break;
40 | }
41 | } while (level > 0)
42 | tprop = getToken(editor, {line: cur.line, ch: tprop.start});
43 | if (tprop.className == 'variable')
44 | tprop.className = 'function';
45 | else return; // no clue
46 | }
47 | if (!context) var context = [];
48 | context.push(tprop);
49 | }
50 | return {list: getCompletions(token, context, keywords),
51 | from: {line: cur.line, ch: token.start},
52 | to: {line: cur.line, ch: token.end}};
53 | }
54 |
55 | CodeMirror.javascriptHint = function(editor) {
56 | return scriptHint(editor, javascriptKeywords,
57 | function (e, cur) {return e.getTokenAt(cur);});
58 | }
59 |
60 | function getCoffeeScriptToken(editor, cur) {
61 | // This getToken, it is for coffeescript, imitates the behavior of
62 | // getTokenAt method in javascript.js, that is, returning "property"
63 | // type and treat "." as indepenent token.
64 | var token = editor.getTokenAt(cur);
65 | if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
66 | token.end = token.start;
67 | token.string = '.';
68 | token.className = "property";
69 | }
70 | else if (/^\.[\w$_]*$/.test(token.string)) {
71 | token.className = "property";
72 | token.start++;
73 | token.string = token.string.replace(/\./, '');
74 | }
75 | return token;
76 | }
77 |
78 | CodeMirror.coffeescriptHint = function(editor) {
79 | return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken);
80 | }
81 |
82 | var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
83 | "toUpperCase toLowerCase split concat match replace search").split(" ");
84 | var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
85 | "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
86 | var funcProps = "prototype apply call bind".split(" ");
87 | var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
88 | "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
89 | var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
90 | "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(" ");
91 |
92 | function getCompletions(token, context, keywords) {
93 | var found = [], start = token.string;
94 | function maybeAdd(str) {
95 | if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
96 | }
97 | function gatherCompletions(obj) {
98 | if (typeof obj == "string") forEach(stringProps, maybeAdd);
99 | else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
100 | else if (obj instanceof Function) forEach(funcProps, maybeAdd);
101 | for (var name in obj) maybeAdd(name);
102 | }
103 |
104 | if (context) {
105 | // If this is a property, see if it belongs to some object we can
106 | // find in the current environment.
107 | var obj = context.pop(), base;
108 | if (obj.className == "variable")
109 | base = window[obj.string];
110 | else if (obj.className == "string")
111 | base = "";
112 | else if (obj.className == "atom")
113 | base = 1;
114 | else if (obj.className == "function") {
115 | if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
116 | (typeof window.jQuery == 'function'))
117 | base = window.jQuery();
118 | else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
119 | base = window._();
120 | }
121 | while (base != null && context.length)
122 | base = base[context.pop().string];
123 | if (base != null) gatherCompletions(base);
124 | }
125 | else {
126 | // If not, just look in the window object and any local scope
127 | // (reading into JS mode internals to get at the local variables)
128 | for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
129 | gatherCompletions(window);
130 | forEach(keywords, maybeAdd);
131 | }
132 | return found;
133 | }
134 | })();
135 |
--------------------------------------------------------------------------------
/app/js/javascript.js:
--------------------------------------------------------------------------------
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 expressionAllowed(stream, state, backUp) {
15 | return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
16 | (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
17 | }
18 |
19 | CodeMirror.defineMode("javascript", function(config, parserConfig) {
20 | var indentUnit = config.indentUnit;
21 | var statementIndent = parserConfig.statementIndent;
22 | var jsonldMode = parserConfig.jsonld;
23 | var jsonMode = parserConfig.json || jsonldMode;
24 | var isTS = parserConfig.typescript;
25 | var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
26 |
27 | // Tokenizer
28 |
29 | var keywords = function(){
30 | function kw(type) {return {type: type, style: "keyword"};}
31 | var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
32 | var operator = kw("operator"), atom = {type: "atom", style: "atom"};
33 |
34 | var jsKeywords = {
35 | "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
36 | "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
37 | "var": kw("var"), "const": kw("var"), "let": kw("var"),
38 | "function": kw("function"), "catch": kw("catch"),
39 | "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
40 | "in": operator, "typeof": operator, "instanceof": operator,
41 | "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
42 | "this": kw("this"), "class": kw("class"), "super": kw("atom"),
43 | "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
44 | "await": C, "async": kw("async")
45 | };
46 |
47 | // Extend the 'normal' keywords with the TypeScript language extensions
48 | if (isTS) {
49 | var type = {type: "variable", style: "variable-3"};
50 | var tsKeywords = {
51 | // object-like things
52 | "interface": kw("class"),
53 | "implements": C,
54 | "namespace": C,
55 | "module": kw("module"),
56 | "enum": kw("module"),
57 | "type": kw("type"),
58 |
59 | // scope modifiers
60 | "public": kw("modifier"),
61 | "private": kw("modifier"),
62 | "protected": kw("modifier"),
63 | "abstract": kw("modifier"),
64 |
65 | // operators
66 | "as": operator,
67 |
68 | // types
69 | "string": type, "number": type, "boolean": type, "any": type
70 | };
71 |
72 | for (var attr in tsKeywords) {
73 | jsKeywords[attr] = tsKeywords[attr];
74 | }
75 | }
76 |
77 | return jsKeywords;
78 | }();
79 |
80 | var isOperatorChar = /[+\-*&%=<>!?|~^]/;
81 | var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
82 |
83 | function readRegexp(stream) {
84 | var escaped = false, next, inSet = false;
85 | while ((next = stream.next()) != null) {
86 | if (!escaped) {
87 | if (next == "/" && !inSet) return;
88 | if (next == "[") inSet = true;
89 | else if (inSet && next == "]") inSet = false;
90 | }
91 | escaped = !escaped && next == "\\";
92 | }
93 | }
94 |
95 | // Used as scratch variables to communicate multiple values without
96 | // consing up tons of objects.
97 | var type, content;
98 | function ret(tp, style, cont) {
99 | type = tp; content = cont;
100 | return style;
101 | }
102 | function tokenBase(stream, state) {
103 | var ch = stream.next();
104 | if (ch == '"' || ch == "'") {
105 | state.tokenize = tokenString(ch);
106 | return state.tokenize(stream, state);
107 | } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
108 | return ret("number", "number");
109 | } else if (ch == "." && stream.match("..")) {
110 | return ret("spread", "meta");
111 | } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
112 | return ret(ch);
113 | } else if (ch == "=" && stream.eat(">")) {
114 | return ret("=>", "operator");
115 | } else if (ch == "0" && stream.eat(/x/i)) {
116 | stream.eatWhile(/[\da-f]/i);
117 | return ret("number", "number");
118 | } else if (ch == "0" && stream.eat(/o/i)) {
119 | stream.eatWhile(/[0-7]/i);
120 | return ret("number", "number");
121 | } else if (ch == "0" && stream.eat(/b/i)) {
122 | stream.eatWhile(/[01]/i);
123 | return ret("number", "number");
124 | } else if (/\d/.test(ch)) {
125 | stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
126 | return ret("number", "number");
127 | } else if (ch == "/") {
128 | if (stream.eat("*")) {
129 | state.tokenize = tokenComment;
130 | return tokenComment(stream, state);
131 | } else if (stream.eat("/")) {
132 | stream.skipToEnd();
133 | return ret("comment", "comment");
134 | } else if (expressionAllowed(stream, state, 1)) {
135 | readRegexp(stream);
136 | stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
137 | return ret("regexp", "string-2");
138 | } else {
139 | stream.eatWhile(isOperatorChar);
140 | return ret("operator", "operator", stream.current());
141 | }
142 | } else if (ch == "`") {
143 | state.tokenize = tokenQuasi;
144 | return tokenQuasi(stream, state);
145 | } else if (ch == "#") {
146 | stream.skipToEnd();
147 | return ret("error", "error");
148 | } else if (isOperatorChar.test(ch)) {
149 | if (ch != ">" || !state.lexical || state.lexical.type != ">")
150 | stream.eatWhile(isOperatorChar);
151 | return ret("operator", "operator", stream.current());
152 | } else if (wordRE.test(ch)) {
153 | stream.eatWhile(wordRE);
154 | var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
155 | return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
156 | ret("variable", "variable", word);
157 | }
158 | }
159 |
160 | function tokenString(quote) {
161 | return function(stream, state) {
162 | var escaped = false, next;
163 | if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
164 | state.tokenize = tokenBase;
165 | return ret("jsonld-keyword", "meta");
166 | }
167 | while ((next = stream.next()) != null) {
168 | if (next == quote && !escaped) break;
169 | escaped = !escaped && next == "\\";
170 | }
171 | if (!escaped) state.tokenize = tokenBase;
172 | return ret("string", "string");
173 | };
174 | }
175 |
176 | function tokenComment(stream, state) {
177 | var maybeEnd = false, ch;
178 | while (ch = stream.next()) {
179 | if (ch == "/" && maybeEnd) {
180 | state.tokenize = tokenBase;
181 | break;
182 | }
183 | maybeEnd = (ch == "*");
184 | }
185 | return ret("comment", "comment");
186 | }
187 |
188 | function tokenQuasi(stream, state) {
189 | var escaped = false, next;
190 | while ((next = stream.next()) != null) {
191 | if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
192 | state.tokenize = tokenBase;
193 | break;
194 | }
195 | escaped = !escaped && next == "\\";
196 | }
197 | return ret("quasi", "string-2", stream.current());
198 | }
199 |
200 | var brackets = "([{}])";
201 | // This is a crude lookahead trick to try and notice that we're
202 | // parsing the argument patterns for a fat-arrow function before we
203 | // actually hit the arrow token. It only works if the arrow is on
204 | // the same line as the arguments and there's no strange noise
205 | // (comments) in between. Fallback is to only notice when we hit the
206 | // arrow, and not declare the arguments as locals for the arrow
207 | // body.
208 | function findFatArrow(stream, state) {
209 | if (state.fatArrowAt) state.fatArrowAt = null;
210 | var arrow = stream.string.indexOf("=>", stream.start);
211 | if (arrow < 0) return;
212 |
213 | if (isTS) { // Try to skip TypeScript return type declarations after the arguments
214 | var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
215 | if (m) arrow = m.index
216 | }
217 |
218 | var depth = 0, sawSomething = false;
219 | for (var pos = arrow - 1; pos >= 0; --pos) {
220 | var ch = stream.string.charAt(pos);
221 | var bracket = brackets.indexOf(ch);
222 | if (bracket >= 0 && bracket < 3) {
223 | if (!depth) { ++pos; break; }
224 | if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
225 | } else if (bracket >= 3 && bracket < 6) {
226 | ++depth;
227 | } else if (wordRE.test(ch)) {
228 | sawSomething = true;
229 | } else if (/["'\/]/.test(ch)) {
230 | return;
231 | } else if (sawSomething && !depth) {
232 | ++pos;
233 | break;
234 | }
235 | }
236 | if (sawSomething && !depth) state.fatArrowAt = pos;
237 | }
238 |
239 | // Parser
240 |
241 | var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
242 |
243 | function JSLexical(indented, column, type, align, prev, info) {
244 | this.indented = indented;
245 | this.column = column;
246 | this.type = type;
247 | this.prev = prev;
248 | this.info = info;
249 | if (align != null) this.align = align;
250 | }
251 |
252 | function inScope(state, varname) {
253 | for (var v = state.localVars; v; v = v.next)
254 | if (v.name == varname) return true;
255 | for (var cx = state.context; cx; cx = cx.prev) {
256 | for (var v = cx.vars; v; v = v.next)
257 | if (v.name == varname) return true;
258 | }
259 | }
260 |
261 | function parseJS(state, style, type, content, stream) {
262 | var cc = state.cc;
263 | // Communicate our context to the combinators.
264 | // (Less wasteful than consing up a hundred closures on every call.)
265 | cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
266 |
267 | if (!state.lexical.hasOwnProperty("align"))
268 | state.lexical.align = true;
269 |
270 | while(true) {
271 | var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
272 | if (combinator(type, content)) {
273 | while(cc.length && cc[cc.length - 1].lex)
274 | cc.pop()();
275 | if (cx.marked) return cx.marked;
276 | if (type == "variable" && inScope(state, content)) return "variable-2";
277 | return style;
278 | }
279 | }
280 | }
281 |
282 | // Combinator utils
283 |
284 | var cx = {state: null, column: null, marked: null, cc: null};
285 | function pass() {
286 | for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
287 | }
288 | function cont() {
289 | pass.apply(null, arguments);
290 | return true;
291 | }
292 | function register(varname) {
293 | function inList(list) {
294 | for (var v = list; v; v = v.next)
295 | if (v.name == varname) return true;
296 | return false;
297 | }
298 | var state = cx.state;
299 | cx.marked = "def";
300 | if (state.context) {
301 | if (inList(state.localVars)) return;
302 | state.localVars = {name: varname, next: state.localVars};
303 | } else {
304 | if (inList(state.globalVars)) return;
305 | if (parserConfig.globalVars)
306 | state.globalVars = {name: varname, next: state.globalVars};
307 | }
308 | }
309 |
310 | // Combinators
311 |
312 | var defaultVars = {name: "this", next: {name: "arguments"}};
313 | function pushcontext() {
314 | cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
315 | cx.state.localVars = defaultVars;
316 | }
317 | function popcontext() {
318 | cx.state.localVars = cx.state.context.vars;
319 | cx.state.context = cx.state.context.prev;
320 | }
321 | function pushlex(type, info) {
322 | var result = function() {
323 | var state = cx.state, indent = state.indented;
324 | if (state.lexical.type == "stat") indent = state.lexical.indented;
325 | else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
326 | indent = outer.indented;
327 | state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
328 | };
329 | result.lex = true;
330 | return result;
331 | }
332 | function poplex() {
333 | var state = cx.state;
334 | if (state.lexical.prev) {
335 | if (state.lexical.type == ")")
336 | state.indented = state.lexical.indented;
337 | state.lexical = state.lexical.prev;
338 | }
339 | }
340 | poplex.lex = true;
341 |
342 | function expect(wanted) {
343 | function exp(type) {
344 | if (type == wanted) return cont();
345 | else if (wanted == ";") return pass();
346 | else return cont(exp);
347 | };
348 | return exp;
349 | }
350 |
351 | function statement(type, value) {
352 | if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
353 | if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
354 | if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
355 | if (type == "{") return cont(pushlex("}"), block, poplex);
356 | if (type == ";") return cont();
357 | if (type == "if") {
358 | if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
359 | cx.state.cc.pop()();
360 | return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
361 | }
362 | if (type == "function") return cont(functiondef);
363 | if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
364 | if (type == "variable") return cont(pushlex("stat"), maybelabel);
365 | if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"),
366 | block, poplex, poplex);
367 | if (type == "case") return cont(expression, expect(":"));
368 | if (type == "default") return cont(expect(":"));
369 | if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
370 | statement, poplex, popcontext);
371 | if (type == "class") return cont(pushlex("form"), className, poplex);
372 | if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
373 | if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
374 | if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
375 | if (type == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
376 | if (type == "async") return cont(statement)
377 | return pass(pushlex("stat"), expression, expect(";"), poplex);
378 | }
379 | function expression(type) {
380 | return expressionInner(type, false);
381 | }
382 | function expressionNoComma(type) {
383 | return expressionInner(type, true);
384 | }
385 | function parenExpr(type) {
386 | if (type != "(") return pass()
387 | return cont(pushlex(")"), expression, expect(")"), poplex)
388 | }
389 | function expressionInner(type, noComma) {
390 | if (cx.state.fatArrowAt == cx.stream.start) {
391 | var body = noComma ? arrowBodyNoComma : arrowBody;
392 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
393 | else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
394 | }
395 |
396 | var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
397 | if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
398 | if (type == "function") return cont(functiondef, maybeop);
399 | if (type == "class") return cont(pushlex("form"), classExpression, poplex);
400 | if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
401 | if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
402 | if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
403 | if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
404 | if (type == "{") return contCommasep(objprop, "}", null, maybeop);
405 | if (type == "quasi") return pass(quasi, maybeop);
406 | if (type == "new") return cont(maybeTarget(noComma));
407 | return cont();
408 | }
409 | function maybeexpression(type) {
410 | if (type.match(/[;\}\)\],]/)) return pass();
411 | return pass(expression);
412 | }
413 | function maybeexpressionNoComma(type) {
414 | if (type.match(/[;\}\)\],]/)) return pass();
415 | return pass(expressionNoComma);
416 | }
417 |
418 | function maybeoperatorComma(type, value) {
419 | if (type == ",") return cont(expression);
420 | return maybeoperatorNoComma(type, value, false);
421 | }
422 | function maybeoperatorNoComma(type, value, noComma) {
423 | var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
424 | var expr = noComma == false ? expression : expressionNoComma;
425 | if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
426 | if (type == "operator") {
427 | if (/\+\+|--/.test(value)) return cont(me);
428 | if (value == "?") return cont(expression, expect(":"), expr);
429 | return cont(expr);
430 | }
431 | if (type == "quasi") { return pass(quasi, me); }
432 | if (type == ";") return;
433 | if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
434 | if (type == ".") return cont(property, me);
435 | if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
436 | }
437 | function quasi(type, value) {
438 | if (type != "quasi") return pass();
439 | if (value.slice(value.length - 2) != "${") return cont(quasi);
440 | return cont(expression, continueQuasi);
441 | }
442 | function continueQuasi(type) {
443 | if (type == "}") {
444 | cx.marked = "string-2";
445 | cx.state.tokenize = tokenQuasi;
446 | return cont(quasi);
447 | }
448 | }
449 | function arrowBody(type) {
450 | findFatArrow(cx.stream, cx.state);
451 | return pass(type == "{" ? statement : expression);
452 | }
453 | function arrowBodyNoComma(type) {
454 | findFatArrow(cx.stream, cx.state);
455 | return pass(type == "{" ? statement : expressionNoComma);
456 | }
457 | function maybeTarget(noComma) {
458 | return function(type) {
459 | if (type == ".") return cont(noComma ? targetNoComma : target);
460 | else return pass(noComma ? expressionNoComma : expression);
461 | };
462 | }
463 | function target(_, value) {
464 | if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
465 | }
466 | function targetNoComma(_, value) {
467 | if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
468 | }
469 | function maybelabel(type) {
470 | if (type == ":") return cont(poplex, statement);
471 | return pass(maybeoperatorComma, expect(";"), poplex);
472 | }
473 | function property(type) {
474 | if (type == "variable") {cx.marked = "property"; return cont();}
475 | }
476 | function objprop(type, value) {
477 | if (type == "async") {
478 | cx.marked = "property";
479 | return cont(objprop);
480 | } else if (type == "variable" || cx.style == "keyword") {
481 | cx.marked = "property";
482 | if (value == "get" || value == "set") return cont(getterSetter);
483 | return cont(afterprop);
484 | } else if (type == "number" || type == "string") {
485 | cx.marked = jsonldMode ? "property" : (cx.style + " property");
486 | return cont(afterprop);
487 | } else if (type == "jsonld-keyword") {
488 | return cont(afterprop);
489 | } else if (type == "modifier") {
490 | return cont(objprop)
491 | } else if (type == "[") {
492 | return cont(expression, expect("]"), afterprop);
493 | } else if (type == "spread") {
494 | return cont(expression);
495 | } else if (type == ":") {
496 | return pass(afterprop)
497 | }
498 | }
499 | function getterSetter(type) {
500 | if (type != "variable") return pass(afterprop);
501 | cx.marked = "property";
502 | return cont(functiondef);
503 | }
504 | function afterprop(type) {
505 | if (type == ":") return cont(expressionNoComma);
506 | if (type == "(") return pass(functiondef);
507 | }
508 | function commasep(what, end, sep) {
509 | function proceed(type, value) {
510 | if (sep ? sep.indexOf(type) > -1 : type == ",") {
511 | var lex = cx.state.lexical;
512 | if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
513 | return cont(function(type, value) {
514 | if (type == end || value == end) return pass()
515 | return pass(what)
516 | }, proceed);
517 | }
518 | if (type == end || value == end) return cont();
519 | return cont(expect(end));
520 | }
521 | return function(type, value) {
522 | if (type == end || value == end) return cont();
523 | return pass(what, proceed);
524 | };
525 | }
526 | function contCommasep(what, end, info) {
527 | for (var i = 3; i < arguments.length; i++)
528 | cx.cc.push(arguments[i]);
529 | return cont(pushlex(end, info), commasep(what, end), poplex);
530 | }
531 | function block(type) {
532 | if (type == "}") return cont();
533 | return pass(statement, block);
534 | }
535 | function maybetype(type, value) {
536 | if (isTS) {
537 | if (type == ":") return cont(typeexpr);
538 | if (value == "?") return cont(maybetype);
539 | }
540 | }
541 | function typeexpr(type) {
542 | if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
543 | if (type == "string" || type == "number" || type == "atom") return cont(afterType);
544 | if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex)
545 | if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
546 | }
547 | function maybeReturnType(type) {
548 | if (type == "=>") return cont(typeexpr)
549 | }
550 | function typeprop(type, value) {
551 | if (type == "variable" || cx.style == "keyword") {
552 | cx.marked = "property"
553 | return cont(typeprop)
554 | } else if (value == "?") {
555 | return cont(typeprop)
556 | } else if (type == ":") {
557 | return cont(typeexpr)
558 | }
559 | }
560 | function typearg(type) {
561 | if (type == "variable") return cont(typearg)
562 | else if (type == ":") return cont(typeexpr)
563 | }
564 | function afterType(type, value) {
565 | if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
566 | if (value == "|" || type == ".") return cont(typeexpr)
567 | if (type == "[") return cont(expect("]"), afterType)
568 | }
569 | function vardef() {
570 | return pass(pattern, maybetype, maybeAssign, vardefCont);
571 | }
572 | function pattern(type, value) {
573 | if (type == "modifier") return cont(pattern)
574 | if (type == "variable") { register(value); return cont(); }
575 | if (type == "spread") return cont(pattern);
576 | if (type == "[") return contCommasep(pattern, "]");
577 | if (type == "{") return contCommasep(proppattern, "}");
578 | }
579 | function proppattern(type, value) {
580 | if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
581 | register(value);
582 | return cont(maybeAssign);
583 | }
584 | if (type == "variable") cx.marked = "property";
585 | if (type == "spread") return cont(pattern);
586 | if (type == "}") return pass();
587 | return cont(expect(":"), pattern, maybeAssign);
588 | }
589 | function maybeAssign(_type, value) {
590 | if (value == "=") return cont(expressionNoComma);
591 | }
592 | function vardefCont(type) {
593 | if (type == ",") return cont(vardef);
594 | }
595 | function maybeelse(type, value) {
596 | if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
597 | }
598 | function forspec(type) {
599 | if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
600 | }
601 | function forspec1(type) {
602 | if (type == "var") return cont(vardef, expect(";"), forspec2);
603 | if (type == ";") return cont(forspec2);
604 | if (type == "variable") return cont(formaybeinof);
605 | return pass(expression, expect(";"), forspec2);
606 | }
607 | function formaybeinof(_type, value) {
608 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
609 | return cont(maybeoperatorComma, forspec2);
610 | }
611 | function forspec2(type, value) {
612 | if (type == ";") return cont(forspec3);
613 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
614 | return pass(expression, expect(";"), forspec3);
615 | }
616 | function forspec3(type) {
617 | if (type != ")") cont(expression);
618 | }
619 | function functiondef(type, value) {
620 | if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
621 | if (type == "variable") {register(value); return cont(functiondef);}
622 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
623 | }
624 | function funarg(type) {
625 | if (type == "spread") return cont(funarg);
626 | return pass(pattern, maybetype, maybeAssign);
627 | }
628 | function classExpression(type, value) {
629 | // Class expressions may have an optional name.
630 | if (type == "variable") return className(type, value);
631 | return classNameAfter(type, value);
632 | }
633 | function className(type, value) {
634 | if (type == "variable") {register(value); return cont(classNameAfter);}
635 | }
636 | function classNameAfter(type, value) {
637 | if (value == "extends" || value == "implements") return cont(isTS ? typeexpr : expression, classNameAfter);
638 | if (type == "{") return cont(pushlex("}"), classBody, poplex);
639 | }
640 | function classBody(type, value) {
641 | if (type == "variable" || cx.style == "keyword") {
642 | if ((value == "static" || value == "get" || value == "set" ||
643 | (isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
644 | cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
645 | cx.marked = "keyword";
646 | return cont(classBody);
647 | }
648 | cx.marked = "property";
649 | return cont(isTS ? classfield : functiondef, classBody);
650 | }
651 | if (value == "*") {
652 | cx.marked = "keyword";
653 | return cont(classBody);
654 | }
655 | if (type == ";") return cont(classBody);
656 | if (type == "}") return cont();
657 | }
658 | function classfield(type, value) {
659 | if (value == "?") return cont(classfield)
660 | if (type == ":") return cont(typeexpr, maybeAssign)
661 | return pass(functiondef)
662 | }
663 | function afterExport(type, value) {
664 | if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
665 | if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
666 | if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
667 | return pass(statement);
668 | }
669 | function exportField(type, value) {
670 | if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
671 | if (type == "variable") return pass(expressionNoComma, exportField);
672 | }
673 | function afterImport(type) {
674 | if (type == "string") return cont();
675 | return pass(importSpec, maybeMoreImports, maybeFrom);
676 | }
677 | function importSpec(type, value) {
678 | if (type == "{") return contCommasep(importSpec, "}");
679 | if (type == "variable") register(value);
680 | if (value == "*") cx.marked = "keyword";
681 | return cont(maybeAs);
682 | }
683 | function maybeMoreImports(type) {
684 | if (type == ",") return cont(importSpec, maybeMoreImports)
685 | }
686 | function maybeAs(_type, value) {
687 | if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
688 | }
689 | function maybeFrom(_type, value) {
690 | if (value == "from") { cx.marked = "keyword"; return cont(expression); }
691 | }
692 | function arrayLiteral(type) {
693 | if (type == "]") return cont();
694 | return pass(commasep(expressionNoComma, "]"));
695 | }
696 |
697 | function isContinuedStatement(state, textAfter) {
698 | return state.lastType == "operator" || state.lastType == "," ||
699 | isOperatorChar.test(textAfter.charAt(0)) ||
700 | /[,.]/.test(textAfter.charAt(0));
701 | }
702 |
703 | // Interface
704 |
705 | return {
706 | startState: function(basecolumn) {
707 | var state = {
708 | tokenize: tokenBase,
709 | lastType: "sof",
710 | cc: [],
711 | lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
712 | localVars: parserConfig.localVars,
713 | context: parserConfig.localVars && {vars: parserConfig.localVars},
714 | indented: basecolumn || 0
715 | };
716 | if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
717 | state.globalVars = parserConfig.globalVars;
718 | return state;
719 | },
720 |
721 | token: function(stream, state) {
722 | if (stream.sol()) {
723 | if (!state.lexical.hasOwnProperty("align"))
724 | state.lexical.align = false;
725 | state.indented = stream.indentation();
726 | findFatArrow(stream, state);
727 | }
728 | if (state.tokenize != tokenComment && stream.eatSpace()) return null;
729 | var style = state.tokenize(stream, state);
730 | if (type == "comment") return style;
731 | state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
732 | return parseJS(state, style, type, content, stream);
733 | },
734 |
735 | indent: function(state, textAfter) {
736 | if (state.tokenize == tokenComment) return CodeMirror.Pass;
737 | if (state.tokenize != tokenBase) return 0;
738 | var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
739 | // Kludge to prevent 'maybelse' from blocking lexical scope pops
740 | if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
741 | var c = state.cc[i];
742 | if (c == poplex) lexical = lexical.prev;
743 | else if (c != maybeelse) break;
744 | }
745 | while ((lexical.type == "stat" || lexical.type == "form") &&
746 | (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
747 | (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
748 | !/^[,\.=+\-*:?[\(]/.test(textAfter))))
749 | lexical = lexical.prev;
750 | if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
751 | lexical = lexical.prev;
752 | var type = lexical.type, closing = firstChar == type;
753 |
754 | if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
755 | else if (type == "form" && firstChar == "{") return lexical.indented;
756 | else if (type == "form") return lexical.indented + indentUnit;
757 | else if (type == "stat")
758 | return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
759 | else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
760 | return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
761 | else if (lexical.align) return lexical.column + (closing ? 0 : 1);
762 | else return lexical.indented + (closing ? 0 : indentUnit);
763 | },
764 |
765 | electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
766 | blockCommentStart: jsonMode ? null : "/*",
767 | blockCommentEnd: jsonMode ? null : "*/",
768 | lineComment: jsonMode ? null : "//",
769 | fold: "brace",
770 | closeBrackets: "()[]{}''\"\"``",
771 |
772 | helperType: jsonMode ? "json" : "javascript",
773 | jsonldMode: jsonldMode,
774 | jsonMode: jsonMode,
775 |
776 | expressionAllowed: expressionAllowed,
777 | skipExpression: function(state) {
778 | var top = state.cc[state.cc.length - 1]
779 | if (top == expression || top == expressionNoComma) state.cc.pop()
780 | }
781 | };
782 | });
783 |
784 | CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
785 |
786 | CodeMirror.defineMIME("text/javascript", "javascript");
787 | CodeMirror.defineMIME("text/ecmascript", "javascript");
788 | CodeMirror.defineMIME("application/javascript", "javascript");
789 | CodeMirror.defineMIME("application/x-javascript", "javascript");
790 | CodeMirror.defineMIME("application/ecmascript", "javascript");
791 | CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
792 | CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
793 | CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
794 | CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
795 | CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
796 |
797 | });
798 |
--------------------------------------------------------------------------------
/app/js/loadmode.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
3 |
4 | var loading = {};
5 | function splitCallback(cont, n) {
6 | var countDown = n;
7 | return function() { if (--countDown == 0) cont(); }
8 | }
9 | function ensureDeps(mode, cont) {
10 | var deps = CodeMirror.modes[mode].dependencies;
11 | if (!deps) return cont();
12 | var missing = [];
13 | for (var i = 0; i < deps.length; ++i) {
14 | if (!CodeMirror.modes.hasOwnProperty(deps[i]))
15 | missing.push(deps[i]);
16 | }
17 | if (!missing.length) return cont();
18 | var split = splitCallback(cont, missing.length);
19 | for (var i = 0; i < missing.length; ++i)
20 | CodeMirror.requireMode(missing[i], split);
21 | }
22 |
23 | CodeMirror.requireMode = function(mode, cont) {
24 | if (typeof mode != "string") mode = mode.name;
25 | if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
26 | if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
27 |
28 | var script = document.createElement("script");
29 | script.src = CodeMirror.modeURL.replace(/%N/g, mode);
30 | var others = document.getElementsByTagName("script")[0];
31 | others.parentNode.insertBefore(script, others);
32 | var list = loading[mode] = [cont];
33 | var count = 0, poll = setInterval(function() {
34 | if (++count > 100) return clearInterval(poll);
35 | if (CodeMirror.modes.hasOwnProperty(mode)) {
36 | clearInterval(poll);
37 | loading[mode] = null;
38 | ensureDeps(mode, function() {
39 | for (var i = 0; i < list.length; ++i) list[i]();
40 | });
41 | }
42 | }, 200);
43 | };
44 |
45 | CodeMirror.autoLoadMode = function(instance, mode) {
46 | if (!CodeMirror.modes.hasOwnProperty(mode))
47 | CodeMirror.requireMode(mode, function() {
48 | instance.setOption("mode", instance.getOption("mode"));
49 | });
50 | };
51 | }());
52 |
--------------------------------------------------------------------------------
/app/js/match-highlighter.js:
--------------------------------------------------------------------------------
1 | // Define match-highlighter commands. Depends on searchcursor.js
2 | // Use by attaching the following function call to the onCursorActivity event:
3 | //myCodeMirror.matchHighlight(minChars);
4 | // And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html)
5 |
6 | (function() {
7 | var DEFAULT_MIN_CHARS = 2;
8 |
9 | function MatchHighlightState() {
10 | this.marked = [];
11 | }
12 | function getMatchHighlightState(cm) {
13 | return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState());
14 | }
15 |
16 | function clearMarks(cm) {
17 | var state = getMatchHighlightState(cm);
18 | for (var i = 0; i < state.marked.length; ++i)
19 | state.marked[i].clear();
20 | state.marked = [];
21 | }
22 |
23 | function markDocument(cm, className, minChars) {
24 | clearMarks(cm);
25 | minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS);
26 | if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length >= minChars) {
27 | var state = getMatchHighlightState(cm);
28 | var query = cm.getSelection();
29 | cm.operation(function() {
30 | if (cm.lineCount() < 2000) { // This is too expensive on big documents.
31 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
32 | //Only apply matchhighlight to the matches other than the one actually selected
33 | if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch))
34 | state.marked.push(cm.markText(cursor.from(), cursor.to(), className));
35 | }
36 | }
37 | });
38 | }
39 | }
40 |
41 | CodeMirror.defineExtension("matchHighlight", function(className, minChars) {
42 | markDocument(this, className, minChars);
43 | });
44 | })();
45 |
--------------------------------------------------------------------------------
/app/js/meta.js:
--------------------------------------------------------------------------------
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.modeInfo = [
15 | {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
16 | {name: "PGP", mimes: ["application/pgp", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["pgp"]},
17 | {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
18 | {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
19 | {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
20 | {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]},
21 | {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
22 | {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
23 | {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
24 | {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
25 | {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
26 | {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
27 | {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
28 | {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
29 | {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
30 | {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
31 | {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
32 | {name: "Crystal", mime: "text/x-crystal", mode: "crystal", ext: ["cr"]},
33 | {name: "CSS", mime: "text/css", mode: "css", ext: ["css"]},
34 | {name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]},
35 | {name: "D", mime: "text/x-d", mode: "d", ext: ["d"]},
36 | {name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]},
37 | {name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]},
38 | {name: "Django", mime: "text/x-django", mode: "django"},
39 | {name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/},
40 | {name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]},
41 | {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
42 | {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
43 | {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
44 | {name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]},
45 | {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
46 | {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
47 | {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
48 | {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
49 | {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
50 | {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
51 | {name: "FCL", mime: "text/x-fcl", mode: "fcl"},
52 | {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
53 | {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
54 | {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
55 | {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
56 | {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
57 | {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
58 | {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
59 | {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
60 | {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
61 | {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
62 | {name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]},
63 | {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
64 | {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
65 | {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
66 | {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]},
67 | {name: "HTTP", mime: "message/http", mode: "http"},
68 | {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
69 | {name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]},
70 | {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
71 | {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
72 | {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
73 | mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]},
74 | {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
75 | {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
76 | {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
77 | {name: "Jinja2", mime: "null", mode: "jinja2"},
78 | {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
79 | {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
80 | {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
81 | {name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]},
82 | {name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]},
83 | {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
84 | {name: "mIRC", mime: "text/mirc", mode: "mirc"},
85 | {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
86 | {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
87 | {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
88 | {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
89 | {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
90 | {name: "mbox", mime: "application/mbox", mode: "mbox", ext: ["mbox"]},
91 | {name: "MySQL", mime: "text/x-mysql", mode: "sql"},
92 | {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
93 | {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
94 | {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
95 | {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]},
96 | {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
97 | {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
98 | {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
99 | {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
100 | {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
101 | {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
102 | {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]},
103 | {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
104 | {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
105 | {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
106 | {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
107 | {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
108 | {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
109 | {name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/},
110 | {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
111 | {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
112 | {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]},
113 | {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
114 | {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
115 | {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
116 | {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
117 | {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
118 | {name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]},
119 | {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
120 | {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
121 | {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
122 | {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
123 | {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/},
124 | {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]},
125 | {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]},
126 | {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
127 | {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
128 | {name: "Solr", mime: "text/x-solr", mode: "solr"},
129 | {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
130 | {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
131 | {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
132 | {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
133 | {name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
134 | {name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]},
135 | {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
136 | {name: "sTeX", mime: "text/x-stex", mode: "stex"},
137 | {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
138 | {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
139 | {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
140 | {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
141 | {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
142 | {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
143 | {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
144 | {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
145 | {name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
146 | {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
147 | {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
148 | {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
149 | {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
150 | {name: "Twig", mime: "text/x-twig", mode: "twig"},
151 | {name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]},
152 | {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
153 | {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
154 | {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
155 | {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
156 | {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
157 | {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]},
158 | {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]},
159 | {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
160 | {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]},
161 | {name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
162 | {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
163 | {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
164 | {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
165 | {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]}
166 | ];
167 | // Ensure all modes have a mime property for backwards compatibility
168 | for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
169 | var info = CodeMirror.modeInfo[i];
170 | if (info.mimes) info.mime = info.mimes[0];
171 | }
172 |
173 | CodeMirror.findModeByMIME = function(mime) {
174 | mime = mime.toLowerCase();
175 | for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
176 | var info = CodeMirror.modeInfo[i];
177 | if (info.mime == mime) return info;
178 | if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
179 | if (info.mimes[j] == mime) return info;
180 | }
181 | if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml")
182 | if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json")
183 | };
184 |
185 | CodeMirror.findModeByExtension = function(ext) {
186 | for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
187 | var info = CodeMirror.modeInfo[i];
188 | if (info.ext) for (var j = 0; j < info.ext.length; j++)
189 | if (info.ext[j] == ext) return info;
190 | }
191 | };
192 |
193 | CodeMirror.findModeByFileName = function(filename) {
194 | for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
195 | var info = CodeMirror.modeInfo[i];
196 | if (info.file && info.file.test(filename)) return info;
197 | }
198 | var dot = filename.lastIndexOf(".");
199 | var ext = dot > -1 && filename.substring(dot + 1, filename.length);
200 | if (ext) return CodeMirror.findModeByExtension(ext);
201 | };
202 |
203 | CodeMirror.findModeByName = function(name) {
204 | name = name.toLowerCase();
205 | for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
206 | var info = CodeMirror.modeInfo[i];
207 | if (info.name.toLowerCase() == name) return info;
208 | if (info.alias) for (var j = 0; j < info.alias.length; j++)
209 | if (info.alias[j].toLowerCase() == name) return info;
210 | }
211 | };
212 | });
213 |
--------------------------------------------------------------------------------
/app/js/overlay.js:
--------------------------------------------------------------------------------
1 | // Utility function that allows modes to be combined. The mode given
2 | // as the base argument takes care of most of the normal mode
3 | // functionality, but a second (typically simple) mode is used, which
4 | // can override the style of text. Both modes get to parse all of the
5 | // text, but when both assign a non-null style to a piece of code, the
6 | // overlay wins, unless the combine argument was true, in which case
7 | // the styles are combined.
8 |
9 | CodeMirror.overlayParser = function(base, overlay, combine) {
10 | return {
11 | startState: function() {
12 | return {
13 | base: CodeMirror.startState(base),
14 | overlay: CodeMirror.startState(overlay),
15 | basePos: 0, baseCur: null,
16 | overlayPos: 0, overlayCur: null
17 | };
18 | },
19 | copyState: function(state) {
20 | return {
21 | base: CodeMirror.copyState(base, state.base),
22 | overlay: CodeMirror.copyState(overlay, state.overlay),
23 | basePos: state.basePos, baseCur: null,
24 | overlayPos: state.overlayPos, overlayCur: null
25 | };
26 | },
27 |
28 | token: function(stream, state) {
29 | if (stream.start == state.basePos) {
30 | state.baseCur = base.token(stream, state.base);
31 | state.basePos = stream.pos;
32 | }
33 | if (stream.start == state.overlayPos) {
34 | stream.pos = stream.start;
35 | state.overlayCur = overlay.token(stream, state.overlay);
36 | state.overlayPos = stream.pos;
37 | }
38 | stream.pos = Math.min(state.basePos, state.overlayPos);
39 | if (stream.eol()) state.basePos = state.overlayPos = 0;
40 |
41 | if (state.overlayCur == null) return state.baseCur;
42 | if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
43 | else return state.overlayCur;
44 | },
45 |
46 | indent: base.indent && function(state, textAfter) {
47 | return base.indent(state.base, textAfter);
48 | },
49 | electricChars: base.electricChars
50 | };
51 | };
52 |
--------------------------------------------------------------------------------
/app/js/runmode.js:
--------------------------------------------------------------------------------
1 | CodeMirror.runMode = function(string, modespec, callback, options) {
2 | var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
3 | var isNode = callback.nodeType == 1;
4 | var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
5 | if (isNode) {
6 | var node = callback, accum = [], col = 0;
7 | callback = function(text, style) {
8 | if (text == "\n") {
9 | accum.push("
");
10 | col = 0;
11 | return;
12 | }
13 | var escaped = "";
14 | // HTML-escape and replace tabs
15 | for (var pos = 0;;) {
16 | var idx = text.indexOf("\t", pos);
17 | if (idx == -1) {
18 | escaped += CodeMirror.htmlEscape(text.slice(pos));
19 | col += text.length - pos;
20 | break;
21 | } else {
22 | col += idx - pos;
23 | escaped += CodeMirror.htmlEscape(text.slice(pos, idx));
24 | var size = tabSize - col % tabSize;
25 | col += size;
26 | for (var i = 0; i < size; ++i) escaped += " ";
27 | pos = idx + 1;
28 | }
29 | }
30 |
31 | if (style)
32 | accum.push("" + escaped + "");
33 | else
34 | accum.push(escaped);
35 | }
36 | }
37 | var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
38 | for (var i = 0, e = lines.length; i < e; ++i) {
39 | if (i) callback("\n");
40 | var stream = new CodeMirror.StringStream(lines[i]);
41 | while (!stream.eol()) {
42 | var style = mode.token(stream, state);
43 | callback(stream.current(), style, i, stream.start);
44 | stream.start = stream.pos;
45 | }
46 | }
47 | if (isNode)
48 | node.innerHTML = accum.join("");
49 | };
50 |
--------------------------------------------------------------------------------
/app/js/search.js:
--------------------------------------------------------------------------------
1 | // Define search commands. Depends on dialog.js or another
2 | // implementation of the openDialog method.
3 |
4 | // Replace works a little oddly -- it will do the replace on the next
5 | // Ctrl-G (or whatever is bound to findNext) press. You prevent a
6 | // replace by making sure the match is no longer selected when hitting
7 | // Ctrl-G.
8 |
9 | (function() {
10 | function SearchState() {
11 | this.posFrom = this.posTo = this.query = null;
12 | this.marked = [];
13 | }
14 | function getSearchState(cm) {
15 | return cm._searchState || (cm._searchState = new SearchState());
16 | }
17 | function dialog(cm, text, shortText, f) {
18 | if (cm.openDialog) cm.openDialog(text, f);
19 | else f(prompt(shortText, ""));
20 | }
21 | function confirmDialog(cm, text, shortText, fs) {
22 | if (cm.openConfirm) cm.openConfirm(text, fs);
23 | else if (confirm(shortText)) fs[0]();
24 | }
25 | function parseQuery(query) {
26 | var isRE = query.match(/^\/(.*)\/$/);
27 | return isRE ? new RegExp(isRE[1]) : query;
28 | }
29 | var queryDialog =
30 | 'Search: (Use /re/ syntax for regexp search)';
31 | function doSearch(cm, rev) {
32 | var state = getSearchState(cm);
33 | if (state.query) return findNext(cm, rev);
34 | dialog(cm, queryDialog, "Search for:", function(query) {
35 | cm.operation(function() {
36 | if (!query || state.query) return;
37 | state.query = parseQuery(query);
38 | if (cm.lineCount() < 2000) { // This is too expensive on big documents.
39 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
40 | state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
41 | }
42 | state.posFrom = state.posTo = cm.getCursor();
43 | findNext(cm, rev);
44 | });
45 | });
46 | }
47 | function findNext(cm, rev) {cm.operation(function() {
48 | var state = getSearchState(cm);
49 | var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
50 | if (!cursor.find(rev)) {
51 | cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
52 | if (!cursor.find(rev)) return;
53 | }
54 | cm.setSelection(cursor.from(), cursor.to());
55 | state.posFrom = cursor.from(); state.posTo = cursor.to();
56 | })}
57 | function clearSearch(cm) {cm.operation(function() {
58 | var state = getSearchState(cm);
59 | if (!state.query) return;
60 | state.query = null;
61 | for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
62 | state.marked.length = 0;
63 | })}
64 |
65 | var replaceQueryDialog =
66 | 'Replace: (Use /re/ syntax for regexp search)';
67 | var replacementQueryDialog = 'With: ';
68 | var doReplaceConfirm = "Replace? ";
69 | function replace(cm, all) {
70 | dialog(cm, replaceQueryDialog, "Replace:", function(query) {
71 | if (!query) return;
72 | query = parseQuery(query);
73 | dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
74 | if (all) {
75 | cm.compoundChange(function() { cm.operation(function() {
76 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
77 | if (typeof query != "string") {
78 | var match = cm.getRange(cursor.from(), cursor.to()).match(query);
79 | cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
80 | } else cursor.replace(text);
81 | }
82 | })});
83 | } else {
84 | clearSearch(cm);
85 | var cursor = cm.getSearchCursor(query, cm.getCursor());
86 | function advance() {
87 | var start = cursor.from(), match;
88 | if (!(match = cursor.findNext())) {
89 | cursor = cm.getSearchCursor(query);
90 | if (!(match = cursor.findNext()) ||
91 | (cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
92 | }
93 | cm.setSelection(cursor.from(), cursor.to());
94 | confirmDialog(cm, doReplaceConfirm, "Replace?",
95 | [function() {doReplace(match);}, advance]);
96 | }
97 | function doReplace(match) {
98 | cursor.replace(typeof query == "string" ? text :
99 | text.replace(/\$(\d)/, function(w, i) {return match[i];}));
100 | advance();
101 | }
102 | advance();
103 | }
104 | });
105 | });
106 | }
107 |
108 | CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
109 | CodeMirror.commands.findNext = doSearch;
110 | CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
111 | CodeMirror.commands.clearSearch = clearSearch;
112 | CodeMirror.commands.replace = replace;
113 | CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
114 | })();
115 |
--------------------------------------------------------------------------------
/app/js/searchcursor.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | function SearchCursor(cm, query, pos, caseFold) {
3 | this.atOccurrence = false; this.cm = cm;
4 | if (caseFold == null && typeof query == "string") caseFold = false;
5 |
6 | pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
7 | this.pos = {from: pos, to: pos};
8 |
9 | // The matches method is filled in based on the type of query.
10 | // It takes a position and a direction, and returns an object
11 | // describing the next occurrence of the query, or null if no
12 | // more matches were found.
13 | if (typeof query != "string") // Regexp match
14 | this.matches = function(reverse, pos) {
15 | if (reverse) {
16 | var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0;
17 | while (match) {
18 | var ind = line.indexOf(match[0]);
19 | start += ind;
20 | line = line.slice(ind + 1);
21 | var newmatch = line.match(query);
22 | if (newmatch) match = newmatch;
23 | else break;
24 | start++;
25 | }
26 | }
27 | else {
28 | var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query),
29 | start = match && pos.ch + line.indexOf(match[0]);
30 | }
31 | if (match)
32 | return {from: {line: pos.line, ch: start},
33 | to: {line: pos.line, ch: start + match[0].length},
34 | match: match};
35 | };
36 | else { // String query
37 | if (caseFold) query = query.toLowerCase();
38 | var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
39 | var target = query.split("\n");
40 | // Different methods for single-line and multi-line queries
41 | if (target.length == 1)
42 | this.matches = function(reverse, pos) {
43 | var line = fold(cm.getLine(pos.line)), len = query.length, match;
44 | if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
45 | : (match = line.indexOf(query, pos.ch)) != -1)
46 | return {from: {line: pos.line, ch: match},
47 | to: {line: pos.line, ch: match + len}};
48 | };
49 | else
50 | this.matches = function(reverse, pos) {
51 | var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
52 | var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
53 | if (reverse ? offsetA >= pos.ch || offsetA != match.length
54 | : offsetA <= pos.ch || offsetA != line.length - match.length)
55 | return;
56 | for (;;) {
57 | if (reverse ? !ln : ln == cm.lineCount() - 1) return;
58 | line = fold(cm.getLine(ln += reverse ? -1 : 1));
59 | match = target[reverse ? --idx : ++idx];
60 | if (idx > 0 && idx < target.length - 1) {
61 | if (line != match) return;
62 | else continue;
63 | }
64 | var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
65 | if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
66 | return;
67 | var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
68 | return {from: reverse ? end : start, to: reverse ? start : end};
69 | }
70 | };
71 | }
72 | }
73 |
74 | SearchCursor.prototype = {
75 | findNext: function() {return this.find(false);},
76 | findPrevious: function() {return this.find(true);},
77 |
78 | find: function(reverse) {
79 | var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
80 | function savePosAndFail(line) {
81 | var pos = {line: line, ch: 0};
82 | self.pos = {from: pos, to: pos};
83 | self.atOccurrence = false;
84 | return false;
85 | }
86 |
87 | for (;;) {
88 | if (this.pos = this.matches(reverse, pos)) {
89 | this.atOccurrence = true;
90 | return this.pos.match || true;
91 | }
92 | if (reverse) {
93 | if (!pos.line) return savePosAndFail(0);
94 | pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length};
95 | }
96 | else {
97 | var maxLine = this.cm.lineCount();
98 | if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
99 | pos = {line: pos.line+1, ch: 0};
100 | }
101 | }
102 | },
103 |
104 | from: function() {if (this.atOccurrence) return this.pos.from;},
105 | to: function() {if (this.atOccurrence) return this.pos.to;},
106 |
107 | replace: function(newText) {
108 | var self = this;
109 | if (this.atOccurrence)
110 | self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to);
111 | }
112 | };
113 |
114 | CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
115 | return new SearchCursor(this, query, pos, caseFold);
116 | });
117 | })();
118 |
--------------------------------------------------------------------------------
/app/js/simple-hint.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | CodeMirror.simpleHint = function(editor, getHints) {
3 | // We want a single cursor position.
4 | if (editor.somethingSelected()) return;
5 | var result = getHints(editor);
6 | if (!result || !result.list.length) return;
7 | var completions = result.list;
8 | function insert(str) {
9 | editor.replaceRange(str, result.from, result.to);
10 | }
11 | // When there is only one completion, use it directly.
12 | if (completions.length == 1) {insert(completions[0]); return true;}
13 |
14 | // Build the select widget
15 | var complete = document.createElement("div");
16 | complete.className = "CodeMirror-completions";
17 | var sel = complete.appendChild(document.createElement("select"));
18 | // Opera doesn't move the selection when pressing up/down in a
19 | // multi-select, but it does properly support the size property on
20 | // single-selects, so no multi-select is necessary.
21 | if (!window.opera) sel.multiple = true;
22 | for (var i = 0; i < completions.length; ++i) {
23 | var opt = sel.appendChild(document.createElement("option"));
24 | opt.appendChild(document.createTextNode(completions[i]));
25 | }
26 | sel.firstChild.selected = true;
27 | sel.size = Math.min(10, completions.length);
28 | var pos = editor.cursorCoords();
29 | complete.style.left = pos.x + "px";
30 | complete.style.top = pos.yBot + "px";
31 | document.body.appendChild(complete);
32 | // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
33 | var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
34 | if(winW - pos.x < sel.clientWidth)
35 | complete.style.left = (pos.x - sel.clientWidth) + "px";
36 | // Hack to hide the scrollbar.
37 | if (completions.length <= 10)
38 | complete.style.width = (sel.clientWidth - 1) + "px";
39 |
40 | var done = false;
41 | function close() {
42 | if (done) return;
43 | done = true;
44 | complete.parentNode.removeChild(complete);
45 | }
46 | function pick() {
47 | insert(completions[sel.selectedIndex]);
48 | close();
49 | setTimeout(function(){editor.focus();}, 50);
50 | }
51 | CodeMirror.connect(sel, "blur", close);
52 | CodeMirror.connect(sel, "keydown", function(event) {
53 | var code = event.keyCode;
54 | // Enter
55 | if (code == 13) {CodeMirror.e_stop(event); pick();}
56 | // Escape
57 | else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
58 | else if (code != 38 && code != 40) {
59 | close(); editor.focus();
60 | // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
61 | editor.triggerOnKeyDown(event);
62 | setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
63 | }
64 | });
65 | CodeMirror.connect(sel, "dblclick", pick);
66 |
67 | sel.focus();
68 | // Opera sometimes ignores focusing a freshly created node
69 | if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
70 | return true;
71 | };
72 | })();
73 |
--------------------------------------------------------------------------------
/app/js/simplescrollbars.js:
--------------------------------------------------------------------------------
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 Bar(cls, orientation, scroll) {
15 | this.orientation = orientation;
16 | this.scroll = scroll;
17 | this.screen = this.total = this.size = 1;
18 | this.pos = 0;
19 |
20 | this.node = document.createElement("div");
21 | this.node.className = cls + "-" + orientation;
22 | this.inner = this.node.appendChild(document.createElement("div"));
23 |
24 | var self = this;
25 | CodeMirror.on(this.inner, "mousedown", function(e) {
26 | if (e.which != 1) return;
27 | CodeMirror.e_preventDefault(e);
28 | var axis = self.orientation == "horizontal" ? "pageX" : "pageY";
29 | var start = e[axis], startpos = self.pos;
30 | function done() {
31 | CodeMirror.off(document, "mousemove", move);
32 | CodeMirror.off(document, "mouseup", done);
33 | }
34 | function move(e) {
35 | if (e.which != 1) return done();
36 | self.moveTo(startpos + (e[axis] - start) * (self.total / self.size));
37 | }
38 | CodeMirror.on(document, "mousemove", move);
39 | CodeMirror.on(document, "mouseup", done);
40 | });
41 |
42 | CodeMirror.on(this.node, "click", function(e) {
43 | CodeMirror.e_preventDefault(e);
44 | var innerBox = self.inner.getBoundingClientRect(), where;
45 | if (self.orientation == "horizontal")
46 | where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0;
47 | else
48 | where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0;
49 | self.moveTo(self.pos + where * self.screen);
50 | });
51 |
52 | function onWheel(e) {
53 | var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"];
54 | var oldPos = self.pos;
55 | self.moveTo(self.pos + moved);
56 | if (self.pos != oldPos) CodeMirror.e_preventDefault(e);
57 | }
58 | CodeMirror.on(this.node, "mousewheel", onWheel);
59 | CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
60 | }
61 |
62 | Bar.prototype.setPos = function(pos, force) {
63 | if (pos < 0) pos = 0;
64 | if (pos > this.total - this.screen) pos = this.total - this.screen;
65 | if (!force && pos == this.pos) return false;
66 | this.pos = pos;
67 | this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
68 | (pos * (this.size / this.total)) + "px";
69 | return true
70 | };
71 |
72 | Bar.prototype.moveTo = function(pos) {
73 | if (this.setPos(pos)) this.scroll(pos, this.orientation);
74 | }
75 |
76 | var minButtonSize = 10;
77 |
78 | Bar.prototype.update = function(scrollSize, clientSize, barSize) {
79 | var sizeChanged = this.screen != clientSize || this.total != scrollSize || this.size != barSize
80 | if (sizeChanged) {
81 | this.screen = clientSize;
82 | this.total = scrollSize;
83 | this.size = barSize;
84 | }
85 |
86 | var buttonSize = this.screen * (this.size / this.total);
87 | if (buttonSize < minButtonSize) {
88 | this.size -= minButtonSize - buttonSize;
89 | buttonSize = minButtonSize;
90 | }
91 | this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
92 | buttonSize + "px";
93 | this.setPos(this.pos, sizeChanged);
94 | };
95 |
96 | function SimpleScrollbars(cls, place, scroll) {
97 | this.addClass = cls;
98 | this.horiz = new Bar(cls, "horizontal", scroll);
99 | place(this.horiz.node);
100 | this.vert = new Bar(cls, "vertical", scroll);
101 | place(this.vert.node);
102 | this.width = null;
103 | }
104 |
105 | SimpleScrollbars.prototype.update = function(measure) {
106 | if (this.width == null) {
107 | var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle;
108 | if (style) this.width = parseInt(style.height);
109 | }
110 | var width = this.width || 0;
111 |
112 | var needsH = measure.scrollWidth > measure.clientWidth + 1;
113 | var needsV = measure.scrollHeight > measure.clientHeight + 1;
114 | this.vert.node.style.display = needsV ? "block" : "none";
115 | this.horiz.node.style.display = needsH ? "block" : "none";
116 |
117 | if (needsV) {
118 | this.vert.update(measure.scrollHeight, measure.clientHeight,
119 | measure.viewHeight - (needsH ? width : 0));
120 | this.vert.node.style.bottom = needsH ? width + "px" : "0";
121 | }
122 | if (needsH) {
123 | this.horiz.update(measure.scrollWidth, measure.clientWidth,
124 | measure.viewWidth - (needsV ? width : 0) - measure.barLeft);
125 | this.horiz.node.style.right = needsV ? width + "px" : "0";
126 | this.horiz.node.style.left = measure.barLeft + "px";
127 | }
128 |
129 | return {right: needsV ? width : 0, bottom: needsH ? width : 0};
130 | };
131 |
132 | SimpleScrollbars.prototype.setScrollTop = function(pos) {
133 | this.vert.setPos(pos);
134 | };
135 |
136 | SimpleScrollbars.prototype.setScrollLeft = function(pos) {
137 | this.horiz.setPos(pos);
138 | };
139 |
140 | SimpleScrollbars.prototype.clear = function() {
141 | var parent = this.horiz.node.parentNode;
142 | parent.removeChild(this.horiz.node);
143 | parent.removeChild(this.vert.node);
144 | };
145 |
146 | CodeMirror.scrollbarModel.simple = function(place, scroll) {
147 | return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll);
148 | };
149 | CodeMirror.scrollbarModel.overlay = function(place, scroll) {
150 | return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll);
151 | };
152 | });
153 |
--------------------------------------------------------------------------------
/app/js/xml.js:
--------------------------------------------------------------------------------
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 htmlConfig = {
15 | autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
16 | 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
17 | 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
18 | 'track': true, 'wbr': true, 'menuitem': true},
19 | implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
20 | 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
21 | 'th': true, 'tr': true},
22 | contextGrabbers: {
23 | 'dd': {'dd': true, 'dt': true},
24 | 'dt': {'dd': true, 'dt': true},
25 | 'li': {'li': true},
26 | 'option': {'option': true, 'optgroup': true},
27 | 'optgroup': {'optgroup': true},
28 | 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
29 | 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
30 | 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
31 | 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
32 | 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
33 | 'rp': {'rp': true, 'rt': true},
34 | 'rt': {'rp': true, 'rt': true},
35 | 'tbody': {'tbody': true, 'tfoot': true},
36 | 'td': {'td': true, 'th': true},
37 | 'tfoot': {'tbody': true},
38 | 'th': {'td': true, 'th': true},
39 | 'thead': {'tbody': true, 'tfoot': true},
40 | 'tr': {'tr': true}
41 | },
42 | doNotIndent: {"pre": true},
43 | allowUnquoted: true,
44 | allowMissing: true,
45 | caseFold: true
46 | }
47 |
48 | var xmlConfig = {
49 | autoSelfClosers: {},
50 | implicitlyClosed: {},
51 | contextGrabbers: {},
52 | doNotIndent: {},
53 | allowUnquoted: false,
54 | allowMissing: false,
55 | caseFold: false
56 | }
57 |
58 | CodeMirror.defineMode("xml", function(editorConf, config_) {
59 | var indentUnit = editorConf.indentUnit
60 | var config = {}
61 | var defaults = config_.htmlMode ? htmlConfig : xmlConfig
62 | for (var prop in defaults) config[prop] = defaults[prop]
63 | for (var prop in config_) config[prop] = config_[prop]
64 |
65 | // Return variables for tokenizers
66 | var type, setStyle;
67 |
68 | function inText(stream, state) {
69 | function chain(parser) {
70 | state.tokenize = parser;
71 | return parser(stream, state);
72 | }
73 |
74 | var ch = stream.next();
75 | if (ch == "<") {
76 | if (stream.eat("!")) {
77 | if (stream.eat("[")) {
78 | if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
79 | else return null;
80 | } else if (stream.match("--")) {
81 | return chain(inBlock("comment", "-->"));
82 | } else if (stream.match("DOCTYPE", true, true)) {
83 | stream.eatWhile(/[\w\._\-]/);
84 | return chain(doctype(1));
85 | } else {
86 | return null;
87 | }
88 | } else if (stream.eat("?")) {
89 | stream.eatWhile(/[\w\._\-]/);
90 | state.tokenize = inBlock("meta", "?>");
91 | return "meta";
92 | } else {
93 | type = stream.eat("/") ? "closeTag" : "openTag";
94 | state.tokenize = inTag;
95 | return "tag bracket";
96 | }
97 | } else if (ch == "&") {
98 | var ok;
99 | if (stream.eat("#")) {
100 | if (stream.eat("x")) {
101 | ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
102 | } else {
103 | ok = stream.eatWhile(/[\d]/) && stream.eat(";");
104 | }
105 | } else {
106 | ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
107 | }
108 | return ok ? "atom" : "error";
109 | } else {
110 | stream.eatWhile(/[^&<]/);
111 | return null;
112 | }
113 | }
114 | inText.isInText = true;
115 |
116 | function inTag(stream, state) {
117 | var ch = stream.next();
118 | if (ch == ">" || (ch == "/" && stream.eat(">"))) {
119 | state.tokenize = inText;
120 | type = ch == ">" ? "endTag" : "selfcloseTag";
121 | return "tag bracket";
122 | } else if (ch == "=") {
123 | type = "equals";
124 | return null;
125 | } else if (ch == "<") {
126 | state.tokenize = inText;
127 | state.state = baseState;
128 | state.tagName = state.tagStart = null;
129 | var next = state.tokenize(stream, state);
130 | return next ? next + " tag error" : "tag error";
131 | } else if (/[\'\"]/.test(ch)) {
132 | state.tokenize = inAttribute(ch);
133 | state.stringStartCol = stream.column();
134 | return state.tokenize(stream, state);
135 | } else {
136 | stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
137 | return "word";
138 | }
139 | }
140 |
141 | function inAttribute(quote) {
142 | var closure = function(stream, state) {
143 | while (!stream.eol()) {
144 | if (stream.next() == quote) {
145 | state.tokenize = inTag;
146 | break;
147 | }
148 | }
149 | return "string";
150 | };
151 | closure.isInAttribute = true;
152 | return closure;
153 | }
154 |
155 | function inBlock(style, terminator) {
156 | return function(stream, state) {
157 | while (!stream.eol()) {
158 | if (stream.match(terminator)) {
159 | state.tokenize = inText;
160 | break;
161 | }
162 | stream.next();
163 | }
164 | return style;
165 | };
166 | }
167 | function doctype(depth) {
168 | return function(stream, state) {
169 | var ch;
170 | while ((ch = stream.next()) != null) {
171 | if (ch == "<") {
172 | state.tokenize = doctype(depth + 1);
173 | return state.tokenize(stream, state);
174 | } else if (ch == ">") {
175 | if (depth == 1) {
176 | state.tokenize = inText;
177 | break;
178 | } else {
179 | state.tokenize = doctype(depth - 1);
180 | return state.tokenize(stream, state);
181 | }
182 | }
183 | }
184 | return "meta";
185 | };
186 | }
187 |
188 | function Context(state, tagName, startOfLine) {
189 | this.prev = state.context;
190 | this.tagName = tagName;
191 | this.indent = state.indented;
192 | this.startOfLine = startOfLine;
193 | if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
194 | this.noIndent = true;
195 | }
196 | function popContext(state) {
197 | if (state.context) state.context = state.context.prev;
198 | }
199 | function maybePopContext(state, nextTagName) {
200 | var parentTagName;
201 | while (true) {
202 | if (!state.context) {
203 | return;
204 | }
205 | parentTagName = state.context.tagName;
206 | if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
207 | !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
208 | return;
209 | }
210 | popContext(state);
211 | }
212 | }
213 |
214 | function baseState(type, stream, state) {
215 | if (type == "openTag") {
216 | state.tagStart = stream.column();
217 | return tagNameState;
218 | } else if (type == "closeTag") {
219 | return closeTagNameState;
220 | } else {
221 | return baseState;
222 | }
223 | }
224 | function tagNameState(type, stream, state) {
225 | if (type == "word") {
226 | state.tagName = stream.current();
227 | setStyle = "tag";
228 | return attrState;
229 | } else {
230 | setStyle = "error";
231 | return tagNameState;
232 | }
233 | }
234 | function closeTagNameState(type, stream, state) {
235 | if (type == "word") {
236 | var tagName = stream.current();
237 | if (state.context && state.context.tagName != tagName &&
238 | config.implicitlyClosed.hasOwnProperty(state.context.tagName))
239 | popContext(state);
240 | if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
241 | setStyle = "tag";
242 | return closeState;
243 | } else {
244 | setStyle = "tag error";
245 | return closeStateErr;
246 | }
247 | } else {
248 | setStyle = "error";
249 | return closeStateErr;
250 | }
251 | }
252 |
253 | function closeState(type, _stream, state) {
254 | if (type != "endTag") {
255 | setStyle = "error";
256 | return closeState;
257 | }
258 | popContext(state);
259 | return baseState;
260 | }
261 | function closeStateErr(type, stream, state) {
262 | setStyle = "error";
263 | return closeState(type, stream, state);
264 | }
265 |
266 | function attrState(type, _stream, state) {
267 | if (type == "word") {
268 | setStyle = "attribute";
269 | return attrEqState;
270 | } else if (type == "endTag" || type == "selfcloseTag") {
271 | var tagName = state.tagName, tagStart = state.tagStart;
272 | state.tagName = state.tagStart = null;
273 | if (type == "selfcloseTag" ||
274 | config.autoSelfClosers.hasOwnProperty(tagName)) {
275 | maybePopContext(state, tagName);
276 | } else {
277 | maybePopContext(state, tagName);
278 | state.context = new Context(state, tagName, tagStart == state.indented);
279 | }
280 | return baseState;
281 | }
282 | setStyle = "error";
283 | return attrState;
284 | }
285 | function attrEqState(type, stream, state) {
286 | if (type == "equals") return attrValueState;
287 | if (!config.allowMissing) setStyle = "error";
288 | return attrState(type, stream, state);
289 | }
290 | function attrValueState(type, stream, state) {
291 | if (type == "string") return attrContinuedState;
292 | if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
293 | setStyle = "error";
294 | return attrState(type, stream, state);
295 | }
296 | function attrContinuedState(type, stream, state) {
297 | if (type == "string") return attrContinuedState;
298 | return attrState(type, stream, state);
299 | }
300 |
301 | return {
302 | startState: function(baseIndent) {
303 | var state = {tokenize: inText,
304 | state: baseState,
305 | indented: baseIndent || 0,
306 | tagName: null, tagStart: null,
307 | context: null}
308 | if (baseIndent != null) state.baseIndent = baseIndent
309 | return state
310 | },
311 |
312 | token: function(stream, state) {
313 | if (!state.tagName && stream.sol())
314 | state.indented = stream.indentation();
315 |
316 | if (stream.eatSpace()) return null;
317 | type = null;
318 | var style = state.tokenize(stream, state);
319 | if ((style || type) && style != "comment") {
320 | setStyle = null;
321 | state.state = state.state(type || style, stream, state);
322 | if (setStyle)
323 | style = setStyle == "error" ? style + " error" : setStyle;
324 | }
325 | return style;
326 | },
327 |
328 | indent: function(state, textAfter, fullLine) {
329 | var context = state.context;
330 | // Indent multi-line strings (e.g. css).
331 | if (state.tokenize.isInAttribute) {
332 | if (state.tagStart == state.indented)
333 | return state.stringStartCol + 1;
334 | else
335 | return state.indented + indentUnit;
336 | }
337 | if (context && context.noIndent) return CodeMirror.Pass;
338 | if (state.tokenize != inTag && state.tokenize != inText)
339 | return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
340 | // Indent the starts of attribute names.
341 | if (state.tagName) {
342 | if (config.multilineTagIndentPastTag !== false)
343 | return state.tagStart + state.tagName.length + 2;
344 | else
345 | return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
346 | }
347 | if (config.alignCDATA && /$/,
376 | blockCommentStart: "",
378 |
379 | configuration: config.htmlMode ? "html" : "xml",
380 | helperType: config.htmlMode ? "html" : "xml",
381 |
382 | skipAttribute: function(state) {
383 | if (state.state == attrValueState)
384 | state.state = attrState
385 | }
386 | };
387 | });
388 |
389 | CodeMirror.defineMIME("text/xml", "xml");
390 | CodeMirror.defineMIME("application/xml", "xml");
391 | if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
392 | CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
393 |
394 | });
395 |
--------------------------------------------------------------------------------
/app/lib/anime.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | 2017 Julian Garnier
3 | Released under the MIT license
4 | */
5 | var $jscomp$this=this;
6 | (function(u,r){"function"===typeof define&&define.amd?define([],r):"object"===typeof module&&module.exports?module.exports=r():u.anime=r()})(this,function(){function u(a){if(!g.col(a))try{return document.querySelectorAll(a)}catch(b){}}function r(a){return a.reduce(function(a,c){return a.concat(g.arr(c)?r(c):c)},[])}function v(a){if(g.arr(a))return a;g.str(a)&&(a=u(a)||a);return a instanceof NodeList||a instanceof HTMLCollection?[].slice.call(a):[a]}function E(a,b){return a.some(function(a){return a===b})}
7 | function z(a){var b={},c;for(c in a)b[c]=a[c];return b}function F(a,b){var c=z(a),d;for(d in a)c[d]=b.hasOwnProperty(d)?b[d]:a[d];return c}function A(a,b){var c=z(a),d;for(d in b)c[d]=g.und(a[d])?b[d]:a[d];return c}function R(a){a=a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,function(a,b,c,h){return b+b+c+c+h+h});var b=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);a=parseInt(b[1],16);var c=parseInt(b[2],16),b=parseInt(b[3],16);return"rgb("+a+","+c+","+b+")"}function S(a){function b(a,b,c){0>
8 | c&&(c+=1);1c?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var c=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a);a=parseInt(c[1])/360;var d=parseInt(c[2])/100,c=parseInt(c[3])/100;if(0==d)d=c=a=c;else{var e=.5>c?c*(1+d):c+d-c*d,k=2*c-e,d=b(k,e,a+1/3),c=b(k,e,a);a=b(k,e,a-1/3)}return"rgb("+255*d+","+255*c+","+255*a+")"}function w(a){if(a=/([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|pc|vw|vh|deg|rad|turn)?/.exec(a))return a[2]}function T(a){if(-1k&&q=m&&(f.began=!0,e("begin")),e("run")):(q<=k&&0!==O&&(d(0),p&&g()),q>=h&&O!==h&&(d(h),p||g()));a>=h&&(f.remaining?(t=n,"alternate"===f.direction&&(f.reversed=!f.reversed)):(f.pause(),P(),Q=b(),f.completed||(f.completed=!0,e("complete"))),l=0);if(f.children)for(a=f.children,h=0;h=b&&
22 | 0<=d&&1>=d){var g=new Float32Array(11);if(b!==c||d!==e)for(var h=0;11>h;++h)g[h]=a(.1*h,b,d);return function(h){if(b===c&&d===e)return h;if(0===h)return 0;if(1===h)return 1;for(var k=0,l=1;10!==l&&g[l]<=h;++l)k+=.1;--l;var l=k+(h-g[l])/(g[l+1]-g[l])*.1,n=3*(1-3*d+3*b)*l*l+2*(3*d-6*b)*l+3*b;if(.001<=n){for(k=0;4>k;++k){n=3*(1-3*d+3*b)*l*l+2*(3*d-6*b)*l+3*b;if(0===n)break;var m=a(l,b,d)-h,l=l-m/n}h=l}else if(0===n)h=l;else{var l=k,k=k+.1,f=0;do m=l+(k-l)/2,n=a(m,b,d)-h,0++f);h=m}return a(h,c,e)}}}}(),M=function(){function a(a,b){return 0===a||1===a?a:-Math.pow(2,10*(a-1))*Math.sin(2*(a-1-b/(2*Math.PI)*Math.asin(1))*Math.PI/b)}var b="Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "),c={In:[[.55,.085,.68,.53],[.55,.055,.675,.19],[.895,.03,.685,.22],[.755,.05,.855,.06],[.47,0,.745,.715],[.95,.05,.795,.035],[.6,.04,.98,.335],[.6,-.28,.735,.045],a],Out:[[.25,.46,.45,.94],[.215,.61,.355,1],[.165,.84,.44,1],[.23,1,.32,1],[.39,.575,.565,1],[.19,1,.22,1],
24 | [.075,.82,.165,1],[.175,.885,.32,1.275],function(b,c){return 1-a(1-b,c)}],InOut:[[.455,.03,.515,.955],[.645,.045,.355,1],[.77,0,.175,1],[.86,0,.07,1],[.445,.05,.55,.95],[1,0,0,1],[.785,.135,.15,.86],[.68,-.55,.265,1.55],function(b,c){return.5>b?a(2*b,c)/2:1-a(-2*b+2,c)/2}]},d={linear:x(.25,.25,.75,.75)},e={},k;for(k in c)e.type=k,c[e.type].forEach(function(a){return function(c,e){d["ease"+a.type+b[e]]=g.fnc(c)?c:x.apply($jscomp$this,c)}}(e)),e={type:e.type};return d}(),ha={css:function(a,b,c){return a.style[b]=
25 | c},attribute:function(a,b,c){return a.setAttribute(b,c)},object:function(a,b,c){return a[b]=c},transform:function(a,b,c,d,e){d[e]||(d[e]=[]);d[e].push(b+"("+c+")")}},p=[],y=0,ia=function(){function a(){y=requestAnimationFrame(b)}function b(b){var c=p.length;if(c){for(var e=0;ed&&(b.duration=a.duration);b.children.push(a)});return b};return b};m.random=function(a,b){return Math.floor(Math.random()*(b-a+1))+a};return m});
--------------------------------------------------------------------------------
/app/lib/font-awesome.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */@font-face{font-family:'FontAwesome';src:url('fontawesome-webfont.eot?v=4.7.0');src:url('fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('fontawesome-webfont.woff?v=4.7.0') format('woff'),url('fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
5 |
--------------------------------------------------------------------------------
/app/lib/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/app/lib/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/app/lib/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/app/lib/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/lib/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/lib/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/lib/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/app/lib/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/main.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron')
2 | // Module to control application life.
3 | const app = electron.app
4 | // Module to create native browser window.
5 | const BrowserWindow = electron.BrowserWindow
6 | const path = require('path')
7 |
8 | let mainWindow
9 |
10 | // Quit when all windows are closed.
11 | app.on('window-all-closed', () => {
12 | if (process.platform != 'darwin') {
13 | app.quit()
14 | }
15 | })
16 |
17 | app.setAppUserModelId('CodePad')
18 |
19 | // This method will be called when Electron has done everything
20 | // initialization and ready for creating browser windows.
21 | app.on('ready', () => {
22 | // Create the browser window.
23 | mainWindow = new BrowserWindow({
24 | title: 'CodePad',
25 | width: 1024,
26 | height: 720,
27 | frame: false,
28 | minHeight: 600,
29 | minWidth: 600,
30 | icon: path.join(__dirname, '../build/CB.ico')
31 | })
32 |
33 | // and load the index.html of the app.
34 | mainWindow.loadURL(path.join('file://', __dirname, '/index.html'))
35 |
36 | // Emitted when the window is closed.
37 | mainWindow.on('closed', () => {
38 | // Dereference the window object, usually you would store windows
39 | // in an array if your app supports multi windows, this is the time
40 | // when you should delete the corresponding element.
41 | mainWindow = null
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codepad",
3 | "version": "0.1.1",
4 | "description": "An offline front-end development playground",
5 | "productName": "CodePad",
6 | "main": "main.js",
7 | "scripts": {
8 | "start": "electron ."
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/thecodepad/codepad"
13 | },
14 | "keywords": [
15 | "electron",
16 | "front-end",
17 | "editor"
18 | ],
19 | "license": "MIT",
20 | "devDependencies": {
21 | "electron": "^1.6.1",
22 | "standard": "^9.0.0"
23 | }
24 | }
--------------------------------------------------------------------------------
/app/scripts.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | addScript,
3 | getJsLibs
4 | }
5 |
6 | function getJsLibs () {
7 | var jsHtml = ''
8 | for (var i = 0; i < jsLib.length; i++) {
9 | if (scrFlags[i] === 1) {
10 | jsHtml += jsLib[i][1].replace('lib/', '')
11 | }
12 | }
13 | return jsHtml
14 | }
15 |
16 | function addScript () {
17 | var jsMenu = document.getElementById('js-menu')
18 | var jsButtons = jsMenu.getElementsByTagName('a')
19 | let jsSpan = jsMenu.querySelectorAll('span')
20 | jsButtons[0].addEventListener('click', function (e) {
21 | var jqScr = jsLib[0][1]
22 | if (scrFlags[0] === 0) {
23 | scripts += jqScr
24 | scrFlags[0] = 1
25 | toggleStatus(0, jsSpan)
26 | } else if (scrFlags[2] === 0) {
27 | scripts = scripts.replace(jqScr, '')
28 | scrFlags[0] = 0
29 | toggleStatus(0, jsSpan)
30 | }
31 | })
32 | jsButtons[1].addEventListener('click', function (e) {
33 | var aniScr = jsLib[1][1]
34 | if (scrFlags[1] === 0) {
35 | scripts += aniScr
36 | scrFlags[1] = 1
37 | toggleStatus(1, jsSpan)
38 | } else {
39 | scripts = scripts.replace(aniScr, '')
40 | scrFlags[1] = 0
41 | toggleStatus(1, jsSpan)
42 | }
43 | })
44 | jsButtons[2].addEventListener('click', function (e) {
45 | var jqScr = jsLib[0][1]
46 | var boScr = jsLib[2][1]
47 | if (scrFlags[0] === 0) {
48 | toggleStatus(0, jsSpan)
49 | scripts += jqScr
50 | scrFlags[0] = 1
51 | }
52 | if (scrFlags[2] === 0) {
53 | scripts += boScr
54 | scrFlags[2] = 1
55 | toggleStatus(2, jsSpan)
56 | } else {
57 | scripts = scripts.replace(boScr, '')
58 | scrFlags[2] = 0
59 | toggleStatus(2, jsSpan)
60 | }
61 | })
62 | jsButtons[3].addEventListener('click', function (e) {
63 | var p5Scr = jsLib[3][1]
64 | if (scrFlags[3] === 0) {
65 | scripts += p5Scr
66 | scrFlags[3] = 1
67 | toggleStatus(3, jsSpan)
68 | } else {
69 | scripts = scripts.replace(p5Scr, '')
70 | scrFlags[3] = 0
71 | toggleStatus(3, jsSpan)
72 | }
73 | })
74 | jsButtons[4].addEventListener('click', function (e) {
75 | var thScr = jsLib[4][1]
76 | if (scrFlags[4] === 0) {
77 | scripts += thScr
78 | scrFlags[4] = 1
79 | toggleStatus(4, jsSpan)
80 | } else {
81 | scripts = scripts.replace(thScr, '')
82 | scrFlags[4] = 0
83 | toggleStatus(4, jsSpan)
84 | }
85 | })
86 | }
87 |
--------------------------------------------------------------------------------
/app/shortcuts.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | shortcuts
3 | }
4 |
5 | function shortcuts () {
6 | window.addEventListener('keydown', (e) => {
7 | if (e.ctrlKey && e.key === 'Tab') {
8 | toggleEditors(getCurrenEditor())
9 | }
10 | if (e.key === 'F11') {
11 | if (!remote.getCurrentWindow().isMaximized()) {
12 | remote.getCurrentWindow().maximize()
13 | } else {
14 | remote.getCurrentWindow().unmaximize()
15 | }
16 | }
17 | if (e.key === 'F12') {
18 | remote.getCurrentWindow().toggleDevTools()
19 | }
20 | if (e.ctrlKey && (e.key === 's' || e.key === 'S')) {
21 | FILE.handleSave()
22 | }
23 | if (e.ctrlKey && (e.key === 'n' || e.key === 'N')) {
24 | FILE.handleNew()
25 | }
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/app/styles.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | addStyle,
3 | getCssLibs
4 | }
5 |
6 | function getCssLibs () {
7 | var cssHtml = ''
8 | for (var i = 0; i < cssLib.length; i++) {
9 | if (styFlags[i] === 1) {
10 | cssHtml += cssLib[i][1].replace('lib/', '')
11 | }
12 | }
13 | return cssHtml
14 | }
15 |
16 | function addStyle () {
17 | var cssMenu = document.getElementById('css-menu')
18 | var cssButtons = cssMenu.getElementsByTagName('a')
19 | let cssSpan = cssMenu.querySelectorAll('span')
20 | cssButtons[0].addEventListener('click', function (e) {
21 | var anSty = cssLib[0][1]
22 | if (styFlags[0] === 0) {
23 | styles += anSty
24 | styFlags[0] = 1
25 | toggleStatus(0, cssSpan)
26 | } else {
27 | styles = styles.replace(anSty, '')
28 | styFlags[0] = 0
29 | toggleStatus(0, cssSpan)
30 | }
31 | })
32 | cssButtons[1].addEventListener('click', function (e) {
33 | var boSty = cssLib[1][1]
34 | if (styFlags[1] === 0) {
35 | styles += boSty
36 | styFlags[1] = 1
37 | toggleStatus(1, cssSpan)
38 | } else {
39 | styles = styles.replace(boSty, '')
40 | styFlags[1] = 0
41 | toggleStatus(1, cssSpan)
42 | }
43 | })
44 | cssButtons[2].addEventListener('click', function (e) {
45 | var faSty = cssLib[2][1]
46 | if (styFlags[2] === 0) {
47 | styles += faSty
48 | styFlags[2] = 1
49 | toggleStatus(2, cssSpan)
50 | } else {
51 | styles = styles.replace(faSty, '')
52 | styFlags[2] = 0
53 | toggleStatus(2, cssSpan)
54 | }
55 | })
56 | }
57 |
--------------------------------------------------------------------------------
/app/viewMenu.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | viewMenu
3 | }
4 |
5 | // 'View' Menu Buttons
6 | function viewMenu () {
7 | document.getElementById('dev').addEventListener('click', () => {
8 | remote.getCurrentWindow().toggleDevTools()
9 | })
10 | document.getElementById('full').addEventListener('click', () => {
11 | if (!remote.getCurrentWindow().isMaximized()) {
12 | remote.getCurrentWindow().maximize()
13 | } else {
14 | remote.getCurrentWindow().unmaximize()
15 | }
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/app/windowControl.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | windowClicks,
3 | initContextMenu
4 | }
5 | // Window Control [_][+][x] Buttons
6 | function windowClicks () {
7 | document.getElementById('min-button').addEventListener('click', function (e) {
8 | remote.getCurrentWindow().minimize()
9 | })
10 |
11 | document.getElementById('max-button').addEventListener('click', function (e) {
12 | if (!remote.getCurrentWindow().isMaximized()) {
13 | remote.getCurrentWindow().maximize()
14 | } else {
15 | remote.getCurrentWindow().unmaximize()
16 | }
17 | })
18 |
19 | document.getElementById('close-button').addEventListener('click', function (e) {
20 | remote.getCurrentWindow().close()
21 | })
22 | }
23 |
24 | // Context menu init()
25 | function initContextMenu () {
26 | menu = new Menu()
27 | menu.append(new MenuItem({
28 | label: 'Copy',
29 | role: 'copy'
30 | // click: copy
31 | }))
32 | menu.append(new MenuItem({
33 | label: 'Cut',
34 | role: 'cut'
35 | // click: cut
36 | }))
37 | menu.append(new MenuItem({
38 | label: 'Paste',
39 | role: 'paste'
40 | // click: paste
41 | }))
42 |
43 | window.addEventListener('contextmenu', function (ev) {
44 | ev.preventDefault()
45 | menu.popup(remote.getCurrentWindow(), ev.x, ev.y)
46 | }, false)
47 | }
48 |
--------------------------------------------------------------------------------
/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/build/icon.icns
--------------------------------------------------------------------------------
/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/build/icon.ico
--------------------------------------------------------------------------------
/build/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/build/icons/128x128.png
--------------------------------------------------------------------------------
/build/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodepad/codepad/7bb457c6bd741da50f11b156e44d7893ba2291b1/build/icons/512x512.png
--------------------------------------------------------------------------------
/build/icons/CB.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codepad",
3 | "version": "0.1.1",
4 | "description": "An offline front-end development playground",
5 | "productName": "CodePad",
6 | "main": "./app/",
7 | "scripts": {
8 | "start": "electron ./app/",
9 | "build:win32": "electron-packager . CodePad --app-bundle-id=codepad --overwrite --asar=true --platform=win32 --arch=ia32 --icon=build/icon.ico --prune=true --out=dist --version-string.ProductName=CodePad --version-string.FileDescription=CodePad",
10 | "build:win64": "electron-packager . CodePad --app-bundle-id=codepad --overwrite --asar=true --platform=win32 --arch=x64 --icon=build/icon.ico --prune=true --out=dist --version-string.ProductName=CodePad --version-string.FileDescription=CodePad"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/thecodepad/codepad"
15 | },
16 | "keywords": [
17 | "electron",
18 | "front-end",
19 | "editor"
20 | ],
21 | "license": "MIT",
22 | "devDependencies": {
23 | "asar": "^0.13.0",
24 | "electron": "^1.6.1",
25 | "electron-packager": "^8.5.2",
26 | "standard": "^9.0.0"
27 | }
28 | }
--------------------------------------------------------------------------------