Compare commits

...
199 Commits
Author SHA1 Message Date
MightyPork 9030d5ce85 Merge branch 'patch-clickbuttons' into work 2018-01-21 14:09:14 +01:00
MightyPork 6971fe2036 v bump 2018-01-21 14:08:38 +01:00
MightyPork 9f97d5c9d1 bugfix for the clickbuttons not working 2018-01-21 14:07:54 +01:00
MightyPork 5343d44ea8 bump the frontend v for the hu patch 2017-11-27 21:33:56 +01:00
MightyPork 76fbf5d65f Merge branch 'work' 2017-11-19 23:07:24 +01:00
MightyPork 6b4013f779 v bump 2017-11-19 22:55:54 +01:00
MightyPork 0438f88c83 update frontend ref 2017-11-12 12:57:31 +01:00
MightyPork d0d7200e57 Merge branch 'double-lines' into work 2017-11-12 12:57:04 +01:00
MightyPork 78aaa949a3 support double lines 2017-11-12 11:40:36 +01:00
MightyPork 5dbb592946 added OSC for color buttons 2017-10-30 21:25:56 +01:00
MightyPork d9aa0418fa updated protocol, added button themeing and font conf 2017-10-30 20:47:41 +01:00
MightyPork 9008f2e1af ref upd 2017-10-26 00:57:40 +02:00
MightyPork bc240e676b added hu to build script 2017-10-26 00:51:51 +02:00
MightyPork 3af928b39d version bump for pre-release build 2017-10-26 00:45:43 +02:00
MightyPork ead9120ae8 ref update 2017-10-26 00:41:24 +02:00
MightyPork dca44963e8 add new OSC and configurable button count 2017-10-26 00:31:10 +02:00
MightyPork 3c12efe28f updated submodule ref 2017-10-25 23:24:07 +02:00
MightyPork e98588b317 Fix broken validation for bm* 2017-10-23 23:49:19 +02:00
MightyPork 0e6c297fe4 be smarter about detecting changes in loaded ini 2017-10-23 23:24:20 +02:00
MightyPork 3e4181f18e Merge branch 'xmacro-config' into work 2017-10-23 22:43:34 +02:00
MightyPork 2f4cd08c60 import now fully working 2017-10-23 22:43:04 +02:00
MightyPork ba2b73a287 ini upload and parse (no loading to conf yet) 2017-10-23 01:40:56 +02:00
MightyPork 4e285694d1 ini export! 2017-10-22 23:41:07 +02:00
MightyPork 9700465927 fixed many bugs 2017-10-22 22:23:09 +02:00
MightyPork 1ab4101ac0 use xmacros for terminal config 2017-10-22 20:30:24 +02:00
MightyPork f0bc70553a use xmacros for system 2017-10-22 17:55:52 +02:00
MightyPork 3eac0ee794 fmt again 2017-10-22 16:50:45 +02:00
MightyPork 2c80b59d71 formatting 2017-10-22 16:46:28 +02:00
MightyPork 9146c9880a slightly cleaner XTABLE_WIFI 2017-10-22 16:45:45 +02:00
MightyPork cabd42f2b4 base of xmarco-based config, used for wifi and network 2017-10-22 16:34:00 +02:00
MightyPork fbd4693035 Merge branch 'master' into work 2017-10-08 13:26:40 +02:00
MightyPork c5670c09bb update frontend ref 2017-10-08 12:57:36 +02:00
MightyPork 4e74d1cd79 updated front-end ref 2017-10-08 12:54:26 +02:00
MightyPork 4c8360dbb5 Merge remote-tracking branch 'origin/work' 2017-10-08 12:35:21 +02:00
MightyPork c0adc253b4 add cgi for setting background image 2017-10-08 12:34:50 +02:00
MightyPork be3e06aac1 version bump 2017-10-08 11:21:11 +02:00
MightyPork 992c927490 Merge remote-tracking branch 'origin/work' 2017-10-08 11:16:44 +02:00
MightyPork ef3b02e68c added new chars to cp 1 2017-10-07 00:46:19 +02:00
MightyPork 1c556457c7 Merge branch 'new-codepages' into work 2017-10-07 00:15:34 +02:00
MightyPork e49a8b0adf added codepages 2 and 3 2017-10-06 23:25:01 +02:00
MightyPork 81c3e426e7 added quarter blocks to codepage 1 2017-10-06 22:28:36 +02:00
MightyPorkandGitHub c90de79a34 Update README.md 2017-10-06 00:12:28 +02:00
MightyPork df404f5f63 2.1.1 - patched cslang 2017-10-04 21:47:32 +02:00
MightyPork 00153656f1 flip front-end back to "work" 2017-10-04 00:22:08 +02:00
MightyPork aa920aee27 Merge branch 'master' into work 2017-10-04 00:21:45 +02:00
MightyPork 7b8c936559 Version bump 2017-10-04 00:13:14 +02:00
MightyPork 17c18ed1c9 update front-end to latest master 2017-10-04 00:12:47 +02:00
MightyPork 274e3b359b Merge branch 'work' 2017-10-04 00:11:26 +02:00
MightyPork 73c98eb2d1 some logging adjustments 2017-10-04 00:10:54 +02:00
MightyPork 022e882001 added IP to answerback message 2017-10-03 22:16:07 +02:00
MightyPork dc08512397 one timezone is probably enough in the release readme 2017-10-03 20:58:00 +02:00
MightyPork 6c1ab28e75 improved build script, automatic version fetch from source 2017-10-03 20:30:53 +02:00
MightyPork 2796709624 version bump to beta2 2017-10-03 01:55:46 +02:00
MightyPork d2edcd7fd5 added new release system 2017-10-03 00:59:21 +02:00
MightyPork 76272530ec improved ENQ response, now includes hashes and ID. Added ID to boot msg 2017-10-02 22:55:56 +02:00
MightyPork a514601897 use async buffer for apars respond other than http 2017-10-02 22:20:38 +02:00
MightyPork 935e05a56a Disable Rx pin pull-up, caused malfunction with cheap adapters 2017-10-02 19:51:58 +02:00
MightyPork a72e2bed63 makefile improvements 2017-10-02 03:18:43 +02:00
MightyPork 679f0adbae Merge branch 'http-comm' into work 2017-10-02 01:40:45 +02:00
MightyPork 791f6e716f finished basic d2d and external, adde flags etc 2017-10-02 01:40:26 +02:00
MightyPork 9a5bc0a274 Add codename 2017-10-01 22:56:13 +02:00
MightyPork dca02976a7 Fixed a horrible MegaBug and added HTTP message sending + D2D sending (no Rx yet) 2017-10-01 19:46:14 +02:00
MightyPork 6665b5c183 CAN and SUB correctly abort current sequence, including string. Start of adding PM's 2017-10-01 14:09:39 +02:00
MightyPork 55afcca955 fix incorrect DCS command handling 2017-10-01 13:47:22 +02:00
MightyPork 7ffc947f1a added client + testing command ESC#7 2017-10-01 12:54:52 +02:00
MightyPork 0eeed9c7d9 add %debugbar% to terminal page 2017-10-01 03:42:15 +02:00
MightyPork 253473daed version bump for next rel 2017-10-01 03:35:52 +02:00
MightyPork 9321cd4ebb made it survive idiots cat'ing image files etc 2017-10-01 03:35:31 +02:00
MightyPork faffa68794 use binary messages and fix bugs in utf sanitizer 2017-10-01 03:23:04 +02:00
MightyPork a6ee808a1d add SKIP tag to defines 2017-09-30 22:59:46 +02:00
MightyPork 5150cc32eb align serializer with front-end changes 2017-09-30 22:57:40 +02:00
MightyPork 42d5f6bc89 decopt 12 configurable 2017-09-30 19:11:34 +02:00
MightyPork d2fe37403f Fix htop display bugs - wrong serialization 2017-09-30 17:48:42 +02:00
MightyPork f6c2b06d8a notify about mouse attrs change 2017-09-30 15:10:52 +02:00
MightyPork b6c5648690 allow zero redraw delay 2017-09-30 15:02:19 +02:00
MightyPork 062b0e6188 fix messed up bg color encoding 2017-09-30 13:52:28 +02:00
MightyPork c83b68405f Merge branch 'partial-updates' into work 2017-09-30 02:55:54 +02:00
MightyPork 97552b30c3 fix some bugs + optimize stuff 2017-09-30 02:40:24 +02:00
MightyPork 1c23e79c59 partial update, may be a bit buggy in places 2017-09-30 01:18:03 +02:00
MightyPork b70c65868b dump context and stop listening for a bit on rx of bad UTF 2017-09-29 21:57:20 +02:00
MightyPork 1614194d76 Removed one NOTIFY_LOCK() that shouldn't have been there 2017-09-29 20:49:52 +02:00
MightyPork 7bca46384e Merge branch 'new-message-format' into work 2017-09-28 23:11:28 +02:00
MightyPork 03c7f4d0ad removed bugs 2017-09-28 22:09:30 +02:00
MightyPork da6c5bf5be re-arranged attr bits and changed string encoding for labels and title to use terminator rather than byte length 2017-09-28 21:50:51 +02:00
MightyPork 2e0648be8e re-ordered cell attr bits for shorter serialize word length 2017-09-28 21:13:10 +02:00
MightyPork 404ccaeb20 new message format 2017-09-28 20:58:45 +02:00
MightyPork 7300e0003c Merge branch 'master' into work 2017-09-26 17:42:55 +02:00
MightyPork 8c55202b42 added exampe of the main config file 2017-09-26 17:41:49 +02:00
MightyPork 65977bfbae Overclock, fix buffer overflow causing total lock-up, small tweaks
removed the main make config file from VCS so it can be easier edited
added overclocking option to enable 160 MHz mode
2017-09-26 17:41:24 +02:00
MightyPork 74d52a0c61 add confirmation messages to form saving 2017-09-26 15:01:22 +02:00
MightyPork 0fae510207 change version to 2.0.0 to indicate the breaking change 2017-09-26 13:43:08 +02:00
MightyPork 1a8d3cb332 show real sdk version, make tpw setting actually work 2017-09-26 11:30:58 +02:00
MightyPork ca5a7e3de9 Merge remote-tracking branch 'origin/work' 2017-09-26 10:53:35 +02:00
MightyPork fa5489ccfc support for truecolor default colors 2017-09-25 01:53:59 +02:00
MightyPork 502babf7b0 updated front-end ref 2017-09-24 20:50:01 +02:00
MightyPork 47f6cd38cd Merge branch 'utf-removal-fix' into work 2017-09-24 20:36:38 +02:00
MightyPork 0f10d84a59 disable non-error ansi logging 2017-09-24 20:36:09 +02:00
MightyPork cb71586138 remove spammy debug 2017-09-24 20:35:55 +02:00
MightyPork 58bd27a082 FIXED A BUG 2017-09-24 20:19:40 +02:00
MightyPork 7eb1bdeec6 fixed off-by one etc errors in the rewritten functions, fixed a lag due to heartbeat packet 2017-09-24 18:16:21 +02:00
MightyPork 674e89c8c3 fix a bug with backspace when cursor is hanging 2017-09-24 14:57:10 +02:00
MightyPork 62a0925586 fix stuff not removed from utf cache in some operations 2017-09-24 14:17:41 +02:00
MightyPork 4f4ea95c06 Merge branch 'offscale-bg' into work 2017-09-24 03:03:52 +02:00
MightyPork 2ede271c65 removed obsolete microoptimization from parser repeat code 2017-09-24 03:02:28 +02:00
MightyPork 692b2c4d11 fix serializer being completely broken 2017-09-24 00:17:58 +02:00
MightyPork 948bcb62ff Backend changes for offscale default fg and bg + future-proofing
- 16-bit attribs
- added attribs FG and BG, if not set, default colors
- added attrib INVERT, removed server-side color flipping
- added screen attrib REVERSE_VIDEO (can't be done server-side if we want it to work with off-scale colors)
- changed Attribs encoding to 3B
- removed old migrations, made useless by the flash wipe caused by adding Admin PW section
- some cleaning in CSI parser
- removed function to set SGR inverse separately (now use normal SGR setter)
- added functions to set fg and bg to defaults
2017-09-23 20:50:37 +02:00
MightyPork 7607b639b0 Merge branch 'passwords-stuff' into work 2017-09-23 02:14:27 +02:00
MightyPork 2e8ec41115 lib bump 2017-09-23 02:13:02 +02:00
MightyPork 80e8e4f7da added username config for basic auth 2017-09-23 01:59:53 +02:00
MightyPork 357a9d43e3 password changing, changed default pw to "adminpw", added settings revert if validation fails 2017-09-23 01:33:55 +02:00
MightyPork a464a73a0e cgi form handlers for setting password stuff 2017-09-22 01:05:13 +02:00
MightyPork 38b3ce2dc8 cgi handler for setting passwords (not tested) 2017-09-22 01:00:52 +02:00
MightyPork 37de3a095d configurable pw lock (not yet tested and not connected to front-end) 2017-09-22 00:48:57 +02:00
MightyPork 82961568b8 increased sysconbf allocated flash size (safe now bc we alrady have a breaking change that wipes old settings) 2017-09-22 00:33:03 +02:00
MightyPork 3849e161e5 add pwlock settings to sysconf 2017-09-22 00:30:16 +02:00
MightyPork 43241c2679 admin pw now lives in a separate config block. BREAKING CHANGE! will wipe old settings :( 2017-09-22 00:22:46 +02:00
MightyPorkandGitHub 3bfd51061e added browser support list 2017-09-19 01:44:52 +02:00
MightyPork 781cf8825b remove theme max num chekc to allow adding themes purely by front-end 2017-09-18 01:58:15 +02:00
MightyPork 079b522540 implemented focus tracking reports 2017-09-17 20:18:57 +02:00
MightyPork 471aa95c34 add timezone to the about page 2017-09-17 19:18:56 +02:00
MightyPork ac56b1dc61 added timezone to bootlog 2017-09-17 19:14:24 +02:00
MightyPork 82fd9e5ad1 raise utf8 cache to max of 160 characters, re-enable buttons by default 2017-09-17 19:10:16 +02:00
MightyPork 92a454a2cf renamed input debug log funcs to imp_ to avoid build collision if DEBUG_WS is enabled also 2017-09-16 01:46:41 +02:00
MightyPork 0012c92c4a added front-end patch 2017-09-14 23:24:35 +02:00
MightyPorkandGitHub 0e8af5712b add info about the mailing list 2017-09-14 01:34:47 +02:00
MightyPork 51e97232c5 version bump to 1.1.1 2017-09-14 00:16:08 +02:00
MightyPork 7e2491cd7b fix broken urxvt mouse reports 2017-09-14 00:11:43 +02:00
MightyPork cd79d5cf25 fix #172 2017-09-13 23:32:18 +02:00
MightyPork 184c772b57 update frontend ref 2017-09-13 02:30:34 +02:00
MightyPork 6e2978492b oops messed up front-end 2017-09-13 02:22:54 +02:00
MightyPork 0d0246b12b updated branch cfg in .gitmodules 2017-09-13 01:40:33 +02:00
MightyPork 62888d4473 update frontend to use branch master 2017-09-13 01:33:10 +02:00
MightyPork 3f0b6f2d26 fix bad submodue ref 2017-09-13 01:21:45 +02:00
MightyPork 5846d46e0c Merge remote-tracking branch 'origin/work' 2017-09-13 01:20:34 +02:00
MightyPork 1454987fcf Merge branch 'work' of github.com:espterm/espterm-firmware into work 2017-09-13 01:12:13 +02:00
MightyPork 2ba04b92d7 frontend update + fixes 2017-09-13 01:12:07 +02:00
MightyPorkandGitHub 6a7493a7be Update README.md 2017-09-12 15:47:15 +02:00
MightyPork 565b2113a5 submodue update - cache busting 2017-09-12 00:53:32 +02:00
MightyPork 128515a9a7 git hashes on about page 2017-09-12 00:26:43 +02:00
MightyPork 038c3b6466 update build script 2017-09-11 22:59:26 +02:00
MightyPork fa5953a231 front-end update 2017-09-11 15:05:29 +02:00
MightyPork 5aef8a0f11 Fix js error prevending wifi scanning 2017-09-11 12:36:23 +02:00
MightyPork 356c4557bb change default size back to 26x10 so it makes better first impression on a phone 2017-09-11 11:34:26 +02:00
MightyPork 5ff9d17850 adjusted defaults (disabled buttons by default so we dont confuse users with something they dont expect) 2017-09-11 05:09:22 +02:00
MightyPork ccbb1886af two hundred and fifty six colors, ladies and gentlemen!! 2017-09-11 04:27:50 +02:00
MightyPork 65d177f149 shortened utf cache & added missing flash storage attr 2017-09-11 03:26:57 +02:00
MightyPork 7cf82753ff bugfixes 2017-09-11 03:15:20 +02:00
MightyPork c4d399ccb0 added utf8 cache implementation, not yet used 2017-09-11 02:07:17 +02:00
MightyPork 521bc63c22 submodule ref 2017-09-11 00:58:49 +02:00
MightyPork b02aebf8c2 repeat character command 2017-09-11 00:53:42 +02:00
MightyPork 4c2421121f moved funcs to flash to make it build again, reduced logging buffer, disabled some logging; add missing files 2017-09-11 00:08:50 +02:00
MightyPork 6e1173cfcf make canvas branch be the default now 2017-09-10 14:05:02 +02:00
MightyPork 1742f4604a small cleaning 2017-09-10 10:15:35 +02:00
MightyPork 10fafd7c23 upse capital G for consistency 2017-09-10 02:24:50 +02:00
MightyPork c838883e69 back-end for #123 2017-09-10 02:23:57 +02:00
MightyPork 384372e6c8 backend support for SGR overline, bit 7 of attrib byte 2017-09-10 02:13:34 +02:00
MightyPork 74c7628474 groundwork for 256 color parsing, added conceal 2017-09-10 02:02:43 +02:00
MightyPork bd43c4d9c3 prevent compressor blowing up short repetitions 2017-09-10 01:28:30 +02:00
MightyPork 2e004b6048 changes to terminal settings now have immediate effect via notify 2017-09-10 00:43:31 +02:00
MightyPork ab921d2523 fix newline mode, add backend for cursor and crlf config in terminal config page 2017-09-09 23:51:26 +02:00
MightyPork 9ac5143228 fix compile error - missing declaration 2017-09-09 23:08:48 +02:00
MightyPork 2bea6397c6 cursor shape CSI and cursor blink toggle 2017-09-09 23:06:58 +02:00
MightyPork ea97752867 implemented saving to alternate buffer (except screen content) 2017-09-09 22:27:29 +02:00
MightyPork a12dcfc86f update github repo link 2017-09-09 20:59:17 +02:00
MightyPork b89db56c48 fix build script and switch default submodule to use master branch 2017-09-09 19:52:37 +02:00
MightyPork 6b603a1a8c Delete old html files & moved front-end to a submodule 2017-09-09 19:42:29 +02:00
cpsdqs 0caadb6f41 Actually fix selection not working
by just adding the selection colors to the palette
2017-09-09 16:20:47 +02:00
MightyPork ff5aa4c12c Merge branch 'canvas' of github.com:MightyPork/ESPTerm into canvas 2017-09-09 16:11:36 +02:00
MightyPork 0967d7f94a fixed bad submodule revision 2017-09-09 16:11:30 +02:00
cpsdqs 26e385b4c0 Fix selection not working 2017-09-09 16:10:10 +02:00
cpsdqs 5cc3003e47 Only redraw changed cells (huge performance boost!)
also add semicolons
2017-09-09 16:01:36 +02:00
cpsdqs 3e6187dba9 Add resize button 2017-09-09 15:15:11 +02:00
cpsdqs 7407419e56 Use proper soft keyboard events
...or as close as it gets because the way input events work on mobile is awful.
2017-09-09 14:55:54 +02:00
MightyPork 93824964ed gitignore update 2017-09-09 14:45:05 +02:00
cpsdqsandMightyPork abecf0d4ce Add fitIntoWidth/Height 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork d6d985a172 Make operators more readable
(it'll be minified anyway)
2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork 71cab02b3e Set to ctx.font as little as possible to improve Firefox performance 2017-09-09 14:38:03 +02:00
MightyPork 3926776adc Fixed the stupid unicode bug 2017-09-09 14:38:03 +02:00
MightyPork 3b7cd0a42e yarn lock 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork f85bcb3ef6 Use local sass instead of mysterious global CLI 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork 0f9809c290 Prevent space from scrolling 2017-09-09 14:38:03 +02:00
MightyPork 2d22d5cff1 fix firmware build scripts & disable yuicompressor 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork ab2dc10e35 Add Menlo to monospace font stack
lest it be Courier on iOS
2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork 34b72625a5 Add touch selection 2017-09-09 14:38:03 +02:00
MightyPork a3567ec338 nicer underlines & allow underline + strike together 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork 7576cd859a Add floating soft keyboard input 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork d82c33d774 Fix misaligned characters(?) 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork d57ed19c42 Add events to TermScreen; use correct cursor 2017-09-09 14:38:03 +02:00
cpsdqsandMightyPork bee99b4c55 Add babel-minify to packjs 2017-09-09 14:38:03 +02:00
MightyPork fe44927a62 cleaning and jslint syntax fixes 2017-09-09 14:35:37 +02:00
cpsdqsandMightyPork 8f81616ca8 Add hanging cursor 2017-09-09 14:33:50 +02:00
cpsdqsandMightyPork 15f539f4d4 Add mouse events, ⌃⇧C to copy, alt-select override
Also prevent body scroll when the terminal is scrollable
2017-09-09 14:33:50 +02:00
cpsdqsandMightyPork 3b6dfbda49 Add selection, other themes, cursor styles
and fix some issues
2017-09-09 14:33:50 +02:00
cpsdqsandMightyPork dd08290587 Rewrite term_screen with canvas 2017-09-09 14:33:50 +02:00
MightyPork b8ed46cbea removed some generated junk 2017-09-09 03:47:36 +02:00
MightyPork 8d7419b666 You wouldn't believe this simple trick that freed 10 kB of RAM! 2017-09-09 03:45:41 +02:00
MightyPork 830ec073bf fix #109 2017-09-09 03:03:12 +02:00
MightyPork 7d6cb2b660 screen serialize speedup + fix bad utf encode 2017-09-09 01:57:15 +02:00
MightyPork 1d6d6ee228 Implement initial load through websocket to cut one unnecessary HTTP GET that caused conn pool overflow. Increased reload / retry delays to reduce server spamming by poorly loaded client. 2017-09-08 23:53:23 +02:00
257 changed files with 6535 additions and 19078 deletions
+5 -1
View File
@@ -11,10 +11,14 @@ espfs/espfstest/espfstest
html_compressed/
ldscript_memspecific.ld
eagle.app.sym
node_modules
esphttpdconfig.mk
# Garbage added by CLion
.idea/
cmake-build-debug/
cmake-build-debug*/
.sass-cache
*.map
!.gitignore
+5
View File
@@ -1,3 +1,8 @@
[submodule "libesphttpd"]
path = libesphttpd
url = git@github.com:MightyPork/libesphttpd.git
branch = master
[submodule "front-end"]
path = front-end
url = git@github.com:espterm/espterm-front-end.git
branch = master
+44 -7
View File
@@ -56,6 +56,8 @@ set(SOURCE_FILES
libesphttpd/util/cgiwebsocket.c
libesphttpd/util/cgiflash.c
libesphttpd/util/captdns.c
libesphttpd/esphttpclient/httpclient.c
libesphttpd/include/httpclient.h
esp_iot_sdk_v1.5.2/include/user_interface.h
esp_iot_sdk_v1.5.2/include/upgrade.h
@@ -85,9 +87,9 @@ set(SOURCE_FILES
esp_iot_sdk_v1.5.2/include/json/jsontree.h
esp_iot_sdk_v1.5.2/include/json/jsonparse.h
esp_iot_sdk_v1.5.2/include/json/json.h
include/user_config.h
include/ets_sys_extra.h
include/helpers.h
user/io.c
user/io.h
user/cgi_wifi.c
@@ -110,8 +112,6 @@ set(SOURCE_FILES
user/serial.h
user/routes.c
user/routes.h
user/uart_asyncdrv.c-
user/uart_asyncdrv.h-
user/cgi_main.c
user/cgi_main.h
user/cgi_sockets.c
@@ -123,7 +123,6 @@ set(SOURCE_FILES
user/wifimgr.h
user/persist.c
user/persist.h
include/helpers.h
user/syscfg.c
user/syscfg.h
user/ascii.h
@@ -141,9 +140,21 @@ set(SOURCE_FILES
user/apars_osc.c
user/apars_osc.h
user/apars_dcs.c
user/apars_dcs.h user/uart_buffer.c user/uart_buffer.h user/jstring.c user/jstring.h user/character_sets.h)
user/apars_dcs.h
user/uart_buffer.c
user/uart_buffer.h
user/jstring.c
user/jstring.h
user/character_sets.h
user/ini_parser.h
user/ini_parser.c
user/ini_parser.rl
user/utf8.h
user/utf8.c
user/cgi_logging.h user/config_xmacros.h user/config_xmacros.c)
include_directories(include)
include_directories(libesphttpd/esphttpclient)
include_directories(user)
include_directories(libesphttpd/include)
include_directories(libesphttpd/espfs)
@@ -155,15 +166,41 @@ include_directories(esp_iot_sdk_v1.5.2/include)
add_definitions(
-D__ets__
-DICACHE_FLASH
-DDEBUG_LOGBUF_SIZE=2048
-DUSE_OPTIMIZE_PRINTF=1
-DHTTPD_MAX_CONNECTIONS=5
-DHTTPD_STACKSIZE=1000
-DICACHE_FLASH_ATTR=
-DICACHE_RODATA_ATTR=
-DFLAG_GZIP=2
-DADMIN_PASSWORD="asdf"
-DESP_LANG="en"
-DGIT_HASH_BACKEND="asdf"
-DGIT_HASH_FRONTEND="asdf"
-DGIT_HASH="blabla"
-D__TIMEZONE__="UTC"
-DESPFS_HEATSHRINK
-DDEBUG_ANSI=1
-DDEBUG_ANSI_NOIMPL=1
-DDEBUG_CAPTDNS=1
-DDEBUG_CGI=0
-DDEBUG_ESPFS=1
-DDEBUG_HEAP=1
-DDEBUG_HTTP=1
-DDEBUG_HTTPC=1
-DDEBUG_INPUT=1
-DDEBUG_MALLOC=1
-DESPFS_HEATSHRINK)
-DDEBUG_PERSIST=1
-DDEBUG_ROUTER=1
-DDEBUG_UTFCACHE=1
-DDEBUG_WIFI=1
-DDEBUG_WS=1
-DDEBUG_ROUTER=1
)
# all the debug keys should be listed here ^ so clion thinks they are used
# and doesn't mess up the formatting and inspections
add_executable(ESPTerm ${SOURCE_FILES})
+33 -10
View File
@@ -62,13 +62,18 @@ LIBS = c gcc hal phy pp net80211 wpa main lwip crypto
#Add in esphttpd lib
LIBS += esphttpd
# compiler flags using during compilation of source files
CFLAGS = -Os -ggdb -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
ifndef ESP_LANG
ESP_LANG = en
endif
# compiler flags using during compilation of source files -ggdb
CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH \
-Wno-address -Wno-unused
CFLAGS += -DGIT_HASH='"$(shell git rev-parse --short HEAD)"'
CFLAGS += -DADMIN_PASSWORD=$(ADMIN_PASSWORD)
CFLAGS += -DGIT_HASH_BACKEND='"$(shell git rev-parse --short HEAD)"'
CFLAGS += -DGIT_HASH_FRONTEND='"$(shell cd front-end && git rev-parse --short HEAD)"'
CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"' -DESP_LANG='"$(ESP_LANG)"'
ifdef GLOBAL_CFLAGS
CFLAGS += $(GLOBAL_CFLAGS)
@@ -152,7 +157,6 @@ define maplookup
$(patsubst $(strip $(1)):%,%,$(filter $(strip $(1)):%,$(2)))
endef
#Include options and target specific to the OUTPUT_TYPE
include Makefile.$(OUTPUT_TYPE)
@@ -171,7 +175,7 @@ MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
ESP_FLASH_SIZE_IX=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:0 1024:2 2048:5 4096:6)
ESPTOOL_FREQ=$(call maplookup,$(ESP_FLASH_FREQ_DIV),0:40m 1:26m 2:20m 0xf:80m 15:80m)
ESPTOOL_MODE=$(call maplookup,$(ESP_FLASH_MODE),0:qio 1:qout 2:dio 3:dout)
ESPTOOL_SIZE=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:4m 256:2m 1024:8m 2048:16m 4096:32m)
ESPTOOL_SIZE=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:512KB 256:256KB 1024:1MB 2048:2MB 4096:4MB)
ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD)
ESPTOOL_FLASHDEF=--flash_freq $(ESPTOOL_FREQ) --flash_mode $(ESPTOOL_MODE) --flash_size $(ESPTOOL_SIZE)
@@ -189,27 +193,46 @@ $1/%.o: %.S
$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
endef
.PHONY: all web parser checkdirs clean libesphttpd default-tgt
.PHONY: all web parser checkdirs clean libesphttpd default-tgt espsize espmac
web:
$(Q) ./build_web.sh
updweb:
$(Q) cd front-end && git pull
$(Q) ./build_web.sh
parser:
$(Q) ./build_parser.sh
all: checkdirs web parser $(TARGET_OUT) $(FW_BASE)
espsize:
$(Q) esptool --port /dev/ttyUSB0 flash_id
espmac:
$(Q) esptool --port /dev/ttyUSB0 read_mac
all: checkdirs
$(Q) make actual_all -j4 -B
release:
$(Q) ./release.sh
actual_all: parser $(TARGET_OUT) $(FW_BASE)
libesphttpd/Makefile:
$(Q) [[ -e "libesphttpd/Makefile" ]] || echo -e "\e[31mlibesphttpd submodule missing.\nIf build fails, run \"git submodule init\" and \"git submodule update\".\e[0m"
libesphttpd: libesphttpd/Makefile
$(Q) make -C libesphttpd USE_OPENSDK=$(USE_OPENSDK) SERVERNAME_PREFIX="ESPTerm "
$(Q) make -C libesphttpd USE_OPENSDK=$(USE_OPENSDK) -j4
$(APP_AR): libesphttpd $(OBJ)
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $(OBJ)
checkdirs: $(BUILD_DIR)
checkdirs: $(BUILD_DIR) html/favicon.ico
html/favicon.ico:
$(Q) [[ -e "html/favicon.ico" ]] || ./build_web.sh
$(BUILD_DIR):
$(Q) mkdir -p $@
+80 -38
View File
@@ -5,21 +5,24 @@
![Photo][photo-hw]<br>
*Fig 1: Breadboard adapter developed for ESPTerm*
Version 1.0.0 **passes most of VTTEST test cases** (from the main menu and some Xterm specific), making it
functionally comparable to eg. gnome-terminal, terminator, konsole, GtkTerm or PuTTY.
ESPTerm **passes most of VTTEST test cases**, making it functionally comparable to eg.
gnome-terminal, terminator, konsole, GtkTerm or PuTTY.
ESPTerm is **capable of running Midnight Commander** through agetty, **including full
mouse support**, provided agetty is made to believe it's Xterm, which shows ESPTerm is sufficiently well
implemented to work with ncurses.
mouse support**, provided agetty is made to believe it's Xterm, which shows ESPTerm
is compatible with ncurses.
In addition to control sequences that manipulate the terminal or user input, there
is a set of simple **networking commands** for device-to-device message exchange and
interacting with remote servers.
To see what escape sequences are supported, check out this [annotated Xterm manual page][xterm-compare]
which was used for reference, or the built-in help page ([online demo][demo-help])
The terminal screen can be accessed using any web browser, even on a phone or tablet.
It works with ESP-01, ESP-01S, ESP-12 and likely many other modules (I use an ESP-12
on a LoLin NodeMCU board from eBay for development).
It works with ESP-01, ESP-01S, ESP-12 and likely many other modules.
With ESPTerm, you can add remote access via WiFi to any embeded project, all you need is
a serial port and some imagination!
UART and some imagination!
## Try it online
@@ -27,25 +30,71 @@ You can try the web user interface here: [espterm.github.io][demo-term]
The demo is almost identical to the real thing, except, of course, it doesn't do much without the
emulator backend that runs on the ESP8266. The web version will be updated to match this repository
after each minor release.
after each minor release (and sometimes in between for testing; the version currently being show-cased
can be read on the About page of the demo).
### Browser support
Use the above linked online demo to verify compatibility with your browser.
To our knowledge, ESPTerm **works with**:
- Google Chrome (desktop, mobile)
- Firefox (desktop, mobile not tested)
- Safari (desktop, mobile)
- Chromium
- Opera
- Brave
- Konqueror
It **does not work with**:
- Microsoft Edge - runs, but is extremely laggy
- Internet Explorer (any version) - crashes, missing JS features
- Opera Mini - crashes, missing JS and CSS features
- Blackberry browser - not tested, but unlikely
- Safari on old iOS versions - missing features
- WebOS browser
- Old Android Browser (before 4.4?) - not tested, likely missing JS features
## Main features
- **Almost complete VT102 emulation** with some extras from Xterm, eg.
- Screen size up to 80x25
- Screen size up to 80x25 (the limit can be modified when compiling from source)
- All standard text styles and 16 colors supported
- Full UTF-8 support, alternate character sets
- Standard mouse tracking modes
- You can dynamically set screen title, button labels...
- **Web Interface**
- **Networking commands**
- Command for sending a message to another ESPTerm
- API endpoint (`/api/v1/msg`) for receiving messages sent e.g. from a script on PC, web browser or CURL
- Command for requesting remote servers and getting back response headers and/or body
- **Web Terminal Interface**
- Real-time screen update via WebSocket
- Button to open keyboard on Android
- 5 buttons under the screen for quick commands
- Text file upload tool with configurable delays and line endings
- Mouse and keyboard input, works also on mobile
- 5 optional buttons for quick commands
- Text file upload tool with adjustable delays and line endings
- *Built-in help page* ([demo][demo-help]) with basic troubleshooting and command reference
- **Robust WiFi configuration interface** (Demo: [WiFi][demo-wifi], [network][demo-network] config)
- **User-friendly comprehensive WiFi configuration** (Demo: [WiFi][demo-wifi], [network][demo-network] config)
- Static IP, DHCP, channel selection, power
- SSID search utility for finding your existing network
- **Basic security features**
- Possibility to password-lock parts of the web interface
- Admin password for some sensitive operations (can be changed!)
- Configurable AP password & Hidden attribute
- **Advanced settings storage**
- Stored in Flash
- Seamlesly updated and usually backwards compatible in minor releases
- Settings can be saved as defaults and later easily restored (ideal e.g. for classroom use, saving
good tested settings before giving the module to students)
## Bugs? Ideas?
To ask any questions or discuss new features you'd like to see added, it's best to use
the **[ESPTerm Dev mailing list](https://groups.google.com/forum/#!forum/espterm-dev)**
Subscribe to the mailing list to also receive new release announcements.
If you found a bug (that happens alot!), please submit it to our [bug tracker](https://github.com/espterm/espterm-firmware/issues).
We also use it to track planned ideas. If you don't want to create a GitHub account for that, just send it to the mailing list.
## Running ESPTerm
@@ -77,36 +126,31 @@ It can happen that some changes to the WiFi or network config make the module in
- To reset all settings to defaults, hold the button a couple seconds until the LED flashes rapidly, then release it.
- You can cancel this wipe/reset operation (when triggered by accident) by pressing Reset or disconnecting the power supply.
### Config files
### Config banks
ESPTerm has two config "files", one for defaults and one for the currently used settings. In the case of the terminal
config, there is also a third, temporary file for changes done via ESC commands.
When you get your settings *just right*, you can store them as defaults, which can then be at any time restored
by holding the BOOT (GPIO0) button. You can do this on the System Settings page. This asks for an "admin password",
which you can define when building the firmware in the `esphttpdconfig.mk` file.
The default password is `19738426`. This password can't presently be changed without re-flashing the firmware.
which can (and should!) be changed. This password can't be easily recovered when forgotten.
You can also restore everything (except the saved defaults) to "factory defaults", there is a button for this
on the System Settings page. Those are the initial values in the config files.
on the System Settings page. Those are the initial values you would get after a clean install.
## Research resources
Developing ESPTerm wasn't an easy task, because the information is scattered across many places and the existing
terminal emulators I originally used for reference (terminator, Konsole) are not implemented correctly in some details.
Developing the terminal emulator was complicated by the information being scattered across many places and the existing
implementations I used for reference often got some details wrong or didn't implement certain features at all. Xterm proved to be by far the most complete implementation.
A great tool for checking my implementation has proven to be [VTTTEST][vttest] and Xterm as a reference
implementation that is probably the most complete emulator available, although it's cumbersome to use and its age
really shows in the looks.
A great tool for checking my code has proven to be [VTTTEST][vttest]. ESPTerm passes most of the tests on the main page and some additional Xterm specific ones, like Mouse Tracking.
I've comnpiled a list of those I found most helpful here: [VT100 emulation resources][resources]
Here is a list of useful [VT100 emulation resources][resources] I've collected for reference.
## Development
ESPTerm's firmware is written in C and is based on SpriteTM's `libesphttpd` http server library forked to
[MightyPork/libesphttpd][httpdlib]. This fork includes various improvements
and changes required by the project.
[MightyPork/libesphttpd][httpdlib]. This fork includes various improvements and changes required by the project.
### Installation for development
@@ -121,8 +165,7 @@ and changes required by the project.
```
- Install Ragel if you wish to make modifications to the ANSI sequence parser.
If not, comment out its call in `build_parser.sh`. The `.rl` file is the actual source, the `.c` is generated.
- Install Ruby and then the `sass` package with `gem install sass` (or try some other implementation, such as
`sassc`)
- Install dependencies of the front-end submodule (`yarn install` in the front-end folder, installed PHP)
- Make sure your `esphttpdconfig.mk` is set up properly - link to the SDK etc.
The IoT SDK is now included in the project due to problems with obtaining the correct version and patching it.
@@ -131,24 +174,23 @@ than welcome!
### Web resources
The web resources are in `html_orig`. To prepare for a build, run `build_web.sh`, which packs them and
copies over to `html`. The compression and minification is handled by scripts in libesphttpd, specifically,
it runs yuicompressor on js and css and gzip or heatshrink on the other files. The `html` folder is
then embedded in the firmware image.
The web resources are in the `front-end` git submodule. To prepare the web resources for a build,
run `make web`. The resulting files are copied to `html/`. The `html/` folder is then embedded in the firmware image.
It's kind of tricky to develop the web resources locally; you might want to try the "split image"
Makefile option, then you can flash just the html portion with `make htmlflash`. I haven't tried this.
For local development, use the `server.sh` script in `html_orig`. It's possible to talk to API of a running
ESP8266 from here, if you configure `_env.php` with its IP.
For local development, use the `server.sh` script in `html_orig` (more details in the front-end repo's readme).
It's possible to talk to the API endpoints of a running ESP8266 from a page served by your local server
if you configure `_env.php` with its IP.
### Flashing
The Makefile should automatically build the parser and web resources for you when you run `make`.
Sometimes it does not, particularly with `make -B`. Try just plain `make`. You can always run those
build scripts manually, too.
The web resources are normally no re-built, because the build process is quite slow. To manually rebuild them,
run `make web` before `make`.
To flash, just run `make flash`.
To flash, just run `make flash`. It will use parameters you setup in the `esphttpdconfig.mk` file.
[releases]: https://github.com/MightyPork/esp-vt100-firmware/releases
[httpdlib]: https://github.com/MightyPork/libesphttpd
-26
View File
@@ -1,26 +0,0 @@
#!/bin/bash
echo "-- Preparing WWW files --"
[[ -e html_demo ]] && rm -r html_demo
mkdir -p html_demo/img
mkdir -p html_demo/js
mkdir -p html_demo/css
cd html_orig
sh ./packjs.sh
ESP_DEMO=1 php ./build_html.php
cd ..
cp html_orig/js/app.js html_demo/js/
sass html_orig/sass/app.scss html_demo/css/app.css
rm html_demo/css/app.css.map
cp html_orig/img/* html_demo/img/
cp html_orig/favicon.ico html_demo/favicon.ico
# cleanup
find html_demo/ -name "*.orig" -delete
find html_demo/ -name "*.xcf" -delete
find html_demo/ -name "*~" -delete
+7
View File
@@ -3,3 +3,10 @@
echo "-- Building parser from Ragel source --"
ragel -L -G0 user/ansi_parser.rl -o user/ansi_parser.c
ragel -L -G0 user/ini_parser.rl -o user/ini_parser.c
sed -i "s/static const char _ansi_actions\[\]/static const char _ansi_actions\[\] ESP_CONST_DATA/" user/ansi_parser.c
sed -i "s/static const char _ansi_eof_actions\[\]/static const char _ansi_eof_actions\[\] ESP_CONST_DATA/" user/ansi_parser.c
sed -i "s/static const char _ini_actions\[\]/static const char _ini_actions\[\] ESP_CONST_DATA/" user/ini_parser.c
sed -i "s/static const char _ini_eof_actions\[\]/static const char _ini_eof_actions\[\] ESP_CONST_DATA/" user/ini_parser.c
+3 -18
View File
@@ -3,24 +3,9 @@
echo "-- Preparing WWW files --"
[[ -e html ]] && rm -r html
mkdir -p html/img
mkdir -p html/js
mkdir -p html/css
cd html_orig
sh ./packjs.sh
php ./build_html.php
cd ..
ESP_PROD=1 front-end/build.sh
cp html_orig/js/app.js html/js/
echo "Copying from submodule..."
sass html_orig/sass/app.scss html/css/app.css
rm html/css/app.css.map
cp html_orig/img/* html/img/
cp html_orig/favicon.ico html/favicon.ico
# cleanup
find html/ -name "*.orig" -delete
find html/ -name "*.xcf" -delete
find html/ -name "*~" -delete
cp -r front-end/out html
-14
View File
@@ -1,14 +0,0 @@
#!/bin/bash
./build_demo.sh
cp -r html_demo/* ../espterm.github.io/
cd ../espterm.github.io/
echo "Enter to deploy (^C to abort):"
read
git add --all
git commit -m "Deploy updates"
git push
+3 -3
View File
@@ -35,9 +35,9 @@
#define os_snprintf ets_snprintf
#ifdef USE_OPTIMIZE_PRINTF
#define os_printf(fmt, ...) do { \
static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \
os_printf_plus(flash_str, ##__VA_ARGS__); \
#define os_printf(fmt, ...) do { \
static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \
os_printf_plus(flash_str, ##__VA_ARGS__); \
} while(0)
#else
#define os_printf os_printf_plus
@@ -18,7 +18,7 @@ GZIP_COMPRESSION = yes
# This option works only when GZIP_COMPRESSION is set to "yes"
# http://yui.github.io/yuicompressor/
#Disabled by default.
COMPRESS_W_YUI = yes
COMPRESS_W_YUI = no
YUI-COMPRESSOR = /usr/bin/yui-compressor
@@ -38,20 +38,28 @@ OUTPUT_TYPE = combined
# SPI flash size, in K
ESP_SPI_FLASH_SIZE_K = 1024
# Admin password, used to store settings to flash as defaults
ADMIN_PASSWORD = "19738426"
GLOBAL_CFLAGS = \
-DASYNC_LOG=1 \
-DDEBUG_INI=1 \
-DDEBUG_D2D=0 \
-DDEBUG_ROUTER=0 \
-DDEBUG_CAPTDNS=0 \
-DDEBUG_HTTP=1 \
-DDEBUG_HTTP=0 \
-DDEBUG_HTTPC=0 \
-DDEBUG_ESPFS=0 \
-DDEBUG_PERSIST=1 \
-DDEBUG_UTFCACHE=0 \
-DDEBUG_CGI=0 \
-DDEBUG_WIFI=0 \
-DDEBUG_WS=0 \
-DDEBUG_ANSI=1 \
-DDEBUG_ANSI_NOIMPL=1 \
-DDEBUG_INPUT=0 \
-DDEBUG_HEAP=1 \
-DDEBUG_MALLOC=0 \
-DHTTPD_MAX_BACKLOG_SIZE=8192 \
-DHTTPD_MAX_HEAD_LEN=1024 \
-DHTTPD_MAX_POST_LEN=512 \
-DDEBUG_INPUT=0 \
-DDEBUG_HEAP=1 \
-DDEBUG_MALLOC=0
-DDEBUG_LOGBUF_SIZE=1024 \
-mforce-l32 \
-DUSE_OPTIMIZE_PRINTF=1
Submodule
+1
Submodule front-end added at e25523de11
+14
View File
@@ -0,0 +1,14 @@
//
// Created by MightyPork on 2017/10/03.
//
// helper for building release packages
//
// Run with `tcc -run`
//
#include "user/version.h"
#include <stdio.h>
void main() {
printf(FW_VERSION);
}
-1
View File
@@ -1 +0,0 @@
pages/_test_env.php
-86
View File
@@ -1,86 +0,0 @@
<?php
/**
* Those replacements are done by the development server to test it locally
* without esphttpd. This is needed mainly for places where the replacements
* are given to JavaScript, to avoid syntax errors with
*/
$vers = '???';
$f = file_get_contents(__DIR__ . '/../user/version.h');
preg_match_all('/#define FW_V_.*? (\d+)/', $f, $vm);
#define FW_V_MAJOR 1
#define FW_V_MINOR 0
#define FW_V_PATCH 0
$vers = $vm[1][0].'.'.$vm[1][1].'.'.$vm[1][2];
return [
'term_title' => ESP_DEMO ? 'ESPTerm Web UI Demo' : 'ESPTerm local debug',
'btn1' => 'OK',
'btn2' => 'Cancel',
'btn3' => '',
'btn4' => '',
'btn5' => 'Help',
'bm1' => '01,'.ord('y'),
'bm2' => '01,'.ord('n'),
'bm3' => '',
'bm4' => '',
'bm5' => '05',
'labels_seq' => ESP_DEMO ? 'TESPTerm Web UI DemoOKCancelHelp' : 'TESPTerm local debugOKCancelHelp',
'parser_tout_ms' => 10,
'display_tout_ms' => 15,
'display_cooldown_ms' => 35,
'fn_alt_mode' => '1',
'opmode' => '2',
'sta_enable' => '1',
'ap_enable' => '1',
'tpw' => '60',
'ap_channel' => '7',
'ap_ssid' => 'TERM-027451',
'ap_password' => '',
'ap_hidden' => '0',
'sta_ssid' => 'Cisco',
'sta_password' => 'Passw0rd!',
'sta_active_ip' => ESP_DEMO ? '192.168.82.66' : '192.168.0.19',
'sta_active_ssid' => 'Cisco',
'vers_fw' => $vers,
'date' => date('Y-m-d'),
'time' => date('G:i'),
'vers_httpd' => '0.4',
'vers_sdk' => '010502',
'githubrepo' => 'https://github.com/MightyPork/esp-vt100-firmware',
'ap_dhcp_time' => '120',
'ap_dhcp_start' => '192.168.4.100',
'ap_dhcp_end' => '192.168.4.200',
'ap_addr_ip' => '192.168.4.1',
'ap_addr_mask' => '255.255.255.0',
'sta_dhcp_enable' => '1',
'sta_addr_ip' => '192.168.0.33',
'sta_addr_mask' => '255.255.255.0',
'sta_addr_gw' => '192.168.0.1',
'sta_mac' => '5c:cf:7f:02:74:51',
'ap_mac' => '5e:cf:7f:02:74:51',
'term_width' => '80',
'term_height' => '25',
'default_bg' => '0',
'default_fg' => '7',
'show_buttons' => '1',
'show_config_links' => '1',
'uart_baud' => 115200,
'uart_stopbits' => 1,
'uart_parity' => 2,
'theme' => 0,
];
-3
View File
@@ -1,3 +0,0 @@
<?php
define("ESP_IP", "192.168.0.19");
-3
View File
@@ -1,3 +0,0 @@
<?php
define("ESP_IP", "192.168.0.19");
-50
View File
@@ -1,50 +0,0 @@
<?php
$pages = [];
if (! function_exists('pg')) {
/** Add a page */
function pg($key, $bc, $icon, $path, $titleKey = null)
{
global $pages;
$pages[$key] = (object) [
'key' => $key,
'bodyclass' => $bc,
'path' => $path,
'icon' => $icon ? "icn-$icon" : '',
'label' => tr("menu.$key"),
'title' => $titleKey ? tr($titleKey) : tr("menu.$key"),
];
}
}
pg('cfg_term', 'cfg', 'terminal', '/cfg/term');
pg('term_set', 'api', '', '/cfg/term/set');
pg('cfg_wifi', 'cfg', 'wifi', '/cfg/wifi');
pg('cfg_wifi_conn', '', '', '/cfg/wifi/connecting');
pg('wifi_connstatus', 'api', '', '/cfg/wifi/connstatus');
pg('wifi_set', 'api', '', '/cfg/wifi/set');
pg('wifi_scan', 'api', '', '/cfg/wifi/scan');
pg('cfg_network', 'cfg', 'network', '/cfg/network');
pg('network_set', 'api', '', '/cfg/network/set');
pg('cfg_system', 'cfg', 'configure', '/cfg/system');
pg('system_set', 'api', '', '/cfg/system/set');
pg('write_defaults', 'api', '', '/cfg/system/write_defaults');
pg('restore_defaults', 'api', '', '/cfg/system/restore_defaults');
pg('restore_hard', 'api', '', '/cfg/system/restore_hard');
pg('help', 'cfg page-help', 'help', '/help');
pg('about', 'cfg page-about', 'about', '/about');
pg('term', 'term', '', '/', 'title.term');
pg('reset_screen', 'api', '', '/system/cls', 'title.term');
pg('index', 'api', '', '/', '');
// ajax API
return $pages;
-177
View File
@@ -1,177 +0,0 @@
<?php
/**
* The common stuff required by both index.php and build_html.php
* this must be required_once
*/
if (defined('BASE_INITED')) return;
define('BASE_INITED', true);
if (!empty($argv[1])) {
parse_str($argv[1], $_GET);
}
if (!file_exists(__DIR__ . '/_env.php')) {
die("Copy <b>_env.php.example</b> to <b>_env.php</b> and check the settings inside!");
}
require_once __DIR__ . '/_env.php';
$prod = defined('STDIN');
define('DEBUG', !$prod);
$root = DEBUG ? json_encode(ESP_IP) : 'location.host';
define('JS_WEB_ROOT', $root);
define('ESP_DEMO', (bool)getenv('ESP_DEMO'));
if (ESP_DEMO) {
define('DEMO_SCREEN', '"S\u0019\u0001Q\u0001\u0017\u0001K\u0001\u0015\u0004\u0003\b\u0001 \u0002P\u0001┌ESPTerm─Demo─\u0002\u0002\u0001\u0003\u0002\u000131\u0003\u0003\u000132\u0003\u0004\u00013\u0002\u0002\u0001\u0003\u0005\u000134\u0003\u0006\u000135\u0003\u0007\u000136\u0003\b\u000137\u0003\t\u000190\u0003\n\u000191\u0003\u000b\u000192\u0003\f\u000193\u0003\r\u000194\u0003\u000e\u000195\u0003\u000f\u000196\u0003\u0010\u000197\u0003\b\u0001─\u0002\r\u0001┐ \u0002\u0015\u0001│ \u00029\u0001│ \u0002\u0004\u0001│\u0002\t\u0001 \u0002\b\u0001│\u0004\u0002\u0001Bold \u0004\u0003\u0001F\u0004\u0003\u0001a\u0004\u0003\u0001i\u0004\u0003\u0001n\u0004\u0003\u0001t\u0004\u0003\u0001 \u0004\u0005\u0001I\u0004\u0005\u0001t\u0004\u0005\u0001a\u0004\u0005\u0001l\u0004\u0005\u0001i\u0004\u0005\u0001c\u0004\u0005\u0001 \u0004\t\u0001U\u0004\t\u0001n\u0004\t\u0001d\u0004\t\u0001e\u0004\t\u0001r\u0004\t\u0001l\u0004\t\u0001i\u0004\t\u0001n\u0004\t\u0001e\u0004\u0001\u0001 \u0004\u0011\u0001B\u0004\u0011\u0001l\u0004\u0011\u0001i\u0004\u0011\u0001n\u0004\u0011\u0001k\u0004\u0011\u0001 \u0001q\u0001\u0001Inverse\u0003\b\u0001 \u0004A\u0001S\u0004A\u0001t\u0004A\u0001r\u0004A\u0001i\u0004A\u0001k\u0004A\u0001e\u0004\u0001\u0001 \u0004!\u0001F\u0004!\u0001r\u0004!\u0001a\u0004!\u0001k\u0004!\u0001t\u0004!\u0001u\u0004!\u0001r\u0004\u0001\u0001 │ \u0002\u0002\u0001─\u0002\u0002\u0001\u0003\n\u0002 \u0002\t\u0001\u0003\b\u0001─\u0002\u0002\u0001 \u0002\u0006\u0001│ \u00029\u0001│ \u0002\u0002\u0001─\u0002\u0002\u0001\u0003\n\u0002 \u0003\u0002\u0002ESP826\u0002\u0002\u0001\u0003\n\u0002 \u0003\b\u0001─\u0002\u0002\u0001 \u0002\u0006\u0001└─\u00029\u0001┤ \u0002\u0002\u0001─\u0002\u0002\u0001\u0003\n\u0002 \u0002\t\u0001\u0003\b\u0001─\u0002\u0002\u0001 \u0002@\u0001│ \u0002\u0002\u0001─\u0002\u0002\u0001\u0003\n\u0002 \u0003\u0002\u0002(@)#\u0002\u0004\u0001\u0003\n\u0002 \u0003\b\u0001─\u0002\u0002\u0001 \u0002\u0007\u0001\u0003O\u0001 This is a static demo of the ESPTerm Web Interface \u0002\u0004\u0001\u0003\b\u0001 \u0002\u0002\u0001│ \u0002\u0002\u0001─\u0002\u0002\u0001\u0003\n\u0002 \u0002\t\u0001\u0003\b\u0001─\u0002\u0002\u0001 \u0002\u0007\u0001\u0003O\u0001 \u00027\u0001\u0003\b\u0001 \u0002\u0002\u0001│ \u0002\u0004\u0001│\u0002\t\u0001 \u0002\t\u0001\u0003O\u0001 Try the links beneath this scre\u0002\u0002\u0001n to browse the menu. \u0003\b\u0001 \u0002\u0002\u0001♦ \u0002\u0016\u0001\u0003O\u0001 \u00027\u0001\u0003\b\u0001 \u0002\u0019\u0001\u0003O\u0001 <°)\u0002\u0003\u0001>< ESPTerm ful\u0002\u0002\u0001y sup\u0002\u0002\u0001orts UTF-8 お は よ ー \u0002\u0002\u0001><(\u0002\u0003\u0001°> \u0003\b\u0001 \u0002\u0019\u0001\u0003O\u0001 \u00027\u0001\u0003\b\u0001 \u0002i\u0001\u0003\u000b\u0001Other interesting features:\u0003\b\u0001 \u0002\u0018\u0001↓ \u0002n\u0001\u0003\u0003\u0001- Almost ful\u0002\u0002\u0001 VT10\u0002\u0002\u0001 emulation \u0003\b\u0001 \u0003\u0006\u0001()\u0003\b\u0001 \u0003\u0006\u0001()\u0003\b\u0001 \u0002\b\u0001Funguje tu čeština! \u0002\u0011\u0001\u0003\u0005\u0001- Xterm-like mouse tracking\u0003\b\u0001 \u0002\u0003\u0001=\u0002\u0002\u0001\u0003\t\u0002°.°\u0003\b\u0001=\u0002\u0002\u0001 \u0003\u0006\u0001<-\u0002\u0003\u0001, \u0003\b\u0001 \u0002$\u0001\u0003\u0004\u0001- File upload utility\u0003\b\u0001 \u0002\n\u0001\'\u0002\u0002\u0001 \'\u0002\u0002\u0001 \u0002\u0002\u0001\u0003\u0006\u0001 \u0002\u0004\u0001mouse\u0003\b\u0001 \u0002!\u0001\u0003\u0002\u0001- User-friendly config interface\u0003\b\u0001 \u00020\u0001\u0003\u000e\u0001-\u0003\u0002\u0001 \u0003\u000e\u0001Advanced WiFi & network set\u0002\u0002\u0001ings\u0003\b\u0001 \u0002\u0011\u0001\u0003\f\u0001Try ESPTerm today!\u0003\b\u0001 \u0002\u000b\u0001- Built-in help page \u0002\u001a\u0001\u0003\u0007\u0001-\u0002\u0002\u0001>\u0003\b\u0001 \u0002\u0002\u0001\u0003\f\u0001Pre-built binaries\u0003\b\u0001 \u0003\f\u0001are\u0003\b\u0001 \u0002\"\u0001\u0003\u0007\u0001link on the About page \u0002\u0002\u0001\u0003\f\u0001available on GitHub! \u0003\b\u0001 \u0002U\u0001"');
define('DEMO_APS', <<<APS
{
"result": {
"inProgress": 0,
"APs": [
{"essid": "Cisco", "bssid": "88:f7:c7:52:b3:99", "rssi": 205, "rssi_perc": 100, "enc": 4, "channel": 7},
{"essid": "UPC Wi-Free", "bssid": "8a:f7:c7:52:b3:9b", "rssi": 203, "rssi_perc": 100, "enc": 5, "channel": 1},
{"essid": "UPC Wi-Free", "bssid": "0a:95:2a:0c:84:31", "rssi": 166, "rssi_perc": 32, "enc": 5, "channel": 1},
{"essid": "MujO2Internet_2EEB96", "bssid": "d0:60:8c:2e:eb:96", "rssi": 174, "rssi_perc": 48, "enc": 4, "channel": 4},
{"essid": "Internet", "bssid": "38:72:c0:32:bd:0d", "rssi": 164, "rssi_perc": 28, "enc": 2, "channel": 10},
{"essid": "MyO2Internet_08C850", "bssid": "78:c1:a7:08:c8:50", "rssi": 186, "rssi_perc": 72, "enc": 4, "channel": 11},
{"essid": "UPC Wi-Free", "bssid": "06:7c:34:9a:6f:7c", "rssi": 167, "rssi_perc": 34, "enc": 0, "channel": 11},
{"essid": "Internet_B0", "bssid": "5c:f4:ab:11:3b:b3", "rssi": 175, "rssi_perc": 50, "enc": 3, "channel": 13},
{"essid": "UPC5716805", "bssid": "08:95:2a:0c:84:3f", "rssi": 165, "rssi_perc": 30, "enc": 4, "channel": 1}
]
}
}
APS
);
}
define('LOCALE', isset($_GET['locale']) ? $_GET['locale'] : 'en');
$_messages = require(__DIR__ . '/lang/' . LOCALE . '.php');
$_pages = require(__DIR__ . '/_pages.php');
define('APP_NAME', 'ESPTerm');
/** URL (dev or production) */
function url($name, $relative = false)
{
global $_pages;
if ($relative) return $_pages[$name]->path;
if (DEBUG) return "/index.php?page=$name";
if (ESP_DEMO) return "$name.html";
else return $_pages[$name]->path;
}
/** URL label for a button */
function label($name)
{
global $_pages;
return $_pages[$name]->label;
}
function e($s)
{
return htmlspecialchars($s, ENT_HTML5 | ENT_QUOTES);
}
function je($s)
{
return htmlspecialchars(json_encode($s), ENT_HTML5);
}
function tr($key)
{
global $_messages;
return isset($_messages[$key]) ? $_messages[$key] : ('??' . $key . '??');
}
/** Like eval, but allows <?php and ?> */
function include_str($code)
{
$tmp = tmpfile();
$tmpf = stream_get_meta_data($tmp);
$tmpf = $tmpf ['uri'];
fwrite($tmp, $code);
$ret = include($tmpf);
fclose($tmp);
return $ret;
}
if (!function_exists('utf8')) {
function utf8($num)
{
if($num<=0x7F) return chr($num);
if($num<=0x7FF) return chr(($num>>6)+192).chr(($num&63)+128);
if($num<=0xFFFF) return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
if($num<=0x1FFFFF) return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128).chr(($num&63)+128);
return '';
}
}
if (!function_exists('load_esp_charsets')) {
function load_esp_charsets() {
$chsf = __DIR__ . '/../user/character_sets.h';
$re_table = '/\/\/ %%BEGIN:(.)%%\s*(.*?)\s*\/\/ %%END:\1%%/s';
preg_match_all($re_table, file_get_contents($chsf), $m_tbl);
$re_bounds = '/#define CODEPAGE_(.)_BEGIN\s+(\d+)\n#define CODEPAGE_\1_END\s+(\d+)/';
preg_match_all($re_bounds, file_get_contents($chsf), $m_bounds);
$cps = [];
foreach ($m_tbl[2] as $i => $str) {
$name = $m_tbl[1][$i];
$start = intval($m_bounds[2][$i]);
$table = [];
$str = preg_replace('/,\s*\/\/[^\n]*/', '', $str);
$rows = explode("\n", $str);
$rows = array_map('trim', $rows);
foreach($rows as $j => $v) {
if (strpos($v, '0x') === 0) {
$v = substr($v, 2);
$v = hexdec($v);
} else {
$v = intval($v);
}
$ascii = $start+$j;
$table[] = [
$ascii,
chr($ascii),
utf8($v==0? $ascii :$v),
];
}
$cps[$name] = $table;
}
return $cps;
}
}
if (!function_exists('tplSubs')) {
function tplSubs($str, $reps)
{
return preg_replace_callback('/%(j:|js:|h:|html:)?([a-z0-9-_.]+)%/i', function ($m) use ($reps) {
$key = $m[2];
if (array_key_exists($key, $reps)) {
$val = $reps[$key];
} else {
$val = '';
}
switch ($m[1]) {
case 'j:':
case 'js:':
$v = json_encode($val);
return substr($v, 1, strlen($v) - 2);
case 'h:':
case 'html:':
return htmlspecialchars($val);
default:
return $val;
}
}, $str);
}
}
-50
View File
@@ -1,50 +0,0 @@
<?php
require_once __DIR__ . '/base.php';
function process_html($s) {
$pattern = '/<!--(.*)-->/Uis';
$s = preg_replace($pattern, '', $s);
$pattern = '/(?:(?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/)|(?:(?<!\:|\\\|\'|\")\/\/.*))/';
$s = preg_replace($pattern, '', $s);
$pattern = '/\s+/s';
$s = preg_replace($pattern, ' ', $s);
return $s;
}
$no_tpl_files = ['help', 'cfg_wifi_conn'];
$dest = ESP_DEMO ? __DIR__ . '/../html_demo/' : __DIR__ . '/../html/';
ob_start();
foreach($_pages as $_k => $p) {
if ($p->bodyclass == 'api') {
if (ESP_DEMO) {
$target = 'term.html';
echo "Generating: ~$_k.html -> $target\n";
$s = "<!DOCTYPE HTML><meta http-equiv=\"refresh\" content=\"0;url=$target\">";
} else {
continue;
}
} else {
echo "Generating: $_k ($p->title)\n";
$_GET['page'] = $_k;
ob_flush(); // print the message
ob_clean(); // clean up
include(__DIR__ . '/index.php');
$s = ob_get_contents(); // grab the output
// remove newlines and comments
// as tests have shown, it saves just a couple kilobytes,
// making it not a very big improvement at the expense of ugly html.
// $s = process_html($s);
ob_clean();
} // clean up
$of = $dest . $_k . ((in_array($_k, $no_tpl_files)||ESP_DEMO) ? '.html' : '.tpl');
file_put_contents($of, $s); // write to a file
}
ob_flush();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-23
View File
@@ -1,23 +0,0 @@
<?php
/* This script is run on demand to generate JS version of tr() */
require_once __DIR__ . '/base.php';
$selected = [
'wifi.connected_ip_is',
'wifi.not_conn',
'wifi.enter_passwd',
'wifi.passwd_saved',
];
$out = [];
foreach ($selected as $key) {
$out[$key] = $_messages[$key];
}
file_put_contents(__DIR__. '/jssrc/lang.js',
"// Generated from PHP locale file\n" .
'var _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" .
"function tr(key) { return _tr[key] || '?'+key+'?'; }\n"
);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

-1
View File
@@ -1 +0,0 @@
/out/
Binary file not shown.
-93
View File
@@ -1,93 +0,0 @@
#!/bin/bash
# resolve current file's directory
DIR=$(dirname $(realpath $0))
OUTPUT_DIR="$DIR/out"
SASS_DIR="$DIR/../sass"
ICON_PREFIX='icn'
# list with full paths, sort from newest
NEWEST=$(ls -dt1 "$DIR"/*.zip | head -1)
if [[ -z "$NEWEST" ]]; then
echo "Fontello zip not found."
exit 1
fi
# Clean the output folder
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
echo "Unpacking fontello..."
unzip -ju "$NEWEST" -d "$OUTPUT_DIR"
echo "Patching paths in the fontello CSS..."
# Fix bad relative paths in the CSS
sed -i "s|\.\./font/|/fonts/|g" "$OUTPUT_DIR/"*.css
echo "Generating SASS file with icon codes..."
SASSFILE="$SASS_DIR/_fontello.scss"
echo -e "@charset \"UTF-8\";\n\n/* Fontello data, processed by the unpack script. */\n" > "$SASSFILE"
# Extract the base font-face style
#grep -Pazo "(?s)@font-face.*?normal;\n\}" "$OUTPUT_DIR/fontello.css" \
# | sed 's/\x0//g' >> "$SASSFILE"
grep -Pazo "(?s)@font-face \{\n\s*font-family: 'fontello';\n\s*src: url\('data.*?woff'\)" "$OUTPUT_DIR/fontello-embedded.css" \
| sed 's/\x0//g' >> "$SASSFILE"
echo -e ";\n}" >> "$SASSFILE"
grep -Pazo "(?s)$ICON_PREFIX-\"\]:before .*?\}" "$OUTPUT_DIR/fontello.css" \
| sed 's/\x0//g' \
| sed "s/$ICON_PREFIX-\"\]:before/\n\n%fontello-icon-base \{\n\&::before /g" \
>> "$SASSFILE"
echo -e "\n}" >> "$SASSFILE"
echo -e "\n\n/* Fontello icon codes */" >> "$SASSFILE"
echo -n "\$icon-codes: (" >> "$SASSFILE"
sed -r "s|\.$ICON_PREFIX-([a-z0-9-]+):before \{ content: ('.*?');.*?$|\t\1: \2,|g" "$OUTPUT_DIR/fontello-codes.css" \
| sed -r "s|@.*||g" >> "$SASSFILE"
echo -ne "\n);\n" >> "$SASSFILE"
echo -ne "\n/* Fontello classes */" >> "$SASSFILE"
cat "$OUTPUT_DIR/fontello-codes.css" \
| sed -r 's/\/\*.+\*\///g' \
| sed -r "s|@.*||g" \
| sed 's/:before/::before/g' >> "$SASSFILE"
TAIL=$(cat <<ASDF
[class^="$ICON_PREFIX-"], [class*=" $ICON_PREFIX-"] {
@extend %fontello-icon-base;
}
@mixin icon-base() {
@extend %fontello-icon-base;
}
@mixin icon-content(\$icon-name) {
&::before {
content: map-get(\$icon-codes, \$icon-name);
}
}
@mixin icon(\$icon-name) {
@include icon-base();
@include icon-content(\icon-name);
}
ASDF
)
echo "$TAIL" >> "$SASSFILE"
echo -e "\e[32mFontello ready\e[0m"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

-50
View File
@@ -1,50 +0,0 @@
<?php
require_once __DIR__ . '/base.php';
if (!isset($_GET['page'])) $_GET['page'] = 'term';
$_GET['PAGE_TITLE'] = $_pages[$_GET['page']]->title . ' :: ' . APP_NAME;
$_GET['BODYCLASS'] = $_pages[$_GET['page']]->bodyclass;
$_pf = __DIR__ . '/pages/'.$_GET['page'].'.php';
if (!file_exists($_pf)) {
header("Location: /", true, 302);
die();
}
require __DIR__ . '/pages/_head.php';
$include_re = '/<\?php\s*(require|include)\s*\(?\s*?(?:__DIR__\s*\.)?\s*(["\'])(.*?)\2\s*\)?;\s*\?>/';
if (file_exists($_pf)) {
$f = file_get_contents($_pf);
// Resolve requires inline - they wont work after dumping the resulting file to /tmp for eval
$f = preg_replace_callback($include_re, function ($m) use ($_pf) {
$n = dirname($_pf).'/'.$m[3];
if (file_exists($n)) {
return file_get_contents($n);
} else {
return "<p>NOT FOUND: $n</p>";
}
}, $f);
if (DEBUG || ESP_DEMO)
$str = tplSubs($f, require(__DIR__ . '/_debug_replacements.php'));
else $str = $f;
// special symbols
$str = str_replace('\,', '&#8239;', $str);
$str = preg_replace('/(?<=[^ \\\\])~(?=[^ ])/', '&nbsp;', $str);
$str = str_replace('\~', '~', $str);
$str = preg_replace('/(?<![\w\\\\])`([^ `][^`]*?[^ `]|[^ `])`(?!\w)/', '<code>$1</code>', $str);
$str = preg_replace('/(?<![\w\\\\])_([^ _][^_]*?[^ _]|[^ _])_(?!\w)/', '<i>$1</i>', $str);
$str = preg_replace('/(?<![\w\\\\])\*([^ *][^*]*?[^ *]|[^ *])\*(?!\w)/', '<b>$1</b>', $str);
$str = preg_replace("/\s*(\\\\\\\\)[\n \t]+/", '<br>', $str);
include_str($str);
}
require __DIR__ . '/pages/_tail.php';
-2533
View File
File diff suppressed because it is too large Load Diff
-189
View File
@@ -1,189 +0,0 @@
/** Global generic init */
$.ready(function () {
// Checkbox UI (checkbox CSS and hidden input with int value)
$('.Row.checkbox').forEach(function(x) {
var inp = x.querySelector('input');
var box = x.querySelector('.box');
$(box).toggleClass('checked', inp.value);
var hdl = function() {
inp.value = 1 - inp.value;
$(box).toggleClass('checked', inp.value)
};
$(x).on('click', hdl).on('keypress', cr(hdl));
});
// Expanding boxes on mobile
$('.Box.mobcol,.Box.fold').forEach(function(x) {
var h = x.querySelector('h2');
var hdl = function() {
$(x).toggleClass('expanded');
};
$(h).on('click', hdl).on('keypress', cr(hdl));
});
$('form').forEach(function(x) {
$(x).on('keypress', function(e) {
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) {
x.submit();
}
})
});
// loader dots...
setInterval(function () {
$('.anim-dots').each(function (x) {
var $x = $(x);
var dots = $x.html() + '.';
if (dots.length == 5) dots = '.';
$x.html(dots);
});
}, 1000);
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function(e) {
var $this = $(this);
var val = +$this.val();
if (isNaN(val)) val = 1;
var step = +($this.attr('step') || 1);
var min = +$this.attr('min');
var max = +$this.attr('max');
if(e.wheelDelta > 0) {
val += step;
} else {
val -= step;
}
if (typeof min != 'undefined') val = Math.max(val, +min);
if (typeof max != 'undefined') val = Math.min(val, +max);
$this.val(val);
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
$this[0].dispatchEvent(evt);
} else {
$this[0].fireEvent("onchange");
}
e.preventDefault();
});
var errAt = location.search.indexOf('err=');
if (errAt !== -1 && qs('.Box.errors')) {
var errs = location.search.substr(errAt+4).split(',');
var hres = [];
errs.forEach(function(er) {
var lbl = qs('label[for="'+er+'"]');
if (lbl) {
lbl.classList.add('error');
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''));
} else {
hres.push(er);
}
});
qs('.Box.errors .list').innerHTML = hres.join(', ');
qs('.Box.errors').classList.remove('hidden');
}
Modal.init();
Notify.init();
// remove tabindixes from h2 if wide
if (window.innerWidth > 550) {
$('.Box h2').forEach(function (x) {
x.removeAttribute('tabindex');
});
// brand works as a link back to term in widescreen mode
var br = qs('#brand');
br && br.addEventListener('click', function() {
location.href='/'; // go to terminal
});
}
});
$._loader = function(vis) {
$('#loader').toggleClass('show', vis);
};
function showPage() {
$('#content').addClass('load');
}
$.ready(function() {
if (window.noAutoShow !== true) {
setTimeout(function () {
showPage();
}, 1);
}
});
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
if (!String.fromCodePoint) {
(function() {
var defineProperty = (function() {
// IE 8 only supports `Object.defineProperty` on DOM elements
try {
var object = {};
var $defineProperty = Object.defineProperty;
var result = $defineProperty(object, object, object) && $defineProperty;
} catch(error) {}
return result;
}());
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
var fromCodePoint = function() {
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};
if (defineProperty) {
defineProperty(String, 'fromCodePoint', {
'value': fromCodePoint,
'configurable': true,
'writable': true
});
} else {
String.fromCodePoint = fromCodePoint;
}
}());
}
-703
View File
@@ -1,703 +0,0 @@
/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */
// MODIFIED VERSION.
(function () {
'use strict';
var readyfn = [],
loadedfn = [],
domready = false,
pageloaded = false,
d = document,
w = window;
// Fire any function calls on ready event
function fireReady() {
var i;
domready = true;
for (i = 0; i < readyfn.length; i += 1) {
readyfn[i]();
}
readyfn = [];
}
// Fire any function calls on loaded event
function fireLoaded() {
var i;
pageloaded = true;
// For browsers with no DOM loaded support
if (!domready) {
fireReady();
}
for (i = 0; i < loadedfn.length; i += 1) {
loadedfn[i]();
}
loadedfn = [];
}
// Check DOM ready, page loaded
if (d.addEventListener) {
// Standards
d.addEventListener('DOMContentLoaded', fireReady, false);
w.addEventListener('load', fireLoaded, false);
} else if (d.attachEvent) {
// IE
d.attachEvent('onreadystatechange', fireReady);
// IE < 9
w.attachEvent('onload', fireLoaded);
} else {
// Anything else
w.onload = fireLoaded;
}
// Utility functions
// Loop through node array
function nodeLoop(fn, nodes) {
var i;
// Good idea to walk up the DOM
for (i = nodes.length - 1; i >= 0; i -= 1) {
fn(nodes[i]);
}
}
// Convert to camel case
function cssCamel(property) {
return property.replace(/-\w/g, function (result) {
return result.charAt(1).toUpperCase();
});
}
// Get computed style
function computeStyle(elm, property) {
// IE, everything else or null
return (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;
}
// Returns URI encoded query string pair
function queryPair(name, value) {
return encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');
}
// Set CSS, important to wrap in try to prevent error thown on unsupported property
function setCss(elm, property, value) {
try {
elm.style[cssCamel(property)] = value;
} catch (e) {
}
}
// Show CSS
function showCss(elm) {
elm.style.display = '';
// For elements still hidden by style block
if (computeStyle(elm, 'display') === 'none') {
elm.style.display = 'block';
}
}
// Serialize form & JSON values
function serializeData(nodes) {
var querystring = '', subelm, i, j;
if (nodes.constructor === Object) { // Serialize JSON data
for (subelm in nodes) {
if (nodes.hasOwnProperty(subelm)) {
if (nodes[subelm].constructor === Array) {
for (i = 0; i < nodes[subelm].length; i += 1) {
querystring += '&' + queryPair(subelm, nodes[subelm][i]);
}
} else {
querystring += '&' + queryPair(subelm, nodes[subelm]);
}
}
}
} else { // Serialize node data
nodeLoop(function (elm) {
if (elm.nodeName === 'FORM') {
for (i = 0; i < elm.elements.length; i += 1) {
subelm = elm.elements[i];
if (!subelm.disabled) {
switch (subelm.type) {
// Ignore buttons, unsupported XHR 1 form fields
case 'button':
case 'image':
case 'file':
case 'submit':
case 'reset':
break;
case 'select-one':
if (subelm.length > 0) {
querystring += '&' + queryPair(subelm.name, subelm.value);
}
break;
case 'select-multiple':
for (j = 0; j < subelm.length; j += 1) {
if (subelm[j].selected) {
querystring += '&' + queryPair(subelm.name, subelm[j].value);
}
}
break;
case 'checkbox':
case 'radio':
if (subelm.checked) {
querystring += '&' + queryPair(subelm.name, subelm.value);
}
break;
// Everything else including shinny new HTML5 input types
default:
querystring += '&' + queryPair(subelm.name, subelm.value);
}
}
}
}
}, nodes);
}
// Tidy up first &
return (querystring.length > 0) ? querystring.substring(1) : '';
}
// Class helper
function classHelper(classes, action, nodes) {
var classarray, search, i, replace, has = false;
if (classes) {
// Trim any whitespace
classarray = classes.split(/\s+/);
nodeLoop(function (elm) {
for (i = 0; i < classarray.length; i += 1) {
var clz = classarray[i];
if (action === 'remove') {
elm.classList.remove(clz);
}
else if (action === 'add') {
elm.classList.add(clz);
}
else if (action === 'toggle') {
elm.classList.toggle(clz);
}
else if (action === 'has') {
if (elm.classList.contains(clz)) {
has = true;
break;
}
}
// search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
// replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
// if (action === 'remove') {
// elm.className = elm.className.replace(search, '');
// } else if (action === 'toggle') {
// elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
// } else if (action === 'has') {
// if (elm.className.match(search)) {
// has = true;
// break;
// }
// }
}
}, nodes);
}
return has;
}
// HTML insertion helper
function insertHtml(value, position, nodes) {
var tmpnodes, tmpnode;
if (value) {
nodeLoop(function (elm) {
// No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead
// Convert string to node. We can't innerHTML on a document fragment
tmpnodes = d.createElement('div');
tmpnodes.innerHTML = value;
while ((tmpnode = tmpnodes.lastChild) !== null) {
// Catch error in unlikely case elm has been removed
try {
if (position === 'before') {
elm.parentNode.insertBefore(tmpnode, elm);
} else if (position === 'after') {
elm.parentNode.insertBefore(tmpnode, elm.nextSibling);
} else if (position === 'append') {
elm.appendChild(tmpnode);
} else if (position === 'prepend') {
elm.insertBefore(tmpnode, elm.firstChild);
}
} catch (e) {
break;
}
}
}, nodes);
}
}
// Get nodes and return chibi
function chibi(selector) {
var cb, nodes = [], json = false, nodelist, i;
if (selector) {
// Element node, would prefer to use (selector instanceof HTMLElement) but no IE support
if (selector.nodeType && selector.nodeType === 1) {
nodes = [selector]; // return element as node list
} else if (typeof selector === 'object') {
// JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support
json = (typeof selector.length !== 'number');
nodes = selector;
} else if (typeof selector === 'string') {
nodelist = d.querySelectorAll(selector);
// Convert node list to array so results have full access to array methods
// Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway
for (i = 0; i < nodelist.length; i += 1) {
nodes[i] = nodelist[i];
}
}
}
// Only attach nodes if not JSON
cb = json ? {} : nodes;
// Public functions
// Executes a function on nodes
cb.each = function (fn) {
if (typeof fn === 'function') {
nodeLoop(function (elm) {
// <= IE 8 loses scope so need to apply
return fn.apply(elm, arguments);
}, nodes);
}
return cb;
};
// Find first
cb.first = function () {
return chibi(nodes.shift());
};
// Find last
cb.last = function () {
return chibi(nodes.pop());
};
// Find odd
cb.odd = function () {
var odds = [], i;
for (i = 0; i < nodes.length; i += 2) {
odds.push(nodes[i]);
}
return chibi(odds);
};
// Find even
cb.even = function () {
var evens = [], i;
for (i = 1; i < nodes.length; i += 2) {
evens.push(nodes[i]);
}
return chibi(evens);
};
// Hide node
cb.hide = function () {
nodeLoop(function (elm) {
elm.style.display = 'none';
}, nodes);
return cb;
};
// Show node
cb.show = function () {
nodeLoop(function (elm) {
showCss(elm);
}, nodes);
return cb;
};
// Toggle node display
cb.toggle = function (state) {
if (typeof state != 'undefined') { // ADDED
if (state)
cb.show();
else
cb.hide();
} else {
nodeLoop(function (elm) {
// computeStyle instead of style.display == 'none' catches elements that are hidden via style block
if (computeStyle(elm, 'display') === 'none') {
showCss(elm);
} else {
elm.style.display = 'none';
}
}, nodes);
}
return cb;
};
// Remove node
cb.remove = function () {
nodeLoop(function (elm) {
// Catch error in unlikely case elm has been removed
try {
elm.parentNode.removeChild(elm);
} catch (e) {
}
}, nodes);
return chibi();
};
// Get/Set CSS
cb.css = function (property, value) {
if (property) {
if (value || value === '') {
nodeLoop(function (elm) {
setCss(elm, property, value);
}, nodes);
return cb;
}
if (nodes[0]) {
if (nodes[0].style[cssCamel(property)]) {
return nodes[0].style[cssCamel(property)];
}
if (computeStyle(nodes[0], property)) {
return computeStyle(nodes[0], property);
}
}
}
};
// Get class(es)
cb.getClass = function () {
if (nodes[0] && nodes[0].className.length > 0) {
// Weak IE trim support
return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/, ' ');
}
};
// Set (replaces) classes
cb.setClass = function (classes) {
if (classes || classes === '') {
nodeLoop(function (elm) {
elm.className = classes;
}, nodes);
}
return cb;
};
// Add class
cb.addClass = function (classes) {
classHelper(classes, 'add', nodes);
// if (classes) {
// nodeLoop(function (elm) {
// elm.className += ' ' + classes;
// }, nodes);
// }
return cb;
};
// Remove class
cb.removeClass = function (classes) {
classHelper(classes, 'remove', nodes);
return cb;
};
// Toggle class
cb.toggleClass = function (classes, set) {
var method = ((typeof set === 'undefined') ? 'toggle' : (+set ? 'add' : 'remove'));
classHelper(classes, method, nodes);
return cb;
};
// Has class
cb.hasClass = function (classes) {
return classHelper(classes, 'has', nodes);
};
// Get/set HTML
cb.html = function (value) {
if (value || value === '') {
nodeLoop(function (elm) {
elm.innerHTML = value;
}, nodes);
return cb;
}
if (nodes[0]) {
return nodes[0].innerHTML;
}
};
// Insert HTML before selector
cb.htmlBefore = function (value) {
insertHtml(value, 'before', nodes);
return cb;
};
// Insert HTML after selector
cb.htmlAfter = function (value) {
insertHtml(value, 'after', nodes);
return cb;
};
// Insert HTML after selector innerHTML
cb.htmlAppend = function (value) {
insertHtml(value, 'append', nodes);
return cb;
};
// Insert HTML before selector innerHTML
cb.htmlPrepend = function (value) {
insertHtml(value, 'prepend', nodes);
return cb;
};
// Get/Set HTML attributes
cb.attr = function (property, value) {
if (property) {
property = property.toLowerCase();
// IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway
if (typeof value !== 'undefined') {//FIXED BUG HERE
nodeLoop(function (elm) {
if (property === 'style') {
elm.style.cssText = value;
} else if (property === 'class') {
elm.className = value;
} else {
elm.setAttribute(property, value);
}
}, nodes);
return cb;
}
if (nodes[0]) {
if (property === 'style') {
if (nodes[0].style.cssText) {
return nodes[0].style.cssText;
}
} else if (property === 'class') {
if (nodes[0].className) {
return nodes[0].className;
}
} else {
if (nodes[0].getAttribute(property)) {
return nodes[0].getAttribute(property);
}
}
}
}
};
// Get/Set HTML data property
cb.data = function (key, value) {
if (key) {
return cb.attr('data-' + key, value);
}
};
// Get/Set form element values
cb.val = function (value) {
var values, i, j;
if (typeof value != 'undefined') { // FIXED A BUG HERE
nodeLoop(function (elm) {
switch (elm.nodeName) {
case 'SELECT':
if (typeof value === 'string' || typeof value === 'number') {
value = [value];
}
for (i = 0; i < elm.length; i += 1) {
// Multiple select
for (j = 0; j < value.length; j += 1) {
elm[i].selected = '';
if (elm[i].value === ""+value[j]) {
elm[i].selected = 'selected';
break;
}
}
}
break;
case 'INPUT':
case 'TEXTAREA':
case 'BUTTON':
elm.value = value;
break;
}
}, nodes);
return cb;
}
if (nodes[0]) {
switch (nodes[0].nodeName) {
case 'SELECT':
values = [];
for (i = 0; i < nodes[0].length; i += 1) {
if (nodes[0][i].selected) {
values.push(nodes[0][i].value);
}
}
return (values.length > 1) ? values : values[0];
case 'INPUT':
case 'TEXTAREA':
case 'BUTTON':
return nodes[0].value;
}
}
};
// Return matching checked checkbox or radios
cb.checked = function (check) {
if (typeof check === 'boolean') {
nodeLoop(function (elm) {
if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {
elm.checked = check;
}
}, nodes);
return cb;
}
if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {
return (!!nodes[0].checked);
}
};
// Add event handler
cb.on = function (event, fn) {
if (selector === w || selector === d) {
nodes = [selector];
}
nodeLoop(function (elm) {
if (d.addEventListener) {
elm.addEventListener(event, fn, false);
} else if (d.attachEvent) {
// <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)
elm[event + fn] = function () {
return fn.apply(elm, arguments);
};
elm.attachEvent('on' + event, elm[event + fn]);
}
}, nodes);
return cb;
};
// Remove event handler
cb.off = function (event, fn) {
if (selector === w || selector === d) {
nodes = [selector];
}
nodeLoop(function (elm) {
if (d.addEventListener) {
elm.removeEventListener(event, fn, false);
} else if (d.attachEvent) {
elm.detachEvent('on' + event, elm[event + fn]);
// Tidy up
elm[event + fn] = null;
}
}, nodes);
return cb;
};
return cb;
}
// Basic XHR
chibi.ajax = function (options) { // if options is a number, it's timeout in ms
var opts = extend({
method: 'GET',
nocache: true,
timeout: 5000,
loader: true,
callback: null
}, options);
opts.method = opts.method.toUpperCase();
var loaderFn = opts.loader ? chibi._loader : function(){};
var url = opts.url;
var method = opts.method;
var query = null;
if (opts.data) {
query = serializeData(opts.data);
}
if (query && (method === 'GET')) {
url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
query = null;
}
var xhr = new XMLHttpRequest();
// prevent caching
if (opts.nocache) {
var ts = (+(new Date())).toString(36);
url += ((url.indexOf('?') === -1) ? '?' : '&') + '_=' + ts;
}
loaderFn(true);
xhr.open(method, url, true);
xhr.timeout = opts.timeout;
// Abort after given timeout
var abortTmeo = setTimeout(function () {
console.error("XHR timed out.");
xhr.abort();
loaderFn(false);
}, opts.timeout + 10);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
loaderFn(false);
opts.callback && opts.callback(xhr.responseText, xhr.status);
clearTimeout(abortTmeo);
}
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhr.send(query);
return xhr;
};
chibi._loader = function(){};
// Alias to cb.ajax(url, 'get', callback)
chibi.get = function (url, callback, opts) {
opts = opts || {};
opts.url = url;
opts.callback = callback;
opts.method = 'GET';
return chibi.ajax(opts);
};
// Alias to cb.ajax(url, 'post', callback)
chibi.post = function (url, callback, opts) {
opts = opts || {};
opts.url = url;
opts.callback = callback;
opts.method = 'POST';
return chibi.ajax(opts);
};
// Fire on DOM ready
chibi.ready = function (fn) {
if (fn) {
if (domready) {
fn();
return chibi;
} else {
readyfn.push(fn);
}
}
};
// Fire on page loaded
chibi.loaded = function (fn) {
if (fn) {
if (pageloaded) {
fn();
return chibi;
} else {
loadedfn.push(fn);
}
}
};
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
chibi.htmlEscape = function(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
};
// Set Chibi's global namespace here ($)
w.$ = chibi;
}());
-310
View File
@@ -1,310 +0,0 @@
// keymaster.js
// (c) 2011-2013 Thomas Fuchs
// keymaster.js may be freely distributed under the MIT license.
;(function(global){
var k,
_handlers = {},
_mods = { 16: false, 18: false, 17: false, 91: false },
_scope = 'all',
// modifier keys
_MODIFIERS = {
'⇧': 16, shift: 16,
'⌥': 18, alt: 18, option: 18,
'⌃': 17, ctrl: 17, control: 17,
'⌘': 91, command: 91
},
// special keys
_MAP = {
backspace: 8, tab: 9, clear: 12,
enter: 13, 'return': 13,
esc: 27, escape: 27, space: 32,
left: 37, up: 38,
right: 39, down: 40,
del: 46, 'delete': 46,
home: 36, end: 35,
pageup: 33, pagedown: 34,
',': 188, '.': 190, '/': 191,
'`': 192, '-': 189, '=': 187,
';': 186, '\'': 222,
'[': 219, ']': 221, '\\': 220,
// added:
insert: 45,
np_0: 96, np_1: 97, np_2: 98, np_3: 99, np_4: 100, np_5: 101,
np_6: 102, np_7: 103, np_8: 104, np_9: 105, np_mul: 106,
np_add: 107, np_sub: 109, np_point: 110, np_div: 111, numlock: 144,
},
code = function(x){
return _MAP[x] || x.toUpperCase().charCodeAt(0);
},
_downKeys = [];
for(k=1;k<20;k++) _MAP['f'+k] = 111+k;
// IE doesn't support Array#indexOf, so have a simple replacement
function index(array, item){
var i = array.length;
while(i--) if(array[i]===item) return i;
return -1;
}
// for comparing mods before unassignment
function compareArray(a1, a2) {
if (a1.length != a2.length) return false;
for (var i = 0; i < a1.length; i++) {
if (a1[i] !== a2[i]) return false;
}
return true;
}
var modifierMap = {
16:'shiftKey',
18:'altKey',
17:'ctrlKey',
91:'metaKey'
};
function updateModifierKey(event) {
for(k in _mods) _mods[k] = event[modifierMap[k]];
};
function isModifierPressed(mod) {
if (mod=='control'||mod=='ctrl') return _mods[17];
if (mod=='shift') return _mods[16];
if (mod=='meta') return _mods[91];
if (mod=='alt') return _mods[18];
return false;
}
// handle keydown event
function dispatch(event) {
var key, handler, k, i, modifiersMatch, scope;
key = event.keyCode;
if (index(_downKeys, key) == -1) {
_downKeys.push(key);
}
// if a modifier key, set the key.<modifierkeyname> property to true and return
if(key == 93 || key == 224) key = 91; // right command on webkit, command on Gecko
if(key in _mods) {
_mods[key] = true;
// 'assignKey' from inside this closure is exported to window.key
for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = true;
return;
}
updateModifierKey(event);
// see if we need to ignore the keypress (filter() can can be overridden)
// by default ignore key presses if a select, textarea, or input is focused
if(!assignKey.filter.call(this, event)) return;
// abort if no potentially matching shortcuts found
if (!(key in _handlers)) return;
scope = getScope();
// for each potential shortcut
for (i = 0; i < _handlers[key].length; i++) {
handler = _handlers[key][i];
// see if it's in the current scope
if(handler.scope == scope || handler.scope == 'all'){
// check if modifiers match if any
modifiersMatch = handler.mods.length > 0;
for(k in _mods)
if((!_mods[k] && index(handler.mods, +k) > -1) ||
(_mods[k] && index(handler.mods, +k) == -1)) modifiersMatch = false;
// call the handler and stop the event if neccessary
if((handler.mods.length == 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91]) || modifiersMatch){
if(handler.method(event, handler)===false){
if(event.preventDefault) event.preventDefault();
else event.returnValue = false;
if(event.stopPropagation) event.stopPropagation();
if(event.cancelBubble) event.cancelBubble = true;
}
}
}
}
};
// unset modifier keys on keyup
function clearModifier(event){
var key = event.keyCode, k,
i = index(_downKeys, key);
// remove key from _downKeys
if (i >= 0) {
_downKeys.splice(i, 1);
}
if(key == 93 || key == 224) key = 91;
if(key in _mods) {
_mods[key] = false;
for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = false;
}
};
function resetModifiers() {
for(k in _mods) _mods[k] = false;
for(k in _MODIFIERS) assignKey[k] = false;
};
// parse and assign shortcut
function assignKey(key, scope, method){
var keys, mods;
keys = getKeys(key);
if (method === undefined) {
method = scope;
scope = 'all';
}
// for each shortcut
for (var i = 0; i < keys.length; i++) {
// set modifier keys if any
mods = [];
key = keys[i].split('+');
if (key.length > 1){
mods = getMods(key);
key = [key[key.length-1]];
}
// convert to keycode and...
key = key[0]
key = code(key);
// ...store handler
if (!(key in _handlers)) _handlers[key] = [];
_handlers[key].push({ shortcut: keys[i], scope: scope, method: method, key: keys[i], mods: mods });
}
};
// unbind all handlers for given key in current scope
function unbindKey(key, scope) {
var multipleKeys, keys,
mods = [],
i, j, obj;
multipleKeys = getKeys(key);
for (j = 0; j < multipleKeys.length; j++) {
keys = multipleKeys[j].split('+');
if (keys.length > 1) {
mods = getMods(keys);
}
key = keys[keys.length - 1];
key = code(key);
if (scope === undefined) {
scope = getScope();
}
if (!_handlers[key]) {
return;
}
for (i = 0; i < _handlers[key].length; i++) {
obj = _handlers[key][i];
// only clear handlers if correct scope and mods match
if (obj.scope === scope && compareArray(obj.mods, mods)) {
_handlers[key][i] = {};
}
}
}
};
// Returns true if the key with code 'keyCode' is currently down
// Converts strings into key codes.
function isPressed(keyCode) {
if (typeof(keyCode)=='string') {
keyCode = code(keyCode);
}
return index(_downKeys, keyCode) != -1;
}
function getPressedKeyCodes() {
return _downKeys.slice(0);
}
function filter(event){
var tagName = (event.target || event.srcElement).tagName;
// ignore keypressed in any elements that support keyboard data input
return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
}
// initialize key.<modifier> to false
for(k in _MODIFIERS) assignKey[k] = false;
// set current scope (default 'all')
function setScope(scope){ _scope = scope || 'all' };
function getScope(){ return _scope || 'all' };
// delete all handlers for a given scope
function deleteScope(scope){
var key, handlers, i;
for (key in _handlers) {
handlers = _handlers[key];
for (i = 0; i < handlers.length; ) {
if (handlers[i].scope === scope) handlers.splice(i, 1);
else i++;
}
}
};
// abstract key logic for assign and unassign
function getKeys(key) {
var keys;
key = key.replace(/\s/g, '');
keys = key.split(',');
if ((keys[keys.length - 1]) == '') {
keys[keys.length - 2] += ',';
}
return keys;
}
// abstract mods logic for assign and unassign
function getMods(key) {
var mods = key.slice(0, key.length - 1);
for (var mi = 0; mi < mods.length; mi++)
mods[mi] = _MODIFIERS[mods[mi]];
return mods;
}
// cross-browser events
function addEvent(object, event, method) {
if (object.addEventListener)
object.addEventListener(event, method, false);
else if(object.attachEvent)
object.attachEvent('on'+event, function(){ method(window.event) });
};
// set the handlers globally on document
addEvent(document, 'keydown', function(event) { dispatch(event) }); // Passing _scope to a callback to ensure it remains the same by execution. Fixes #48
addEvent(document, 'keyup', clearModifier);
// reset modifiers to false whenever the window is (re)focused.
addEvent(window, 'focus', resetModifiers);
// store previously defined key
var previousKey = global.key;
// restore previously defined key and return reference to our key object
function noConflict() {
var k = global.key;
global.key = previousKey;
return k;
}
// set window.key and window.key.set/get/deleteScope, and the default filter
global.key = assignKey;
global.key.setScope = setScope;
global.key.getScope = getScope;
global.key.deleteScope = deleteScope;
global.key.filter = filter;
global.key.isPressed = isPressed;
global.key.isModifier = isModifierPressed;
global.key.getPressedKeyCodes = getPressedKeyCodes;
global.key.noConflict = noConflict;
global.key.unbind = unbindKey;
if(typeof module !== 'undefined') module.exports = assignKey;
})(this);
-8
View File
@@ -1,8 +0,0 @@
// Generated from PHP locale file
var _tr = {
"wifi.connected_ip_is": "Connected, IP is ",
"wifi.not_conn": "Not connected.",
"wifi.enter_passwd": "Enter password for \":ssid:\""
};
function tr(key) { return _tr[key] || '?'+key+'?'; }
-44
View File
@@ -1,44 +0,0 @@
/** Module for toggling a modal overlay */
(function () {
var modal = {};
var curCloseCb = null;
modal.show = function (sel, closeCb) {
var $m = $(sel);
$m.removeClass('hidden visible');
setTimeout(function () {
$m.addClass('visible');
}, 1);
curCloseCb = closeCb;
};
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
setTimeout(function () {
$m.addClass('hidden');
if (curCloseCb) curCloseCb();
}, 500); // transition time
};
modal.init = function () {
// close modal by click outside the dialog
$('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal
modal.hide(this);
});
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
}
});
};
window.Modal = modal;
})();
-32
View File
@@ -1,32 +0,0 @@
(function (nt) {
var sel = '#notif';
var hideTmeo1; // timeout to start hiding (transition)
var hideTmeo2; // timeout to add the hidden class
nt.show = function (message, timeout) {
$(sel).html(message);
Modal.show(sel);
clearTimeout(hideTmeo1);
clearTimeout(hideTmeo2);
if (undef(timeout)) timeout = 2500;
hideTmeo1 = setTimeout(nt.hide, timeout);
};
nt.hide = function () {
var $m = $(sel);
$m.removeClass('visible');
hideTmeo2 = setTimeout(function () {
$m.addClass('hidden');
}, 250); // transition time
};
nt.init = function() {
$(sel).on('click', function() {
nt.hide(this);
});
};
})(window.Notify = {});
-6
View File
@@ -1,6 +0,0 @@
/** Init the terminal sub-module - called from HTML */
window.termInit = function () {
Conn.init();
Input.init();
TermUpl.init();
};
-131
View File
@@ -1,131 +0,0 @@
/** Handle connections */
var Conn = (function() {
var ws;
var heartbeatTout;
var pingIv;
var xoff = false;
var autoXoffTout;
function onOpen(evt) {
console.log("CONNECTED");
}
function onClose(evt) {
console.warn("SOCKET CLOSED, code "+evt.code+". Reconnecting...");
setTimeout(function() {
init();
}, 200);
// this happens when the buffer gets fucked up via invalid unicode.
// we basically use polling instead of socket then
}
function onMessage(evt) {
try {
// . = heartbeat
switch (evt.data.charAt(0)) {
case 'B':
case 'T':
case 'S':
Screen.load(evt.data);
break;
case '-':
//console.log('xoff');
xoff = true;
autoXoffTout = setTimeout(function(){xoff=false;}, 250);
break;
case '+':
//console.log('xon');
xoff = false;
clearTimeout(autoXoffTout);
break;
}
heartbeat();
} catch(e) {
console.error(e);
}
}
function canSend() {
return !xoff;
}
function doSend(message) {
if (_demo) {
console.log("TX: ", message);
return true; // Simulate success
}
if (xoff) {
// TODO queue
console.log("Can't send, flood control.");
return false;
}
if (!ws) return false; // for dry testing
if (ws.readyState != 1) {
console.error("Socket not ready");
return false;
}
if (typeof message != "string") {
message = JSON.stringify(message);
}
ws.send(message);
return true;
}
function init() {
if (_demo) {
console.log("Demo mode!");
Screen.load(_demo_screen);
showPage();
return;
}
heartbeat();
ws = new WebSocket("ws://"+_root+"/term/update.ws");
ws.onopen = onOpen;
ws.onclose = onClose;
ws.onmessage = onMessage;
console.log("Opening socket.");
// Ask for initial data
$.get('http://'+_root+'/term/init', function(resp, status) {
if (status !== 200) location.reload(true);
console.log("Data received!");
Screen.load(resp);
heartbeat();
showPage();
});
}
function heartbeat() {
clearTimeout(heartbeatTout);
heartbeatTout = setTimeout(heartbeatFail, 2000);
}
function heartbeatFail() {
console.error("Heartbeat lost, probing server...");
pingIv = setInterval(function() {
console.log("> ping");
$.get('http://'+_root+'/system/ping', function(resp, status) {
if (status == 200) {
clearInterval(pingIv);
console.info("Server ready, reloading page...");
location.reload();
}
}, {
timeout: 100,
});
}, 500);
}
return {
ws: null,
init: init,
send: doSend,
canSend: canSend, // check flood control
};
})();
-262
View File
@@ -1,262 +0,0 @@
/**
* User input
*
* --- Rx messages: ---
* S - screen content (binary encoding of the entire screen with simple compression)
* T - text labels - Title and buttons, \0x01-separated
* B - beep
* . - heartbeat
*
* --- Tx messages ---
* s - string
* b - action button
* p - mb press
* r - mb release
* m - mouse move
*/
var Input = (function() {
var opts = {
np_alt: false,
cu_alt: false,
fn_alt: false,
mt_click: false,
mt_move: false,
no_keys: false,
};
/** Send a literal message */
function sendStrMsg(str) {
return Conn.send("s"+str);
}
/** Send a button event */
function sendBtnMsg(n) {
Conn.send("b"+Chr(n));
}
/** Fn alt choice for key message */
function fa(alt, normal) {
return opts.fn_alt ? alt : normal;
}
/** Cursor alt choice for key message */
function ca(alt, normal) {
return opts.cu_alt ? alt : normal;
}
/** Numpad alt choice for key message */
function na(alt, normal) {
return opts.np_alt ? alt : normal;
}
function _bindFnKeys() {
var keymap = {
'tab': '\x09',
'backspace': '\x08',
'enter': '\x0d',
'ctrl+enter': '\x0a',
'esc': '\x1b',
'up': ca('\x1bOA', '\x1b[A'),
'down': ca('\x1bOB', '\x1b[B'),
'right': ca('\x1bOC', '\x1b[C'),
'left': ca('\x1bOD', '\x1b[D'),
'home': ca('\x1bOH', fa('\x1b[H', '\x1b[1~')),
'insert': '\x1b[2~',
'delete': '\x1b[3~',
'end': ca('\x1bOF', fa('\x1b[F', '\x1b[4~')),
'pageup': '\x1b[5~',
'pagedown': '\x1b[6~',
'f1': fa('\x1bOP', '\x1b[11~'),
'f2': fa('\x1bOQ', '\x1b[12~'),
'f3': fa('\x1bOR', '\x1b[13~'),
'f4': fa('\x1bOS', '\x1b[14~'),
'f5': '\x1b[15~', // note the disconnect
'f6': '\x1b[17~',
'f7': '\x1b[18~',
'f8': '\x1b[19~',
'f9': '\x1b[20~',
'f10': '\x1b[21~', // note the disconnect
'f11': '\x1b[23~',
'f12': '\x1b[24~',
'shift+f1': fa('\x1bO1;2P', '\x1b[25~'),
'shift+f2': fa('\x1bO1;2Q', '\x1b[26~'), // note the disconnect
'shift+f3': fa('\x1bO1;2R', '\x1b[28~'),
'shift+f4': fa('\x1bO1;2S', '\x1b[29~'), // note the disconnect
'shift+f5': fa('\x1b[15;2~', '\x1b[31~'),
'shift+f6': fa('\x1b[17;2~', '\x1b[32~'),
'shift+f7': fa('\x1b[18;2~', '\x1b[33~'),
'shift+f8': fa('\x1b[19;2~', '\x1b[34~'),
'shift+f9': fa('\x1b[20;2~', '\x1b[35~'), // 35-38 are not standard - but what is?
'shift+f10': fa('\x1b[21;2~', '\x1b[36~'),
'shift+f11': fa('\x1b[22;2~', '\x1b[37~'),
'shift+f12': fa('\x1b[23;2~', '\x1b[38~'),
'np_0': na('\x1bOp', '0'),
'np_1': na('\x1bOq', '1'),
'np_2': na('\x1bOr', '2'),
'np_3': na('\x1bOs', '3'),
'np_4': na('\x1bOt', '4'),
'np_5': na('\x1bOu', '5'),
'np_6': na('\x1bOv', '6'),
'np_7': na('\x1bOw', '7'),
'np_8': na('\x1bOx', '8'),
'np_9': na('\x1bOy', '9'),
'np_mul': na('\x1bOR', '*'),
'np_add': na('\x1bOl', '+'),
'np_sub': na('\x1bOS', '-'),
'np_point': na('\x1bOn', '.'),
'np_div': na('\x1bOQ', '/'),
// we don't implement numlock key (should change in numpad_alt mode, but it's even more useless than the rest)
};
for (var k in keymap) {
if (keymap.hasOwnProperty(k)) {
bind(k, keymap[k]);
}
}
}
/** Bind a keystroke to message */
function bind(combo, str) {
// mac fix - allow also cmd
if (combo.indexOf('ctrl+') !== -1) {
combo += ',' + combo.replace('ctrl', 'command');
}
// unbind possible old binding
key.unbind(combo);
key(combo, function (e) {
if (opts.no_keys) return;
e.preventDefault();
sendStrMsg(str)
});
}
/** Bind/rebind key messages */
function _initKeys() {
// This takes care of text characters typed
window.addEventListener('keypress', function(evt) {
if (opts.no_keys) return;
var str = '';
if (evt.key) str = evt.key;
else if (evt.which) str = String.fromCodePoint(evt.which);
if (str.length>0 && str.charCodeAt(0) >= 32) {
// console.log("Typed ", str);
sendStrMsg(str);
}
});
// ctrl-letter codes are sent as simple low ASCII codes
for (var i = 1; i<=26;i++) {
bind('ctrl+' + String.fromCharCode(96+i), String.fromCharCode(i));
}
bind('ctrl+]', '\x1b'); // alternate way to enter ESC
bind('ctrl+\\', '\x1c');
bind('ctrl+[', '\x1d');
bind('ctrl+^', '\x1e');
bind('ctrl+_', '\x1f');
_bindFnKeys();
}
// mouse button states
var mb1 = 0;
var mb2 = 0;
var mb3 = 0;
/** Init the Input module */
function init() {
_initKeys();
// Button presses
$('#action-buttons button').forEach(function(s) {
s.addEventListener('click', function() {
sendBtnMsg(+this.dataset['n']);
});
});
// global mouse state tracking - for motion reporting
window.addEventListener('mousedown', function(evt) {
if (evt.button == 0) mb1 = 1;
if (evt.button == 1) mb2 = 1;
if (evt.button == 2) mb3 = 1;
});
window.addEventListener('mouseup', function(evt) {
if (evt.button == 0) mb1 = 0;
if (evt.button == 1) mb2 = 0;
if (evt.button == 2) mb3 = 0;
});
}
/** Prepare modifiers byte for mouse message */
function packModifiersForMouse() {
return (key.isModifier('ctrl')?1:0) |
(key.isModifier('shift')?2:0) |
(key.isModifier('alt')?4:0) |
(key.isModifier('meta')?8:0);
}
return {
/** Init the Input module */
init: init,
/** Send a literal string message */
sendString: sendStrMsg,
/** Enable alternate key modes (cursors, numpad, fn) */
setAlts: function(cu, np, fn) {
if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn) {
opts.cu_alt = cu;
opts.np_alt = np;
opts.fn_alt = fn;
// rebind keys - codes have changed
_bindFnKeys();
}
},
setMouseMode: function(click, move) {
opts.mt_click = click;
opts.mt_move = move;
},
// Mouse events
onMouseMove: function (x, y) {
if (!opts.mt_move) return;
var b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0;
var m = packModifiersForMouse();
Conn.send("m" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
},
onMouseDown: function (x, y, b) {
if (!opts.mt_click) return;
if (b > 3 || b < 1) return;
var m = packModifiersForMouse();
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
onMouseUp: function (x, y, b) {
if (!opts.mt_click) return;
if (b > 3 || b < 1) return;
var m = packModifiersForMouse();
Conn.send("r" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
onMouseWheel: function (x, y, dir) {
if (!opts.mt_click) return;
// -1 ... btn 4 (away from user)
// +1 ... btn 5 (towards user)
var m = packModifiersForMouse();
var b = (dir < 0 ? 4 : 5);
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
mouseTracksClicks: function() {
return opts.mt_click;
},
blockKeys: function(yes) {
opts.no_keys = yes;
}
};
})();
-378
View File
@@ -1,378 +0,0 @@
var Screen = (function () {
var W = 0, H = 0; // dimensions
var inited = false;
var cursor = {
a: false, // active (blink state)
x: 0, // 0-based coordinates
y: 0,
fg: 7, // colors 0-15
bg: 0,
attrs: 0,
suppress: false, // do not turn on in blink interval (for safe moving)
forceOn: false, // force on unless hanging: used to keep cursor visible during move
hidden: false, // do not show (DEC opt)
hanging: false, // cursor at column "W+1" - not visible
};
var screen = [];
var blinkIval;
var cursorFlashStartIval;
// Some non-bold Fraktur symbols are outside the contiguous block
var frakturExceptions = {
'C': '\u212d',
'H': '\u210c',
'I': '\u2111',
'R': '\u211c',
'Z': '\u2128',
};
// for BEL
var audioCtx = null;
try {
audioCtx = new (window.AudioContext || window.audioContext || window.webkitAudioContext)();
} catch (er) {
console.error("No AudioContext!", er);
}
/** Get cell under cursor */
function _curCell() {
return screen[cursor.y*W + cursor.x];
}
/** Safely move cursor */
function cursorSet(y, x) {
// Hide and prevent from showing up during the move
cursor.suppress = true;
_draw(_curCell(), false);
cursor.x = x;
cursor.y = y;
// Show again
cursor.suppress = false;
_draw(_curCell());
}
function alpha2fraktur(t) {
// perform substitution
if (t >= 'a' && t <= 'z') {
t = String.fromCodePoint(0x1d51e - 97 + t.charCodeAt(0));
}
else if (t >= 'A' && t <= 'Z') {
// this set is incomplete, some exceptions are needed
if (frakturExceptions.hasOwnProperty(t)) {
t = frakturExceptions[t];
} else {
t = String.fromCodePoint(0x1d504 - 65 + t.charCodeAt(0));
}
}
return t;
}
/** Update cell on display. inv = invert (for cursor) */
function _draw(cell, inv) {
if (!cell) return;
if (typeof inv == 'undefined') {
inv = cursor.a && cursor.x == cell.x && cursor.y == cell.y;
}
var fg, bg, cn, t;
fg = inv ? cell.bg : cell.fg;
bg = inv ? cell.fg : cell.bg;
t = cell.t;
if (!t.length) t = ' ';
cn = 'fg' + fg + ' bg' + bg;
if (cell.attrs & (1<<0)) cn += ' bold';
if (cell.attrs & (1<<1)) cn += ' faint';
if (cell.attrs & (1<<2)) cn += ' italic';
if (cell.attrs & (1<<3)) cn += ' under';
if (cell.attrs & (1<<4)) cn += ' blink';
if (cell.attrs & (1<<5)) {
cn += ' fraktur';
t = alpha2fraktur(t);
}
if (cell.attrs & (1<<6)) cn += ' strike';
cell.slot.textContent = t;
cell.elem.className = cn;
}
/** Show entire screen */
function _drawAll() {
for (var i = W*H-1; i>=0; i--) {
_draw(screen[i]);
}
}
function _rebuild(rows, cols) {
W = cols;
H = rows;
/* Build screen & show */
var cOuter, cInner, cell, screenDiv = qs('#screen');
// Empty the screen node
while (screenDiv.firstChild) screenDiv.removeChild(screenDiv.firstChild);
screen = [];
for(var i = 0; i < W*H; i++) {
cOuter = mk('span');
cInner = mk('span');
/* Mouse tracking */
(function() {
var x = i % W;
var y = Math.floor(i / W);
cOuter.addEventListener('mouseenter', function (evt) {
Input.onMouseMove(x, y);
});
cOuter.addEventListener('mousedown', function (evt) {
Input.onMouseDown(x, y, evt.button+1);
});
cOuter.addEventListener('mouseup', function (evt) {
Input.onMouseUp(x, y, evt.button+1);
});
cOuter.addEventListener('contextmenu', function (evt) {
if (Input.mouseTracksClicks()) {
evt.preventDefault();
}
});
cOuter.addEventListener('mousewheel', function (evt) {
Input.onMouseWheel(x, y, evt.deltaY>0?1:-1);
return false;
});
})();
/* End of line */
if ((i > 0) && (i % W == 0)) {
screenDiv.appendChild(mk('br'));
}
/* The cell */
cOuter.appendChild(cInner);
screenDiv.appendChild(cOuter);
cell = {
t: ' ',
fg: 7,
bg: 0, // the colors will be replaced immediately as we receive data (user won't see this)
attrs: 0,
elem: cOuter,
slot: cInner,
x: i % W,
y: Math.floor(i / W),
};
screen.push(cell);
_draw(cell);
}
}
/** Init the terminal */
function _init() {
/* Cursor blinking */
clearInterval(blinkIval);
blinkIval = setInterval(function () {
cursor.a = !cursor.a;
if (cursor.hidden || cursor.hanging) {
cursor.a = false;
}
if (!cursor.suppress) {
_draw(_curCell(), cursor.forceOn || cursor.a);
}
}, 500);
/* blink attribute animation */
setInterval(function () {
$('#screen').removeClass('blink-hide');
setTimeout(function () {
$('#screen').addClass('blink-hide');
}, 800); // 200 ms ON
}, 1000);
inited = true;
}
// constants for decoding the update blob
var SEQ_SET_COLOR_ATTR = 1;
var SEQ_REPEAT = 2;
var SEQ_SET_COLOR = 3;
var SEQ_SET_ATTR = 4;
/** Parse received screen update object (leading S removed already) */
function _load_content(str) {
var i = 0, ci = 0, j, jc, num, num2, t = ' ', fg, bg, attrs, cell;
if (!inited) _init();
var cursorMoved;
// Set size
num = parse2B(str, i); i += 2; // height
num2 = parse2B(str, i); i += 2; // width
if (num != H || num2 != W) {
_rebuild(num, num2);
}
// console.log("Size ",num, num2);
// Cursor position
num = parse2B(str, i); i += 2; // row
num2 = parse2B(str, i); i += 2; // col
cursorMoved = (cursor.x != num2 || cursor.y != num);
cursorSet(num, num2);
// console.log("Cursor at ",num, num2);
// Attributes
num = parse2B(str, i); i += 2; // fg bg attribs
cursor.hidden = !(num & (1<<0)); // DEC opt "visible"
cursor.hanging = !!(num & (1<<1));
// console.log("Attributes word ",num.toString(16)+'h');
Input.setAlts(
!!(num & (1<<2)), // cursors alt
!!(num & (1<<3)), // numpad alt
!!(num & (1<<4)) // fn keys alt
);
var mt_click = !!(num & (1<<5));
var mt_move = !!(num & (1<<6));
Input.setMouseMode(
mt_click,
mt_move
);
$('#screen').toggleClass('noselect', mt_move);
var show_buttons = !!(num & (1<<7));
var show_config_links = !!(num & (1<<8));
$('.x-term-conf-btn').toggleClass('hidden', !show_config_links);
$('#action-buttons').toggleClass('hidden', !show_buttons);
fg = 7;
bg = 0;
attrs = 0;
// Here come the content
while(i < str.length && ci<W*H) {
j = str[i++];
jc = j.charCodeAt(0);
if (jc == SEQ_SET_COLOR_ATTR) {
num = parse3B(str, i); i += 3;
fg = num & 0x0F;
bg = (num & 0xF0) >> 4;
attrs = (num & 0xFF00)>>8;
}
else if (jc == SEQ_SET_COLOR) {
num = parse2B(str, i); i += 2;
fg = num & 0x0F;
bg = (num & 0xF0) >> 4;
}
else if (jc == SEQ_SET_ATTR) {
num = parse2B(str, i); i += 2;
attrs = num & 0xFF;
}
else if (jc == SEQ_REPEAT) {
num = parse2B(str, i); i += 2;
// console.log("Repeat x ",num);
for (; num>0 && ci<W*H; num--) {
cell = screen[ci++];
cell.fg = fg;
cell.bg = bg;
cell.t = t;
cell.attrs = attrs;
}
}
else {
cell = screen[ci++];
// Unique cell character
t = cell.t = j;
cell.fg = fg;
cell.bg = bg;
cell.attrs = attrs;
// console.log("Symbol ", j);
}
}
_drawAll();
// if (!cursor.hidden || cursor.hanging || !cursor.suppress) {
// // hide cursor asap
// _draw(_curCell(), false);
// }
if (cursorMoved) {
cursor.forceOn = true;
cursorFlashStartIval = setTimeout(function() {
cursor.forceOn = false;
}, 1200);
_draw(_curCell(), true);
}
}
/** Apply labels to buttons and screen title (leading T removed already) */
function _load_labels(str) {
var pieces = str.split('\x01');
qs('h1').textContent = pieces[0];
$('#action-buttons button').forEach(function(x, i) {
var s = pieces[i+1].trim();
// if empty string, use the "dim" effect and put nbsp instead to stretch the btn vertically
x.innerHTML = s.length > 0 ? e(s) : "&nbsp;";
x.style.opacity = s.length > 0 ? 1 : 0.2;
})
}
/** Audible beep for ASCII 7 */
function _beep() {
var osc, gain;
if (!audioCtx) return;
// Main beep
osc = audioCtx.createOscillator();
gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
gain.gain.value = 0.5;
osc.frequency.value = 750;
osc.type = 'sine';
osc.start();
osc.stop(audioCtx.currentTime+0.05);
// Surrogate beep (making it sound like 'oops')
osc = audioCtx.createOscillator();
gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
gain.gain.value = 0.2;
osc.frequency.value = 400;
osc.type = 'sine';
osc.start(audioCtx.currentTime+0.05);
osc.stop(audioCtx.currentTime+0.08);
}
/** Load screen content from a binary sequence (new) */
function load(str) {
//console.log(JSON.stringify(str));
var content = str.substr(1);
switch(str.charAt(0)) {
case 'S':
_load_content(content);
break;
case 'T':
_load_labels(content);
break;
case 'B':
_beep();
break;
default:
console.warn("Bad data message type, ignoring.");
console.log(str);
}
}
return {
load: load, // full load (string)
};
})();
-146
View File
@@ -1,146 +0,0 @@
/** File upload utility */
var TermUpl = (function() {
var lines, // array of lines without newlines
line_i, // current line index
fuTout, // timeout handle for line sending
send_delay_ms, // delay between lines (ms)
nl_str, // newline string to use
curLine, // current line (when using fuOil)
inline_pos; // Offset in line (for long lines)
// lines longer than this are split to chunks
// sending a super-ling string through the socket is not a good idea
var MAX_LINE_LEN = 128;
function fuOpen() {
fuStatus("Ready...");
Modal.show('#fu_modal', onClose);
$('#fu_form').toggleClass('busy', false);
Input.blockKeys(true);
}
function onClose() {
console.log("Upload modal closed.");
clearTimeout(fuTout);
line_i = 0;
Input.blockKeys(false);
}
function fuStatus(msg) {
qs('#fu_prog').textContent = msg;
}
function fuSend() {
var v = qs('#fu_text').value;
if (!v.length) {
fuClose();
return;
}
lines = v.split('\n');
line_i = 0;
inline_pos = 0; // offset in line
send_delay_ms = qs('#fu_delay').value;
// sanitize - 0 causes overflows
if (send_delay_ms < 0) {
send_delay_ms = 0;
qs('#fu_delay').value = send_delay_ms;
}
nl_str = {
'CR': '\r',
'LF': '\n',
'CRLF': '\r\n',
}[qs('#fu_crlf').value];
$('#fu_form').toggleClass('busy', true);
fuStatus("Starting...");
fuSendLine();
}
function fuSendLine() {
if (!$('#fu_modal').hasClass('visible')) {
// Modal is closed, cancel
return;
}
if (!Conn.canSend()) {
// postpone
fuTout = setTimeout(fuSendLine, 1);
return;
}
if (inline_pos == 0) {
curLine = lines[line_i++] + nl_str;
}
var chunk;
if ((curLine.length - inline_pos) <= MAX_LINE_LEN) {
chunk = curLine.substr(inline_pos, MAX_LINE_LEN);
inline_pos = 0;
} else {
chunk = curLine.substr(inline_pos, MAX_LINE_LEN);
inline_pos += MAX_LINE_LEN;
}
if (!Input.sendString(chunk)) {
fuStatus("FAILED!");
return;
}
var all = lines.length;
fuStatus(line_i+" / "+all+ " ("+(Math.round((line_i/all)*1000)/10)+"%)");
if (lines.length > line_i || inline_pos > 0) {
fuTout = setTimeout(fuSendLine, send_delay_ms);
} else {
closeWhenReady();
}
}
function closeWhenReady() {
if (!Conn.canSend()) {
// stuck in XOFF still, wait to process...
fuStatus("Waiting for Tx buffer...");
setTimeout(closeWhenReady, 100);
} else {
fuStatus("Done.");
// delay to show it
setTimeout(function() {
fuClose();
}, 100);
}
}
function fuClose() {
Modal.hide('#fu_modal');
}
return {
init: function() {
qs('#fu_file').addEventListener('change', function (evt) {
var reader = new FileReader();
var file = evt.target.files[0];
console.log("Selected file type: "+file.type);
if (!file.type.match(/text\/.*|application\/(json|csv|.*xml.*|.*script.*)/)) {
// Deny load of blobs like img - can crash browser and will get corrupted anyway
if (!confirm("This does not look like a text file: "+file.type+"\nReally load?")) {
qs('#fu_file').value = '';
return;
}
}
reader.onload = function(e) {
var txt = e.target.result.replace(/[\r\n]+/,'\n');
qs('#fu_text').value = txt;
};
console.log("Loading file...");
reader.readAsText(file);
}, false);
},
close: fuClose,
start: fuSend,
open: fuOpen,
}
})();
-161
View File
@@ -1,161 +0,0 @@
/** Make a node */
function mk(e) {return document.createElement(e)}
/** Find one by query */
function qs(s) {return document.querySelector(s)}
/** Find all by query */
function qsa(s) {return document.querySelectorAll(s)}
/** Convert any to bool safely */
function bool(x) {
return (x === 1 || x === '1' || x === true || x === 'true');
}
/**
* Filter 'spacebar' and 'return' from keypress handler,
* and when they're pressed, fire the callback.
* use $(...).on('keypress', cr(handler))
*/
function cr(hdl) {
return function(e) {
if (e.which == 10 || e.which == 13 || e.which == 32) {
hdl();
}
};
}
/** Extend an objects with options */
function extend(defaults, options) {
var target = {};
Object.keys(defaults).forEach(function(k){
target[k] = defaults[k];
});
Object.keys(options).forEach(function(k){
target[k] = options[k];
});
return target;
}
/** Escape string for use as literal in RegExp */
function rgxe(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
/** Format number to N decimal places, output as string */
function numfmt(x, places) {
var pow = Math.pow(10, places);
return Math.round(x*pow) / pow;
}
/** Get millisecond timestamp */
function msNow() {
return +(new Date);
}
/** Get ms elapsed since msNow() */
function msElapsed(start) {
return msNow() - start;
}
/** Shim for log base 10 */
Math.log10 = Math.log10 || function(x) {
return Math.log(x) / Math.LN10;
};
/**
* Perform a substitution in the given string.
*
* Arguments - array or list of replacements.
* Arguments numeric keys will replace {0}, {1} etc.
* Named keys also work, ie. {foo: "bar"} -> replaces {foo} with bar.
*
* Braces are added to keys if missing.
*
* @returns {String} result
*/
String.prototype.format = function () {
var out = this;
var repl = arguments;
if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) {
repl = arguments[0];
}
for (var ph in repl) {
if (repl.hasOwnProperty(ph)) {
var ph_orig = ph;
if (!ph.match(/^\{.*\}$/)) {
ph = '{' + ph + '}';
}
// replace all occurrences
var pattern = new RegExp(rgxe(ph), "g");
out = out.replace(pattern, repl[ph_orig]);
}
}
return out;
};
/** HTML escape */
function e(str) {
return $.htmlEscape(str);
}
/** Check for undefined */
function undef(x) {
return typeof x == 'undefined';
}
/** Safe json parse */
function jsp(str) {
try {
return JSON.parse(str);
} catch(e) {
console.error(e);
return null;
}
}
/** Create a character from ASCII code */
function Chr(n) {
return String.fromCharCode(n);
}
/** Decode number from 2B encoding */
function parse2B(s, i) {
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127;
}
/** Decode number from 3B encoding */
function parse3B(s, i) {
return (s.charCodeAt(i) - 1) + (s.charCodeAt(i+1) - 1) * 127 + (s.charCodeAt(i+2) - 1) * 127 * 127;
}
/** Encode using 2B encoding, returns string. */
function encode2B(n) {
var lsb, msb;
lsb = (n % 127);
n = ((n - lsb) / 127);
lsb += 1;
msb = (n + 1);
return Chr(lsb) + Chr(msb);
}
/** Encode using 3B encoding, returns string. */
function encode3B(n) {
var lsb, msb, xsb;
lsb = (n % 127);
n = (n - lsb) / 127;
lsb += 1;
msb = (n % 127);
n = (n - msb) / 127;
msb += 1;
xsb = (n + 1);
return Chr(lsb) + Chr(msb) + Chr(xsb);
}
-163
View File
@@ -1,163 +0,0 @@
(function(w) {
var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2'];
var curSSID;
// Get XX % for a slider input
function rangePt(inp) {
return Math.round(((inp.value / inp.max)*100)) + '%';
}
// Display selected STA SSID etc
function selectSta(name, password, ip) {
$('#sta_ssid').val(name);
$('#sta_password').val(password);
$('#sta-nw').toggleClass('hidden', name.length == 0);
$('#sta-nw-nil').toggleClass('hidden', name.length > 0);
$('#sta-nw .essid').html(e(name));
var nopw = undef(password) || password.length == 0;
$('#sta-nw .passwd').toggleClass('hidden', nopw);
$('#sta-nw .nopasswd').toggleClass('hidden', !nopw);
$('#sta-nw .ip').html(ip.length>0 ? tr('wifi.connected_ip_is')+ip : tr('wifi.not_conn'));
}
/** Update display for received response */
function onScan(resp, status) {
//var ap_json = {
// "result": {
// "inProgress": "0",
// "APs": [
// {"essid": "Chlivek", "bssid": "88:f7:c7:52:b3:99", "rssi": "204", "enc": "4", "channel": "1"},
// {"essid": "TyNikdy", "bssid": "5c:f4:ab:0d:f1:1b", "rssi": "164", "enc": "3", "channel": "1"},
// ]
// }
//};
if (status != 200) {
// bad response
rescan(5000); // wait 5sm then retry
return;
}
try {
resp = JSON.parse(resp);
} catch (e) {
console.log(e);
rescan(5000);
return;
}
var done = !bool(resp.result.inProgress) && (resp.result.APs.length > 0);
rescan(done ? 15000 : 1000);
if (!done) return; // no redraw yet
// clear the AP list
var $list = $('#ap-list');
// remove old APs
$('#ap-list .AP').remove();
$list.toggleClass('hidden', !done);
$('#ap-loader').toggleClass('hidden', done);
// scan done
resp.result.APs.sort(function (a, b) {
return b.rssi - a.rssi;
}).forEach(function (ap) {
ap.enc = parseInt(ap.enc);
if (ap.enc > 4) return; // hide unsupported auths
var item = mk('div');
var $item = $(item)
.data('ssid', ap.essid)
.data('pwd', ap.enc)
.attr('tabindex', 0)
.addClass('AP');
// mark current SSID
if (ap.essid == curSSID) {
$item.addClass('selected');
}
var inner = mk('div');
$(inner).addClass('inner')
.htmlAppend('<div class="rssi">{0}</div>'.format(ap.rssi_perc))
.htmlAppend('<div class="essid" title="{0}">{0}</div>'.format($.htmlEscape(ap.essid)))
.htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc]));
$item.on('click', function () {
var $th = $(this);
var conn_ssid = $th.data('ssid');
var conn_pass = '';
if (+$th.data('pwd')) {
// this AP needs a password
conn_pass = prompt(tr("wifi.enter_passwd").replace(":ssid:", conn_ssid));
if (!conn_pass) return;
}
$('#sta_password').val(conn_pass);
$('#sta_ssid').val(conn_ssid);
selectSta(conn_ssid, conn_pass, '');
});
item.appendChild(inner);
$list[0].appendChild(item);
});
}
function startScanning() {
$('#ap-loader').removeClass('hidden');
$('#ap-scan').addClass('hidden');
$('#ap-loader .anim-dots').html('.');
scanAPs();
}
/** Ask the CGI what APs are visible (async) */
function scanAPs() {
if (_demo) {
onScan(_demo_aps, 200);
} else {
$.get('http://' + _root + '/cfg/wifi/scan', onScan);
}
}
function rescan(time) {
setTimeout(scanAPs, time);
}
/** Set up the WiFi page */
function wifiInit(cfg) {
// Update slider value displays
$('.Row.range').forEach(function(x) {
var inp = x.querySelector('input');
var disp1 = x.querySelector('.x-disp1');
var disp2 = x.querySelector('.x-disp2');
var t = rangePt(inp);
$(disp1).html(t);
$(disp2).html(t);
$(inp).on('input', function() {
t = rangePt(inp);
$(disp1).html(t);
$(disp2).html(t);
});
});
// Forget STA credentials
$('#forget-sta').on('click', function() {
selectSta('', '', '');
return false;
});
selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip);
curSSID = cfg.sta_active_ssid;
}
w.init = wifiInit;
w.startScanning = startScanning;
})(window.WiFi = {});
-180
View File
@@ -1,180 +0,0 @@
<?php
return [
'appname' => 'ESPTerm',
'appname_demo' => 'ESPTerm<sup> DEMO</sup>',
'menu.cfg_wifi' => 'WiFi Settings',
'menu.cfg_network' => 'Network Settings',
'menu.cfg_term' => 'Terminal Settings',
'menu.about' => 'About ESPTerm',
'menu.help' => 'Quick Reference',
'menu.term' => 'Back to Terminal',
'menu.cfg_system' => 'System Settings',
'menu.cfg_wifi_conn' => 'Connecting to Network',
'menu.settings' => 'Settings',
'title.term' => 'Terminal',
'term_nav.config' => 'Config',
'term_nav.wifi' => 'WiFi',
'term_nav.help' => 'Help',
'term_nav.about' => 'About',
'term_nav.paste' => 'Paste',
'term_nav.upload' => 'Upload',
'term_nav.keybd' => 'Keyboard',
'term_nav.paste_prompt' => 'Paste text to send:',
'net.ap' => 'DHCP Server (AP)',
'net.sta' => 'DHCP Client (Station)',
'net.sta_mac' => 'Station MAC',
'net.ap_mac' => 'AP MAC',
'net.details' => 'MAC addresses',
'term.defaults' => 'Initial Settings',
'term.expert' => 'Expert Options',
'term.explain_initials' => '
Those are the initial settings used after ESPTerm powers on or when the screen
reset command is received. Some options can be changed by the application via escape sequences,
those changes won\'t be saved in Flash.
',
'term.explain_expert' => '
Those are advanced config options that usually don\'t need to be changed.
Edit them only if you know what you\'re doing.',
'term.example' => 'Default colors preview',
'term.reset_screen' => 'Reset screen & parser',
'term.term_title' => 'Header text',
'term.term_width' => 'Width / height',
'term.default_fg_bg' => 'Text / background',
'term.buttons' => 'Button labels',
'term.theme' => 'Color scheme',
'term.parser_tout_ms' => 'Parser timeout',
'term.display_tout_ms' => 'Redraw delay',
'term.display_cooldown_ms' => 'Redraw cooldown',
'term.fn_alt_mode' => 'SS3 Fn keys',
'term.show_config_links' => 'Show nav links',
'term.show_buttons' => 'Show buttons',
'term.loopback' => 'Local Echo',
'term.button_msgs' => 'Button codes<br>(ASCII, dec, CSV)',
// terminal color labels
'color.0' => 'Black',
'color.1' => 'Red',
'color.2' => 'Green',
'color.3' => 'Yellow',
'color.4' => 'Blue',
'color.5' => 'Purple',
'color.6' => 'Cyan',
'color.7' => 'Silver',
'color.8' => 'Gray',
'color.9' => 'Light Red',
'color.10' => 'Light Green',
'color.11' => 'Light Yellow',
'color.12' => 'Light Blue',
'color.13' => 'Light Purple',
'color.14' => 'Light Cyan',
'color.15' => 'White',
'net.explain_sta' => '
Switch off Dynamic IP to configure the static IP address.',
'net.explain_ap' => '
Those settings affect the built-in DHCP server in AP mode.',
'net.ap_dhcp_time' => 'Lease time',
'net.ap_dhcp_start' => 'Pool start IP',
'net.ap_dhcp_end' => 'Pool end IP',
'net.ap_addr_ip' => 'Own IP address',
'net.ap_addr_mask' => 'Subnet mask',
'net.sta_dhcp_enable' => 'Use dynamic IP',
'net.sta_addr_ip' => 'ESPTerm static IP',
'net.sta_addr_mask' => 'Subnet mask',
'net.sta_addr_gw' => 'Gateway IP',
'wifi.ap' => 'Built-in Access Point',
'wifi.sta' => 'Join Existing Network',
'wifi.enable' => 'Enabled',
'wifi.tpw' => 'Transmit power',
'wifi.ap_channel' => 'Channel',
'wifi.ap_ssid' => 'AP SSID',
'wifi.ap_password' => 'Password',
'wifi.ap_hidden' => 'Hide SSID',
'wifi.sta_info' => 'Selected',
'wifi.not_conn' => 'Not connected.',
'wifi.sta_none' => 'None',
'wifi.sta_active_pw' => '🔒 Password saved',
'wifi.sta_active_nopw' => '🔓 Open access',
'wifi.connected_ip_is' => 'Connected, IP is ',
'wifi.sta_password' => 'Password:',
'wifi.scanning' => 'Scanning',
'wifi.scan_now' => 'Click here to start scanning!',
'wifi.cant_scan_no_sta' => 'Click here to enable client mode and start scanning!',
'wifi.select_ssid' => 'Available networks:',
'wifi.enter_passwd' => 'Enter password for ":ssid:"',
'wifi.sta_explain' => 'After selecting a network, press Apply to connect.',
'wifi.conn.status' => 'Status:',
'wifi.conn.back_to_config' => 'Back to WiFi config',
'wifi.conn.telemetry_lost' => 'Telemetry lost; something went wrong, or your device disconnected.',
'wifi.conn.explain_android_sucks' => '
If you\'re configuring ESPTerm via a smartphone, or were connected
from another external network, your device may lose connection and this
progress indicator won\'t work. Please wait a while (~ 15 seconds),
then check if the connection succeeded.',
'wifi.conn.explain_reset' => '
To force enable the built-in AP, hold the BOOT
button until the blue LED starts flashing. Hold the button longer (until the LED
flashes rapidly) for a "factory reset".',
'wifi.conn.disabled' =>"Station mode is disabled.",
'wifi.conn.idle' =>"Idle, not connected and has no IP.",
'wifi.conn.success' => "Connected! Received IP ",
'wifi.conn.working' => "Connecting to selected AP",
'wifi.conn.fail' => "Connection failed, check settings & try again. Cause: ",
'system.save_restore' => 'Save & Restore',
'system.confirm_restore' => 'Restore all settings to their default values?',
'system.confirm_restore_hard' =>
'Restore to firmware default settings? This will reset ' .
'all active settings and switch to AP mode with the default SSID.',
'system.confirm_store_defaults' =>
'Enter admin password to confirm you want to store the current settings as defaults.',
'system.password' => 'Admin password:',
'system.restore_defaults' => 'Reset active settings to defaults',
'system.write_defaults' => 'Save active settings as defaults',
'system.restore_hard' => 'Reset active settings to firmware defaults',
'system.explain_persist' => '
ESPTerm contains two persistent memory banks, one for default and
one for active settings. Active settings can be stored as defaults
by the administrator (password required).
',
'system.uart' => 'Serial Port',
'system.explain_uart' => '
This form controls the primary, communication UART. The debug UART is fixed at 115.200 baud, one stop-bit and no parity.
',
'uart.baud' => 'Baud rate',
'uart.parity' => 'Parity',
'uart.parity.none' => 'None',
'uart.parity.odd' => 'Odd',
'uart.parity.even' => 'Even',
'uart.stop_bits' => 'Stop-bits',
'uart.stop_bits.one' => 'One',
'uart.stop_bits.one_and_half' => 'One and half',
'uart.stop_bits.two' => 'Two',
'apply' => 'Apply!',
'enabled' => 'Enabled',
'disabled' => 'Disabled',
'yes' => 'Yes',
'no' => 'No',
'confirm' => 'OK',
'form_errors' => 'Validation errors for:',
];
-14
View File
@@ -1,14 +0,0 @@
#!/bin/bash
echo "Packing js..."
cat jssrc/chibi.js \
jssrc/keymaster.js \
jssrc/utils.js \
jssrc/modal.js \
jssrc/notif.js \
jssrc/appcommon.js \
jssrc/lang.js \
jssrc/wifi.js \
jssrc/term_* \
jssrc/term.js > js/app.js
-20
View File
@@ -1,20 +0,0 @@
<nav id="menu">
<div id="brand" tabindex=0><?= tr('appname'.(ESP_DEMO?'_demo':'')) ?></div>
<a href="<?= e(url('term')) ?>" class="icn-back"><?= tr('menu.term') ?></a>
<?php
// generate the menu
foreach ($_pages as $k => $page) {
if (strpos($page->bodyclass, 'cfg') === false) continue;
$sel = ($_GET['page'] == $k) ? 'selected' : '';
$text = $page->label;
$url = e(url($k));
echo "<a href=\"$url\" class=\"$page->icon $sel\">$text</a>";
}
?>
</nav>
<script>
function menuOpen() { $('#menu').toggleClass('expanded') }
$('#brand').on('click', menuOpen).on('keypress', cr(menuOpen));
</script>
-36
View File
@@ -1,36 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title><?= $_GET['PAGE_TITLE'] ?></title>
<link href="/css/app.css" rel="stylesheet">
<script src="/js/app.js"></script>
<script>
var _root = <?= JS_WEB_ROOT ?>;
var _demo = <?= (int)ESP_DEMO ?>;
<?php if($_GET['page']=='term'): ?>var _demo_screen = <?= ESP_DEMO ? DEMO_SCREEN : 0 ?>;<?php endif; ?>
<?php if($_GET['page']=='cfg_wifi'): ?>var _demo_aps = <?= ESP_DEMO ? json_encode(DEMO_APS) : '' ?>;<?php endif; ?>
</script>
</head>
<body class="<?= $_GET['BODYCLASS'] ?>">
<div id="outer">
<?php
$cfg = false;
if (strpos($_GET['BODYCLASS'], 'cfg') !== false) {
$cfg = true;
require __DIR__ . '/_cfg_menu.php';
}
?>
<div id="content">
<img src="/img/loader.gif" alt="Loading…" id="loader">
<?php if ($cfg): ?>
<h1><?= tr('menu.' . $_GET['page']) ?></h1>
<div class="Box errors hidden">
<span class="lead"><?= tr('form_errors') ?></span>&nbsp;<span class="list"></span>
</div>
<?php endif; ?>
-13
View File
@@ -1,13 +0,0 @@
<?php if ($_GET['BODYCLASS'] !== 'page-term'): ?>
<div class="botpad"></div>
<?php endif; ?>
<div class="NotifyMsg hidden" id="notif"></div>
</div>
</div>
</body>
</html>
-69
View File
@@ -1,69 +0,0 @@
<div class="Box">
<img src="/img/cvut.svg" id="logo" class="mq-tablet-min">
<h2>ESP8266 Remote Terminal</h2>
<img src="/img/cvut.svg" id="logo2" class="mq-phone">
<p>
&copy; Ondřej Hruška, 2016-2017
&lt;<a href="mailto:ondra@ondrovo.com">ondra@ondrovo.com</a>&gt;
</p>
<p>
<a href="http://measure.feld.cvut.cz/" target="blank">Katedra měření, FEL ČVUT</a><br>
Department of Measurement, FEE CTU
</p>
</div>
<div class="Box">
<h2>Version</h2>
<table>
<tr>
<th>ESPTerm</th>
<td>v%vers_fw%, built %date% at %time%</td>
</tr>
<tr>
<th>libesphttpd</th>
<td>v%vers_httpd%</td>
</tr>
<tr>
<th>ESP&nbsp;IoT&nbsp;SDK</th>
<td>v%vers_sdk%</td>
</tr>
</table>
</div>
<div class="Box">
<h2>Issues</h2>
<p>
Please report any issues to the <a href="%githubrepo%/issues">bugtracker</a> or send them by e-mail (see above).
</p>
<p>
Firmware updates can be downloaded from the <a href="%githubrepo%/releases">releases page</a> and flashed
with <a href="https://github.com/espressif/esptool">esptool.py</a>.
</p>
</div>
<div class="Box">
<h2>Contributing</h2>
<p>
<i class="icn-github"></i> You're welcome to submit your improvements and ideas to our <a href="%githubrepo%">GitHub repository</a>!
</p>
<p>
<i class="icn-donate"></i> If you'd like to donate, please try <a href="https://paypal.me/mightypork">PayPal</a> or
<a href="https://liberapay.com/MightyPork/">LiberaPay</a>.
</p>
</div>
<div class="Box">
<h2>Thanks</h2>
<p>
The webserver is based on a <a href="https://github.com/MightyPork/libesphttpd">fork</a> of the
<a href="https://github.com/Spritetm/esphttpd">esphttpd</a> library by Jeroen Domburg (Sprite_tm).
</p>
<p>
Using (modified) JS library <a href="https://github.com/kylebarrow/chibi">chibi.js</a> by
Kyle Barrow as a lightweight jQuery alternative.
</p>
</div>
-98
View File
@@ -1,98 +0,0 @@
<?php
$ipmask='pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}$"';
?>
<form class="Box str mobcol" action="<?= e(url('network_set')) ?>" method="GET" id="form-2">
<h2 tabindex=0><?= tr('net.sta') ?></h2>
<div class="Row explain">
<?= tr('net.explain_sta') ?>
</div>
<div class="Row checkbox x-static-toggle" >
<label><?= tr('net.sta_dhcp_enable') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="sta_dhcp_enable" name="sta_dhcp_enable" value="%sta_dhcp_enable%">
</div>
<div class="Row x-static">
<label for="sta_addr_ip"><?= tr('net.sta_addr_ip') ?></label>
<input type="text" name="sta_addr_ip" id="sta_addr_ip" value="%h:sta_addr_ip%" <?=$ipmask?> required>
</div>
<div class="Row x-static">
<label for="sta_addr_mask"><?= tr('net.sta_addr_mask') ?></label>
<input type="text" name="sta_addr_mask" id="sta_addr_mask" value="%h:sta_addr_mask%" <?=$ipmask?> required>
</div>
<div class="Row x-static">
<label for="sta_addr_gw"><?= tr('net.sta_addr_gw') ?></label>
<input type="text" name="sta_addr_gw" id="sta_addr_gw" value="%h:sta_addr_gw%" <?=$ipmask?> required>
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-2').submit()"><?= tr('apply') ?></a>
</div>
</form>
<form class="Box str mobcol" action="<?= e(url('network_set')) ?>" method="GET" id="form-1">
<h2 tabindex=0><?= tr('net.ap') ?></h2>
<div class="Row explain">
<?= tr('net.explain_ap') ?>
</div>
<div class="Row">
<label for="ap_addr_mask"><?= tr('net.ap_addr_mask') ?></label>
<input type="text" name="ap_addr_mask" id="ap_addr_mask" value="%h:ap_addr_mask%" <?=$ipmask?> required>
</div>
<div class="Row">
<label for="ap_addr_ip"><?= tr('net.ap_addr_ip') ?></label>
<input type="text" name="ap_addr_ip" id="ap_addr_ip" value="%h:ap_addr_ip%" <?=$ipmask?> required>
</div>
<div class="Row">
<label for="ap_dhcp_start"><?= tr('net.ap_dhcp_start') ?></label>
<input type="text" name="ap_dhcp_start" id="ap_dhcp_start" value="%h:ap_dhcp_start%" <?=$ipmask?> required>
</div>
<div class="Row">
<label for="ap_dhcp_end"><?= tr('net.ap_dhcp_end') ?></label>
<input type="text" name="ap_dhcp_end" id="ap_dhcp_end" value="%h:ap_dhcp_end%" <?=$ipmask?> required>
</div>
<div class="Row">
<label for="ap_dhcp_time"><?= tr('net.ap_dhcp_time') ?><span class="mq-phone">&nbsp;(min)</span></label>
<input type="number" step=1 min=1 max=2880 name="ap_dhcp_time" id="ap_dhcp_time" value="%ap_dhcp_time%" required>
<span class="mq-no-phone">&nbsp;min</span>
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-1').submit()"><?= tr('apply') ?></a>
</div>
</form>
<div class="Box mobcol">
<h2><?= tr('net.details') ?></h2>
<div class="Row">
<label><?= tr('net.sta_mac') ?></label><input type="text" readonly value="%sta_mac%">
</div>
<div class="Row">
<label><?= tr('net.ap_mac') ?></label><input type="text" readonly value="%ap_mac%">
</div>
</div>
<script>
function updateStaticDisp() {
var sttc = !parseInt($('#sta_dhcp_enable').val());
$('.x-static').toggleClass('hidden', !sttc);
}
$('.x-static-toggle').on('click', function() {
setTimeout(function() {
updateStaticDisp();
}, 0)
});
updateStaticDisp();
</script>
-90
View File
@@ -1,90 +0,0 @@
<div class="Box str mobcol">
<h2 tabindex=0><?= tr('system.save_restore') ?></h2>
<div class="Row explain nomargintop">
<?= tr('system.explain_persist') ?>
</div>
<div class="Row buttons2">
<a class="button icn-restore"
onclick="return confirm('<?= tr('system.confirm_restore') ?>');"
href="<?= e(url('restore_defaults')) ?>">
<?= tr('system.restore_defaults') ?>
</a>
</div>
<div class="Row buttons2">
<a onclick="writeDefaults(); return false;" href="#"><?= tr('system.write_defaults') ?></a>
</div>
<div class="Row buttons2">
<a onclick="return confirm('<?= tr('system.confirm_restore_hard') ?>');"
href="<?= e(url('restore_hard')) ?>">
<?= tr('system.restore_hard') ?>
</a>
</div>
</div>
<form class="Box str mobcol" action="<?= e(url('system_set')) ?>" method="GET" id="form-1">
<h2 tabindex=0><?= tr('system.uart') ?></h2>
<div class="Row explain">
<?= tr('system.explain_uart') ?>
</div>
<div class="Row">
<label for="uart_baud"><?= tr('uart.baud') ?><span class="mq-phone">&nbsp;(bps)</span></label>
<select name="uart_baud" id="uart_baud" class="short">
<?php foreach([
300, 600, 1200, 2400, 4800, 9600, 19200, 38400,
57600, 74880, 115200, 230400, 460800, 921600, 1843200, 3686400,
] as $b):
?><option value="<?=$b?>"><?= number_format($b, 0, ',', '.') ?></option>
<?php endforeach; ?>
</select>
<span class="mq-no-phone">&nbsp;bps</span>
</div>
<div class="Row">
<label for="uart_parity"><?= tr('uart.parity') ?></label>
<select name="uart_parity" id="uart_parity" class="short">
<?php foreach([
2 => tr('uart.parity.none'),
1 => tr('uart.parity.odd'),
0 => tr('uart.parity.even'),
] as $k => $label):
?><option value="<?=$k?>"><?=$label?></option>
<?php endforeach; ?>
</select>
</div>
<div class="Row">
<label for="uart_stopbits"><?= tr('uart.stop_bits') ?></label>
<select name="uart_stopbits" id="uart_stopbits" class="short">
<?php foreach([
1 => tr('uart.stop_bits.one'),
2 => tr('uart.stop_bits.one_and_half'),
3 => tr('uart.stop_bits.two'),
] as $k => $label):
?><option value="<?=$k?>"><?=$label?></option>
<?php endforeach; ?>
</select>
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-1').submit()"><?= tr('apply') ?></a>
</div>
</form>
<script>
function writeDefaults() {
var pw = prompt('<?= tr('system.confirm_store_defaults') ?>');
if (!pw) return;
location.href = <?=json_encode(url('write_defaults')) ?> + '?pw=' + pw;
}
$('#uart_baud').val(%uart_baud%);
$('#uart_parity').val(%uart_parity%);
$('#uart_stopbits').val(%uart_stopbits%);
</script>
-203
View File
@@ -1,203 +0,0 @@
<div class="Box">
<a href="<?= e(url('reset_screen')) ?>"><?= tr('term.reset_screen') ?></a>
</div>
<form class="Box mobopen str" action="<?= e(url('term_set')) ?>" method="GET" id='form-1'>
<h2><?= tr('term.defaults') ?></h2>
<div class="Row explain">
<?= tr('term.explain_initials') ?>
</div>
<div class="Row">
<label for="theme"><?= tr("term.theme") ?></label>
<select name="theme" id="theme" class="short" onchange="showColor()">
<option value="0">Tango</option>
<option value="1">Linux</option>
<option value="2">XTerm</option>
<option value="3">Rxvt</option>
<option value="4">Ambience</option>
<option value="5">Solarized</option>
</select>
</div>
<div class="Row color-preview">
<div class="colorprev">
<span data-fg=0 class="bg0 fg0">30</span><!--
--><span data-fg=1 class="bg0 fg1">31</span><!--
--><span data-fg=2 class="bg0 fg2">32</span><!--
--><span data-fg=3 class="bg0 fg3">33</span><!--
--><span data-fg=4 class="bg0 fg4">34</span><!--
--><span data-fg=5 class="bg0 fg5">35</span><!--
--><span data-fg=6 class="bg0 fg6">36</span><!--
--><span data-fg=7 class="bg0 fg7">37</span>
</div>
<div class="colorprev">
<span data-fg=8 class="bg0 fg8">90</span><!--
--><span data-fg=9 class="bg0 fg9">91</span><!--
--><span data-fg=10 class="bg0 fg10">92</span><!--
--><span data-fg=11 class="bg0 fg11">93</span><!--
--><span data-fg=12 class="bg0 fg12">94</span><!--
--><span data-fg=13 class="bg0 fg13">95</span><!--
--><span data-fg=14 class="bg0 fg14">96</span><!--
--><span data-fg=15 class="bg0 fg15">97</span>
</div>
<div class="colorprev">
<span data-bg=0 class="bg0 fg15">40</span><!--
--><span data-bg=1 class="bg1 fg15">41</span><!--
--><span data-bg=2 class="bg2 fg15">42</span><!--
--><span data-bg=3 class="bg3 fg0">43</span><!--
--><span data-bg=4 class="bg4 fg15">44</span><!--
--><span data-bg=5 class="bg5 fg15">45</span><!--
--><span data-bg=6 class="bg6 fg15">46</span><!--
--><span data-bg=7 class="bg7 fg0">47</span>
</div>
<div class="colorprev">
<span data-bg=8 class="bg8 fg15">100</span><!--
--><span data-bg=9 class="bg9 fg0">101</span><!--
--><span data-bg=10 class="bg10 fg0">102</span><!--
--><span data-bg=11 class="bg11 fg0">103</span><!--
--><span data-bg=12 class="bg12 fg0">104</span><!--
--><span data-bg=13 class="bg13 fg0">105</span><!--
--><span data-bg=14 class="bg14 fg0">106</span><!--
--><span data-bg=15 class="bg15 fg0">107</span>
</div>
</div>
<div class="Row color-preview">
<div style="
" id="color-example">
<?= tr("term.example") ?>
</div>
</div>
<div class="Row">
<label><?= tr("term.default_fg_bg") ?></label>
<select name="default_fg" id="default_fg" class="short" onchange="showColor()">
<?php for($i=0; $i<16; $i++): ?>
<option value="<?=$i?>"><?= tr("color.$i") ?></option>
<?php endfor; ?>
</select>&nbsp;<!--
--><select name="default_bg" id="default_bg" class="short" onchange="showColor()">
<?php for($i=0; $i<16; $i++): ?>
<option value="<?=$i?>"><?= tr("color.$i") ?></option>
<?php endfor; ?>
</select>
</div>
<div class="Row">
<label for="term_width"><?= tr('term.term_width') ?></label>
<input type="number" step=1 min=1 max=255 name="term_width" id="term_width" value="%term_width%" required>&nbsp;<!--
--><input type="number" step=1 min=1 max=255 name="term_height" id="term_height" value="%term_height%" required>
</div>
<div class="Row">
<label for="term_title"><?= tr('term.term_title') ?></label>
<input type="text" name="term_title" id="term_title" value="%h:term_title%" required>
</div>
<div class="Row">
<label><?= tr("term.buttons") ?></label>
<input class="short" type="text" name="btn1" id="btn1" value="%h:btn1%">&nbsp;
<input class="short" type="text" name="btn2" id="btn2" value="%h:btn2%">&nbsp;
<input class="short" type="text" name="btn3" id="btn3" value="%h:btn3%">&nbsp;
<input class="short" type="text" name="btn4" id="btn4" value="%h:btn4%">&nbsp;
<input class="short" type="text" name="btn5" id="btn5" value="%h:btn5%">
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-1').submit()"><?= tr('apply') ?></a>
</div>
</form>
<form class="Box fold str" action="<?= e(url('term_set')) ?>" method="GET" id='form-2'>
<h2><?= tr('term.expert') ?></h2>
<div class="Row explain">
<?= tr('term.explain_expert') ?>
</div>
<div class="Row">
<label for="parser_tout_ms"><?= tr('term.parser_tout_ms') ?><span class="mq-phone">&nbsp;(ms)</span></label>
<input type="number" step=1 min=0 name="parser_tout_ms" id="parser_tout_ms" value="%parser_tout_ms%" required>
<span class="mq-no-phone">&nbsp;ms</span>
</div>
<div class="Row">
<label for="display_tout_ms"><?= tr('term.display_tout_ms') ?><span class="mq-phone">&nbsp;(ms)</span></label>
<input type="number" step=1 min=0 name="display_tout_ms" id="display_tout_ms" value="%display_tout_ms%" required>
<span class="mq-no-phone">&nbsp;ms</span>
</div>
<div class="Row">
<label for="display_cooldown_ms"><?= tr('term.display_cooldown_ms') ?><span class="mq-phone">&nbsp;(ms)</span></label>
<input type="number" step=1 min=0 name="display_cooldown_ms" id="display_cooldown_ms" value="%display_cooldown_ms%" required>
<span class="mq-no-phone">&nbsp;ms</span>
</div>
<div class="Row">
<label><?= tr("term.button_msgs") ?></label>
<input class="short" type="text" name="bm1" id="bm1" value="%h:bm1%">&nbsp;
<input class="short" type="text" name="bm2" id="bm2" value="%h:bm2%">&nbsp;
<input class="short" type="text" name="bm3" id="bm3" value="%h:bm3%">&nbsp;
<input class="short" type="text" name="bm4" id="bm4" value="%h:bm4%">&nbsp;
<input class="short" type="text" name="bm5" id="bm5" value="%h:bm5%">
</div>
<div class="Row checkbox" >
<label><?= tr('term.fn_alt_mode') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="fn_alt_mode" name="fn_alt_mode" value="%fn_alt_mode%">
</div>
<div class="Row checkbox" >
<label><?= tr('term.show_buttons') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="show_buttons" name="show_buttons" value="%show_buttons%">
</div>
<div class="Row checkbox" >
<label><?= tr('term.show_config_links') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="show_config_links" name="show_config_links" value="%show_config_links%">
</div>
<div class="Row checkbox" >
<label><?= tr('term.loopback') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span>
<input type="hidden" id="loopback" name="loopback" value="%loopback%">
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-2').submit()"><?= tr('apply') ?></a>
</div>
</form>
<script>
$('#default_fg').val(%default_fg%);
$('#default_bg').val(%default_bg%);
$('#theme').val(%theme%);
function showColor() {
var ex = qs('#color-example');
ex.className = '';
ex.classList.add('fg'+$('#default_fg').val());
ex.classList.add('bg'+$('#default_bg').val());
var th = $('#theme').val();
$('.color-preview').forEach(function(e) {
e.className = 'Row color-preview theme-'+th;
});
}
showColor();
$('.colorprev span').on('click', function() {
var fg = this.dataset.fg;
var bg = this.dataset.bg;
if (typeof fg != 'undefined') $('#default_fg').val(fg);
if (typeof bg != 'undefined') $('#default_bg').val(bg);
showColor()
});
</script>
-123
View File
@@ -1,123 +0,0 @@
<form class="Box str mobcol" action="<?= e(url('wifi_set')) ?>" method="GET" id="form-1">
<h2 tabindex=0><?= tr('wifi.ap') ?></h2>
<div class="Row checkbox x-ap-toggle">
<label><?= tr('wifi.enable') ?></label><!--
--><span class="box" tabindex=0></span>
<input type="hidden" id="ap_enabled" name="ap_enable" value="%ap_enable%">
</div>
<div class="Row x-ap-on">
<label for="ap_ssid"><?= tr('wifi.ap_ssid') ?></label>
<input type="text" name="ap_ssid" id="ap_ssid" value="%h:ap_ssid%" required>
</div>
<div class="Row x-ap-on">
<label for="ap_password"><?= tr('wifi.ap_password') ?></label>
<input type="text" name="ap_password" id="ap_password" value="%h:ap_password%">
</div>
<div class="Row x-ap-on">
<label for="ap_channel"><?= tr('wifi.ap_channel') ?></label>
<input type="number" name="ap_channel" id="ap_channel" min=1 max=14 value="%ap_channel%" required>
</div>
<div class="Row range x-ap-on">
<label for="tpw">
<?= tr('wifi.tpw') ?>
<span class="display x-disp1 mq-phone"></span>
</label>
<input type="range" name="tpw" id="tpw" step=1 min=0 max=82 value="%tpw%">
<span class="display x-disp2 mq-no-phone"></span>
</div>
<div class="Row checkbox x-ap-on">
<label><?= tr('wifi.ap_hidden') ?></label><!--
--><span class="box" tabindex=0></span>
<input type="hidden" name="ap_hidden" value="%ap_hidden%">
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-1').submit()"><?= tr('apply') ?></a>
</div>
</form>
<form class="Box str mobcol expanded" action="<?= e(url('wifi_set')) ?>" method="GET" id="form-2">
<h2 tabindex=0><?= tr('wifi.sta') ?></h2>
<div class="Row checkbox x-sta-toggle">
<label><?= tr('wifi.enable') ?></label><!--
--><span class="box" tabindex=0></span>
<input type="hidden" id="sta_enabled" name="sta_enable" value="%sta_enable%">
</div>
<div class="Row explain nomargintop x-sta-on">
<span class="spacer"></span>
<?= tr("wifi.sta_explain") ?>
</div>
<input type="hidden" name="sta_ssid" id="sta_ssid" value="">
<input type="hidden" name="sta_password" id="sta_password" value="">
<div class="Row sta-info x-sta-on">
<label><?= tr('wifi.sta_info') ?></label>
<div class="AP-preview hidden" id="sta-nw">
<div class="wrap">
<div class="inner">
<div class="essid"></div>
<div class="passwd"><?= tr('wifi.sta_active_pw') ?></div>
<div class="nopasswd"><?= tr('wifi.sta_active_nopw') ?></div>
<div class="ip"></div>
</div>
<a class="forget" href="#" id="forget-sta">×</a>
</div>
</div>
<div class="AP-preview-nil" id="sta-nw-nil">
<?= tr('wifi.sta_none') ?>
</div>
</div>
<div id="ap-box" class="x-sta-on">
<label><?= tr('wifi.select_ssid') ?></label>
<div id="ap-scan"><a href="#" onclick="WiFi.startScanning(); return false"><?= tr('wifi.scan_now') ?></a></div>
<div id="ap-loader" class="hidden"><?= tr('wifi.scanning') ?><span class="anim-dots">.</span></div>
<div id="ap-list" class="hidden"></div>
</div>
<div class="Row buttons">
<a class="button icn-ok" href="#" onclick="qs('#form-2').submit()"><?= tr('apply') ?></a>
</div>
</form>
<script>
WiFi.scan_url = '<?= url('wifi_scan', true) ?>';
WiFi.init({
sta_ssid: '%j:sta_ssid%',
sta_password: '%j:sta_password%',
sta_active_ip: '%j:sta_active_ip%',
sta_active_ssid: '%j:sta_active_ssid%',
});
function updateApDisp() {
var a = !!parseInt($('#ap_enabled').val());
$('.x-ap-on').toggleClass('hidden', !a);
}
$('.x-ap-toggle').on('click', function() {
setTimeout(function() {
updateApDisp();
}, 0)
});
function updateStaDisp() {
var a = !!parseInt($('#sta_enabled').val());
$('.x-sta-on').toggleClass('hidden', !a);
}
$('.x-sta-toggle').on('click', function() {
setTimeout(function() {
updateStaDisp();
}, 0)
});
updateApDisp();
updateStaDisp();
</script>
-89
View File
@@ -1,89 +0,0 @@
<h1><?= tr('menu.cfg_wifi_conn') ?></h1>
<div class="Box">
<p><b><?= tr('wifi.conn.status') ?></b> <span id="status"></span><span class="anim-dots">.</span></p>
<a href="<?= e(url('cfg_wifi')) ?>" id="backbtn" class="button"><?= tr('wifi.conn.back_to_config') ?></a>
</div>
<div class="Box">
<p><?= tr('wifi.conn.explain_android_sucks') ?></p>
<p><?= tr('wifi.conn.explain_reset') ?></p>
</div>
<script>
var xhr = new XMLHttpRequest();
var abortTmeo;
var failCounter = 0;
var messages = <?= json_encode([
'disabled' => tr('wifi.conn.disabled'),
'idle' => tr('wifi.conn.idle'),
'success' => tr('wifi.conn.success'),
'working' => tr('wifi.conn.working'),
'fail' => tr('wifi.conn.fail'),
]) ?>;
function onFail() {
$("#status").html(<?= json_encode(tr('wifi.conn.telemetry_lost')) ?>);
$('.anim-dots').addClass('hidden');
}
function getStatus() {
xhr.open("GET", 'http://'+_root+'<?= url('wifi_connstatus', true) ?>');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
clearTimeout(abortTmeo);
try {
var data = JSON.parse(xhr.responseText);
var done = false;
var msg = messages[data.status] || '...';
if (data.status == 'success') {
msg += data.ip;
done = true;
}
if (data.status == 'fail') {
msg += data.cause;
done = true;
}
$("#status").html(msg);
if (done) {
// $('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
} else {
// ask again after a short delay
window.setTimeout(getStatus, 1000);
}
} catch(e) {
failCounter++;
console.log(e);
// repeat
if (failCounter > 5) {
onFail();
}
else {
window.setTimeout(getStatus, 1000);
}
}
} else {
onFail();
}
}
};
// XHR timeout
abortTmeo = setTimeout(function () {
xhr.abort();
onFail();
}, 4000);
xhr.send();
}
getStatus();
</script>
-20
View File
@@ -1,20 +0,0 @@
<div class="Box">
<a href="#" onclick="hpfold(1);return false">Expand all</a>&nbsp;|&nbsp;<a href="#" onclick="hpfold(0);return false">Collapse all</a>
</div>
<?php require __DIR__ . "/help/troubleshooting.php"; ?>
<?php require __DIR__ . "/help/nomenclature.php"; ?>
<?php require __DIR__ . "/help/screen_behavior.php"; ?>
<?php require __DIR__ . "/help/input.php"; ?>
<?php require __DIR__ . "/help/charsets.php"; ?>
<?php require __DIR__ . "/help/sgr_styles.php"; ?>
<?php require __DIR__ . "/help/sgr_colors.php"; ?>
<?php require __DIR__ . "/help/cmd_cursor.php"; ?>
<?php require __DIR__ . "/help/cmd_screen.php"; ?>
<?php require __DIR__ . "/help/cmd_system.php"; ?>
<script>
function hpfold(yes) {
$('.fold').toggleClass('expanded', !!yes);
}
</script>
-80
View File
@@ -1,80 +0,0 @@
<div class="Box fold">
<h2>Alternate Character Sets</h2>
<div class="Row v">
<p>
ESPTerm implements Alternate Character Sets as a way to print box drawing characters
and special symbols. A character set can change what each received ASCII character
is printed as on the screen (eg. "{" is "π" in codepage `0`). The implementation is based
on the original VT devices.
</p>
<p>
Since ESPTerm also supports UTF-8, this feature is the most useful for applications
which can't print UTF-8 or already use alternate character sets for historical reasons.
</p>
<h3>Supported codepages</h3>
<ul>
<li>`B` - US ASCII (default)</li>
<li>`A` - UK ASCII: # replaced with £</li>
<li>`0` - Symbols and basic line drawing (standard DEC alternate character set)</li>
<li>`1` - Symbols and advanced line drawing (based on DOS codepage 437, ESPTerm specific)</li>
</ul>
<p>
All codepages use codes 32-127, 32 being space. A character with no entry in the active codepage
stays unchanged.
</p>
<?php
$codepages = load_esp_charsets();
foreach($codepages as $name => $cp) {
echo "<h4>Codepage `$name`</h4>\n";
echo '<div class="charset">';
foreach($cp as $point) {
$dis = $point[1]==$point[2]?' class="none"' : '';
echo "<div$dis><span>$point[0]</span><span>$point[1]</span><span>$point[2]</span></div>";
}
echo '</div>';
}
?>
<h3>Switching commands</h3>
<p>
There are two character set slots, G0 and G1.
Those slots are selected as active using ASCII codes Shift In and Shift Out (those originally served for shifting
a red-black typewriter tape). Often only G0 is used for simplicity.
</p>
<p>
Each slot (G0 and G1) can have a different codepage assigned. G0 and G1 and the active slot number are
saved and restored with the cursor and cleared with a screen reset (<code>\ec</code>).
</p>
<p>The following commands are used:</p>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\e(<i>x</i>`</td>
<td>Set G0 = codepage <i>x</i></td>
</tr>
<tr>
<td>`\e)<i>x</i>`</td>
<td>Set G1 = codepage <i>x</i></td>
</tr>
<tr>
<td>_SO_ (14)</td>
<td>Activate G0</td>
</tr>
<tr>
<td>_SI_ (15)</td>
<td>Activate G1</td>
</tr>
</table>
</div>
</div>
-199
View File
@@ -1,199 +0,0 @@
<div class="Box fold">
<h2>Commands: Cursor Functions</h2>
<div class="Row v">
<p>
The coordinates are 1-based, origin is top left. The cursor can move within the entire screen,
or in the active Scrolling Region if Origin Mode is enabled.
</p>
<p>After writing a character, the cursor advances to the right. If it has reached the end of the row,
it stays on the same line, but writing the next character makes it jump to the start of the next
line first, scrolling up if needed. If Auto-wrap mode is disabled, the cursor never wraps or scrolls
the screen.
</p>
<p>
*Legend:*
Italic letters such as _n_ are ASCII numbers that serve as arguments, separated with a semicolon.
If an argument is left out, it's treated as 0 or 1, depending on what makes sense for the command.
</p>
<h3>Movement</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
<code>
\e[<i>n</i>A \\
\e[<i>n</i>B \\
\e[<i>n</i>C \\
\e[<i>n</i>D
</code>
</td>
<td>Move cursor up (`A`), down (`B`), right (`C`), left (`D`)</td>
</tr>
<tr>
<td>
<code>
\e[<i>n</i>F \\
\e[<i>n</i>E
</code>
</td>
<td>Go _n_ lines up (`F`) or down (`E`), start of line</td>
</tr>
<tr>
<td>
<code>
\e[<i>r</i>d \\
\e[<i>c</i>G \\
\e[<i>r</i>;<i>c</i>H
</code>
</td>
<td>
Go to absolute position - row (`d`), column (`G`), or both (`H`). Use `\e[H` to go to 1,1.
</td>
</tr>
<tr>
<td>
`\e[6n`
</td>
<td>
Query cursor position. Sent back as `\e[<i>r</i>;<i>c</i>R`.
</td>
</tr>
</tbody>
</table>
<h3>Save / restore</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
<code>
\e[s \\
\e[u
</code>
</td>
<td>Save (`s`) or restore (`u`) cursor position</td>
</tr>
<tr>
<td>
<code>
\e7 \\
\e8
</code>
</td>
<td>Save (`7`) or restore (`8`) cursor position and attributes</td>
</tr>
</tbody>
</table>
<h3>Scrolling Region</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
`\e[<i>a</i>;<i>b</i>r`
</td>
<td>
Set scrolling region to rows _a_ through _b_ and go to 1,1. By default, the
scrolling region spans the entire screen height. The cursor can leave the region using
absolute position commands, unless Origin Mode (see below) is active.
</td>
</tr>
<tr>
<td>
<code>
\e[?6h \\
\e[?6l
</code>
</td>
<td>
Enable (`h`) or disable (`l`) Origin Mode and go to 1,1. In Origin Mode, all coordinates
are relative to the Scrolling Region and the cursor can't leave the region.
</td>
</tr>
<tr>
<td>
<code>
\e[<i>n</i>S \\
\e[<i>n</i>T
</code>
</td>
<td>
Move contents of the Scrolling Region up (`S`) or down (`T`), pad with empty
lines of the current background color. This is similar to what happens when AutoWrap
is enabled and some text is printed at the very end of the screen.
</td>
</tr>
</tbody>
</table>
<h3>Tab stops</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
`\eH`
</td>
<td>
Set tab stop at the current column. There are, by default, tabs every 8 columns.
</td>
</tr>
<tr>
<td>
<code>
\e[<i>n</i>I \\
\e[<i>n</i>Z
</code>
</td>
<td>Advance (`I`) or go back (`Z`) _n_ tab stops or end/start of line. ASCII _TAB_ (9) is equivalent to <code>\e[1I</code></td>
</tr>
<tr>
<td>
<code>
\e[0g \\
\e[3g \\
</code>
</td>
<td>Clear tab stop at the current column (`0`), or all columns (`3`).</td>
</tr>
</tbody>
</table>
<h3>Other options</h3>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
<code>
\e[?7h \\
\e[?7l
</code>
</td>
<td>Enable (`h`) or disable (`l`) cursor auto-wrap and screen auto-scroll</td>
</tr>
<tr>
<td>
<code>
\e[?25h \\
\e[?25l
</code>
</td>
<td>Show (`h`) or hide (`l`) the cursor</td>
</tr>
</tbody>
</table>
</div>
</div>
-63
View File
@@ -1,63 +0,0 @@
<div class="Box fold">
<h2>Commands: Screen Functions</h2>
<div class="Row v">
<p>
<b>Legend:</b>
Italic letters such as _n_ are ASCII numbers that serve as arguments, separated with a semicolon.
If an argument is left out, it's treated as 0 or 1, depending on what makes sense for the command.
</p>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>
`\e[<i>m</i>J`
</td>
<td>
Clear part of screen. _m_: 0 - from cursor, 1 - to cursor, 2 - all
</td>
</tr>
<tr>
<td>
`\e[<i>m</i>K`
</td>
<td>
Erase part of line. _m_: 0 - from cursor, 1 - to cursor, 2 - all
</td>
</tr>
<tr>
<td>
`\e[<i>n</i>X`</td>
<td>
Erase _n_ characters in line.
</td>
</tr>
<tr>
<td>
<code>
\e[<i>n</i>L \\
\e[<i>n</i>M
</code>
</td>
<td>
Insert (`L`) or delete (`M`) _n_ lines. Following lines are pulled up or pushed down.
</td>
</tr>
<tr>
<td>
<code>
\e[<i>n</i>@ \\
\e[<i>n</i>P
</code>
</td>
<td>
Insert (`@`) or delete (`P`) _n_ characters. The rest of the line is pulled left or pushed right.
Characters going past the end of line are lost.
</td>
</tr>
</tbody>
</table>
</div>
</div>
-103
View File
@@ -1,103 +0,0 @@
<div class="Box fold">
<h2>Commands: System Functions</h2>
<div class="Row v">
<p>
It's possible to dynamically change the screen title text and action button labels.
Setting an empty label to a button makes it look disabled. The buttons send ASCII 1-5 when clicked.
Those changes are not retained after restart.
</p>
<table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody>
<tr>
<td>`\ec`</td>
<td>
Clear screen, reset attributes and cursor.
The screen size, title and button labels remain unchanged.
</td>
</tr>
<tr>
<td>`\e[5n`</td>
<td>
Query device status, ESPTerm replies with `\e[0n` "device is OK".
Can be used to check if the terminal has booted up and is ready to receive commands.
</td>
</tr>
<tr>
<td>_CAN_ (24)</td>
<td>
This ASCII code is not a command, but is sent by ESPTerm when it becomes ready to receive commands.
When this code is received on the UART, it means ESPTerm has restarted and is ready. Use this to detect
spontaneous restarts which require a full screen repaint.
</td>
</tr>
<tr>
<td>`\e]0;<i>t</i>\a`</td>
<td>Set screen title to _t_ (this is a standard OSC command)</td>
</tr>
<tr>
<td>
<code>
\e]<i>80+n</i>;<i>t</i>\a
</code>
</td>
<td>
Set label for button _n_ = 1-5 (code 81-85) to _t_ - e.g.`\e]81;Yes\a`
sets the first button text to "Yes".
</td>
</tr>
<tr>
<td>
<code>
\e]<i>90+n</i>;<i>m</i>\a
</code>
</td>
<td>
Set message for button _n_ = 1-5 (code 81-85) to _m_ - e.g.`\e]94;iv\a`
sets the 3rd button to send string "iv" when pressed.
</td>
</tr>
<tr>
<td>
<code>
\e[?800h \\
\e[?800l
</code>
</td>
<td>
Show (`h`) or hide (`l`) action buttons (the blue buttons under the screen).
</td>
</tr>
<tr>
<td>
<code>
\e[?801h \\
\e[?801l
</code>
</td>
<td>
Show (`h`) or hide (`l`) menu/help links under the screen.
</td>
</tr>
<tr>
<td>
<code>
\e[12h \\
\e[12l
</code>
</td>
<td>
Enable (`h`) or disable (`l`) Send-Receive Mode (SRM).
SRM is the opposite of Local Echo, meaning `\e[12h` disables and `\e[12l` enables Local Echo.
</td>
</tr>
<tr>
<td>`\e[8;<i>r</i>;<i>c</i>t`</td>
<td>Set screen size to _r_ rows and _c_ columns (this is a command borrowed from Xterm)</td>
</tr>
</tbody>
</table>
</div>
</div>
-254
View File
@@ -1,254 +0,0 @@
<div class="Box fold">
<h2>User Input: Keyboard, Mouse</h2>
<div class="Row v">
<h3>Keyboard</h3>
<p>
The user can input text using their keyboard, or on Android, using the on-screen keyboard which is open using
a button beneath the screen. Supported are all printable characters, as well as many control keys, such as arrows, _Ctrl+letters_
and function keys. Sequences sent by function keys are based on VT102 and Xterm.
</p>
<p>
The codes sent by _Home_, _End_, _F1-F4_ and cursor keys are affected by various keyboard modes (_Application Cursor Keys_,
_Application Numpad Mode_, _SS3 Fn Keys Mode_). Some can be set in the <a href="<?= url('cfg_term') ?>">Terminal Settings</a>,
others via commands.
</p>
<p>
Here are some examples of control key codes:
</p>
<table>
<thead><tr><th>Key</th><th>Code</th><th>Key</th><th>Code</th></tr></thead>
<tr>
<td>Up</td>
<td>`\e[A`,~`\eOA`</td>
<td>F1</td>
<td>`\eOP`,~`\e[11\~`</td>
</tr>
<tr>
<td>Down</td>
<td>`\e[B`,~`\eOB`</td>
<td>F2</td>
<td>`\eOQ`,~`\e[12\~`</td>
</tr>
<tr>
<td>Right</td>
<td>`\e[C`,~`\eOC`</td>
<td>F3</td>
<td>`\eOR`,~`\e[13\~`</td>
</tr>
<tr>
<td>Left</td>
<td>`\e[D`,~`\eOD`</td>
<td>F4</td>
<td>`\eOS`,~`\e[14\~`</td>
</tr>
<tr>
<td>Home</td>
<td>`\eOH`,~`\e[H`,~`\e[1\~`</td>
<td>F5</td>
<td>`\e[15~`</td>
</tr>
<tr>
<td>End</td>
<td>`\eOF`,~`\e[F`,~`\e[4\~`</td>
<td>F6</td>
<td>`\e[17\~`</td>
</tr>
<tr>
<td>Insert</td>
<td>`\e[2\~`</td>
<td>F7</td>
<td>`\e[18\~`</td>
</tr>
<tr>
<td>Delete</td>
<td>`\e[3\~`</td>
<td>F8</td>
<td>`\e[19\~`</td>
</tr>
<tr>
<td>Page Up</td>
<td>`\e[5\~`</td>
<td>F9</td>
<td>`\e[20\~`</td>
</tr>
<tr>
<td>Page Down</td>
<td>`\e[6\~`</td>
<td>F10</td>
<td>`\e[21\~`</td>
</tr>
<tr>
<td>Enter</td>
<td>`\r` (13)</td>
<td>F11</td>
<td>`\e[23\~`</td>
</tr>
<tr>
<td>Ctrl+Enter</td>
<td>`\n` (10)</td>
<td>F12</td>
<td>`\e[24\~`</td>
</tr>
<tr>
<td>Tab</td>
<td>`\t` (9)</td>
<td>ESC</td>
<td>`\e` (27)</td>
</tr>
<tr>
<td>Backspace</td>
<td>`\b` (8)</td>
<td>Ctrl+A..Z</td>
<td>ASCII 1-26</td>
</tr>
</table>
<h3>Action buttons</h3>
<p>
The blue buttons under the screen send ASCII codes 1, 2, 3, 4, 5, which incidentally
correspond to _Ctrl+A,B,C,D,E_. This choice was made to make button press parsing as simple as possible.
</p>
<h3>Mouse</h3>
<p>
ESPTerm implements standard mouse tracking modes based on Xterm. Mouse tracking can be used to implement
powerful user interactions such as on-screen buttons, draggable sliders or dials, menus etc. ESPTerm's
mouse tracking was tested using VTTest and should be compatible with all terminal applications
that request mouse tracking.
</p>
<p>
Mouse can be tracked in different ways; some are easier to parse, others more powerful. The coordinates
can also be encoded in different ways. All mouse tracking options are set using option commands:
`CSI ? _n_ h` to enable, `CSI ? _n_ l` to disable option _n_.
</p>
<h4>Mouse Tracking Modes</h4>
<p>
All tracking modes produce three numbers which are then encoded and send to the application.
First is the _event number_ N, then the _X and Y coordinates_, 1-based.
</p>
<p>
Mouse buttons are numbered: 1=left, 2=middle, 3=right.
Wheel works as two buttons (4 and 5) which generate only press events (no release).
</p>
<div class="tscroll">
<table class="nomen">
<thead><tr><th>Option</th><th>Name</th><th>Description</th></tr></thead>
<tr>
<td>`9`</td>
<td>*X10~mode*</td>
<td>
This is the most basic tracking mode, in which <b>only button presses</b> are reported.
N = button - 1: (0 left, 1 middle, 2 right, 3, 4 wheel).
</td>
</tr>
<tr>
<td>`1000`</td>
<td>*Normal~mode*</td>
<td>
In Normal mode, both button presses and releases are reported.
The lower two bits of N indicate the button pressed:
`00b` (0) left, `01b` (1) middle, `10b` (2) right, `11b` (3) button release.
Wheel buttons are reported as 0 and 1 with added 64 (e.g. 64 and 65).
Normal mode also supports tracking of modifier keys, which are added to N as bit masks:
4=_Shift_, 8=_Meta/Alt_, 16=_Control/Cmd_. Example: middle button with _Shift_ = 1 + 4 = `101b` (5).
</td>
</tr>
<tr>
<td>`1002`</td>
<td>*Button-Event tracking*</td>
<td>
This is similar to Normal mode (`1000`), but mouse motion with a button held is also reported.
A motion event is generated when the mouse cursor moves between screen character cells.
A motion event has the same N as a press event, but 32 is added.
For example, drag-drop event with the middle button will produce N = 1 (press), 33 (dragging) and 3 (release).
</td>
</tr>
<tr>
<td>`1003`</td>
<td>*Any-Event tracking*</td>
<td>
This mode is almost identical to Button Event tracking (1002), but motion events
are sent even when no mouse buttons are held. This could be used to draw on-screen mouse cursor, for example.
Motion events with no buttons will use N = 32 + _11b_ (35).
</td>
</tr>
<tr>
<td>`1004`</td>
<td>*Focus~tracking*</td>
<td>
Focus tracking is a separate function from the other mouse tracking modes, therefore they can be enabled together.
Focus tracking reports when the terminal window (in Xterm) gets or loses focus, or in ESPTerm's case, when any
user is connected. This can be used to pause/resume a game or on-screen animations.
Focus tracking mode sends `CSI I` when the terminal receives, and `CSI O` when it loses focus.
</td>
</tr>
</table>
</div>
<h4>Mouse Report Encoding</h4>
<p>
The following encoding schemes can be used with any of the tracking modes (except Focus tracking, which is not affected).
</p>
<div class="tscroll">
<table class="nomen">
<thead><tr><th>Option</th><th>Name</th><th>Description</th></tr></thead>
<tr>
<td>--</td>
<td>*Normal~encoding*</td>
<td>
This is the default encoding scheme used when no other option is selected.
In this mode, a mouse report has the format `CSI M _n_ _x_ _y_`,
where _n_, _x_ and _y_ are characters with ASCII value = 32 (space) + the respective number, e.g.
0 becomes 32 (space), 1 becomes 33 (!). The reason for adding 32 is to avoid producing control characters.
Example: `\e[M !!` - left button press at coordinates 1,1 when using X10 mode.
</td>
</tr>
<tr>
<td>`1005`</td>
<td>*UTF-8~encoding*</td>
<td>
This scheme should encode each of the numbers as a UTF-8 code point, expanding the maximum possible value.
Since ESPTerm's screen size is limited and this has no practical benefit, this serves simply as an alias
to the normal scheme.
</td>
</tr>
<tr>
<td>`1006`</td>
<td>*SGR~encoding*</td>
<td>
In SGR encoding, the response looks like a SGR sequence with the three numbers as semicolon-separated
ASCII values. In this case 32 is not added like in the Normal and UTF-8 schemes, because
it would serve nor purpose here. Also, button release is not reported as 11b,
but using the normal button code while changing the final SGR character: `M` for button press
and `m` for button release. Example: `\e[2;80;24m` - the right button was released
at row 80, column 24.
</td>
</tr>
<tr>
<td>`1015`</td>
<td>*URXVT~encoding*</td>
<td>
This is similar to SGR encoding, but the final character is always `M` and the numbers are
like in the Normal scheme, with 32 added. This scheme has no real advantage over the previous schemes and
was added solely for completeness.
</td>
</tr>
</table>
</div>
</div>
</div>
-84
View File
@@ -1,84 +0,0 @@
<div class="Box fold">
<h2>Basic Intro & Nomenclature</h2>
<div class="Row v">
<img src="/img/vt100.jpg" class="aside" alt="VT102">
<p>
ESPTerm emulates VT102 (pictured) with some additions from later VT models and Xterm.
All commonly used attributes and commands are supported.
ESPTerm is capable of displaying ncurses applications such as _Midnight Commander_ using _agetty_.
</p>
<p>
ESPTerm accepts UTF-8 characters received on the communication UART and displays them on the screen,
interpreting some codes as Control Characters. Those are e.g. _Carriage Return_ (13), _Line Feed_ (10),
_Tab_ (9), _Backspace_ (8) and _Bell_ (7).
</p>
<p>
Escape sequences start with the control character _ESC_ (27),
followed by any number of ASCII characters forming the body of the command.
</p>
<h3>Nomenclature & Command Types</h3>
<p>
Examples on this help page use the following symbols for special characters and command types:\\
(spaces are for clarity only, _DO NOT_ include them in the commands!)
</p>
<div class="tscroll">
<table class="nomen">
<thead><tr><th>Name</th><th>Symbol</th><th>ASCII</th><th>C string</th><th>Function</th></tr></thead>
<tbody>
<tr>
<td>*ESC*</td>
<td>`\e`</td>
<td>`ESC` (27)</td>
<td>`"\e"`, `"\x1b"`, `"\033"`</td>
<td>Introduces an escape sequence. _(Note: `\e` is a GCC extension)_</td>
</tr>
<tr>
<td>*Bell*</td>
<td>`\a`</td>
<td>`BEL`~(7)</td>
<td>`"\a"`, `"\x7"`, `"\07"`</td>
<td>Audible beep</td>
</tr>
<tr>
<td>*String Terminator*</td>
<td>`ST`</td>
<td>`ESC \`~(27~92)<br>_or_~`\a`~(7)</td>
<td>`"\x1b\\"`, `"\a"`</td>
<td>Terminates a string command (`\a` can be used as an alternative)</td>
</tr>
<tr>
<td>*Control Sequence Introducer*</td>
<td>`CSI`</td>
<td>`ESC [`</td>
<td>`"\x1b["`</td>
<td>Starts a CSI command. Examples: `\e[?7;10h`, `\e[2J`</td>
</tr>
<tr>
<td>*Operating System Command*</td>
<td>`OSC`</td>
<td>`ESC ]`</td>
<td>`"\x1b]"`</td>
<td>Starts an OSC command. Is followed by a command string terminated by `ST`. Example: `\e]0;My Screen Title\a`</td>
</tr>
<tr>
<td>*Select Graphic Rendition*</td>
<td>`SGR`</td>
<td>`CSI <i>n</i>;<i>n</i>;<i>n</i>m`</td>
<td>`"\x1b[1;2;3m"`</td>
<td>Set text attributes, like color or style. 0 to 10 numbers can be used, `\e[m` is treated as `\e[0m`</td>
</tr>
</tbody>
</table>
</div>
<p>There are also some other commands that don't follow the CSI, SGR or OSC pattern, such as `\e7` or
`\e#8`. A list of the most important escape sequences is presented in the following sections.</p>
</div>
</div>
-17
View File
@@ -1,17 +0,0 @@
<div class="Box fold">
<h2>Screen Behavior & Refreshing</h2>
<div class="Row v">
<p>
The initial screen size, title text and button labels can be configured in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>.
</p>
<p>
Screen updates are sent to the browser through a WebSocket after some time of inactivity on the communication UART
(called "Redraw Delay"). After an update is sent, at least a time of "Redraw Cooldown" must elapse before the next
update can be sent. Those delays are used is to avoid burdening the server with tiny updates during a large screen
repaint. If you experience issues (broken image due to dropped bytes), try adjusting those config options. It may also
be useful to try different baud rates.
</p>
</div>
</div>
-65
View File
@@ -1,65 +0,0 @@
<div class="Box fold theme-0">
<h2>Commands: Color SGR</h2>
<div class="Row v">
<p>
Colors are set using SGR commands (like `\e[10;20;30m`). The following tables list the SGR codes to use.
Selected colors are used for any new text entered, as well as for empty space when using line and screen clearing commands.
The configured default colors can be restored using SGR 39 for foreground and SGR 49 for background.
</p>
<p>
The actual color representation depends on a color theme which
can be selected in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>.
</p>
<h3>Foreground colors</h3>
<div class="colorprev">
<span class="bg7 fg0">30</span>
<span class="bg0 fg1">31</span>
<span class="bg0 fg2">32</span>
<span class="bg0 fg3">33</span>
<span class="bg0 fg4">34</span>
<span class="bg0 fg5">35</span>
<span class="bg0 fg6">36</span>
<span class="bg0 fg7">37</span>
</div>
<div class="colorprev">
<span class="bg0 fg8">90</span>
<span class="bg0 fg9">91</span>
<span class="bg0 fg10">92</span>
<span class="bg0 fg11">93</span>
<span class="bg0 fg12">94</span>
<span class="bg0 fg13">95</span>
<span class="bg0 fg14">96</span>
<span class="bg0 fg15">97</span>
</div>
<h3>Background colors</h3>
<div class="colorprev">
<span class="bg0 fg15">40</span>
<span class="bg1 fg15">41</span>
<span class="bg2 fg15">42</span>
<span class="bg3 fg0">43</span>
<span class="bg4 fg15">44</span>
<span class="bg5 fg15">45</span>
<span class="bg6 fg15">46</span>
<span class="bg7 fg0">47</span>
</div>
<div class="colorprev">
<span class="bg8 fg15">100</span>
<span class="bg9 fg0">101</span>
<span class="bg10 fg0">102</span>
<span class="bg11 fg0">103</span>
<span class="bg12 fg0">104</span>
<span class="bg13 fg0">105</span>
<span class="bg14 fg0">106</span>
<span class="bg15 fg0">107</span>
</div>
</div>
</div>
-26
View File
@@ -1,26 +0,0 @@
<div class="Box fold">
<h2>Commands: Style SGR</h2>
<div class="Row v">
<p>
All text attributes are set using SGR commands like `\e[10;20;30m`, with up to 10 numbers separated by semicolons.
To restore all attributes to their default states, use SGR 0: `\e[0m` or `\e[m`.
</p>
<p>Those are the supported text attributes SGR codes:</p>
<table>
<thead><tr><th>Style</th><th>Enable</th><th>Disable</th></tr></thead>
<tbody>
<tr><td><b>Bold</b></td><td>1</td><td>21, 22</td></tr>
<tr><td style="opacity:.6">Faint</td><td>2</td><td>22</td></tr>
<tr><td><i>Italic</i></td><td>3</td><td>23</td></tr>
<tr><td><u>Underlined</u></td><td>4</td><td>24</td></tr>
<tr><td>Blink</td><td>5</td><td>25</td></tr>
<tr><td><span style="color:black;background:#ccc;">Inverse</span></td><td>7</td><td>27</td></tr>
<tr><td><s>Striked</s></td><td>9</td><td>29</td></tr>
<tr><td>𝔉𝔯𝔞𝔨𝔱𝔲𝔯</td><td>20</td><td>23</td></tr>
</tbody>
</table>
</div>
</div>
-33
View File
@@ -1,33 +0,0 @@
<div class="Box fold">
<h2>Tips & Troubleshooting</h2>
<div class="Row v">
<ul>
<li>*Communication UART (Rx, Tx)* can be configured in the <a href="<?= url('cfg_system') ?>">System Settings</a>.
<li>*Boot log and debug messages* are available on pin *GPIO2* (P2) at 115200\,baud, 1 stop bit, no parity.
Those messages may be disabled through compile flags.
<li>*Loopback test*: Connect the Rx and Tx pins with a piece of wire. Anything you type in the browser should
appear on the screen. Set _Parser Timeout = 0_ in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>
to be able to manually enter escape sequences.
<li>There is very little RAM available to the webserver, and it can support at most 4 connections at the same time.
Each terminal session (open window with the terminal screen) uses one persistent connection for screen updates.
*Avoid leaving unused windows open*, or either the RAM or connections may be exhausted.
<li>*For best performance*, use the module in Client mode (connected to external network) and minimize the number
of simultaneous connections. Enabling AP consumes extra RAM because the DHCP server and Captive Portal
DNS server are started.
<li>In AP mode, *check that the WiFi channel used is clear*; interference may cause flaky connection.
A good mobile app to use for this is
<a href="https://play.google.com/store/apps/details?id=com.farproc.wifi.analyzer">WiFi Analyzer (Google Play)</a>.
Adjust the hotspot strength and range using the _Tx Power setting_.
<li>Hold the BOOT button (GPIO0 to GND) for ~1 second to force enable AP. Hold it for ~6 seconds to restore default settings.
(This is indicated by the blue LED rapidly flashing). Default settings can be overwritten in the
<a href="<?= url('cfg_system') ?>">System Settings</a>.
</ul>
</div>
</div>
-93
View File
@@ -1,93 +0,0 @@
<script>
// Workaround for badly loaded page
setTimeout(function() {
if (typeof termInit == 'undefined' || typeof $ == 'undefined') {
console.error("Page load failed, refreshing…");
location.reload(true);
}
}, 3000);
</script>
<div class="Modal light hidden" id="fu_modal">
<div id="fu_form" class="Dialog">
<div class="fu-content">
<h2>Text Upload</h2>
<p>
<label for="fu_file">Load a text file:</label>
<input type="file" id="fu_file" accept="text/*" /><br>
<textarea id="fu_text"></textarea>
</p>
<p>
<label for="fu_crlf">Line Endings:</label>
<select id="fu_crlf">
<option value="CR">CR (Enter key)</option>
<option value="CRLF">CR LF (Windows)</option>
<option value="LF">LF (Linux)</option>
</select>
</p>
<p>
<label for="fu_delay">Line Delay (ms):</label>
<input id="fu_delay" type="number" value=1 min=0>
</p>
</div>
<div class="fu-buttons">
<button onclick="TermUpl.start()" class="icn-ok x-fu-go">Start</button>&nbsp;
<button onclick="TermUpl.close()" class="icn-cancel x-fu-cancel">Cancel</button>&nbsp;
<i class="fu-prog-box">Upload: <span id="fu_prog"></span></i>
</div>
</div>
</div>
<h1><!-- Screen title gets loaded here by JS --></h1>
<div id="term-wrap">
<div id="screen" class="theme-%theme%"></div>
<div id="action-buttons">
<button data-n="1"></button><!--
--><button data-n="2"></button><!--
--><button data-n="3"></button><!--
--><button data-n="4"></button><!--
--><button data-n="5"></button>
</div>
</div>
<textarea id="softkb-input" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
<nav id="term-nav">
<a href="#" onclick="kbOpen(true);return false" class="mq-tablet-max"><i class="icn-keyboard"></i><span><?= tr('term_nav.keybd') ?></span></a><!--
--><a href="#" onclick="TermUpl.open();return false"><i class="icn-download"></i><span><?= tr('term_nav.upload') ?></a><!--
--><a href="<?= url('cfg_term') ?>" class="x-term-conf-btn"><i class="icn-configure"></i><span><?= tr('term_nav.config') ?></span></a><!--
--><a href="<?= url('cfg_wifi') ?>" class="x-term-conf-btn"><i class="icn-wifi"></i><span><?= tr('term_nav.wifi') ?></span></a><!--
--><a href="<?= url('help') ?>" class="x-term-conf-btn"><i class="icn-help"></i><span><?= tr('term_nav.help') ?></span></a><!--
--><a href="<?= url('about') ?>" class="x-term-conf-btn"><i class="icn-about"></i><span><?= tr('term_nav.about') ?></span></a>
</nav>
<script>
try {
window.noAutoShow = true;
termInit(); // the screen will be loaded via ajax
Screen.load('%j:labels_seq%');
// auto-clear the input box
$('#softkb-input').on('input', function(e) {
setTimeout(function(){
var str = $('#softkb-input').val();
$('#softkb-input').val('');
Input.sendString(str);
}, 1);
});
} catch(e) {
console.error(e);
console.error("Fail, reloading in 3s…");
setTimeout(function() {
location.reload(true);
}, 3000);
}
function kbOpen(yes) {
var i = qs('#softkb-input');
if (yes) i.focus();
else i.blur();
}
</script>
File diff suppressed because one or more lines are too long
-17
View File
@@ -1,17 +0,0 @@
// Customize Neat grid
@import "lib/neat/neat-helpers";
// optionally change gri settings
// Define breakpoints
$phone: new-breakpoint(max-width 544px);
$tablet: new-breakpoint(min-width 545px max-width 1000px);
$normal: new-breakpoint(min-width 1001px max-width 1376px);
$large: new-breakpoint(min-width 1377px);
$tablet-max: new-breakpoint(max-width 1000px);
$normal-max: new-breakpoint(max-width 1376px);
$tablet-min: new-breakpoint(min-width 545px);
$normal-min: new-breakpoint(min-width 1001px);
-439
View File
@@ -1,439 +0,0 @@
/* normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
*, *:before, *:after {
box-sizing: border-box;
}
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
//article,
//aside,
//details,
//figcaption,
figure,
//footer,
//header,
//hgroup,
//main,
//menu,
nav
//section,
//summary
{
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
//audio,
canvas,
progress
//video
{
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
//
//audio:not([controls]) {
// display: none;
// height: 0;
//}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden]
//template
{
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
//abbr[title] {
// border-bottom: 1px dotted;
//}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b
//strong
{
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
//
//dfn {
// font-style: italic;
//}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
h2 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
//
//mark {
// background: #ff0;
// color: #000;
//}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
//figure {
// margin: 1em 40px;
//}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
//kbd,
pre
//samp
{
font-family: "DejaVu Sans Mono", "Inconsolata", monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
//optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
//html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
//input[type="number"]::-webkit-inner-spin-button,
//input[type="number"]::-webkit-outer-spin-button {
// height: auto;
//}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
//
//input[type="search"] {
// -webkit-appearance: textfield; /* 1 */
// box-sizing: content-box; /* 2 */
//}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
//
//input[type="search"]::-webkit-search-cancel-button,
//input[type="search"]::-webkit-search-decoration {
// -webkit-appearance: none;
//}
/**
* Define consistent border, margin, and padding.
*/
//
//fieldset {
// border: 1px solid #c0c0c0;
// margin: 0 2px;
// padding: 0.35em 0.625em 0.75em;
//}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
//
//optgroup {
// font-weight: bold;
//}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
-55
View File
@@ -1,55 +0,0 @@
// Add a highlight for debugging
@mixin highlight($color) {
outline: 1px solid $color;
background: rgba($color, .05);
box-shadow: 0 0 2px 2px rgba($color, .2), inset 0 0 2px 2px rgba($color, .2);
}
// Ellipsis, but for block elements
@mixin block-ellipsis($width: 100%) {
display: block;
max-width: $width;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
// No margins, padding, borders
@mixin naked() {
border: 0 none;
margin: 0;
padding: 0;
text-decoration: none;
}
@mixin translate($x, $y) {
@include transform(translate($x, $y));
}
// Disallow wrapping
@mixin nowrap() {
white-space: nowrap;
word-wrap: normal;
}
@mixin click-through() {
pointer-events: none;
}
// Disallow text selection
@mixin noselect() {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
// Allow text selection
@mixin can-select() {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
cursor: text;
}
-57
View File
@@ -1,57 +0,0 @@
@import "normalize";
@import "fontello";
@import "lib/bourbon/bourbon";
@import "grid-settings";
@import "lib/neat/neat";
@import "utils";
$form-label-w: 160px;
$form-label-gap: 8px;
$form-field-w: 250px;
$c-red-outline: #ff0099;
$c-form-label-fg: white;
$c-form-field-bg: #3c3c3c;
$c-form-field-fg: white;
$c-form-highlight: #2972ba;
$c-form-highlight-a: #2ea1f9;
$c-modal-bg: #242426;
$screen-stack: "DejaVu Sans Mono", "Liberation Mono", "Inconsolata", monospace;
@function dist($x) {
@return modular-scale($x, 1rem, $golden);
}
@function fsize($x) {
@return modular-scale($x, 1em, $major-second);
}
@import "layout/index";
@import "form/index";
// import all our pages
@import "pages/wifi";
@import "pages/term";
@import "pages/about";
// media queries
@include media($tablet-min) {
.mq-phone { display: none!important; }
}
@include media($phone) {
.mq-tablet-min, .mq-no-phone { display: none !important; }
}
@include media($normal-min) {
.mq-tablet-max { display: none !important; }
}
@include media($tablet-max) {
.mq-normal-min { display: none !important; }
}
-58
View File
@@ -1,58 +0,0 @@
@import "fancy_button_mixins";
$btn-gray-f: #DDDDDD;
$btn-gray-b: #505050;
$btn-gray-l: #343434; // line
$btn-green-f: #FEFEFE;
$btn-green-b: #2ca94b;
$btn-green-fa: #FEFEFE;
$btn-green-ba: #28ba5c;
$btn-red-f: #FEFEFE;
$btn-red-b: #D04E51;
$btn-red-fa: #FEFEFE;
$btn-red-ba: #d4403f;
$btn-blue-f: #FEFEFE;
$btn-blue-b: #3983cd;
$btn-blue-fa: #FEFEFE;
$btn-blue-ba: #2076C6;
$btn-orange-f: #FEFEFE;
$btn-orange-b: #dd8751;
$btn-orange-fa: #FEFEFE;
$btn-orange-ba: #C6733F;
button, input[type=submit], .button {
@include fancy-btn-base();
&.narrow {
min-width: initial;
}
&::before {
vertical-align: -1px;
margin-left: 0;
}
text-shadow: 1.5px 1.5px 2px rgba(black, 0.4);
@include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba);
&:focus {
outline-color: $c-red-outline;
}
}
//input[type="submit"], .btn-green {
// @include fancy-btn-colors($btn-green-f, $btn-green-b, $btn-green-fa, $btn-green-ba);
//}
//.btn-red {
// @include fancy-btn-colors($btn-red-f, $btn-red-b, $btn-red-fa, $btn-red-ba);
//}
//.btn-blue {
// @include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba);
//}
@@ -1,58 +0,0 @@
// Button styling
@mixin fancy-btn-base() {
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
padding: 0 0.6em;
border: 0 none;
//outline: 0 none !important;
line-height: 1.8em;
font-size: 1.1em;
margin-bottom: 3px;
min-width: 5em;
@include noselect();
//&[class^="icon-"]::before, &[class*=" icon-"]::before {
// margin-left:0;
//}
&:active {
position: relative;
top: 2px;
}
//&, &:active, &:hover, &:visited {
// text-decoration: none;
//}
}
@mixin fancy-btn-colors-full($text_p, $back_p, $side_p, $text_a, $back_a, $side_a) {
background-color: $back_p;
box-shadow: 0 3px 0 $side_p;
text-decoration: none !important;
&, &:link, &:visited {
color: $text_p;
}
&:hover, &:active, &.active, &.selected {
background-color: $back_a;
color: $text_a;
}
&:hover, &.selected, &.active {
box-shadow: 0 3px 0 $side_a;
}
// thinner shadow
&:active {
box-shadow: 0 1px 0 $side_a;
}
}
@mixin fancy-btn-colors($text_p, $back_p, $text_a, $back_a) {
@include fancy-btn-colors-full($text_p, $back_p, darken($back_p, 14), $text_a, $back_a, darken($back_a, 16));
}
-82
View File
@@ -1,82 +0,0 @@
@import "buttons";
#{$all-text-inputs}, select, label.select-wrap {
width: $form-field-w;
}
input[type="number"], input.short, select.short {
width: $form-field-w/2;
}
#{$all-text-inputs}, select {
border: 0 none;
border-bottom: 2px solid $c-form-highlight;
background-color: $c-form-field-bg;
color: $c-form-field-fg;
padding: 6px;
line-height: 1em;
//outline: 0 none !important;
//-moz-outline: 0 none !important;
font-weight: normal;
&:focus, &:hover {
border-bottom-color: $c-form-highlight-a;
}
}
.Row.checkbox {
$h: 27px;
line-height: $h;
.box {
overflow: hidden;
width: $h;
height: $h;
border: 1px solid #808080;
border-radius: 3px;
background: $c-form-field-bg;
display: inline-block;
position: relative;
cursor: pointer;
color: $c-form-highlight-a;
&::before {
font-family: "fontello";
position: absolute;
//content: '×';
//content: '✓';
left: 0; top: 0; right: 0; bottom: 0;
line-height: 25px;
text-align: center;
font-size: 20px;
vertical-align: middle;
display: none;
}
@include icon-content('ok');
&.checked::before {
display: block;
}
}
}
.Row.range {
.display {
margin-left: 1ex;
}
label .display { font-weight: normal; }
}
//#{$all-text-inputs} {
// @include can-select();
//}
//textarea {
// font-family: monospace;
// line-height: 1.2em;
// display: block; // fixes weird bottom margin
//}
//@import "select";
-204
View File
@@ -1,204 +0,0 @@
// Unified Form wrapper
form { @include naked(); }
.Box.errors {
.list {
color: crimson;
font-weight: bold;
}
.lead {
color: white;
}
}
.Row {
vertical-align: middle;
margin: 12px auto;
text-align: left;
line-height: 1.35em;
display: flex;
flex-direction: row;
align-items: center;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
&.v {
display: block;
}
.aside {
float: right;
margin-left: 5px;
margin-bottom: 5px;
@include media($phone) {
margin: 0; float: none;
}
}
.spacer {
width: $form-label-w;
@include media($phone) {
display: none;
}
}
// buttons2 is the same style, but different selector for use in the admin page
&.buttons, &.buttons2 {
margin: 16px auto;
input, .button {
margin-right: dist(-1);
}
}
&.centered {
justify-content: center;
}
&.message {
font-size: 1em;
//margin-left: $label-gap + $w-labels;
text-shadow: 1px 1px 3px black;
text-align: center;
&.error {
color: crimson;
}
&.ok {
color: #0fe851;
}
}
&.separator {
padding-top: 14px;
border-top: 2px solid rgba(255, 255, 255, 0.1);
}
textarea {
display: inline-block;
vertical-align: top;
min-height: 10rem;
flex-grow: 1;
resize: vertical;
}
label {
font-weight: bold;
color: $c-form-label-fg;
display: inline-block;
width: $form-label-w;
text-align: right;
text-shadow: 1px 1px 3px black;
padding: $form-label-gap;
align-self: flex-start;
@include noselect;
@include nowrap;
}
label.error {
color: crimson;
}
//.checkbox-wrap {
// display: inline-block;
// width: $form-label-w;
// padding: $form-label-gap;
// text-align: right;
// align-self: flex-start;
//
// input[type=checkbox] {
// margin: auto;
// width: auto;
// height: auto;
// }
//
// & + label {
// width: $form-field-w;
// padding-left: 0;
// text-align: left;
// cursor: pointer;
// }
//}
input[type="range"] {
width: 200px;
}
// special phone style
@include media($phone) {
flex-direction: column;
margin: 6px auto;
&.buttons, &.centered, &.checkbox {
flex-direction: row;
}
&.buttons {
justify-content: center;
// remove margin on lats button
:last-child {
margin-right:0;
}
}
label {
padding-left: 0;
text-align: left;
width: auto;
}
.checkbox-wrap {
order: 1;
text-align: left;
padding-bottom: 0;
border-radius: .4px;
width: auto;
& + label {
width: auto;
}
}
#{$all-text-inputs}, input[type="range"], textarea, select {
width: 100%;
}
}
}
// red asterisk
form span.required {
color: red;
}
.RadioGroup {
display: inline-block;
line-height: 1.5em;
vertical-align: middle;
label {
width: auto;
text-align: left;
cursor: pointer;
font-weight: normal;
}
input[type="radio"] {
vertical-align: middle;
margin: 0 0 0 5px;
}
}
-13
View File
@@ -1,13 +0,0 @@
@import 'fancy_button_mixins';
@import 'buttons';
@import 'form_elements';
%form-row-spacing {
& > * {
margin-right: dist(-2);
&:last-child { margin-right: 0 }
}
}
@import 'form_layout';
//@import 'select';
-52
View File
@@ -1,52 +0,0 @@
// target chrome only
@media screen and (-webkit-min-device-pixel-ratio: 0) {
select { padding-right: 18px }
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
line-height: 1.2em;
//padding: 3.5px;
padding-right: 1em;
// hack for firefox to disable dotted outline
&:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 $c-form-field-fg;
}
option {
background: $c-form-field-bg;
}
}
label.select-wrap {
position: relative;
display: inline !important;
margin: 0 !important;
padding: 0 !important;
width: auto !important;
&:after {
content: '<>'; /* will be rotated */
font-family: "Consolas", monospace;
font-weight: bold;
color: $c-form-highlight-a;
top: 50%;
@include transform(translate(0, -50%) rotate(90deg));
right: 2px;
position:absolute;
z-index: 100;
pointer-events: none;
}
}
-41
View File
@@ -1,41 +0,0 @@
html {
font-family: Arial, sans-serif;
color: #D0D0D0;
background: #131315;
}
html, body {
@include naked();
width: 100%;
height: 100%;
overflow: hidden;
}
a, a:visited, a:link {
cursor: pointer;
color: #5abfff;
text-decoration: none;
}
a:hover {
color: #5abfff;
text-decoration: underline;
}
.hidden {
display: none !important;
}
[onclick] {
cursor: pointer;
}
ul > * {
padding-top: .3em;
padding-bottom: .3em;
}
ul {
margin-top: 0;
margin-bottom: 0;
}
-179
View File
@@ -1,179 +0,0 @@
.botpad {
display:block;
height: 5em;
}
.Box {
display: block;
max-width: 900px;
margin-top: dist(0);
padding: dist(-1) dist(0);
// clear floats
&::after {
content: '';
display: block;
clear: both
}
@include media($phone) {
margin-top: dist(-1);
}
h1, h2 {
overflow: hidden;
}
h1 + & {
margin-top: 0;
}
h2 {
margin-top: 0;
margin-bottom: 0 !important;
}
p:last-child {
margin-bottom: 0.5em;
}
border-radius: 3px;
background-color: rgba(white, .07);
box-shadow: 0 0 4px black;
border: 1px solid #4f4f4f;
&.wide {
width: initial;
max-width: initial;
}
&.medium {
max-width: 1200px;
}
//.Valfield {
// display: inline-block;
// min-width: 10em;
//}
// Submit Top Right
&.str {
position: relative;
.Row.buttons {
position: absolute;
@include media($phone) {
right: dist(0);
top: 1.8em;
margin: 1rem auto;
}
@include media($tablet-min) {
right: 0;
top: 0;
margin-top: dist(-1);
}
}
}
&.str.mobopen .Row.buttons {
top: 0;
margin-top: dist(-1);
}
.Row.explain {
display: block; // this stops flex messing up text with inline tags
max-width: 600px; margin-left: 0;
line-height: 1.2;
@include media($phone) {
margin-top: 60px;
}
&.nomargintop {
margin-top: 12px !important;
}
&.padleft {
}
}
&.mobopen .Row.explain {
margin-top: 12px; // default from .Row
@include media($phone) {
margin-top: 18px;
}
}
}
@mixin mobcol-base {
h2 {
position: relative;
cursor: pointer;
padding: 2px 1.3rem 2px 5px;
margin: 0 -5px 0 -5px;
&::after {
position: absolute;
right: 4px;
content: '';
top:50%;
font-size: 120%;
font-weight: bold;
transform: translate(0,-50%) rotate(90deg);
}
}
&.expanded h2::after {
transform: translate(-25%,-50%) rotate(-90deg);
margin-bottom: dist(0);
}
.Row {
display: none;
}
&.expanded {
.Row {
display: flex;
&.v {
display: block;
}
}
}
}
.Box.fold {
@include mobcol-base;
}
@include media($phone) {
.Box.fold, .Box.mobcol {
h2 {
padding: 2px 1.3rem 2px 5px;
margin: 0 -5px 0 -5px;
}
&.expanded h2::after {
margin-bottom: dist(0);
}
}
.Box.mobcol {
@include mobcol-base;
#ap-box {
display: none;
}
&.expanded {
#ap-box {
display: block;
}
}
}
}
-60
View File
@@ -1,60 +0,0 @@
#content {
flex-grow: 1;
position: relative;
padding: dist(0);
@include media($phone) {
padding: dist(-1);
}
overflow-y: auto;
& > * {
margin-left: auto;
margin-right: auto;
}
h1 {
text-align: center;
font-size: fsize(7);
margin-top: 0;
margin-bottom: dist(0);
}
h2 {
font-size: fsize(3);
margin-bottom: dist(-1);
}
@include media($phone) {
h1 {
font-size: fsize(5);
margin-bottom: dist(-1);
}
h2 {
font-size: fsize(2);
margin-bottom: dist(-1);
}
}
td, th {
padding: dist(-2);
}
tbody th {
text-align: right;
width: $form-label-w;
color: $c-form-label-fg;
}
}
#content {
// fade in effect
opacity: 0;
transition: opacity 0.15s ease-in;
}
#content.load {
opacity: 1;
}
-9
View File
@@ -1,9 +0,0 @@
@import "base";
@import "outer-wrap";
@import "menu";
@import "content";
@import "loader";
@import "box";
@import "modal";
-18
View File
@@ -1,18 +0,0 @@
// Loader wheel in top right corner
#loader {
position: absolute;
right: dist(1);
top: dist(1);
transition: opacity .2s;
opacity: 0;
@include media($phone) {
top: dist(0);
right: dist(0);
}
&.show {
opacity:1;
}
}
-111
View File
@@ -1,111 +0,0 @@
#menu {
$menu-bg: #3983CD;
$menu-hl: #5badff; //#1bd886;
$menu-fg: white;
flex: 0 0 15rem;
background: $menu-bg;
& > * {
display: block;
text-decoration: none;
padding: dist(-1) dist(0);
@include nowrap;
@include noselect;
}
#brand {
cursor: pointer;
color: $menu-fg;
background: darken($menu-bg, 10%);
font-size: 120%;
text-align: center;
position:relative;
transition: none;
font-weight: bold;
margin-bottom: dist(0);
@include media($phone) {
background: $menu-bg;
cursor: pointer;
margin-bottom: dist(-2);
&::after {
position: absolute;
color: rgba(black, .4);
right: dist(0);
content: '';
top:50%;
font-size: 120%;
font-weight: bold;
transform: translate(0,-50%) rotate(90deg);
}
}
}
&.expanded #brand {
background: darken($menu-bg, 10%);
@include media($phone) {
&:after { transform: translate(-25%,-50%) rotate(-90deg) }
}
}
a {
font-size: 130%;
color: $menu-fg;
transition: background-color 0.2s;
text-shadow: 0 0 5px rgba(black, .4);
&:hover, &.selected {
background: $menu-hl;
text-shadow: 0 0 5px rgba(black, .6);
}
&.selected {
position: relative;
box-shadow: 0 0 5px rgba(black, .5);
}
&:focus {
outline-color: $c-red-outline;
}
//&::before {
// content: "▸";
// padding-right: .5rem;
// position: relative;
// top: -0.1rem;
//}
// Fontello
&::before {
vertical-align: -2px;
margin-left: 0;
margin-right: 15px;
}
@include media($phone) {
display: none;
&::before {margin-left: 10px;}
}
}
&.expanded a { display:block }
@include media($tablet) {
#brand {
font-size: 95%;
margin-bottom: dist(-1);
}
a { font-size: 105%; }
flex-basis: 10rem;
& > * { padding: dist(-2) dist(-1); }
}
}
-95
View File
@@ -1,95 +0,0 @@
.Modal {
z-index: 100;
position: fixed;
width: 100%; height: 100%;
left: 0; top: 0; right: 0; bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(black, .65);
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
&.light {
background: rgba(black, .25);
}
@include media($phone) {
flex-direction: column;
justify-content: flex-start;
overflow-y: auto;
.Dialog {
margin-top: dist(-1) !important;
flex-basis: unset;
flex-shrink: 0;
}
}
}
.Dialog {
margin: dist(-1);
padding: dist(0);
overflow: hidden;
//max-width: 100%;
//max-height: 100%;
flex-basis: 35rem;
//min-height: 15rem;
background: $c-modal-bg;//#1c1c1e;
border-left: 6px solid $c-form-highlight;
border-right: 6px solid $c-form-highlight;
//border-top: 1px solid $c-form-highlight;
//border-bottom: 1px solid $c-form-highlight;
box-shadow: 0 0 6px 0 black;
border-radius: 6px;
h1,h2 {
margin-top:0;
}
p:last-child {
margin-bottom: 0;
}
}
// "toast"
.NotifyMsg {
position: fixed;
top: dist(1);
right: dist(2);
padding: dist(-1) dist(0);
// center horizontally
//left: 50%;
//@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #3887d0;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - #{dist(0)});
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
-22
View File
@@ -1,22 +0,0 @@
/* Main outer container */
#outer {
display: flex;
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
flex-direction: row;
}
@include media($phone) {
#outer {
display: block;
overflow-y: scroll;
}
}
@@ -1,411 +0,0 @@
// The following features have been deprecated and will be removed in the next MAJOR version release
@mixin inline-block {
display: inline-block;
@warn "The inline-block mixin is deprecated and will be removed in the next major version release";
}
@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) {
@if type-of($style) == string and type-of($base-color) == color {
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == string and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: #4294f0;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == color {
$base-color: $style;
$style: simple;
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: $style;
$style: simple;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == number {
$padding: $base-color;
$text-size: $style;
$base-color: #4294f0;
$style: simple;
@if $padding == #4294f0 {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
@warn "The button mixin is deprecated and will be removed in the next major version release";
}
// Selector Style Button
@mixin buttonstyle($type, $b-color, $t-size, $pad) {
// Grayscale button
@if $type == simple and $b-color == grayscale($b-color) {
@include simple($b-color, true, $t-size, $pad);
}
@if $type == shiny and $b-color == grayscale($b-color) {
@include shiny($b-color, true, $t-size, $pad);
}
@if $type == pill and $b-color == grayscale($b-color) {
@include pill($b-color, true, $t-size, $pad);
}
@if $type == flat and $b-color == grayscale($b-color) {
@include flat($b-color, true, $t-size, $pad);
}
// Colored button
@if $type == simple {
@include simple($b-color, false, $t-size, $pad);
}
@else if $type == shiny {
@include shiny($b-color, false, $t-size, $pad);
}
@else if $type == pill {
@include pill($b-color, false, $t-size, $pad);
}
@else if $type == flat {
@include flat($b-color, false, $t-size, $pad);
}
}
// Simple Button
@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
$stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
$text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border;
border-radius: 3px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-decoration: none;
text-shadow: 0 1px 0 $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%);
$stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
@if $grayscale == true {
$border-active: grayscale($border-active);
$inset-shadow-active: grayscale($inset-shadow-active);
}
border: 1px solid $border-active;
box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active;
}
}
// Shiny Button
@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
$border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
$fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46);
$inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12);
$second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33);
$text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
$third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$border-bottom: grayscale($border-bottom);
$fourth-stop: grayscale($fourth-stop);
$inset-shadow: grayscale($inset-shadow);
$second-stop: grayscale($second-stop);
$text-shadow: grayscale($text-shadow);
$third-stop: grayscale($third-stop);
}
@include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
border: 1px solid $border;
border-bottom: 1px solid $border-bottom;
border-radius: 5px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
&:hover:not(:disabled) {
$first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18);
$second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51);
$third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66);
$fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63);
@if $grayscale == true {
$first-stop-hover: grayscale($first-stop-hover);
$second-stop-hover: grayscale($second-stop-hover);
$third-stop-hover: grayscale($third-stop-hover);
$fourth-stop-hover: grayscale($fourth-stop-hover);
}
@include linear-gradient(top, $first-stop-hover 0%,
$second-stop-hover 50%,
$third-stop-hover 50%,
$fourth-stop-hover 100%);
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
@if $grayscale == true {
$inset-shadow-active: grayscale($inset-shadow-active);
}
box-shadow: inset 0 0 20px 0 $inset-shadow-active;
}
}
// Pill Button
@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%);
$inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%);
$stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
$text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
border-radius: 16px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: normal;
line-height: 1;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $lightness: -4.5%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%);
$stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%);
$text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
$text-shadow-hover: grayscale($text-shadow-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
background-clip: padding-box;
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
text-shadow: 0 -1px 1px $text-shadow-hover;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
$border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
$border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
$inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%);
$text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%);
@if $grayscale == true {
$active-color: grayscale($active-color);
$border-active: grayscale($border-active);
$border-bottom-active: grayscale($border-bottom-active);
$inset-shadow-active: grayscale($inset-shadow-active);
$text-shadow-active: grayscale($text-shadow-active);
}
background: $active-color;
border: 1px solid $border-active;
border-bottom: 1px solid $border-bottom-active;
box-shadow: inset 0 0 6px 3px $inset-shadow-active;
text-shadow: 0 -1px 1px $text-shadow-active;
}
}
// Flat Button
@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
}
background-color: $base-color;
border-radius: 3px;
border: 0;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-decoration: none;
background-clip: padding-box;
&:hover:not(:disabled){
$base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
}
background-color: $base-color-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
@if $grayscale == true {
$base-color-active: grayscale($base-color-active);
}
background-color: $base-color-active;
cursor: pointer;
}
}
// Flexible grid
@function flex-grid($columns, $container-columns: $fg-max-columns) {
$width: $columns * $fg-column + ($columns - 1) * $fg-gutter;
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($width / $container-width);
@warn "The flex-grid function is deprecated and will be removed in the next major version release";
}
// Flexible gutter
@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) {
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($gutter / $container-width);
@warn "The flex-gutter function is deprecated and will be removed in the next major version release";
}
@function grid-width($n) {
@return $n * $gw-column + ($n - 1) * $gw-gutter;
@warn "The grid-width function is deprecated and will be removed in the next major version release";
}
@function golden-ratio($value, $increment) {
@return modular-scale($increment, $value, $ratio: $golden);
@warn "The golden-ratio function is deprecated and will be removed in the next major version release. Please use the modular-scale function, instead.";
}
@mixin box-sizing($box) {
@include prefixer(box-sizing, $box, webkit moz spec);
@warn "The box-sizing mixin is deprecated and will be removed in the next major version release. This property can now be used un-prefixed.";
}
-87
View File
@@ -1,87 +0,0 @@
// Bourbon 4.2.6
// http://bourbon.io
// Copyright 2011-2015 thoughtbot, inc.
// MIT License
@import "settings/prefixer";
@import "settings/px-to-em";
@import "settings/asset-pipeline";
@import "functions/assign-inputs";
@import "functions/contains";
@import "functions/contains-falsy";
@import "functions/is-length";
@import "functions/is-light";
@import "functions/is-number";
@import "functions/is-size";
@import "functions/px-to-em";
@import "functions/px-to-rem";
@import "functions/shade";
@import "functions/strip-units";
@import "functions/tint";
@import "functions/transition-property-name";
@import "functions/unpack";
@import "functions/modular-scale";
@import "helpers/convert-units";
@import "helpers/directional-values";
@import "helpers/font-source-declaration";
@import "helpers/gradient-positions-parser";
@import "helpers/linear-angle-parser";
@import "helpers/linear-gradient-parser";
@import "helpers/linear-positions-parser";
@import "helpers/linear-side-corner-parser";
@import "helpers/radial-arg-parser";
@import "helpers/radial-positions-parser";
@import "helpers/radial-gradient-parser";
@import "helpers/render-gradients";
@import "helpers/shape-size-stripper";
@import "helpers/str-to-num";
@import "css3/animation";
@import "css3/appearance";
@import "css3/backface-visibility";
@import "css3/background";
@import "css3/background-image";
@import "css3/border-image";
@import "css3/calc";
@import "css3/columns";
@import "css3/filter";
@import "css3/flex-box";
@import "css3/font-face";
@import "css3/font-feature-settings";
@import "css3/hidpi-media-query";
@import "css3/hyphens";
@import "css3/image-rendering";
@import "css3/keyframes";
@import "css3/linear-gradient";
@import "css3/perspective";
@import "css3/placeholder";
@import "css3/radial-gradient";
@import "css3/selection";
@import "css3/text-decoration";
@import "css3/transform";
@import "css3/transition";
@import "css3/user-select";
@import "addons/border-color";
@import "addons/border-radius";
@import "addons/border-style";
@import "addons/border-width";
@import "addons/buttons";
@import "addons/clearfix";
@import "addons/ellipsis";
@import "addons/font-stacks";
@import "addons/hide-text";
@import "addons/margin";
@import "addons/padding";
@import "addons/position";
@import "addons/prefixer";
@import "addons/retina-image";
@import "addons/size";
@import "addons/text-inputs";
@import "addons/timing-functions";
@import "addons/triangle";
@import "addons/word-wrap";
@import "bourbon-deprecated-upcoming";
-26
View File
@@ -1,26 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-color` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-color(#a60b55 #76cd9c null #e8ae1a);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-left-color: #e8ae1a;
/// border-right-color: #76cd9c;
/// border-top-color: #a60b55;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-color`
@mixin border-color($vals...) {
@include directional-property(border, color, $vals...);
}
-48
View File
@@ -1,48 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-radius` on both corners on the side of a box.
///
/// @param {Number} $radii
/// List of arguments
///
/// @example scss - Usage
/// .element-one {
/// @include border-top-radius(5px);
/// }
///
/// .element-two {
/// @include border-left-radius(3px);
/// }
///
/// @example css - CSS Output
/// .element-one {
/// border-top-left-radius: 5px;
/// border-top-right-radius: 5px;
/// }
///
/// .element-two {
/// border-bottom-left-radius: 3px;
/// border-top-left-radius: 3px;
/// }
///
/// @output `border-radius`
@mixin border-top-radius($radii) {
border-top-left-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-right-radius($radii) {
border-bottom-right-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-bottom-radius($radii) {
border-bottom-left-radius: $radii;
border-bottom-right-radius: $radii;
}
@mixin border-left-radius($radii) {
border-bottom-left-radius: $radii;
border-top-left-radius: $radii;
}
-25
View File
@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-style` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-style(dashed null solid);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-style: solid;
/// border-top-style: dashed;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-style`
@mixin border-style($vals...) {
@include directional-property(border, style, $vals...);
}
-25
View File
@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-width` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-width(1em null 20px);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-width: 20px;
/// border-top-width: 1em;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-width`
@mixin border-width($vals...) {
@include directional-property(border, width, $vals...);
}
-64
View File
@@ -1,64 +0,0 @@
@charset "UTF-8";
/// Generates variables for all buttons. Please note that you must use interpolation on the variable: `#{$all-buttons}`.
///
/// @example scss - Usage
/// #{$all-buttons} {
/// background-color: #f00;
/// }
///
/// #{$all-buttons-focus},
/// #{$all-buttons-hover} {
/// background-color: #0f0;
/// }
///
/// #{$all-buttons-active} {
/// background-color: #00f;
/// }
///
/// @example css - CSS Output
/// button,
/// input[type="button"],
/// input[type="reset"],
/// input[type="submit"] {
/// background-color: #f00;
/// }
///
/// button:focus,
/// input[type="button"]:focus,
/// input[type="reset"]:focus,
/// input[type="submit"]:focus,
/// button:hover,
/// input[type="button"]:hover,
/// input[type="reset"]:hover,
/// input[type="submit"]:hover {
/// background-color: #0f0;
/// }
///
/// button:active,
/// input[type="button"]:active,
/// input[type="reset"]:active,
/// input[type="submit"]:active {
/// background-color: #00f;
/// }
///
/// @require assign-inputs
///
/// @type List
///
/// @todo Remove double assigned variables (Lines 5962) in v5.0.0
$buttons-list: 'button',
'input[type="button"]',
'input[type="reset"]',
'input[type="submit"]';
$all-buttons: assign-inputs($buttons-list);
$all-buttons-active: assign-inputs($buttons-list, active);
$all-buttons-focus: assign-inputs($buttons-list, focus);
$all-buttons-hover: assign-inputs($buttons-list, hover);
$all-button-inputs: $all-buttons;
$all-button-inputs-active: $all-buttons-active;
$all-button-inputs-focus: $all-buttons-focus;
$all-button-inputs-hover: $all-buttons-hover;
-25
View File
@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides an easy way to include a clearfix for containing floats.
///
/// @link http://cssmojo.com/latest_new_clearfix_so_far/
///
/// @example scss - Usage
/// .element {
/// @include clearfix;
/// }
///
/// @example css - CSS Output
/// .element::after {
/// clear: both;
/// content: "";
/// display: table;
/// }
@mixin clearfix {
&::after {
clear: both;
content: "";
display: table;
}
}
-30
View File
@@ -1,30 +0,0 @@
@charset "UTF-8";
/// Truncates text and adds an ellipsis to represent overflow.
///
/// @param {Number} $width [100%]
/// Max-width for the string to respect before being truncated
///
/// @example scss - Usage
/// .element {
/// @include ellipsis;
/// }
///
/// @example css - CSS Output
/// .element {
/// display: inline-block;
/// max-width: 100%;
/// overflow: hidden;
/// text-overflow: ellipsis;
/// white-space: nowrap;
/// word-wrap: normal;
/// }
@mixin ellipsis($width: 100%) {
display: inline-block;
max-width: $width;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
-31
View File
@@ -1,31 +0,0 @@
@charset "UTF-8";
/// Georgia font stack.
///
/// @type List
$georgia: "Georgia", "Cambria", "Times New Roman", "Times", serif;
/// Helvetica font stack.
///
/// @type List
$helvetica: "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
/// Lucida Grande font stack.
///
/// @type List
$lucida-grande: "Lucida Grande", "Tahoma", "Verdana", "Arial", sans-serif;
/// Monospace font stack.
///
/// @type List
$monospace: "Bitstream Vera Sans Mono", "Consolas", "Courier", monospace;
/// Verdana font stack.
///
/// @type List
$verdana: "Verdana", "Geneva", sans-serif;
-27
View File
@@ -1,27 +0,0 @@
/// Hides the text in an element, commonly used to show an image. Some elements will need block-level styles applied.
///
/// @link http://zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement
///
/// @example scss - Usage
/// .element {
/// @include hide-text;
/// }
///
/// @example css - CSS Output
/// .element {
/// overflow: hidden;
/// text-indent: 101%;
/// white-space: nowrap;
/// }
///
/// @todo Remove height argument in v5.0.0
@mixin hide-text($height: null) {
overflow: hidden;
text-indent: 101%;
white-space: nowrap;
@if $height {
@warn "The `hide-text` mixin has changed and no longer requires a height. The height argument will no longer be accepted in v5.0.0";
}
}

Some files were not shown because too many files have changed in this diff Show More