Compare commits
188
Commits
0.6.10
...
2.1.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -1,4 +1,5 @@
|
||||
html/
|
||||
html_demo/
|
||||
build/
|
||||
firmware/
|
||||
espfs/mkespfsimage/*.o
|
||||
@@ -10,6 +11,8 @@ espfs/espfstest/espfstest
|
||||
html_compressed/
|
||||
ldscript_memspecific.ld
|
||||
eagle.app.sym
|
||||
node_modules
|
||||
esphttpdconfig.mk
|
||||
|
||||
# Garbage added by CLion
|
||||
.idea/
|
||||
@@ -17,3 +20,4 @@ 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
|
||||
|
||||
+45
-11
@@ -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
|
||||
@@ -110,8 +112,6 @@ set(SOURCE_FILES
|
||||
user/serial.h
|
||||
user/routes.c
|
||||
user/routes.h
|
||||
user/uart_asyncdrv.c-
|
||||
user/uart_asyncdrv.h-
|
||||
user/cgi_main.c
|
||||
user/cgi_main.h
|
||||
user/cgi_sockets.c
|
||||
@@ -123,7 +123,6 @@ set(SOURCE_FILES
|
||||
user/wifimgr.h
|
||||
user/persist.c
|
||||
user/persist.h
|
||||
include/helpers.h
|
||||
user/syscfg.c
|
||||
user/syscfg.h
|
||||
user/ascii.h
|
||||
@@ -141,9 +140,18 @@ set(SOURCE_FILES
|
||||
user/apars_osc.c
|
||||
user/apars_osc.h
|
||||
user/apars_dcs.c
|
||||
user/apars_dcs.h user/uart_buffer.c user/uart_buffer.h)
|
||||
user/apars_dcs.h
|
||||
user/uart_buffer.c
|
||||
user/uart_buffer.h
|
||||
user/jstring.c
|
||||
user/jstring.h
|
||||
user/character_sets.h
|
||||
user/utf8.h
|
||||
user/utf8.c
|
||||
user/cgi_logging.h)
|
||||
|
||||
include_directories(include)
|
||||
include_directories(libesphttpd/esphttpclient)
|
||||
include_directories(user)
|
||||
include_directories(libesphttpd/include)
|
||||
include_directories(libesphttpd/espfs)
|
||||
@@ -155,14 +163,40 @@ 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"
|
||||
-DDEBUG_HEAP=1
|
||||
-DESPFS_HEATSHRINK)
|
||||
|
||||
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,13 +62,14 @@ 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 \
|
||||
# compiler flags using during compilation of source files -ggdb
|
||||
CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
|
||||
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH \
|
||||
-Wno-address -Wno-unused
|
||||
|
||||
CFLAGS += -DGIT_HASH='"$(shell git rev-parse --short HEAD)"'
|
||||
CFLAGS += -DADMIN_PASSWORD=$(ADMIN_PASSWORD)
|
||||
CFLAGS += -DGIT_HASH_BACKEND='"$(shell git rev-parse --short HEAD)"'
|
||||
CFLAGS += -DGIT_HASH_FRONTEND='"$(shell cd front-end && git rev-parse --short HEAD)"'
|
||||
CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"'
|
||||
|
||||
ifdef GLOBAL_CFLAGS
|
||||
CFLAGS += $(GLOBAL_CFLAGS)
|
||||
@@ -152,7 +153,6 @@ define maplookup
|
||||
$(patsubst $(strip $(1)):%,%,$(filter $(strip $(1)):%,$(2)))
|
||||
endef
|
||||
|
||||
|
||||
#Include options and target specific to the OUTPUT_TYPE
|
||||
include Makefile.$(OUTPUT_TYPE)
|
||||
|
||||
@@ -171,7 +171,7 @@ MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
|
||||
ESP_FLASH_SIZE_IX=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:0 1024:2 2048:5 4096:6)
|
||||
ESPTOOL_FREQ=$(call maplookup,$(ESP_FLASH_FREQ_DIV),0:40m 1:26m 2:20m 0xf:80m 15:80m)
|
||||
ESPTOOL_MODE=$(call maplookup,$(ESP_FLASH_MODE),0:qio 1:qout 2:dio 3:dout)
|
||||
ESPTOOL_SIZE=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:4m 256:2m 1024:8m 2048:16m 4096:32m)
|
||||
ESPTOOL_SIZE=$(call maplookup,$(ESP_SPI_FLASH_SIZE_K),512:512KB 256:256KB 1024:1MB 2048:2MB 4096:4MB)
|
||||
|
||||
ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD)
|
||||
ESPTOOL_FLASHDEF=--flash_freq $(ESPTOOL_FREQ) --flash_mode $(ESPTOOL_MODE) --flash_size $(ESPTOOL_SIZE)
|
||||
@@ -189,27 +189,58 @@ $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:
|
||||
ESP_LANG=cs make web
|
||||
make actual_all -j4
|
||||
cp firmware/0x00000.bin release/0x00000.bin
|
||||
cp firmware/0x40000.bin release/0x40000-CS.bin
|
||||
|
||||
ESP_LANG=en make web
|
||||
make actual_all -j4
|
||||
cp firmware/0x40000.bin release/0x40000-EN.bin
|
||||
|
||||
ESP_LANG=de make web
|
||||
make actual_all -j4
|
||||
cp firmware/0x40000.bin release/0x40000-DE.bin
|
||||
|
||||
|
||||
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,100 +1,158 @@
|
||||
# ESPTerm
|
||||
|
||||
ESPTerm is a terminal emulator running on the ESP8266 WiFi chip.
|
||||
The firmware emulates VT102 with some additional features based on `xterm` and later VT models, and the terminal screen can be accessed using any web browser, even on a phone or tablet. It works with ESP-01, ESP-01S, ESP-12 and likely many other modules (I use ESP-12 on a NodeMCU board for development).
|
||||
**ESPTerm is a VT100-like terminal emulator running on the ESP8266 WiFi chip.**
|
||||
|
||||
ESPTerm can add remote access via WiFi to any embeded project, all you need is a serial port.
|
||||
![Photo][photo-hw]<br>
|
||||
*Fig 1: Breadboard adapter developed for ESPTerm*
|
||||
|
||||
## Screenshots, photos
|
||||
As of release 1.0, ESPTerm **passes most of VTTEST test cases** (from the main menu and some Xterm specific), making it
|
||||
functionally comparable to eg. gnome-terminal, terminator, konsole, GtkTerm or PuTTY.
|
||||
ESPTerm is **capable of running Midnight Commander** through agetty, **including full
|
||||
mouse support**, provided agetty is made to believe it's Xterm, which shows ESPTerm is sufficiently well
|
||||
implemented to work with ncurses.
|
||||
|
||||
- Look at the [GitHub releases page][releases], there are some pics.
|
||||
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])
|
||||
|
||||
## ESPTerm features
|
||||
The terminal screen can be accessed using any web browser, even on a phone or tablet.
|
||||
It works with ESP-01, ESP-01S, ESP-12 and likely many other modules (I use an ESP-12
|
||||
on a LoLin NodeMCU board from eBay for development).
|
||||
|
||||
- **Robust WiFi configuration interface**
|
||||
- static IP
|
||||
- DHCP
|
||||
- AP channel and strength setting
|
||||
- AP password
|
||||
- SSID search for finding your existing network
|
||||
- **Almost complete VT102 emulation** with some extras
|
||||
- *Sufficient to run most Linux console applications, including ncurses-based ones\**
|
||||
- All standard SGR (text style attributes) supported
|
||||
- Full UTF-8 support
|
||||
- Alternate character sets support
|
||||
- 16 colors
|
||||
- Scrolling Region, Origin Mode
|
||||
- Tab Stops
|
||||
- Cursor save/restore
|
||||
- Character/Line insert, delete, clear operations
|
||||
- Audible BEL (ASCII 7 beep)
|
||||
- Most standard queries (get cursor position, get SGR, get screen size...)
|
||||
- All DEC private options either implemented or safely consumed by the parser
|
||||
- **Other features:**
|
||||
- Screen size up to 80x25
|
||||
With ESPTerm, you can add remote access via WiFi to any embeded project, all you need is
|
||||
a serial port and some imagination!
|
||||
|
||||
## Try it online
|
||||
|
||||
You can try the web user interface here: [espterm.github.io][demo-term]
|
||||
|
||||
The demo is almost identical to the real thing, except, of course, it doesn't do much without the
|
||||
emulator backend that runs on the ESP8266. The web version will be updated to match this repository
|
||||
after each minor release (and sometimes in between for testing; the version currently being show-cased
|
||||
can be read on the About page of the demo).
|
||||
|
||||
### Browser support
|
||||
|
||||
Use the above linked online demo to verify compatibility with your browser.
|
||||
|
||||
To our knowledge, ESPTerm **works with**:
|
||||
- Google Chrome (desktop, mobile)
|
||||
- Firefox (desktop, mobile not tested)
|
||||
- Safari (desktop, mobile)
|
||||
- Chromium
|
||||
- Opera
|
||||
- Brave
|
||||
- Konqueror
|
||||
|
||||
It **does not work with**:
|
||||
- Microsoft Edge - runs, but is extremely laggy
|
||||
- Internet Explorer (any version) - crashes, missing JS features
|
||||
- Opera Mini - crashes, missing JS and CSS features
|
||||
- Blackberry browser - not tested, but unlikely
|
||||
- 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...
|
||||
- **Web Terminal Interface**
|
||||
- Real-time screen update via WebSocket
|
||||
- Button to open Android software keyboard
|
||||
- 5 buttons under the screen for quick commands
|
||||
- Button labels can be changed (by OSC commands or via settings)
|
||||
- Screen title can be changed (by OSC commands or via settings)
|
||||
- Built-in help page with basic troubleshooting and command reference
|
||||
- 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
|
||||
|
||||
## Bugs? Ideas?
|
||||
|
||||
\*) Linux console applications run via agetty at ttyUSB0 were used for testing, obviously you'll be better off using SSH for remote shell
|
||||
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)**
|
||||
|
||||
ESPTerm firmware is written in C and is based on SpriteTM's `libesphttpd` http server library, forked by MightyPork to
|
||||
[MightyPork/libesphttpd](https://github.com/MightyPork/libesphttpd) respectively. This fork includes various improvements and changes required by the project.
|
||||
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](https://github.com/espressif/esptool).
|
||||
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. Connect your USB-serial dongle or application microcontroller here.
|
||||
|
||||
### Console commands - escape sequences
|
||||
|
||||
- A list of most supported commands can be found here: http://bits.ondrovo.com/espterm-xterm.html
|
||||
- To set the screen title, use `OSC 0 ; title ST` (`OSC` = `ESC ]`, `ST` = `ESC \` or ASCII 7)
|
||||
- To set buttons text, use `OSC 8 1 ; text ST` with 81 through 85.
|
||||
- Mouse clicks (as of v0.6.9) generate `CSI row ; col M` at the Tx pin (`CSI` = `ESC [`)
|
||||
- For more info, look eg. on Wikipedia or here: http://ascii-table.com/ansi-escape-sequences-vt-100.php
|
||||
- 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.
|
||||
- Connect to it via a smartphone or laptop and configure WiFi as desired.
|
||||
- To re-enable the built-in AP, hold the BOOT (GPIO0) button for about 1 s, until the blue LED starts slowly flashing. Then release the button!
|
||||
- To reset all settings to defaults, hold the BOOT (GPIO0) button until the blue LED flashes rapidly, then release the button.
|
||||
- When you accidentally make the blue LED flash, you can cancel the operation by pressing Reset or disconnecting its power supply. The wipe is done on the button's release.
|
||||
- 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 files
|
||||
|
||||
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.
|
||||
ESPTerm has two config "files", one for defaults and one for the currently used settings. In the case of the terminal
|
||||
config, there is also a third, temporary file for changes done via ESC commands.
|
||||
|
||||
When you get your settings *just right*, you can store them as defaults, which can then be at any time restored by holding the BOOT (GPIO0) button. You can do this on the System Settings page. This asks for an "admin password", which you can define when building the firmware in the `esphttpdconfig.mk` file. The default password is `19738426`. This password can't presently be changed without re-flashing the firmware.
|
||||
When you get your settings *just right*, you can store them as defaults, which can then be at any time restored
|
||||
by holding the BOOT (GPIO0) button. You can do this on the System Settings page. This asks for an "admin password",
|
||||
which you can define when building the firmware in the `esphttpdconfig.mk` file.
|
||||
|
||||
You can also restore everything (except the saved defaults) to "factory defaults", there is a button for this on the System Settings page. Those are the initial values in the config files.
|
||||
The default password is `19738426`. This password can't presently be changed without re-flashing the firmware.
|
||||
|
||||
You can also restore everything (except the saved defaults) to "factory defaults", there is a button for this
|
||||
on the System Settings page. Those are the initial values in the config files.
|
||||
|
||||
## Research resources
|
||||
|
||||
Developing ESPTerm wasn't an easy task, because the information is scattered across many places and the existing
|
||||
terminal emulators I originally used for reference (terminator, Konsole) are not implemented correctly in some details.
|
||||
|
||||
A great tool for checking my implementation has proven to be [VTTTEST][vttest] and Xterm as a reference
|
||||
implementation that is probably the most complete emulator available, although it's cumbersome to use and its age
|
||||
really shows in the looks.
|
||||
|
||||
I've comnpiled a list of those I found most helpful here: [VT100 emulation resources][resources]
|
||||
|
||||
## 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
|
||||
- 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.
|
||||
@@ -103,23 +161,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,6 @@
|
||||
echo "-- Building parser from Ragel source --"
|
||||
|
||||
ragel -L -G0 user/ansi_parser.rl -o user/ansi_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
|
||||
|
||||
+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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,17 +38,27 @@ 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_D2D=0 \
|
||||
-DDEBUG_ROUTER=0 \
|
||||
-DDEBUG_CAPTDNS=0 \
|
||||
-DDEBUG_HTTP=1 \
|
||||
-DDEBUG_HTTP=0 \
|
||||
-DDEBUG_HTTPC=0 \
|
||||
-DDEBUG_ESPFS=0 \
|
||||
-DDEBUG_PERSIST=1 \
|
||||
-DDEBUG_UTFCACHE=0 \
|
||||
-DDEBUG_CGI=0 \
|
||||
-DDEBUG_WIFI=0 \
|
||||
-DDEBUG_WS=0 \
|
||||
-DDEBUG_ANSI=1 \
|
||||
-DDEBUG_ANSI_NOIMPL=1 \
|
||||
-DHTTPD_MAX_BACKLOG_SIZE=8192 \
|
||||
-DDEBUG_INPUT=0 \
|
||||
-DDEBUG_HEAP=1
|
||||
-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 69e5b77447
@@ -1 +0,0 @@
|
||||
pages/_test_env.php
|
||||
@@ -1,70 +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', //,
|
||||
|
||||
'parser_tout_ms' => 10,
|
||||
'display_tout_ms' => 20,
|
||||
'fn_alt_mode' => '1',
|
||||
|
||||
'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';
|
||||
-2132
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
/** Global generic init */
|
||||
$.ready(function () {
|
||||
// Checkbox UI (checkbox CSS and hidden input with int value)
|
||||
$('.Row.checkbox').forEach(function(x) {
|
||||
var inp = x.querySelector('input');
|
||||
var box = x.querySelector('.box');
|
||||
|
||||
$(box).toggleClass('checked', inp.value);
|
||||
|
||||
var hdl = function() {
|
||||
inp.value = 1 - inp.value;
|
||||
$(box).toggleClass('checked', inp.value)
|
||||
};
|
||||
|
||||
$(x).on('click', hdl).on('keypress', cr(hdl));
|
||||
});
|
||||
|
||||
// Expanding boxes on mobile
|
||||
$('.Box.mobcol').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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
|
||||
if (!String.fromCodePoint) {
|
||||
(function() {
|
||||
var defineProperty = (function() {
|
||||
// IE 8 only supports `Object.defineProperty` on DOM elements
|
||||
try {
|
||||
var object = {};
|
||||
var $defineProperty = Object.defineProperty;
|
||||
var result = $defineProperty(object, object, object) && $defineProperty;
|
||||
} catch(error) {}
|
||||
return result;
|
||||
}());
|
||||
var stringFromCharCode = String.fromCharCode;
|
||||
var floor = Math.floor;
|
||||
var fromCodePoint = function() {
|
||||
var MAX_SIZE = 0x4000;
|
||||
var codeUnits = [];
|
||||
var highSurrogate;
|
||||
var lowSurrogate;
|
||||
var index = -1;
|
||||
var length = arguments.length;
|
||||
if (!length) {
|
||||
return '';
|
||||
}
|
||||
var result = '';
|
||||
while (++index < length) {
|
||||
var codePoint = Number(arguments[index]);
|
||||
if (
|
||||
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
|
||||
codePoint < 0 || // not a valid Unicode code point
|
||||
codePoint > 0x10FFFF || // not a valid Unicode code point
|
||||
floor(codePoint) != codePoint // not an integer
|
||||
) {
|
||||
throw RangeError('Invalid code point: ' + codePoint);
|
||||
}
|
||||
if (codePoint <= 0xFFFF) { // BMP code point
|
||||
codeUnits.push(codePoint);
|
||||
} else { // Astral code point; split in surrogate halves
|
||||
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
||||
codePoint -= 0x10000;
|
||||
highSurrogate = (codePoint >> 10) + 0xD800;
|
||||
lowSurrogate = (codePoint % 0x400) + 0xDC00;
|
||||
codeUnits.push(highSurrogate, lowSurrogate);
|
||||
}
|
||||
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
|
||||
result += stringFromCharCode.apply(null, codeUnits);
|
||||
codeUnits.length = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
if (defineProperty) {
|
||||
defineProperty(String, 'fromCodePoint', {
|
||||
'value': fromCodePoint,
|
||||
'configurable': true,
|
||||
'writable': true
|
||||
});
|
||||
} else {
|
||||
String.fromCodePoint = fromCodePoint;
|
||||
}
|
||||
}());
|
||||
}
|
||||
@@ -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,301 +0,0 @@
|
||||
// keymaster.js
|
||||
// (c) 2011-2013 Thomas Fuchs
|
||||
// keymaster.js may be freely distributed under the MIT license.
|
||||
|
||||
;(function(global){
|
||||
var k,
|
||||
_handlers = {},
|
||||
_mods = { 16: false, 18: false, 17: false, 91: false },
|
||||
_scope = 'all',
|
||||
// modifier keys
|
||||
_MODIFIERS = {
|
||||
'⇧': 16, shift: 16,
|
||||
'⌥': 18, alt: 18, option: 18,
|
||||
'⌃': 17, ctrl: 17, control: 17,
|
||||
'⌘': 91, command: 91
|
||||
},
|
||||
// special keys
|
||||
_MAP = {
|
||||
backspace: 8, tab: 9, clear: 12,
|
||||
enter: 13, 'return': 13,
|
||||
esc: 27, escape: 27, space: 32,
|
||||
left: 37, up: 38,
|
||||
right: 39, down: 40,
|
||||
del: 46, 'delete': 46,
|
||||
home: 36, end: 35,
|
||||
pageup: 33, pagedown: 34,
|
||||
',': 188, '.': 190, '/': 191,
|
||||
'`': 192, '-': 189, '=': 187,
|
||||
';': 186, '\'': 222,
|
||||
'[': 219, ']': 221, '\\': 220,
|
||||
// added:
|
||||
insert: 45,
|
||||
np_0: 96, np_1: 97, np_2: 98, np_3: 99, np_4: 100, np_5: 101,
|
||||
np_6: 102, np_7: 103, np_8: 104, np_9: 105, np_mul: 106,
|
||||
np_add: 107, np_sub: 109, np_point: 110, np_div: 111, numlock: 144,
|
||||
},
|
||||
code = function(x){
|
||||
return _MAP[x] || x.toUpperCase().charCodeAt(0);
|
||||
},
|
||||
_downKeys = [];
|
||||
|
||||
for(k=1;k<20;k++) _MAP['f'+k] = 111+k;
|
||||
|
||||
// IE doesn't support Array#indexOf, so have a simple replacement
|
||||
function index(array, item){
|
||||
var i = array.length;
|
||||
while(i--) if(array[i]===item) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// for comparing mods before unassignment
|
||||
function compareArray(a1, a2) {
|
||||
if (a1.length != a2.length) return false;
|
||||
for (var i = 0; i < a1.length; i++) {
|
||||
if (a1[i] !== a2[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var modifierMap = {
|
||||
16:'shiftKey',
|
||||
18:'altKey',
|
||||
17:'ctrlKey',
|
||||
91:'metaKey'
|
||||
};
|
||||
function updateModifierKey(event) {
|
||||
for(k in _mods) _mods[k] = event[modifierMap[k]];
|
||||
};
|
||||
|
||||
// handle keydown event
|
||||
function dispatch(event) {
|
||||
var key, handler, k, i, modifiersMatch, scope;
|
||||
key = event.keyCode;
|
||||
|
||||
if (index(_downKeys, key) == -1) {
|
||||
_downKeys.push(key);
|
||||
}
|
||||
|
||||
// if a modifier key, set the key.<modifierkeyname> property to true and return
|
||||
if(key == 93 || key == 224) key = 91; // right command on webkit, command on Gecko
|
||||
if(key in _mods) {
|
||||
_mods[key] = true;
|
||||
// 'assignKey' from inside this closure is exported to window.key
|
||||
for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = true;
|
||||
return;
|
||||
}
|
||||
updateModifierKey(event);
|
||||
|
||||
// see if we need to ignore the keypress (filter() can can be overridden)
|
||||
// by default ignore key presses if a select, textarea, or input is focused
|
||||
if(!assignKey.filter.call(this, event)) return;
|
||||
|
||||
// abort if no potentially matching shortcuts found
|
||||
if (!(key in _handlers)) return;
|
||||
|
||||
scope = getScope();
|
||||
|
||||
// for each potential shortcut
|
||||
for (i = 0; i < _handlers[key].length; i++) {
|
||||
handler = _handlers[key][i];
|
||||
|
||||
// see if it's in the current scope
|
||||
if(handler.scope == scope || handler.scope == 'all'){
|
||||
// check if modifiers match if any
|
||||
modifiersMatch = handler.mods.length > 0;
|
||||
for(k in _mods)
|
||||
if((!_mods[k] && index(handler.mods, +k) > -1) ||
|
||||
(_mods[k] && index(handler.mods, +k) == -1)) modifiersMatch = false;
|
||||
// call the handler and stop the event if neccessary
|
||||
if((handler.mods.length == 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91]) || modifiersMatch){
|
||||
if(handler.method(event, handler)===false){
|
||||
if(event.preventDefault) event.preventDefault();
|
||||
else event.returnValue = false;
|
||||
if(event.stopPropagation) event.stopPropagation();
|
||||
if(event.cancelBubble) event.cancelBubble = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// unset modifier keys on keyup
|
||||
function clearModifier(event){
|
||||
var key = event.keyCode, k,
|
||||
i = index(_downKeys, key);
|
||||
|
||||
// remove key from _downKeys
|
||||
if (i >= 0) {
|
||||
_downKeys.splice(i, 1);
|
||||
}
|
||||
|
||||
if(key == 93 || key == 224) key = 91;
|
||||
if(key in _mods) {
|
||||
_mods[key] = false;
|
||||
for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = false;
|
||||
}
|
||||
};
|
||||
|
||||
function resetModifiers() {
|
||||
for(k in _mods) _mods[k] = false;
|
||||
for(k in _MODIFIERS) assignKey[k] = false;
|
||||
};
|
||||
|
||||
// parse and assign shortcut
|
||||
function assignKey(key, scope, method){
|
||||
var keys, mods;
|
||||
keys = getKeys(key);
|
||||
if (method === undefined) {
|
||||
method = scope;
|
||||
scope = 'all';
|
||||
}
|
||||
|
||||
// for each shortcut
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
// set modifier keys if any
|
||||
mods = [];
|
||||
key = keys[i].split('+');
|
||||
if (key.length > 1){
|
||||
mods = getMods(key);
|
||||
key = [key[key.length-1]];
|
||||
}
|
||||
// convert to keycode and...
|
||||
key = key[0]
|
||||
key = code(key);
|
||||
// ...store handler
|
||||
if (!(key in _handlers)) _handlers[key] = [];
|
||||
_handlers[key].push({ shortcut: keys[i], scope: scope, method: method, key: keys[i], mods: mods });
|
||||
}
|
||||
};
|
||||
|
||||
// unbind all handlers for given key in current scope
|
||||
function unbindKey(key, scope) {
|
||||
var multipleKeys, keys,
|
||||
mods = [],
|
||||
i, j, obj;
|
||||
|
||||
multipleKeys = getKeys(key);
|
||||
|
||||
for (j = 0; j < multipleKeys.length; j++) {
|
||||
keys = multipleKeys[j].split('+');
|
||||
|
||||
if (keys.length > 1) {
|
||||
mods = getMods(keys);
|
||||
}
|
||||
|
||||
key = keys[keys.length - 1];
|
||||
key = code(key);
|
||||
|
||||
if (scope === undefined) {
|
||||
scope = getScope();
|
||||
}
|
||||
if (!_handlers[key]) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < _handlers[key].length; i++) {
|
||||
obj = _handlers[key][i];
|
||||
// only clear handlers if correct scope and mods match
|
||||
if (obj.scope === scope && compareArray(obj.mods, mods)) {
|
||||
_handlers[key][i] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if the key with code 'keyCode' is currently down
|
||||
// Converts strings into key codes.
|
||||
function isPressed(keyCode) {
|
||||
if (typeof(keyCode)=='string') {
|
||||
keyCode = code(keyCode);
|
||||
}
|
||||
return index(_downKeys, keyCode) != -1;
|
||||
}
|
||||
|
||||
function getPressedKeyCodes() {
|
||||
return _downKeys.slice(0);
|
||||
}
|
||||
|
||||
function filter(event){
|
||||
var tagName = (event.target || event.srcElement).tagName;
|
||||
// ignore keypressed in any elements that support keyboard data input
|
||||
return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
||||
}
|
||||
|
||||
// initialize key.<modifier> to false
|
||||
for(k in _MODIFIERS) assignKey[k] = false;
|
||||
|
||||
// set current scope (default 'all')
|
||||
function setScope(scope){ _scope = scope || 'all' };
|
||||
function getScope(){ return _scope || 'all' };
|
||||
|
||||
// delete all handlers for a given scope
|
||||
function deleteScope(scope){
|
||||
var key, handlers, i;
|
||||
|
||||
for (key in _handlers) {
|
||||
handlers = _handlers[key];
|
||||
for (i = 0; i < handlers.length; ) {
|
||||
if (handlers[i].scope === scope) handlers.splice(i, 1);
|
||||
else i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// abstract key logic for assign and unassign
|
||||
function getKeys(key) {
|
||||
var keys;
|
||||
key = key.replace(/\s/g, '');
|
||||
keys = key.split(',');
|
||||
if ((keys[keys.length - 1]) == '') {
|
||||
keys[keys.length - 2] += ',';
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// abstract mods logic for assign and unassign
|
||||
function getMods(key) {
|
||||
var mods = key.slice(0, key.length - 1);
|
||||
for (var mi = 0; mi < mods.length; mi++)
|
||||
mods[mi] = _MODIFIERS[mods[mi]];
|
||||
return mods;
|
||||
}
|
||||
|
||||
// cross-browser events
|
||||
function addEvent(object, event, method) {
|
||||
if (object.addEventListener)
|
||||
object.addEventListener(event, method, false);
|
||||
else if(object.attachEvent)
|
||||
object.attachEvent('on'+event, function(){ method(window.event) });
|
||||
};
|
||||
|
||||
// set the handlers globally on document
|
||||
addEvent(document, 'keydown', function(event) { dispatch(event) }); // Passing _scope to a callback to ensure it remains the same by execution. Fixes #48
|
||||
addEvent(document, 'keyup', clearModifier);
|
||||
|
||||
// reset modifiers to false whenever the window is (re)focused.
|
||||
addEvent(window, 'focus', resetModifiers);
|
||||
|
||||
// store previously defined key
|
||||
var previousKey = global.key;
|
||||
|
||||
// restore previously defined key and return reference to our key object
|
||||
function noConflict() {
|
||||
var k = global.key;
|
||||
global.key = previousKey;
|
||||
return k;
|
||||
}
|
||||
|
||||
// set window.key and window.key.set/get/deleteScope, and the default filter
|
||||
global.key = assignKey;
|
||||
global.key.setScope = setScope;
|
||||
global.key.getScope = getScope;
|
||||
global.key.deleteScope = deleteScope;
|
||||
global.key.filter = filter;
|
||||
global.key.isPressed = isPressed;
|
||||
global.key.getPressedKeyCodes = getPressedKeyCodes;
|
||||
global.key.noConflict = noConflict;
|
||||
global.key.unbind = unbindKey;
|
||||
|
||||
if(typeof module !== 'undefined') module.exports = assignKey;
|
||||
|
||||
})(this);
|
||||
@@ -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,575 +0,0 @@
|
||||
var Screen = (function () {
|
||||
var W = 0, H = 0; // dimensions
|
||||
var inited = false;
|
||||
|
||||
var cursor = {
|
||||
a: false, // active (blink state)
|
||||
x: 0, // 0-based coordinates
|
||||
y: 0,
|
||||
fg: 7, // colors 0-15
|
||||
bg: 0,
|
||||
attrs: 0,
|
||||
suppress: false, // do not turn on in blink interval (for safe moving)
|
||||
hidden: false, // do not show
|
||||
hanging: false, // xenl
|
||||
};
|
||||
|
||||
var screen = [];
|
||||
var blinkIval;
|
||||
|
||||
var frakturExceptions = {
|
||||
'C': '\u212d',
|
||||
'H': '\u210c',
|
||||
'I': '\u2111',
|
||||
'R': '\u211c',
|
||||
'Z': '\u2128',
|
||||
};
|
||||
|
||||
// for BEL
|
||||
var audioCtx = null;
|
||||
try {
|
||||
audioCtx = new (window.AudioContext || window.audioContext || window.webkitAudioContext)();
|
||||
} catch (er) {
|
||||
console.error("Browser does not support AudioContext, can't beep.", er);
|
||||
}
|
||||
|
||||
/** Get cell under cursor */
|
||||
function _curCell() {
|
||||
return screen[cursor.y*W + cursor.x];
|
||||
}
|
||||
|
||||
/** Safely move cursor */
|
||||
function cursorSet(y, x) {
|
||||
// Hide and prevent from showing up during the move
|
||||
cursor.suppress = true;
|
||||
_draw(_curCell(), false);
|
||||
cursor.x = x;
|
||||
cursor.y = y;
|
||||
// Show again
|
||||
cursor.suppress = false;
|
||||
_draw(_curCell());
|
||||
}
|
||||
|
||||
/** Update cell on display. inv = invert (for cursor) */
|
||||
function _draw(cell, inv) {
|
||||
if (!cell) return;
|
||||
if (typeof inv == 'undefined') {
|
||||
inv = cursor.a && cursor.x == cell.x && cursor.y == cell.y;
|
||||
}
|
||||
|
||||
var elem = cell.e, fg, bg, cn, t;
|
||||
// Colors
|
||||
fg = inv ? cell.bg : cell.fg;
|
||||
bg = inv ? cell.fg : cell.bg;
|
||||
// Update
|
||||
elem.textContent = t = (cell.t + ' ')[0];
|
||||
|
||||
cn = 'fg' + fg + ' bg' + bg;
|
||||
if (cell.attrs & (1<<0)) cn += ' bold';
|
||||
if (cell.attrs & (1<<2)) cn += ' italic';
|
||||
if (cell.attrs & (1<<3)) cn += ' under';
|
||||
if (cell.attrs & (1<<4)) cn += ' blink';
|
||||
if (cell.attrs & (1<<5)) {
|
||||
cn += ' fraktur';
|
||||
// perform substitution
|
||||
if (t >= 'a' && t <= 'z') {
|
||||
t = String.fromCodePoint(0x1d51e - 97 + t.charCodeAt(0));
|
||||
}
|
||||
else if (t >= 'A' && t <= 'Z') {
|
||||
// this set is incomplete, some exceptions are needed
|
||||
if (frakturExceptions.hasOwnProperty(t)) {
|
||||
t = frakturExceptions[t];
|
||||
} else {
|
||||
t = String.fromCodePoint(0x1d504 - 65 + t.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
elem.textContent = t;
|
||||
}
|
||||
if (cell.attrs & (1<<6)) cn += ' strike';
|
||||
|
||||
if (cell.attrs & (1<<1)) {
|
||||
cn += ' faint';
|
||||
// faint requires special html - otherwise it would also dim the background.
|
||||
// we use opacity on the text...
|
||||
elem.innerHTML = '<span>' + e(elem.textContent) + '</span>';
|
||||
}
|
||||
|
||||
elem.className = cn;
|
||||
}
|
||||
|
||||
/** Show entire screen */
|
||||
function _drawAll() {
|
||||
for (var i = W*H-1; i>=0; i--) {
|
||||
_draw(screen[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function _rebuild(rows, cols) {
|
||||
W = cols;
|
||||
H = rows;
|
||||
|
||||
/* Build screen & show */
|
||||
var 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: 7,
|
||||
bg: 0, // the colors will be replaced immediately as we receive data (user won't see this)
|
||||
attrs: 0,
|
||||
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;
|
||||
// TODO try to invent a new way to indicate "hanging" - this is copied from gtkterm
|
||||
if (cursor.hidden || cursor.hanging) {
|
||||
cursor.a = false;
|
||||
}
|
||||
|
||||
if (!cursor.suppress) {
|
||||
_draw(_curCell(), cursor.a);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// blink attribute
|
||||
setInterval(function () {
|
||||
$('#screen').removeClass('blink-hide');
|
||||
setTimeout(function() {
|
||||
$('#screen').addClass('blink-hide');
|
||||
}, 800); // 200 ms ON
|
||||
}, 1000);
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
/** Decode two-byte number */
|
||||
function parse2B(s, i) {
|
||||
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127;
|
||||
}
|
||||
|
||||
/** Decode three-byte number */
|
||||
function parse3B(s, i) {
|
||||
return (s.charCodeAt(i) - 1) + (s.charCodeAt(i+1) - 1) * 127 + (s.charCodeAt(i+2) - 1) * 127 * 127;
|
||||
}
|
||||
|
||||
var SEQ_SET_COLOR_ATTR = 1;
|
||||
var SEQ_REPEAT = 2;
|
||||
var SEQ_SET_COLOR = 3;
|
||||
var SEQ_SET_ATTR = 4;
|
||||
|
||||
function _load_content(str) {
|
||||
var i = 0, ci = 0, j, jc, num, num2, t = ' ', fg, bg, attrs, 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.hidden = !(num & 0x0001);
|
||||
cursor.hanging = !!(num & 0x0002);
|
||||
// console.log("Attributes word ",num.toString(16)+'h');
|
||||
|
||||
Input.setAlts(
|
||||
!!(num & 0x0004), // cu
|
||||
!!(num & 0x0008), // np
|
||||
!!(num & 0x0010) // fn
|
||||
);
|
||||
|
||||
fg = 7;
|
||||
bg = 0;
|
||||
attrs = 0;
|
||||
|
||||
// Here come the content
|
||||
while(i < str.length && ci<W*H) {
|
||||
|
||||
j = str[i++];
|
||||
jc = j.charCodeAt(0);
|
||||
if (jc == SEQ_SET_COLOR_ATTR) {
|
||||
num = parse3B(str, i); i += 3;
|
||||
fg = num & 0x0F;
|
||||
bg = (num & 0xF0) >> 4;
|
||||
attrs = (num & 0xFF00)>>8;
|
||||
}
|
||||
else if (jc == SEQ_SET_COLOR) {
|
||||
num = parse2B(str, i); i += 2;
|
||||
fg = num & 0x0F;
|
||||
bg = (num & 0xF0) >> 4;
|
||||
}
|
||||
else if (jc == SEQ_SET_ATTR) {
|
||||
num = parse2B(str, i); i += 2;
|
||||
attrs = num & 0xFF;
|
||||
}
|
||||
else if (jc == SEQ_REPEAT) {
|
||||
num = parse2B(str, i); i += 2;
|
||||
// console.log("Repeat x ",num);
|
||||
for (; num>0 && ci<W*H; num--) {
|
||||
cell = screen[ci++];
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
cell.t = t;
|
||||
cell.attrs = attrs;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cell = screen[ci++];
|
||||
// Unique cell character
|
||||
t = cell.t = j;
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
cell.attrs = attrs;
|
||||
// console.log("Symbol ", j);
|
||||
}
|
||||
}
|
||||
|
||||
_drawAll();
|
||||
|
||||
if (!cursor.hidden || cursor.hanging) {
|
||||
// hide cursor asap
|
||||
_draw(_curCell(), false);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
function _beep()
|
||||
{
|
||||
var osc, gain;
|
||||
if (!audioCtx) return;
|
||||
|
||||
// Main beep
|
||||
osc = audioCtx.createOscillator();
|
||||
gain = audioCtx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
gain.gain.value = 0.5;
|
||||
osc.frequency.value = 750;
|
||||
osc.type = 'sine';
|
||||
osc.start();
|
||||
osc.stop(audioCtx.currentTime+0.05);
|
||||
|
||||
// Surrogate beep (making it sound like 'oops')
|
||||
osc = audioCtx.createOscillator();
|
||||
gain = audioCtx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
gain.gain.value = 0.2;
|
||||
osc.frequency.value = 400;
|
||||
osc.type = 'sine';
|
||||
osc.start(audioCtx.currentTime+0.05);
|
||||
osc.stop(audioCtx.currentTime+0.08);
|
||||
}
|
||||
|
||||
/** Load screen content from a binary sequence (new) */
|
||||
function load(str) {
|
||||
var content = str.substr(1);
|
||||
switch(str.charAt(0)) {
|
||||
case 'S':
|
||||
_load_content(content);
|
||||
break;
|
||||
case 'T':
|
||||
_load_labels(content);
|
||||
break;
|
||||
case 'B':
|
||||
_beep();
|
||||
break;
|
||||
default:
|
||||
console.warn("Bad data message type, ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}, 200);
|
||||
// this happens when the buffer gets fucked up via invalid unicode.
|
||||
// we basically use polling instead of socket then
|
||||
}
|
||||
|
||||
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() {
|
||||
var opts = {
|
||||
np_alt: false,
|
||||
cu_alt: false,
|
||||
fn_alt: false,
|
||||
};
|
||||
|
||||
function sendStrMsg(str) {
|
||||
Conn.send("STR:"+str);
|
||||
}
|
||||
|
||||
function sendPosMsg(y, x) {
|
||||
Conn.send("TAP:"+y+','+x);
|
||||
}
|
||||
|
||||
function sendBtnMsg(n) {
|
||||
Conn.send("BTN:"+n);
|
||||
}
|
||||
|
||||
function fa(alt, normal) {
|
||||
return opts.fn_alt ? alt : normal;
|
||||
}
|
||||
|
||||
function ca(alt, normal) {
|
||||
return opts.cu_alt ? alt : normal;
|
||||
}
|
||||
|
||||
function na(alt, normal) {
|
||||
return opts.np_alt ? alt : normal;
|
||||
}
|
||||
|
||||
function _bindFnKeys() {
|
||||
var keymap = {
|
||||
'tab': '\x09',
|
||||
'backspace': '\x08',
|
||||
'enter': '\x0d',
|
||||
'ctrl+enter': '\x0a',
|
||||
'esc': '\x1b',
|
||||
'up': ca('\x1bOA', '\x1b[A'),
|
||||
'down': ca('\x1bOB', '\x1b[B'),
|
||||
'right': ca('\x1bOC', '\x1b[C'),
|
||||
'left': ca('\x1bOD', '\x1b[D'),
|
||||
'home': ca('\x1bOH', fa('\x1b[H', '\x1b[1~')),
|
||||
'insert': '\x1b[2~',
|
||||
'delete': '\x1b[3~',
|
||||
'end': ca('\x1bOF', fa('\x1b[F', '\x1b[4~')),
|
||||
'pageup': '\x1b[5~',
|
||||
'pagedown': '\x1b[6~',
|
||||
'f1': fa('\x1bOP', '\x1b[11~'),
|
||||
'f2': fa('\x1bOQ', '\x1b[12~'),
|
||||
'f3': fa('\x1bOR', '\x1b[13~'),
|
||||
'f4': fa('\x1bOS', '\x1b[14~'),
|
||||
'f5': '\x1b[15~', // note the disconnect
|
||||
'f6': '\x1b[17~',
|
||||
'f7': '\x1b[18~',
|
||||
'f8': '\x1b[19~',
|
||||
'f9': '\x1b[20~',
|
||||
'f10': '\x1b[21~', // note the disconnect
|
||||
'f11': '\x1b[23~',
|
||||
'f12': '\x1b[24~',
|
||||
'shift+f1': fa('\x1bO1;2P', '\x1b[25~'),
|
||||
'shift+f2': fa('\x1bO1;2Q', '\x1b[26~'), // note the disconnect
|
||||
'shift+f3': fa('\x1bO1;2R', '\x1b[28~'),
|
||||
'shift+f4': fa('\x1bO1;2S', '\x1b[29~'), // note the disconnect
|
||||
'shift+f5': fa('\x1b[15;2~', '\x1b[31~'),
|
||||
'shift+f6': fa('\x1b[17;2~', '\x1b[32~'),
|
||||
'shift+f7': fa('\x1b[18;2~', '\x1b[33~'),
|
||||
'shift+f8': fa('\x1b[19;2~', '\x1b[34~'),
|
||||
'shift+f9': fa('\x1b[20;2~', '\x1b[35~'), // 35-38 are not standard - but what is?
|
||||
'shift+f10': fa('\x1b[21;2~', '\x1b[36~'),
|
||||
'shift+f11': fa('\x1b[22;2~', '\x1b[37~'),
|
||||
'shift+f12': fa('\x1b[23;2~', '\x1b[38~'),
|
||||
'np_0': na('\x1bOp', '0'),
|
||||
'np_1': na('\x1bOq', '1'),
|
||||
'np_2': na('\x1bOr', '2'),
|
||||
'np_3': na('\x1bOs', '3'),
|
||||
'np_4': na('\x1bOt', '4'),
|
||||
'np_5': na('\x1bOu', '5'),
|
||||
'np_6': na('\x1bOv', '6'),
|
||||
'np_7': na('\x1bOw', '7'),
|
||||
'np_8': na('\x1bOx', '8'),
|
||||
'np_9': na('\x1bOy', '9'),
|
||||
'np_mul': na('\x1bOR', '*'),
|
||||
'np_add': na('\x1bOl', '+'),
|
||||
'np_sub': na('\x1bOS', '-'),
|
||||
'np_point': na('\x1bOn', '.'),
|
||||
'np_div': na('\x1bOQ', '/'),
|
||||
// we don't implement numlock key (should change in numpad_alt mode, but it's even more useless than the rest)
|
||||
};
|
||||
|
||||
for (var k in keymap) {
|
||||
if (keymap.hasOwnProperty(k)) {
|
||||
bind(k, keymap[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bind(combo, str) {
|
||||
// mac fix - allow also cmd
|
||||
if (combo.indexOf('ctrl+') !== -1) {
|
||||
combo += ',' + combo.replace('ctrl', 'command');
|
||||
}
|
||||
|
||||
// unbind possible old binding
|
||||
key.unbind(combo);
|
||||
|
||||
key(combo, function (e) {
|
||||
e.preventDefault();
|
||||
sendStrMsg(str)
|
||||
});
|
||||
}
|
||||
|
||||
function _initKeys() {
|
||||
// This takes care of text characters typed
|
||||
window.addEventListener('keypress', function(evt) {
|
||||
var str = '';
|
||||
if (evt.key) str = evt.key;
|
||||
else if (evt.which) str = String.fromCodePoint(evt.which);
|
||||
if (str.length>0 && str.charCodeAt(0) >= 32) {
|
||||
// console.log("Typed ", str);
|
||||
sendStrMsg(str);
|
||||
}
|
||||
});
|
||||
|
||||
// ctrl-letter codes are sent as simple low ASCII codes
|
||||
for (var i = 1; i<=26;i++) {
|
||||
bind('ctrl+' + String.fromCharCode(96+i), String.fromCharCode(i));
|
||||
}
|
||||
bind('ctrl+]', '\x1b'); // alternate way to enter ESC
|
||||
bind('ctrl+\\', '\x1c');
|
||||
bind('ctrl+[', '\x1d');
|
||||
bind('ctrl+^', '\x1e');
|
||||
bind('ctrl+_', '\x1f');
|
||||
|
||||
_bindFnKeys();
|
||||
}
|
||||
|
||||
function init() {
|
||||
_initKeys();
|
||||
|
||||
// Button presses
|
||||
qsa('#buttons button').forEach(function(s) {
|
||||
s.addEventListener('click', function() {
|
||||
sendBtnMsg(+this.dataset['n']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
onTap: sendPosMsg,
|
||||
sendString: sendStrMsg,
|
||||
setAlts: function(cu, np, fn) {
|
||||
if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn) {
|
||||
opts.cu_alt = cu;
|
||||
opts.np_alt = np;
|
||||
opts.fn_alt = fn;
|
||||
|
||||
// rebind keys - codes have changed
|
||||
_bindFnKeys();
|
||||
}
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
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,166 +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',
|
||||
'term.display_tout_ms' => 'Redraw delay',
|
||||
'term.display_cooldown_ms' => 'Redraw cooldown',
|
||||
'term.fn_alt_mode' => 'SS3 Fn keys',
|
||||
|
||||
// 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,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Packing js..."
|
||||
|
||||
cat jssrc/chibi.js \
|
||||
jssrc/keymaster.js \
|
||||
jssrc/utils.js \
|
||||
jssrc/modal.js \
|
||||
jssrc/notif.js \
|
||||
jssrc/appcommon.js \
|
||||
jssrc/lang.js \
|
||||
jssrc/wifi.js \
|
||||
jssrc/term.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,160 +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">
|
||||
<label for="display_tout_ms"><?= tr('term.display_tout_ms') ?><span class="mq-phone"> (ms)</span></label>
|
||||
<input type="number" step=1 min=0 name="display_tout_ms" id="display_tout_ms" value="%display_tout_ms%" required>
|
||||
<span class="mq-no-phone"> ms</span>
|
||||
</div>
|
||||
|
||||
<div class="Row">
|
||||
<label for="display_cooldown_ms"><?= tr('term.display_cooldown_ms') ?><span class="mq-phone"> (ms)</span></label>
|
||||
<input type="number" step=1 min=0 name="display_cooldown_ms" id="display_cooldown_ms" value="%display_cooldown_ms%" required>
|
||||
<span class="mq-no-phone"> ms</span>
|
||||
</div>
|
||||
|
||||
<div class="Row checkbox" >
|
||||
<label><?= tr('term.fn_alt_mode') ?></label><!--
|
||||
--><span class="box" tabindex=0 role=checkbox></span>
|
||||
<input type="hidden" id="fn_alt_mode" name="fn_alt_mode" value="%fn_alt_mode%">
|
||||
</div>
|
||||
|
||||
<div class="Row 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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user