Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e125aec459 | ||
|
|
ee61b38026 | ||
|
|
7e4d25272a
|
||
|
|
d3130c43da
|
||
|
|
70020581fd
|
||
|
|
8cc9ae8df4
|
||
|
|
6971fe2036
|
||
|
|
9f97d5c9d1
|
||
|
|
5343d44ea8
|
||
|
|
76fbf5d65f
|
||
|
|
6b4013f779
|
||
|
|
0438f88c83
|
||
|
|
d0d7200e57
|
||
|
|
78aaa949a3
|
||
|
|
5dbb592946
|
||
|
|
d9aa0418fa
|
||
|
|
9008f2e1af
|
||
|
|
bc240e676b
|
||
|
|
3af928b39d
|
||
|
|
ead9120ae8
|
||
|
|
dca44963e8
|
||
|
|
3c12efe28f
|
||
|
|
e98588b317
|
||
|
|
0e6c297fe4
|
||
|
|
3e4181f18e
|
||
|
|
2f4cd08c60
|
||
|
|
ba2b73a287
|
||
|
|
4e285694d1
|
||
|
|
9700465927
|
||
|
|
1ab4101ac0
|
||
|
|
f0bc70553a
|
||
|
|
3eac0ee794
|
||
|
|
2c80b59d71
|
||
|
|
9146c9880a
|
||
|
|
cabd42f2b4
|
||
|
|
fbd4693035
|
||
|
|
c5670c09bb
|
||
|
|
4e74d1cd79
|
||
|
|
4c8360dbb5
|
||
|
|
c0adc253b4
|
||
|
|
be3e06aac1
|
||
|
|
992c927490
|
||
|
|
ef3b02e68c
|
||
|
|
1c556457c7
|
||
|
|
e49a8b0adf
|
||
|
|
81c3e426e7
|
||
|
|
c90de79a34 | ||
|
|
df404f5f63
|
||
|
|
00153656f1
|
||
|
|
aa920aee27
|
||
|
|
7b8c936559
|
||
|
|
17c18ed1c9
|
||
|
|
274e3b359b
|
||
|
|
73c98eb2d1
|
||
|
|
022e882001
|
||
|
|
dc08512397
|
||
|
|
6c1ab28e75
|
||
|
|
2796709624
|
||
|
|
d2edcd7fd5
|
||
|
|
76272530ec
|
||
|
|
a514601897
|
||
|
|
935e05a56a
|
||
|
|
a72e2bed63
|
||
|
|
679f0adbae
|
||
|
|
791f6e716f
|
||
|
|
9a5bc0a274
|
||
|
|
dca02976a7
|
||
|
|
6665b5c183
|
||
|
|
55afcca955
|
||
|
|
7ffc947f1a
|
||
|
|
0eeed9c7d9
|
||
|
|
253473daed
|
||
|
|
9321cd4ebb
|
||
|
|
faffa68794
|
||
|
|
a6ee808a1d
|
||
|
|
5150cc32eb
|
||
|
|
42d5f6bc89
|
||
|
|
d2fe37403f
|
||
|
|
f6c2b06d8a
|
||
|
|
b6c5648690
|
||
|
|
062b0e6188
|
||
|
|
c83b68405f
|
||
|
|
97552b30c3
|
||
|
|
1c23e79c59
|
||
|
|
b70c65868b
|
||
|
|
1614194d76
|
||
|
|
7bca46384e
|
||
|
|
03c7f4d0ad
|
||
|
|
da6c5bf5be
|
||
|
|
2e0648be8e
|
||
|
|
404ccaeb20
|
||
|
|
7300e0003c
|
||
|
|
8c55202b42
|
||
|
|
65977bfbae
|
||
|
|
74d52a0c61
|
||
|
|
0fae510207
|
||
|
|
1a8d3cb332
|
||
|
|
ca5a7e3de9
|
||
|
|
fa5489ccfc
|
||
|
|
502babf7b0
|
||
|
|
47f6cd38cd
|
||
|
|
0f10d84a59
|
||
|
|
cb71586138
|
||
|
|
58bd27a082
|
||
|
|
7eb1bdeec6
|
||
|
|
674e89c8c3
|
||
|
|
62a0925586
|
||
|
|
4f4ea95c06
|
||
|
|
2ede271c65
|
||
|
|
692b2c4d11
|
||
|
|
948bcb62ff
|
||
|
|
7607b639b0 | ||
|
|
2e8ec41115 | ||
|
|
80e8e4f7da | ||
|
|
357a9d43e3 | ||
|
|
a464a73a0e | ||
|
|
38b3ce2dc8 | ||
|
|
37de3a095d | ||
|
|
82961568b8 | ||
|
|
3849e161e5 | ||
|
|
43241c2679 | ||
|
|
3bfd51061e | ||
|
|
781cf8825b | ||
|
|
079b522540 | ||
|
|
471aa95c34 | ||
|
|
ac56b1dc61 | ||
|
|
82fd9e5ad1 | ||
|
|
92a454a2cf | ||
|
|
0012c92c4a | ||
|
|
0e8af5712b | ||
|
|
51e97232c5 | ||
|
|
7e2491cd7b | ||
|
|
cd79d5cf25 | ||
|
|
184c772b57 | ||
|
|
6e2978492b | ||
|
|
0d0246b12b | ||
|
|
62888d4473 | ||
|
|
3f0b6f2d26 | ||
|
|
5846d46e0c | ||
|
|
1454987fcf | ||
|
|
2ba04b92d7 | ||
|
|
6a7493a7be | ||
|
|
565b2113a5 | ||
|
|
128515a9a7 | ||
|
|
038c3b6466 | ||
|
|
fa5953a231 | ||
|
|
5aef8a0f11 | ||
|
|
356c4557bb | ||
|
|
5ff9d17850 | ||
|
|
ccbb1886af | ||
|
|
65d177f149 | ||
|
|
7cf82753ff | ||
|
|
c4d399ccb0 | ||
|
|
521bc63c22 | ||
|
|
b02aebf8c2 | ||
|
|
4c2421121f | ||
|
|
6e1173cfcf | ||
|
|
b0992702b9 | ||
|
|
1742f4604a | ||
|
|
10fafd7c23 | ||
|
|
c838883e69 | ||
|
|
384372e6c8 | ||
|
|
74c7628474 | ||
|
|
bd43c4d9c3 | ||
|
|
2e004b6048 | ||
|
|
ab921d2523 | ||
|
|
9ac5143228 | ||
|
|
2bea6397c6 | ||
|
|
ea97752867 | ||
|
|
a12dcfc86f | ||
|
|
b89db56c48 | ||
|
|
6b603a1a8c | ||
|
|
0caadb6f41
|
||
|
|
ff5aa4c12c | ||
|
|
0967d7f94a | ||
|
|
26e385b4c0
|
||
|
|
5cc3003e47
|
||
|
|
3e6187dba9
|
||
|
|
7407419e56
|
||
|
|
93824964ed | ||
|
|
abecf0d4ce | ||
|
|
d6d985a172 | ||
|
|
71cab02b3e | ||
|
|
3926776adc | ||
|
|
3b7cd0a42e | ||
|
|
f85bcb3ef6 | ||
|
|
0f9809c290 | ||
|
|
2d22d5cff1 | ||
|
|
ab2dc10e35 | ||
|
|
34b72625a5 | ||
|
|
a3567ec338 | ||
|
|
7576cd859a | ||
|
|
d82c33d774 | ||
|
|
d57ed19c42 | ||
|
|
bee99b4c55 | ||
|
|
fe44927a62 | ||
|
|
8f81616ca8 | ||
|
|
15f539f4d4 | ||
|
|
3b6dfbda49 | ||
|
|
dd08290587 | ||
|
|
b8ed46cbea | ||
|
|
8d7419b666 | ||
|
|
830ec073bf | ||
|
|
7d6cb2b660 | ||
|
|
1d6d6ee228 | ||
|
|
a20ec8a49e | ||
|
|
831ebe3b54 | ||
|
|
ea3c815a39 | ||
|
|
85f707401d | ||
|
|
0dbfbf707f | ||
|
|
a18b1d726e | ||
|
|
f8e3454250 | ||
|
|
184ef1ec36 | ||
|
|
99b07399b4 | ||
|
|
e46abe175f | ||
|
|
48cd9c1a2a | ||
|
|
07d1a3d3b4 | ||
|
|
44ea1e5b49 | ||
|
|
6fdb23531b | ||
|
|
116201e232 | ||
|
|
a78830f805 | ||
|
|
3f198f8360 | ||
|
|
f693373a34 | ||
|
|
0af62f47e6 | ||
|
|
a673843a63 | ||
|
|
023a2db01a | ||
|
|
979f956e7e | ||
|
|
5f6566a6fd | ||
|
|
6d98d2c6da | ||
|
|
9fa9cb0ca2 | ||
|
|
ba9c757cdc | ||
|
|
d2b2b89593 | ||
|
|
6aa4747d3e | ||
|
|
5eec7d2bf6 | ||
|
|
8028f14387 | ||
|
|
daba5340f7 | ||
|
|
a82e14961c | ||
|
|
6c9ae7e126 | ||
|
|
a3c84f9a8f | ||
|
|
7aa3cd7f75 | ||
|
|
58ed6098c4 | ||
|
|
16a36a3d26 | ||
|
|
9d1cefeaab | ||
|
|
357600de8f | ||
|
|
fe699c7918 | ||
|
|
4edaa0687d | ||
|
|
f8ebae044a | ||
|
|
9e9539472c | ||
|
|
b57e0ee75b | ||
|
|
65e34a1634 | ||
|
|
6f32a6ef1a | ||
|
|
d3468a109c | ||
|
|
8f82b81434 | ||
|
|
653dc55d85 | ||
|
|
dda469ff21 | ||
|
|
3515e178cb | ||
|
|
5fd5c92390 | ||
|
|
e3ae34a932 | ||
|
|
423022b8bc | ||
|
|
fce3995800 | ||
|
|
67625a9317 | ||
|
|
35e1a788f0 | ||
|
|
dd68c112b0 | ||
|
|
2c7c496862 | ||
|
|
73c943bb97 | ||
|
|
beda5e67c0 | ||
|
|
357c81ba07 | ||
|
|
acd8801d33 | ||
|
|
5c57ea3b28 | ||
|
|
0e73f57da1 | ||
|
|
1f18c7d1f6 | ||
|
|
2a76eaee8e | ||
|
|
3b8cfd41e3 | ||
|
|
09cc66c75c | ||
|
|
7947b3a88c | ||
|
|
3355295aa3 | ||
|
|
87e0030be8 | ||
|
|
6d9d068268 | ||
|
|
276af04945 | ||
|
|
8d9c5bb246 | ||
|
|
59f26adf68 | ||
|
|
5995988a9b | ||
|
|
fe714bf473 | ||
|
|
68747d493c | ||
|
|
184b186b85 | ||
|
|
af47249492 | ||
|
|
e22ae1e66a | ||
|
|
bf1507b624 | ||
|
|
b5378a6626 | ||
|
|
9cac029e58 | ||
|
|
8117229926 | ||
|
|
04b75b8218 | ||
|
|
89fca5c40a | ||
|
|
ca410736f7 | ||
|
|
2ca8bf1483 | ||
|
|
35393827a9 | ||
|
|
ea84d1889d | ||
|
|
bc41a21f23 | ||
|
|
e48180ac10 | ||
|
|
e47a5477f9 | ||
|
|
e944a994a7 | ||
|
|
6535b49551 | ||
|
|
2cb8586c94 | ||
|
|
ec1cebdd4c | ||
|
|
af5a3a64ed | ||
|
|
7b94eef448 | ||
|
|
c8067122d5 |
+6
-1
@@ -1,4 +1,5 @@
|
||||
html/
|
||||
html_demo/
|
||||
build/
|
||||
firmware/
|
||||
espfs/mkespfsimage/*.o
|
||||
@@ -10,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+65
-9
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.7)
|
||||
# Do not attempt to build it with cmake, use make instead. #
|
||||
###################################################################
|
||||
|
||||
project(esp_vt100_firmware)
|
||||
project(ESPTerm)
|
||||
|
||||
set(CMAKE_CXX_STANDARD GNU99)
|
||||
|
||||
@@ -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
|
||||
@@ -117,16 +119,42 @@ set(SOURCE_FILES
|
||||
user/cgi_sockets.h
|
||||
user/ansi_parser_callbacks.c
|
||||
user/ansi_parser_callbacks.h
|
||||
user/user_main.h
|
||||
user/wifimgr.c
|
||||
user/wifimgr.h
|
||||
user/persist.c
|
||||
user/persist.h
|
||||
include/helpers.h
|
||||
user/syscfg.c
|
||||
user/syscfg.h)
|
||||
user/syscfg.h
|
||||
user/ascii.h
|
||||
user/sgr.h
|
||||
user/apars_utf8.c
|
||||
user/apars_utf8.h
|
||||
user/apars_logging.h
|
||||
user/version.h
|
||||
user/apars_csi.c
|
||||
user/apars_csi.h
|
||||
user/apars_short.c
|
||||
user/apars_short.h
|
||||
user/apars_string.c
|
||||
user/apars_string.h
|
||||
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/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)
|
||||
@@ -138,13 +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"
|
||||
-DGIT_HASH="blabla"
|
||||
-DESPFS_HEATSHRINK)
|
||||
-DESP_LANG="en"
|
||||
|
||||
add_executable(esp_vt100_firmware ${SOURCE_FILES})
|
||||
-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
|
||||
-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})
|
||||
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@@ -62,11 +62,22 @@ 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 -DHTTPD_MAX_BACKLOG_SIZE=8192 -DADMIN_PASSWORD=$(ADMIN_PASSWORD) \
|
||||
-DGIT_HASH='"$(shell git rev-parse --short HEAD)"'
|
||||
-Wno-address -Wno-unused
|
||||
|
||||
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)
|
||||
endif
|
||||
|
||||
# linker flags used to generate the main object file
|
||||
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
|
||||
@@ -146,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)
|
||||
|
||||
@@ -165,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)
|
||||
@@ -183,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 $@
|
||||
|
||||
@@ -1,76 +1,171 @@
|
||||
# ESPTerm
|
||||
|
||||
ESP8266 Wireless Terminal Emulator project
|
||||
**ESPTerm is a VT100-like terminal emulator running on the ESP8266 WiFi chip.**
|
||||
|
||||
This project is based on SpriteTM's esphttpd and libesphttpd, forked by MightyPork to
|
||||
[MightyPork/esphttpd](https://github.com/MightyPork/esphttpd) and
|
||||
[MightyPork/libesphttpd](https://github.com/MightyPork/libesphttpd) respectively.
|
||||
![Photo][photo-hw]<br>
|
||||
*Fig 1: Breadboard adapter developed for ESPTerm*
|
||||
|
||||
Those forks include improvements not available upstream.
|
||||
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 compatible with ncurses.
|
||||
|
||||
## Goals
|
||||
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.
|
||||
|
||||
The project aims to be a wireless terminal emulator that'll work with the likes of
|
||||
Arduino, AVR, PIC, STM8, STM32, mbed etc, anything with UART, even your USB-serial dongle will work.
|
||||
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])
|
||||
|
||||
Connect it to the master device via UART and use the terminal on the built-in web page for debug logging,
|
||||
remote control etc. It works like a simple LCD screen, in a way.
|
||||
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.
|
||||
|
||||
It lets you make simple UI (manipulating the screen with ANSI sequences) and receive input from buttons on
|
||||
the webpage (and keyboard on PC). There is some rudimentary touch input as well.
|
||||
With ESPTerm, you can add remote access via WiFi to any embeded project, all you need is
|
||||
UART and some imagination!
|
||||
|
||||
The screen size is adjustable up to 25x80 (via a special control sequence) and uses 16 standard colors
|
||||
(8 dark and 8 bright). Both default size and colors can be configured in the settings.
|
||||
## Try it online
|
||||
|
||||
## Project status
|
||||
You can try the web user interface here: [espterm.github.io][demo-term]
|
||||
|
||||
*A little buggy, but mostly okay! There are many features and fixes planned, but it should be fairly usable already.*
|
||||
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 (and sometimes in between for testing; the version currently being show-cased
|
||||
can be read on the About page of the demo).
|
||||
|
||||
- We have a working **2-way terminal** (UART->ESP->Browser and vice versa) with real-time update via websocket.
|
||||
### 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 (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...
|
||||
- **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
|
||||
- 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
|
||||
- **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)
|
||||
|
||||
This means that what you type in the browser is sent to UART0 and what's received on UART0 is processed by the
|
||||
ANSI parser and applied to the internal screen buffer. You'll also immediately see the changes in your browser.
|
||||
There's a filter in the way that discards garbage characters (like unicode and most ASCII outside 32-126).
|
||||
|
||||
For a quick test, try connecting the UART0 Rx and Tx with a piece of wire to make a loopback interface.
|
||||
*NOTE: Use the bare module, not something like LoLin or NodeMCU with a FTDI, it'll interfere*.
|
||||
You should then directly see what you type & can even try some ANSI sequences, right from the browser.
|
||||
|
||||
- All ANSI sequences that make sense, as well as control codes like Backspace and CR / LF are implemented.
|
||||
Set colors with your usual `\e[31;1m` etc (see Wikipedia). `\e` is the ASCII code 27 (ESC).
|
||||
|
||||
Arrow keys generate ANSI sequences, ESC sends literal ASCII code 27 etc. Almost everything can be input
|
||||
straight from the browser.
|
||||
## Bugs? Ideas?
|
||||
|
||||
- Buttons pressed in the browser UI send ASCII codes 1..5. Mouse clicks are sent as `\e[<row>;<col>M`.
|
||||
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)**
|
||||
|
||||
- There's a built-in WiFi config page and a Help page with a list of all supported ANSI sequences and other details.
|
||||
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
|
||||
|
||||
To run ESPTerm on your ESP8266, either build it yourself from source using `xtensa-lx106-elf-gcc`
|
||||
(and the included Makefile), or download pre-built binaries from the [GitHub releases section][releases].
|
||||
Flash the binaries using [esptool][esptool].
|
||||
|
||||
### Pins
|
||||
|
||||
- Pin GPIO2 is used for debug messages at 115200 baud, 8 bit, no parity.
|
||||
- Pins Rx and Tx are used for the main communication UART, parameters of which can be set on the system config page.
|
||||
Connect your USB-serial dongle or application microcontroller here.
|
||||
|
||||
### Setup
|
||||
|
||||
- When flashed for the first time, ESPTerm wipes any possible previous WiFi configuration, because it implements its own WiFi
|
||||
config manager with many additional features.
|
||||
- It should start in AP mode, the default SSID being `TERM-MACADR` with `MACADR` being three unique bytes from the MAC
|
||||
address / Device ID as ASCII hex.
|
||||
- Connect to the AP via a smartphone or laptop and configure WiFi as desired. If a captive portal page does not open,
|
||||
try 192.168.4.1 in your web browser.
|
||||
|
||||
### Rescue from messed up config
|
||||
|
||||
It can happen that some changes to the WiFi or network config make the module inaccessible.
|
||||
|
||||
- To re-enable the built-in AP, hold the BOOT (GPIO0 -> GND) button for about 1 s, until the blue LED starts flashing.
|
||||
Then quickly release the button.
|
||||
- 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 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 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 you would get after a clean install.
|
||||
|
||||
## Research resources
|
||||
|
||||
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 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.
|
||||
|
||||
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.
|
||||
|
||||
### Installation for development
|
||||
|
||||
- Clone this project with `--recursive`, or afterwards run `git submodule init` and `git submodule update`.
|
||||
|
||||
- Install [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk/) and build it with
|
||||
`make toolchain esptool libhal STANDALONE=n`.
|
||||
|
||||
- Install [esp-open-sdk][opensdk] and build it with
|
||||
`make toolchain esptool libhal STANDALONE=n`.
|
||||
Make sure the `xtensa-lx106-elf/bin` folder is on $PATH.
|
||||
|
||||
- Install [esptool](https://github.com/espressif/esptool) (it's in the Arch community repo and on AUR, too)
|
||||
|
||||
- Install [esptool][esptool] (it's in the Arch community repo and on AUR, too)
|
||||
- Set up udev rules so you have access to ttyUSB0 without root, eg:
|
||||
|
||||
```
|
||||
KERNEL=="tty[A-Z]*[0-9]*", GROUP="uucp", MODE="0666"
|
||||
```
|
||||
|
||||
- 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.
|
||||
@@ -79,21 +174,35 @@ 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 Makefile should automatically build the parser and web resources for you when you run `make`.
|
||||
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
|
||||
[esptool]: https://github.com/espressif/esptool
|
||||
[opensdk]: https://github.com/pfalcon/esp-open-sdk/
|
||||
|
||||
[demo-help]: https://espterm.github.io/help.html
|
||||
[demo-wifi]: https://espterm.github.io/cfg_wifi.html
|
||||
[demo-network]: https://espterm.github.io/cfg_network.html
|
||||
[demo-term]: https://espterm.github.io/term.html
|
||||
|
||||
[xterm-compare]: https://espterm.github.io/docs/espterm-xterm.html
|
||||
[photo-hw]: https://espterm.github.io/docs/espterm-hw-small.jpg
|
||||
[resources]: https://espterm.github.io/docs/index.html
|
||||
[vttest]: http://invisible-island.net/vttest/
|
||||
|
||||
@@ -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
-13
@@ -3,19 +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
|
||||
cp -r front-end/out html
|
||||
|
||||
@@ -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,5 +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=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_LOGBUF_SIZE=1024 \
|
||||
-mforce-l32 \
|
||||
-DUSE_OPTIMIZE_PRINTF=1
|
||||
Submodule
+1
Submodule front-end added at 9aae724df2
@@ -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 +0,0 @@
|
||||
pages/_test_env.php
|
||||
@@ -1,74 +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
|
||||
*/
|
||||
return [
|
||||
'term_title' => 'ESPTerm local debug',
|
||||
|
||||
'btn1' => '1',
|
||||
'btn2' => '2',
|
||||
'btn3' => '3',
|
||||
'btn4' => '',
|
||||
'btn5' => '5',
|
||||
'labels_seq' => 'TESPTerm local debug1235',
|
||||
|
||||
'screenData' => 'HELLOxNRE3',//'\u000b\u0001\u001b\u0001\u0001\u0001\u0001\u0001\f\u0005\u0001\u0010\u0003HELLOx\u0002\u000b\u0001\u0001N\u0001RE\u00023\u0001', //,
|
||||
/*'{
|
||||
"w": 26, "h": 10,
|
||||
"x": 10, "y": 5,
|
||||
"cv": 1, "fg": 10, "bg": 2,
|
||||
"screen": ""
|
||||
}',//"70 t259"*/
|
||||
|
||||
'parser_tout_ms' => 10,
|
||||
|
||||
'opmode' => '2',
|
||||
'sta_enable' => '0',
|
||||
'ap_enable' => '1',
|
||||
|
||||
'tpw' => '60',
|
||||
'ap_channel' => '7',
|
||||
'ap_ssid' => 'ESP-123456',
|
||||
'ap_password' => 'Passw0rd!',
|
||||
'ap_hidden' => '0',
|
||||
|
||||
'sta_ssid' => 'Chlivek',
|
||||
'sta_password' => 'windows XP is The Best',
|
||||
'sta_active_ip' => '1.2.3.4',
|
||||
'sta_active_ssid' => 'Chlivek',
|
||||
|
||||
'vers_fw' => '1.2.3',
|
||||
'date' => date('Y-m-d'),
|
||||
'time' => date('G:i'),
|
||||
'vers_httpd' => '4.5.6',
|
||||
'vers_sdk' => '1.52',
|
||||
'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' => 'ab:cd:ef:01:23:45',
|
||||
'ap_mac' => '01:23:45:ab:cd:ef',
|
||||
|
||||
'term_width' => '26',
|
||||
'term_height' => '10',
|
||||
'default_bg' => '0',
|
||||
'default_fg' => '7',
|
||||
|
||||
'uart_baud' => 115200,
|
||||
'uart_stopbits' => 1,
|
||||
'uart_parity' => 2,
|
||||
|
||||
'theme' => 5,
|
||||
];
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
define("ESP_IP", "192.168.0.19");
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
define("ESP_IP", "192.168.0.19");
|
||||
@@ -1,46 +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');
|
||||
|
||||
// ajax API
|
||||
|
||||
return $pages;
|
||||
@@ -1,71 +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('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";
|
||||
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 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;
|
||||
}
|
||||
@@ -1,37 +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;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
foreach($_pages as $_k => $p) {
|
||||
if ($p->bodyclass == 'api') continue;
|
||||
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 = __DIR__ . '/../html/' . $_k . '.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
@@ -1,22 +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',
|
||||
];
|
||||
|
||||
$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 +0,0 @@
|
||||
/out/
|
||||
Binary file not shown.
@@ -1,90 +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.*?truetype'\);\n\}" "$OUTPUT_DIR/fontello-embedded.css" \
|
||||
| sed 's/\x0//g' >> "$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"
|
||||
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 |
@@ -1,53 +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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
require __DIR__ . '/pages/_head.php';
|
||||
$_pf = __DIR__ . '/pages/'.$_GET['page'].'.php';
|
||||
if (file_exists($_pf)) {
|
||||
$f = file_get_contents($_pf);
|
||||
|
||||
if (DEBUG)
|
||||
$str = tplSubs($f, require(__DIR__ . '/_debug_replacements.php'));
|
||||
else $str = $f;
|
||||
|
||||
// special symbols
|
||||
$str = str_replace('\,', ' ', $str);
|
||||
$str = preg_replace('/(?<=\w)~(?=\w)/', ' ', $str);
|
||||
|
||||
include_str($str);
|
||||
} else {
|
||||
echo "404";
|
||||
}
|
||||
|
||||
require __DIR__ . '/pages/_tail.php';
|
||||
-1560
File diff suppressed because it is too large
Load Diff
@@ -1,125 +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').forEach(function(x) {
|
||||
var h = x.querySelector('h2');
|
||||
|
||||
var hdl = function() {
|
||||
$(x).toggleClass('expanded');
|
||||
};
|
||||
$(h).on('click', hdl).on('keypress', cr(hdl));
|
||||
});
|
||||
|
||||
qsa('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) {
|
||||
qsa('.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);
|
||||
}
|
||||
});
|
||||
@@ -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 = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '='
|
||||
};
|
||||
|
||||
chibi.htmlEscape = function(string) {
|
||||
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
};
|
||||
|
||||
// Set Chibi's global namespace here ($)
|
||||
w.$ = chibi;
|
||||
}());
|
||||
@@ -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+'?'; }
|
||||
@@ -1,41 +0,0 @@
|
||||
/** Module for toggling a modal overlay */
|
||||
(function () {
|
||||
var modal = {};
|
||||
|
||||
modal.show = function (sel) {
|
||||
var $m = $(sel);
|
||||
$m.removeClass('hidden visible');
|
||||
setTimeout(function () {
|
||||
$m.addClass('visible');
|
||||
}, 1);
|
||||
};
|
||||
|
||||
modal.hide = function (sel) {
|
||||
var $m = $(sel);
|
||||
$m.removeClass('visible');
|
||||
setTimeout(function () {
|
||||
$m.addClass('hidden');
|
||||
}, 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;
|
||||
})();
|
||||
@@ -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 = {});
|
||||
@@ -1,368 +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,
|
||||
bold: false,
|
||||
suppress: false, // do not turn on in blink interval (for safe moving)
|
||||
hidden: false // do not show
|
||||
};
|
||||
|
||||
var screen = [];
|
||||
var blinkIval;
|
||||
|
||||
/** Clear screen */
|
||||
function _clear() {
|
||||
for (var i = W*H-1; i>=0; i--) {
|
||||
var cell = screen[i];
|
||||
cell.t = ' ';
|
||||
cell.bg = cursor.bg;
|
||||
cell.fg = cursor.fg;
|
||||
cell.bold = false;
|
||||
_draw(cell);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set text and color at XY */
|
||||
function _cellAt(y, x) {
|
||||
return screen[y*W+x];
|
||||
}
|
||||
|
||||
/** Get cell under cursor */
|
||||
function _curCell() {
|
||||
return screen[cursor.y*W + cursor.x];
|
||||
}
|
||||
|
||||
/** Enable or disable cursor visibility */
|
||||
function _cursorEnable(enable) {
|
||||
cursor.hidden = !enable;
|
||||
cursor.a &= enable;
|
||||
_draw(_curCell());
|
||||
}
|
||||
|
||||
/** 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());
|
||||
}
|
||||
|
||||
/** Update cell on display. inv = invert (for cursor) */
|
||||
function _draw(cell, inv) {
|
||||
if (typeof inv == 'undefined') {
|
||||
inv = cursor.a && cursor.x == cell.x && cursor.y == cell.y;
|
||||
}
|
||||
|
||||
var e = cell.e, fg, bg;
|
||||
// Colors
|
||||
fg = inv ? cell.bg : cell.fg;
|
||||
bg = inv ? cell.fg : cell.bg;
|
||||
// Update
|
||||
e.innerText = (cell.t + ' ')[0];
|
||||
e.className = 'fg' + fg + ' bg' + bg + (cell.bold ? ' bold' : '');
|
||||
}
|
||||
|
||||
/** 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 e, cell, scr = qs('#screen');
|
||||
|
||||
// Empty the screen node
|
||||
while (scr.firstChild) scr.removeChild(scr.firstChild);
|
||||
|
||||
screen = [];
|
||||
|
||||
for(var i = 0; i < W*H; i++) {
|
||||
e = mk('span');
|
||||
|
||||
(function() {
|
||||
var x = i % W;
|
||||
var y = Math.floor(i / W);
|
||||
e.addEventListener('click', function () {
|
||||
Input.onTap(y, x);
|
||||
});
|
||||
})();
|
||||
|
||||
/* End of line */
|
||||
if ((i > 0) && (i % W == 0)) {
|
||||
scr.appendChild(mk('br'));
|
||||
}
|
||||
/* The cell */
|
||||
scr.appendChild(e);
|
||||
|
||||
cell = {
|
||||
t: ' ',
|
||||
fg: cursor.fg,
|
||||
bg: cursor.bg,
|
||||
e: e,
|
||||
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.a = false;
|
||||
}
|
||||
|
||||
if (!cursor.suppress) {
|
||||
_draw(_curCell(), cursor.a);
|
||||
}
|
||||
}, 500);
|
||||
inited = true;
|
||||
}
|
||||
|
||||
/** Decode two-byte number */
|
||||
function parse2B(s, i) {
|
||||
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127;
|
||||
}
|
||||
|
||||
var SEQ_SET_COLOR = 1;
|
||||
var SEQ_REPEAT = 2;
|
||||
|
||||
function _load_content(str) {
|
||||
var i = 0, ci = 0, j, jc, num, num2, t = ' ', fg, bg, bold, cell;
|
||||
|
||||
if (!inited) _init();
|
||||
|
||||
// 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
|
||||
cursorSet(num, num2);
|
||||
// console.log("Cursor at ",num, num2);
|
||||
|
||||
// Attributes
|
||||
num = parse2B(str, i); i += 2; // fg bg bold hidden
|
||||
cursor.fg = num & 0x0F;
|
||||
cursor.bg = (num & 0xF0) >> 4;
|
||||
cursor.bold = !!(num & 0x100);
|
||||
cursor.hidden = !(num & 0x200);
|
||||
// console.log("FG ",cursor.fg, ", BG ", cursor.bg,", BOLD ", cursor.bold, ", HIDE ", cursor.hidden);
|
||||
|
||||
fg = cursor.fg;
|
||||
bg = cursor.bg;
|
||||
bold = cursor.bold;
|
||||
|
||||
// Here come the content
|
||||
while(i < str.length && ci<W*H) {
|
||||
|
||||
j = str[i++];
|
||||
jc = j.charCodeAt(0);
|
||||
if (jc == SEQ_SET_COLOR) {
|
||||
num = parse2B(str, i); i += 2;
|
||||
fg = num & 0x0F;
|
||||
bg = (num & 0xF0) >> 4;
|
||||
bold = !!(num & 0x100);
|
||||
// console.log("Switch to ",fg,bg,bold);
|
||||
}
|
||||
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.bold = bold;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cell = screen[ci++];
|
||||
// Unique cell character
|
||||
t = cell.t = j;
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
cell.bold = bold;
|
||||
// console.log("Symbol ", j);
|
||||
}
|
||||
}
|
||||
|
||||
_drawAll();
|
||||
}
|
||||
|
||||
function _load_labels(str) {
|
||||
var pieces = str.split('\x01');
|
||||
qs('h1').textContent = pieces[0];
|
||||
qsa('#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) : " ";
|
||||
x.style.opacity = s.length > 0 ? 1 : 0.2;
|
||||
});
|
||||
}
|
||||
|
||||
/** Load screen content from a binary sequence (new) */
|
||||
function load(str) {
|
||||
var content = str.substr(1);
|
||||
switch(str.charAt(0)) {
|
||||
case 'S':
|
||||
_load_content(content);
|
||||
break;
|
||||
case 'T':
|
||||
_load_labels(content);
|
||||
break;
|
||||
default:
|
||||
console.warn("Bad data message type, ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
load: load, // full load (string)
|
||||
};
|
||||
})();
|
||||
|
||||
/** Handle connections */
|
||||
var Conn = (function() {
|
||||
var ws;
|
||||
|
||||
function onOpen(evt) {
|
||||
console.log("CONNECTED");
|
||||
}
|
||||
|
||||
function onClose(evt) {
|
||||
console.warn("SOCKET CLOSED, code "+evt.code+". Reconnecting...");
|
||||
setTimeout(function() {
|
||||
init();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onMessage(evt) {
|
||||
try {
|
||||
console.log("RX: ", evt.data);
|
||||
// Assume all our messages are screen updates
|
||||
Screen.load(evt.data);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
function doSend(message) {
|
||||
console.log("TX: ", message);
|
||||
if (!ws) return; // for dry testing
|
||||
if (ws.readyState != 1) {
|
||||
console.error("Socket not ready");
|
||||
return;
|
||||
}
|
||||
if (typeof message != "string") {
|
||||
message = JSON.stringify(message);
|
||||
}
|
||||
ws.send(message);
|
||||
}
|
||||
|
||||
function init() {
|
||||
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);
|
||||
|
||||
showPage();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
ws: null,
|
||||
init: init,
|
||||
send: doSend
|
||||
};
|
||||
})();
|
||||
|
||||
/** User input */
|
||||
var Input = (function() {
|
||||
function sendStrMsg(str) {
|
||||
Conn.send("STR:"+str);
|
||||
}
|
||||
|
||||
function sendPosMsg(y, x) {
|
||||
Conn.send("TAP:"+y+','+x);
|
||||
}
|
||||
|
||||
function sendBtnMsg(n) {
|
||||
Conn.send("BTN:"+n);
|
||||
}
|
||||
|
||||
function init() {
|
||||
window.addEventListener('keypress', function(e) {
|
||||
var code = +e.which;
|
||||
if (code >= 32 && code < 127) {
|
||||
var ch = String.fromCharCode(code);
|
||||
//console.log("Typed ", ch, "code", code, e);
|
||||
sendStrMsg(ch);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', function(e) {
|
||||
var code = e.keyCode;
|
||||
//console.log("Down ", code, e);
|
||||
switch(code) {
|
||||
case 8: sendStrMsg('\x08'); break;
|
||||
case 10:
|
||||
case 13: sendStrMsg('\x0d\x0a'); break;
|
||||
case 27: sendStrMsg('\x1b'); break; // this allows to directly enter control sequences
|
||||
case 37: sendStrMsg('\x1b[D'); break;
|
||||
case 38: sendStrMsg('\x1b[A'); break;
|
||||
case 39: sendStrMsg('\x1b[C'); break;
|
||||
case 40: sendStrMsg('\x1b[B'); break;
|
||||
}
|
||||
});
|
||||
|
||||
qsa('#buttons button').forEach(function(s) {
|
||||
s.addEventListener('click', function() {
|
||||
sendBtnMsg(+this.dataset['n']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onTap: sendPosMsg,
|
||||
sendString: sendStrMsg,
|
||||
};
|
||||
})();
|
||||
|
||||
window.termInit = function () {
|
||||
Conn.init();
|
||||
Input.init();
|
||||
};
|
||||
@@ -1,123 +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() {
|
||||
try {
|
||||
return JSON.parse(e);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,160 +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 .x-passwd').html(e(password));
|
||||
$('#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() {
|
||||
$.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 = {});
|
||||
@@ -1,163 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'appname' => 'ESPTerm',
|
||||
|
||||
'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',
|
||||
|
||||
'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.explain_initials' => '
|
||||
Those are the initial settings used after ESPTerm powers on.
|
||||
The selected colors will also be used after receiving a
|
||||
screen- or attributes-reset command. Those settings will be
|
||||
applied immediately after saving to preview the changes live.',
|
||||
|
||||
'term.example' => 'Default colors preview',
|
||||
|
||||
'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',
|
||||
|
||||
// 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' => '🔒',
|
||||
'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:',
|
||||
];
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Packing js..."
|
||||
|
||||
cat jssrc/chibi.js \
|
||||
jssrc/utils.js \
|
||||
jssrc/modal.js \
|
||||
jssrc/notif.js \
|
||||
jssrc/appcommon.js \
|
||||
jssrc/lang.js \
|
||||
jssrc/wifi.js \
|
||||
jssrc/term.js > js/app.js
|
||||
@@ -1,20 +0,0 @@
|
||||
<nav id="menu">
|
||||
<div id="brand" tabindex=0><?= tr('appname') ?></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>
|
||||
@@ -1,31 +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 ?>;</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> <span class="list"></span>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
© Ondřej Hruška, 2016-2017
|
||||
<<a href="mailto:ondra@ondrovo.com">ondra@ondrovo.com</a>>
|
||||
</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 IoT 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>
|
||||
@@ -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"> (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"> 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>
|
||||
@@ -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"> (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"> 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>
|
||||
@@ -1,142 +0,0 @@
|
||||
<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> <!--
|
||||
--><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> <!--
|
||||
--><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%">
|
||||
<input class="short" type="text" name="btn2" id="btn2" value="%h:btn2%">
|
||||
<input class="short" type="text" name="btn3" id="btn3" value="%h:btn3%">
|
||||
<input class="short" type="text" name="btn4" id="btn4" value="%h:btn4%">
|
||||
<input class="short" type="text" name="btn5" id="btn5" value="%h:btn5%">
|
||||
</div>
|
||||
|
||||
<div class="Row">
|
||||
<label for="parser_tout_ms"><?= tr('term.parser_tout_ms') ?><span class="mq-phone"> (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"> ms</span>
|
||||
</div>
|
||||
|
||||
<div class="Row buttons">
|
||||
<a class="button icn-ok" href="#" onclick="qs('#form-1').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>
|
||||
@@ -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') ?> <span class="x-passwd"></span></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>
|
||||
@@ -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>
|
||||
@@ -1,361 +0,0 @@
|
||||
<div class="Box">
|
||||
<h2>Troubleshooting</h2>
|
||||
|
||||
<ul>
|
||||
<li>ESPTerm communicates with external µC via UART on pins <b>Rx</b> and <b>Tx</b>.
|
||||
It can be configured in <a href="<?= url('cfg_system') ?>">System Settings</a>.
|
||||
Make sure you're using the correct baud rate and other settings on the other side.
|
||||
|
||||
<li>Boot log and debug messages are available on pin <b>GPIO2</b> (P2) at 115200\,bps, 1 stop bit, no parity.
|
||||
|
||||
<li>ESPTerm uses 3.3\,V logic. For communication with 5\,V logic (eg. Aurdino), 470\,R
|
||||
protection resistors are recommended. The ESPTerm breakout board already includes those resistors.
|
||||
|
||||
<li>If the Low Voltage Detector ("LVD") LED on the ESPTerm breakout lights up, your power connections have too high
|
||||
resistance or the power supply is insufficient. ESP8266 can consume in short spikes up to 500\,A and
|
||||
the supply voltage on the module must not drop below about 2.7\,V. Avoid needless breadboard jumpers and too thin wires.
|
||||
|
||||
<li>Connect Rx and Tx with a piece of wire to verify that the terminal works correctly; you should then immediately
|
||||
see what you type in the browser. <i>This won't work if your ESP8266 board has a built-in USB-serial
|
||||
converter connected to those pins.</i>
|
||||
|
||||
<li>For best performance, use the module in Client mode (connected to external network). Enabling AP mode consumes
|
||||
extra RAM and cycles, since the captive portal DNS server and DHCP server are be loaded.
|
||||
|
||||
<li>In AP mode, check that the channel used by ESPTerm 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>
|
||||
|
||||
<li>The terminal browser display needs WebSockets for the real-time updating to work.
|
||||
It will not work with some old browsers (Android < 4.4, IE < 10, Opera Mini)
|
||||
- see the <a href="https://caniuse.com/websockets/embed/">compatibility chart</a>.
|
||||
|
||||
<li>At most 4 clients can be connected to the AP at the same time. This is a limitation of the ESP8266 SDK.
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="Box">
|
||||
<h2>Screen</h2>
|
||||
|
||||
<ul>
|
||||
<li>Most ANSI escape sequences are supported.
|
||||
|
||||
<li>The initial screen size and other terminal options can be configured in
|
||||
<a href="<?= url('cfg_term') ?>">Terminal Settings</a>
|
||||
|
||||
<li>Display updates are sent to the browser after 20 ms of inactivity on the communication UART.
|
||||
This is to avoid hogging the server with tiny updates during large screen repaints.
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="Box theme-0">
|
||||
<h2>Color Reference</h2>
|
||||
|
||||
<p>Color is set using <code>\e[<c>m</code> where <code><c></code> are numbers separated by semicolons
|
||||
(and <code>\e</code> is ESC, code 27). The actual color representation depends on a color theme which
|
||||
can be selected in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>.</p>
|
||||
|
||||
<b>Foreground</b>
|
||||
|
||||
<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>
|
||||
|
||||
<b>Background</b>
|
||||
|
||||
<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>
|
||||
|
||||
<p>To make the text bold, use the "bold" attribute (eg. <code>\e[31;40;1m</code> for
|
||||
<span style="padding: 2px;" class="bg0 fg1 bold">bold red on black</span>).</p>
|
||||
|
||||
<p>The colors are reset to default using <code>\e[0m</code>. For more info, see the tables below.</p>
|
||||
</div>
|
||||
|
||||
<div class="Box">
|
||||
<h2>User Input</h2>
|
||||
|
||||
<p>
|
||||
All the user types on their keyboard is sent as-is to the UART, including ESC, ANSI sequences for arrow keys and CR-LF for Enter.
|
||||
</p>
|
||||
|
||||
<p>The buttons under the screen send ASCII codes 1, 2, 3, 4, 5. This choice was made to make their parsing as simple as possible.</p>
|
||||
|
||||
<p>
|
||||
Mouse input (click/tap) is sent as <code>\e[<y>;<x>M</code>. You can use this for virtual on-screen buttons.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="Box">
|
||||
<h2>Supported ANSI Escape Sequences</h2>
|
||||
|
||||
<p>Sequences are started by ASCII code 27 (ESC, <code>\e</code>, <code>\x1b</code>, <code>\033</code>)</p>
|
||||
|
||||
<p>Instead of <code>\a</code> (BELL, ASCII 7) in the commands, you can use `\e\` (ESC + backslash). It's the Text Separator code.</p>
|
||||
|
||||
<h3>Text Attributes</h3>
|
||||
|
||||
<p>
|
||||
All text attributes are set using <code>\e[...m</code> where the dots are numbers separated by semicolons.
|
||||
You can combine up to 3 attributes in a single command.
|
||||
</p>
|
||||
|
||||
<table class="ansiref">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>Reset text attributes to default</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Bold</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>21 or 22</td>
|
||||
<td>Bold off</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>7</td>
|
||||
<td>Inverse (fg/bg swap when printing)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>27</td>
|
||||
<td>Inverse OFF</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>30-37, 90-97</td>
|
||||
<td>Foreground color, normal and bright</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>40-47, 100-107</td>
|
||||
<td>Background color, normal and bright</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Cursor</h3>
|
||||
|
||||
<p>Movement commands scroll the screen if needed. The coordinates are 1-based, origin top left.</p>
|
||||
|
||||
<table class="ansiref w100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Params</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>\e[<n>A</td>
|
||||
<td>[count]</td>
|
||||
<td>Move cursor up</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>B</td>
|
||||
<td>[count]</td>
|
||||
<td>Move cursor down</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>C</td>
|
||||
<td>[count]</td>
|
||||
<td>Move cursor forward (right)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>D</td>
|
||||
<td>[count]</td>
|
||||
<td>Move cursor backward (left)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>E</td>
|
||||
<td>[count]</td>
|
||||
<td>Go N lines down, start of line</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>F</td>
|
||||
<td>[count]</td>
|
||||
<td>Go N lines up, start of line</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>G</td>
|
||||
<td>column</td>
|
||||
<td>Go to column</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<y>;<x>G</td>
|
||||
<td>[row=1];[col=1]</td>
|
||||
<td>Go to row and column</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[6n</td>
|
||||
<td>--</td>
|
||||
<td>Query cursor position. Position is sent back as <code>\e[?;?R</code> with row;column.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[s</td>
|
||||
<td>--</td>
|
||||
<td>Store position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[u</td>
|
||||
<td>--</td>
|
||||
<td>Restore position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e7</td>
|
||||
<td>--</td>
|
||||
<td>Store position & attributes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e8</td>
|
||||
<td>--</td>
|
||||
<td>Restore position & attributes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[?25l</td>
|
||||
<td>--</td>
|
||||
<td>Hide cursor</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[?25h</td>
|
||||
<td>--</td>
|
||||
<td>Show cursor</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[?7l</td>
|
||||
<td>--</td>
|
||||
<td>Disable cursor auto-wrap & auto-scroll at end of screen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[?7h</td>
|
||||
<td>--</td>
|
||||
<td>Enable cursor auto-wrap & auto-scroll at end of screen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Screen</h3>
|
||||
|
||||
<table class="ansiref w100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Params</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>\e[<m>J</td>
|
||||
<td>[mode=0]</td>
|
||||
<td>Clear screen. Mode: 0 - from cursor, 1 - to cursor, 2 - all</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<m>K</td>
|
||||
<td>[mode=0]</td>
|
||||
<td>Erase line. Mode: 0 - from cursor, 1 - to cursor, 2 - all</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>S</td>
|
||||
<td>[lines]</td>
|
||||
<td>Scroll screen content up, add empty line at the bottom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[<n>T</td>
|
||||
<td>[lines]</td>
|
||||
<td>Scroll screen content down, add empty line at the top</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e]W<r>;<c>\a</td>
|
||||
<td>rows;cols</td>
|
||||
<td>Set screen size (max ~ 80x30). This also clears the screen. This is a custom ESPTerm OSC command.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>System Commands</h3>
|
||||
|
||||
<table class="ansiref w100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Params</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>\ec</td>
|
||||
<td>--</td>
|
||||
<td>
|
||||
"Device Reset" - clear screen, reset attributes, show cursor & move it to 1,1.
|
||||
The screen size and WiFi settings stay unchanged.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e[5n</td>
|
||||
<td>--</td>
|
||||
<td>Query device status, replies with <code>\e[0n</code> "device is OK". Can be used to check if the UART works.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e]TITLE=…\a</td>
|
||||
<td>Title text</td>
|
||||
<td>Set terminal title. This is a custom ESPTerm OSC command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>\e]BTNn=…\a</td>
|
||||
<td>1-5, label</td>
|
||||
<td>Set button label. This is a custom ESPTerm OSC command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ASCII 24 (18h)</td>
|
||||
<td></td>
|
||||
<td>This symbol is sent by ESPTerm when it becomes ready to receive commands. It can be used to wait before it becomes
|
||||
ready on power-up, or to detect a spontaneous ESPTerm restart - that could happen due to RAM exhaustion due
|
||||
to a memory leak, or perhaps a power outage.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -1,62 +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);
|
||||
}
|
||||
}, 2000);
|
||||
</script>
|
||||
|
||||
<h1></h1>
|
||||
|
||||
<div id="termwrap">
|
||||
<div id="screen" class="theme-%theme%"></div>
|
||||
|
||||
<div id="buttons">
|
||||
<button data-n="1" class="btn-blue"></button><!--
|
||||
--><button data-n="2" class="btn-blue"></button><!--
|
||||
--><button data-n="3" class="btn-blue"></button><!--
|
||||
--><button data-n="4" class="btn-blue"></button><!--
|
||||
--><button data-n="5" class="btn-blue"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea id="softkb-input" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
|
||||
|
||||
<nav id="botnav">
|
||||
<a href="#" onclick="toggleSoftKb(true); return false" class="icn-keyboard mq-tablet-max"></a><!--
|
||||
--><a href="<?= url('cfg_term') ?>"><?= tr('term_nav.config') ?></a><!--
|
||||
--><a href="<?= url('cfg_wifi') ?>"><?= tr('term_nav.wifi') ?></a><!--
|
||||
--><a href="<?= url('help') ?>"><?= tr('term_nav.help') ?></a><!--
|
||||
--><a href="<?= url('about') ?>"><?= tr('term_nav.about') ?></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 1s…");
|
||||
setTimeout(function() {
|
||||
location.reload(true);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function toggleSoftKb(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
@@ -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);
|
||||
@@ -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: 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,53 +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;
|
||||
|
||||
@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; }
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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";
|
||||
@@ -1,189 +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;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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: .2em;
|
||||
padding-bottom: .2em;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media($phone) {
|
||||
.Box.mobcol {
|
||||
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;
|
||||
}
|
||||
|
||||
#ap-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
.Row {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#ap-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
@import "base";
|
||||
|
||||
@import "outer-wrap";
|
||||
@import "menu";
|
||||
@import "content";
|
||||
@import "loader";
|
||||
|
||||
@import "box";
|
||||
@import "modal";
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
.Modal {
|
||||
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 }
|
||||
}
|
||||
|
||||
.Dialog {
|
||||
margin: dist(-1);
|
||||
padding: dist(0);
|
||||
overflow: hidden;
|
||||
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
flex: 0 1 30rem;
|
||||
//min-height: 15rem;
|
||||
|
||||
background: #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 }
|
||||
}
|
||||
@@ -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
@@ -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";
|
||||
@@ -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...);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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...);
|
||||
}
|
||||
@@ -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
@@ -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 59–62) 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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Provides a quick method for targeting `margin` 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 margin(null 10px 3em 20vh);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .element {
|
||||
/// margin-bottom: 3em;
|
||||
/// margin-left: 20vh;
|
||||
/// margin-right: 10px;
|
||||
/// }
|
||||
///
|
||||
/// @require {mixin} directional-property
|
||||
///
|
||||
/// @output `margin`
|
||||
|
||||
@mixin margin($vals...) {
|
||||
@include directional-property(margin, false, $vals...);
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Provides a quick method for targeting `padding` 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 padding(12vh null 10px 5%);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .element {
|
||||
/// padding-bottom: 10px;
|
||||
/// padding-left: 5%;
|
||||
/// padding-top: 12vh;
|
||||
/// }
|
||||
///
|
||||
/// @require {mixin} directional-property
|
||||
///
|
||||
/// @output `padding`
|
||||
|
||||
@mixin padding($vals...) {
|
||||
@include directional-property(padding, false, $vals...);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Provides a quick method for setting an element’s position. Use a `null` value to “skip” a side.
|
||||
///
|
||||
/// @param {Position} $position [relative]
|
||||
/// A CSS position value
|
||||
///
|
||||
/// @param {Arglist} $coordinates [null null null null]
|
||||
/// List of values that correspond to the 4-value syntax for the edges of a box
|
||||
///
|
||||
/// @example scss - Usage
|
||||
/// .element {
|
||||
/// @include position(absolute, 0 null null 10em);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .element {
|
||||
/// left: 10em;
|
||||
/// position: absolute;
|
||||
/// top: 0;
|
||||
/// }
|
||||
///
|
||||
/// @require {function} is-length
|
||||
/// @require {function} unpack
|
||||
|
||||
@mixin position($position: relative, $coordinates: null null null null) {
|
||||
@if type-of($position) == list {
|
||||
$coordinates: $position;
|
||||
$position: relative;
|
||||
}
|
||||
|
||||
$coordinates: unpack($coordinates);
|
||||
|
||||
$offsets: (
|
||||
top: nth($coordinates, 1),
|
||||
right: nth($coordinates, 2),
|
||||
bottom: nth($coordinates, 3),
|
||||
left: nth($coordinates, 4)
|
||||
);
|
||||
|
||||
position: $position;
|
||||
|
||||
@each $offset, $value in $offsets {
|
||||
@if is-length($value) {
|
||||
#{$offset}: $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// A mixin for generating vendor prefixes on non-standardized properties.
|
||||
///
|
||||
/// @param {String} $property
|
||||
/// Property to prefix
|
||||
///
|
||||
/// @param {*} $value
|
||||
/// Value to use
|
||||
///
|
||||
/// @param {List} $prefixes
|
||||
/// Prefixes to define
|
||||
///
|
||||
/// @example scss - Usage
|
||||
/// .element {
|
||||
/// @include prefixer(border-radius, 10px, webkit ms spec);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .element {
|
||||
/// -webkit-border-radius: 10px;
|
||||
/// -moz-border-radius: 10px;
|
||||
/// border-radius: 10px;
|
||||
/// }
|
||||
///
|
||||
/// @require {variable} $prefix-for-webkit
|
||||
/// @require {variable} $prefix-for-mozilla
|
||||
/// @require {variable} $prefix-for-microsoft
|
||||
/// @require {variable} $prefix-for-opera
|
||||
/// @require {variable} $prefix-for-spec
|
||||
|
||||
@mixin prefixer($property, $value, $prefixes) {
|
||||
@each $prefix in $prefixes {
|
||||
@if $prefix == webkit {
|
||||
@if $prefix-for-webkit {
|
||||
-webkit-#{$property}: $value;
|
||||
}
|
||||
} @else if $prefix == moz {
|
||||
@if $prefix-for-mozilla {
|
||||
-moz-#{$property}: $value;
|
||||
}
|
||||
} @else if $prefix == ms {
|
||||
@if $prefix-for-microsoft {
|
||||
-ms-#{$property}: $value;
|
||||
}
|
||||
} @else if $prefix == o {
|
||||
@if $prefix-for-opera {
|
||||
-o-#{$property}: $value;
|
||||
}
|
||||
} @else if $prefix == spec {
|
||||
@if $prefix-for-spec {
|
||||
#{$property}: $value;
|
||||
}
|
||||
} @else {
|
||||
@warn "Unrecognized prefix: #{$prefix}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin disable-prefix-for-all() {
|
||||
$prefix-for-webkit: false !global;
|
||||
$prefix-for-mozilla: false !global;
|
||||
$prefix-for-microsoft: false !global;
|
||||
$prefix-for-opera: false !global;
|
||||
$prefix-for-spec: false !global;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) {
|
||||
@if $asset-pipeline {
|
||||
background-image: image-url("#{$filename}.#{$extension}");
|
||||
} @else {
|
||||
background-image: url("#{$filename}.#{$extension}");
|
||||
}
|
||||
|
||||
@include hidpi {
|
||||
@if $asset-pipeline {
|
||||
@if $retina-filename {
|
||||
background-image: image-url("#{$retina-filename}.#{$extension}");
|
||||
} @else {
|
||||
background-image: image-url("#{$filename}#{$retina-suffix}.#{$extension}");
|
||||
}
|
||||
} @else {
|
||||
@if $retina-filename {
|
||||
background-image: url("#{$retina-filename}.#{$extension}");
|
||||
} @else {
|
||||
background-image: url("#{$filename}#{$retina-suffix}.#{$extension}");
|
||||
}
|
||||
}
|
||||
|
||||
background-size: $background-size;
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Sets the `width` and `height` of the element.
|
||||
///
|
||||
/// @param {List} $size
|
||||
/// A list of at most 2 size values.
|
||||
///
|
||||
/// If there is only a single value in `$size` it is used for both width and height. All units are supported.
|
||||
///
|
||||
/// @example scss - Usage
|
||||
/// .first-element {
|
||||
/// @include size(2em);
|
||||
/// }
|
||||
///
|
||||
/// .second-element {
|
||||
/// @include size(auto 10em);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .first-element {
|
||||
/// width: 2em;
|
||||
/// height: 2em;
|
||||
/// }
|
||||
///
|
||||
/// .second-element {
|
||||
/// width: auto;
|
||||
/// height: 10em;
|
||||
/// }
|
||||
///
|
||||
/// @todo Refactor in 5.0.0 to use a comma-separated argument
|
||||
|
||||
@mixin size($value) {
|
||||
$width: nth($value, 1);
|
||||
$height: $width;
|
||||
|
||||
@if length($value) > 1 {
|
||||
$height: nth($value, 2);
|
||||
}
|
||||
|
||||
@if is-size($height) {
|
||||
height: $height;
|
||||
} @else {
|
||||
@warn "`#{$height}` is not a valid length for the `$height` parameter in the `size` mixin.";
|
||||
}
|
||||
|
||||
@if is-size($width) {
|
||||
width: $width;
|
||||
} @else {
|
||||
@warn "`#{$width}` is not a valid length for the `$width` parameter in the `size` mixin.";
|
||||
}
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Generates variables for all text-based inputs. Please note that you must use interpolation on the variable: `#{$all-text-inputs}`.
|
||||
///
|
||||
/// @example scss - Usage
|
||||
/// #{$all-text-inputs} {
|
||||
/// border: 1px solid #f00;
|
||||
/// }
|
||||
///
|
||||
/// #{$all-text-inputs-focus},
|
||||
/// #{$all-text-inputs-hover} {
|
||||
/// border: 1px solid #0f0;
|
||||
/// }
|
||||
///
|
||||
/// #{$all-text-inputs-active} {
|
||||
/// border: 1px solid #00f;
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// input[type="color"],
|
||||
/// input[type="date"],
|
||||
/// input[type="datetime"],
|
||||
/// input[type="datetime-local"],
|
||||
/// input[type="email"],
|
||||
/// input[type="month"],
|
||||
/// input[type="number"],
|
||||
/// input[type="password"],
|
||||
/// input[type="search"],
|
||||
/// input[type="tel"],
|
||||
/// input[type="text"],
|
||||
/// input[type="time"],
|
||||
/// input[type="url"],
|
||||
/// input[type="week"],
|
||||
/// textarea {
|
||||
/// border: 1px solid #f00;
|
||||
/// }
|
||||
///
|
||||
/// input[type="color"]:focus,
|
||||
/// input[type="date"]:focus,
|
||||
/// input[type="datetime"]:focus,
|
||||
/// input[type="datetime-local"]:focus,
|
||||
/// input[type="email"]:focus,
|
||||
/// input[type="month"]:focus,
|
||||
/// input[type="number"]:focus,
|
||||
/// input[type="password"]:focus,
|
||||
/// input[type="search"]:focus,
|
||||
/// input[type="tel"]:focus,
|
||||
/// input[type="text"]:focus,
|
||||
/// input[type="time"]:focus,
|
||||
/// input[type="url"]:focus,
|
||||
/// input[type="week"]:focus,
|
||||
/// textarea:focus,
|
||||
/// input[type="color"]:hover,
|
||||
/// input[type="date"]:hover,
|
||||
/// input[type="datetime"]:hover,
|
||||
/// input[type="datetime-local"]:hover,
|
||||
/// input[type="email"]:hover,
|
||||
/// input[type="month"]:hover,
|
||||
/// input[type="number"]:hover,
|
||||
/// input[type="password"]:hover,
|
||||
/// input[type="search"]:hover,
|
||||
/// input[type="tel"]:hover,
|
||||
/// input[type="text"]:hover,
|
||||
/// input[type="time"]:hover,
|
||||
/// input[type="url"]:hover,
|
||||
/// input[type="week"]:hover,
|
||||
/// textarea:hover {
|
||||
/// border: 1px solid #0f0;
|
||||
/// }
|
||||
///
|
||||
/// input[type="color"]:active,
|
||||
/// input[type="date"]:active,
|
||||
/// input[type="datetime"]:active,
|
||||
/// input[type="datetime-local"]:active,
|
||||
/// input[type="email"]:active,
|
||||
/// input[type="month"]:active,
|
||||
/// input[type="number"]:active,
|
||||
/// input[type="password"]:active,
|
||||
/// input[type="search"]:active,
|
||||
/// input[type="tel"]:active,
|
||||
/// input[type="text"]:active,
|
||||
/// input[type="time"]:active,
|
||||
/// input[type="url"]:active,
|
||||
/// input[type="week"]:active,
|
||||
/// textarea:active {
|
||||
/// border: 1px solid #00f;
|
||||
/// }
|
||||
///
|
||||
/// @require assign-inputs
|
||||
///
|
||||
/// @type List
|
||||
|
||||
$text-inputs-list: //'input[type="color"]',
|
||||
//'input[type="date"]',
|
||||
//'input[type="datetime"]',
|
||||
//'input[type="datetime-local"]',
|
||||
//'input[type="email"]',
|
||||
//'input[type="month"]',
|
||||
'input[type="number"]',
|
||||
'input[type="password"]',
|
||||
//'input[type="search"]',
|
||||
//'input[type="tel"]',
|
||||
'input[type="text"]',
|
||||
//'input[type="time"]',
|
||||
//'input[type="url"]',
|
||||
//'input[type="week"]',
|
||||
//'input:not([type])',
|
||||
'textarea';
|
||||
|
||||
$all-text-inputs: assign-inputs($text-inputs-list);
|
||||
$all-text-inputs-active: assign-inputs($text-inputs-list, active);
|
||||
$all-text-inputs-focus: assign-inputs($text-inputs-list, focus);
|
||||
$all-text-inputs-hover: assign-inputs($text-inputs-list, hover);
|
||||
@@ -1,34 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
|
||||
///
|
||||
/// Timing functions are the same as demoed here: http://jqueryui.com/resources/demos/effect/easing.html
|
||||
///
|
||||
/// @type cubic-bezier
|
||||
|
||||
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
|
||||
$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
|
||||
$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
|
||||
$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
|
||||
$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
|
||||
$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
|
||||
|
||||
$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
|
||||
$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
|
||||
$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
|
||||
$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
|
||||
$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
||||
$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
|
||||
|
||||
$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
|
||||
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
|
||||
$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
|
||||
$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
|
||||
$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
|
||||
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
|
||||
$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);
|
||||
@@ -1,63 +0,0 @@
|
||||
@mixin triangle($size, $color, $direction) {
|
||||
$width: nth($size, 1);
|
||||
$height: nth($size, length($size));
|
||||
$foreground-color: nth($color, 1);
|
||||
$background-color: if(length($color) == 2, nth($color, 2), transparent);
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
|
||||
$width: $width / 2;
|
||||
$height: if(length($size) > 1, $height, $height/2);
|
||||
|
||||
@if $direction == up {
|
||||
border-bottom: $height solid $foreground-color;
|
||||
border-left: $width solid $background-color;
|
||||
border-right: $width solid $background-color;
|
||||
} @else if $direction == right {
|
||||
border-bottom: $width solid $background-color;
|
||||
border-left: $height solid $foreground-color;
|
||||
border-top: $width solid $background-color;
|
||||
} @else if $direction == down {
|
||||
border-left: $width solid $background-color;
|
||||
border-right: $width solid $background-color;
|
||||
border-top: $height solid $foreground-color;
|
||||
} @else if $direction == left {
|
||||
border-bottom: $width solid $background-color;
|
||||
border-right: $height solid $foreground-color;
|
||||
border-top: $width solid $background-color;
|
||||
}
|
||||
} @else if ($direction == up-right) or ($direction == up-left) {
|
||||
border-top: $height solid $foreground-color;
|
||||
|
||||
@if $direction == up-right {
|
||||
border-left: $width solid $background-color;
|
||||
} @else if $direction == up-left {
|
||||
border-right: $width solid $background-color;
|
||||
}
|
||||
} @else if ($direction == down-right) or ($direction == down-left) {
|
||||
border-bottom: $height solid $foreground-color;
|
||||
|
||||
@if $direction == down-right {
|
||||
border-left: $width solid $background-color;
|
||||
} @else if $direction == down-left {
|
||||
border-right: $width solid $background-color;
|
||||
}
|
||||
} @else if ($direction == inset-up) {
|
||||
border-color: $background-color $background-color $foreground-color;
|
||||
border-style: solid;
|
||||
border-width: $height $width;
|
||||
} @else if ($direction == inset-down) {
|
||||
border-color: $foreground-color $background-color $background-color;
|
||||
border-style: solid;
|
||||
border-width: $height $width;
|
||||
} @else if ($direction == inset-right) {
|
||||
border-color: $background-color $background-color $background-color $foreground-color;
|
||||
border-style: solid;
|
||||
border-width: $width $height;
|
||||
} @else if ($direction == inset-left) {
|
||||
border-color: $background-color $foreground-color $background-color $background-color;
|
||||
border-style: solid;
|
||||
border-width: $width $height;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/// Provides an easy way to change the `word-wrap` property.
|
||||
///
|
||||
/// @param {String} $wrap [break-word]
|
||||
/// Value for the `word-break` property.
|
||||
///
|
||||
/// @example scss - Usage
|
||||
/// .wrapper {
|
||||
/// @include word-wrap(break-word);
|
||||
/// }
|
||||
///
|
||||
/// @example css - CSS Output
|
||||
/// .wrapper {
|
||||
/// overflow-wrap: break-word;
|
||||
/// word-break: break-all;
|
||||
/// word-wrap: break-word;
|
||||
/// }
|
||||
|
||||
@mixin word-wrap($wrap: break-word) {
|
||||
overflow-wrap: $wrap;
|
||||
word-wrap: $wrap;
|
||||
|
||||
@if $wrap == break-word {
|
||||
word-break: break-all;
|
||||
} @else {
|
||||
word-break: $wrap;
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
// http://www.w3.org/TR/css3-animations/#the-animation-name-property-
|
||||
// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
|
||||
|
||||
@mixin animation($animations...) {
|
||||
@include prefixer(animation, $animations, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-name($names...) {
|
||||
@include prefixer(animation-name, $names, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-duration($times...) {
|
||||
@include prefixer(animation-duration, $times, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-timing-function($motions...) {
|
||||
// ease | linear | ease-in | ease-out | ease-in-out
|
||||
@include prefixer(animation-timing-function, $motions, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-iteration-count($values...) {
|
||||
// infinite | <number>
|
||||
@include prefixer(animation-iteration-count, $values, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-direction($directions...) {
|
||||
// normal | alternate
|
||||
@include prefixer(animation-direction, $directions, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-play-state($states...) {
|
||||
// running | paused
|
||||
@include prefixer(animation-play-state, $states, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-delay($times...) {
|
||||
@include prefixer(animation-delay, $times, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin animation-fill-mode($modes...) {
|
||||
// none | forwards | backwards | both
|
||||
@include prefixer(animation-fill-mode, $modes, webkit moz spec);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@mixin appearance($value) {
|
||||
@include prefixer(appearance, $value, webkit moz ms o spec);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@mixin backface-visibility($visibility) {
|
||||
@include prefixer(backface-visibility, $visibility, webkit spec);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
//************************************************************************//
|
||||
// Background-image property for adding multiple background images with
|
||||
// gradients, or for stringing multiple gradients together.
|
||||
//************************************************************************//
|
||||
|
||||
@mixin background-image($images...) {
|
||||
$webkit-images: ();
|
||||
$spec-images: ();
|
||||
|
||||
@each $image in $images {
|
||||
$webkit-image: ();
|
||||
$spec-image: ();
|
||||
|
||||
@if (type-of($image) == string) {
|
||||
$url-str: str-slice($image, 1, 3);
|
||||
$gradient-type: str-slice($image, 1, 6);
|
||||
|
||||
@if $url-str == "url" {
|
||||
$webkit-image: $image;
|
||||
$spec-image: $image;
|
||||
}
|
||||
|
||||
@else if $gradient-type == "linear" {
|
||||
$gradients: _linear-gradient-parser($image);
|
||||
$webkit-image: map-get($gradients, webkit-image);
|
||||
$spec-image: map-get($gradients, spec-image);
|
||||
}
|
||||
|
||||
@else if $gradient-type == "radial" {
|
||||
$gradients: _radial-gradient-parser($image);
|
||||
$webkit-image: map-get($gradients, webkit-image);
|
||||
$spec-image: map-get($gradients, spec-image);
|
||||
}
|
||||
}
|
||||
|
||||
$webkit-images: append($webkit-images, $webkit-image, comma);
|
||||
$spec-images: append($spec-images, $spec-image, comma);
|
||||
}
|
||||
|
||||
background-image: $webkit-images;
|
||||
background-image: $spec-images;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
//************************************************************************//
|
||||
// Background property for adding multiple backgrounds using shorthand
|
||||
// notation.
|
||||
//************************************************************************//
|
||||
|
||||
@mixin background($backgrounds...) {
|
||||
$webkit-backgrounds: ();
|
||||
$spec-backgrounds: ();
|
||||
|
||||
@each $background in $backgrounds {
|
||||
$webkit-background: ();
|
||||
$spec-background: ();
|
||||
$background-type: type-of($background);
|
||||
|
||||
@if $background-type == string or $background-type == list {
|
||||
$background-str: if($background-type == list, nth($background, 1), $background);
|
||||
|
||||
$url-str: str-slice($background-str, 1, 3);
|
||||
$gradient-type: str-slice($background-str, 1, 6);
|
||||
|
||||
@if $url-str == "url" {
|
||||
$webkit-background: $background;
|
||||
$spec-background: $background;
|
||||
}
|
||||
|
||||
@else if $gradient-type == "linear" {
|
||||
$gradients: _linear-gradient-parser("#{$background}");
|
||||
$webkit-background: map-get($gradients, webkit-image);
|
||||
$spec-background: map-get($gradients, spec-image);
|
||||
}
|
||||
|
||||
@else if $gradient-type == "radial" {
|
||||
$gradients: _radial-gradient-parser("#{$background}");
|
||||
$webkit-background: map-get($gradients, webkit-image);
|
||||
$spec-background: map-get($gradients, spec-image);
|
||||
}
|
||||
|
||||
@else {
|
||||
$webkit-background: $background;
|
||||
$spec-background: $background;
|
||||
}
|
||||
}
|
||||
|
||||
@else {
|
||||
$webkit-background: $background;
|
||||
$spec-background: $background;
|
||||
}
|
||||
|
||||
$webkit-backgrounds: append($webkit-backgrounds, $webkit-background, comma);
|
||||
$spec-backgrounds: append($spec-backgrounds, $spec-background, comma);
|
||||
}
|
||||
|
||||
background: $webkit-backgrounds;
|
||||
background: $spec-backgrounds;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
@mixin border-image($borders...) {
|
||||
$webkit-borders: ();
|
||||
$spec-borders: ();
|
||||
|
||||
@each $border in $borders {
|
||||
$webkit-border: ();
|
||||
$spec-border: ();
|
||||
$border-type: type-of($border);
|
||||
|
||||
@if $border-type == string or list {
|
||||
$border-str: if($border-type == list, nth($border, 1), $border);
|
||||
|
||||
$url-str: str-slice($border-str, 1, 3);
|
||||
$gradient-type: str-slice($border-str, 1, 6);
|
||||
|
||||
@if $url-str == "url" {
|
||||
$webkit-border: $border;
|
||||
$spec-border: $border;
|
||||
}
|
||||
|
||||
@else if $gradient-type == "linear" {
|
||||
$gradients: _linear-gradient-parser("#{$border}");
|
||||
$webkit-border: map-get($gradients, webkit-image);
|
||||
$spec-border: map-get($gradients, spec-image);
|
||||
}
|
||||
|
||||
@else if $gradient-type == "radial" {
|
||||
$gradients: _radial-gradient-parser("#{$border}");
|
||||
$webkit-border: map-get($gradients, webkit-image);
|
||||
$spec-border: map-get($gradients, spec-image);
|
||||
}
|
||||
|
||||
@else {
|
||||
$webkit-border: $border;
|
||||
$spec-border: $border;
|
||||
}
|
||||
}
|
||||
|
||||
@else {
|
||||
$webkit-border: $border;
|
||||
$spec-border: $border;
|
||||
}
|
||||
|
||||
$webkit-borders: append($webkit-borders, $webkit-border, comma);
|
||||
$spec-borders: append($spec-borders, $spec-border, comma);
|
||||
}
|
||||
|
||||
-webkit-border-image: $webkit-borders;
|
||||
border-image: $spec-borders;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
//Examples:
|
||||
// @include border-image(url("image.png"));
|
||||
// @include border-image(url("image.png") 20 stretch);
|
||||
// @include border-image(linear-gradient(45deg, orange, yellow));
|
||||
// @include border-image(linear-gradient(45deg, orange, yellow) stretch);
|
||||
// @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round);
|
||||
// @include border-image(radial-gradient(top, cover, orange, yellow, orange));
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
@mixin calc($property, $value) {
|
||||
#{$property}: -webkit-calc(#{$value});
|
||||
#{$property}: calc(#{$value});
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
@mixin columns($arg: auto) {
|
||||
// <column-count> || <column-width>
|
||||
@include prefixer(columns, $arg, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-count($int: auto) {
|
||||
// auto || integer
|
||||
@include prefixer(column-count, $int, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-gap($length: normal) {
|
||||
// normal || length
|
||||
@include prefixer(column-gap, $length, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-fill($arg: auto) {
|
||||
// auto || length
|
||||
@include prefixer(column-fill, $arg, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-rule($arg) {
|
||||
// <border-width> || <border-style> || <color>
|
||||
@include prefixer(column-rule, $arg, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-rule-color($color) {
|
||||
@include prefixer(column-rule-color, $color, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-rule-style($style: none) {
|
||||
// none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid
|
||||
@include prefixer(column-rule-style, $style, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-rule-width ($width: none) {
|
||||
@include prefixer(column-rule-width, $width, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-span($arg: none) {
|
||||
// none || all
|
||||
@include prefixer(column-span, $arg, webkit moz spec);
|
||||
}
|
||||
|
||||
@mixin column-width($length: auto) {
|
||||
// auto || length
|
||||
@include prefixer(column-width, $length, webkit moz spec);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
@mixin filter($function: none) {
|
||||
// <filter-function> [<filter-function]* | none
|
||||
@include prefixer(filter, $function, webkit spec);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user