1
0
mirror of https://github.com/s00500/ESPUI.git synced 2025-07-04 01:00:19 +00:00

7 Commits

7 changed files with 157 additions and 11 deletions

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -78,6 +78,8 @@ Now you are set to go and use any code you want to with this library
- Control pad - Control pad
- Control pad with center button - Control pad with center button
- Slider - Slider
- Text Input (updateable)
- Numberinput (updateable)
Checkout the example for the usage Checkout the example for the usage
@ -100,11 +102,12 @@ Now you are set to go and use any code you want to with this library
- ~~Multiline Labels~~ - ~~Multiline Labels~~
- ~~GZip Files and serve from memory~~ - ~~GZip Files and serve from memory~~
- Datagraph output -> *WIP* - Datagraph output -> *WIP*
- Number input -> *WIP* - ~~Number input ~~
- Text input -> *WIP* - ~~Text input ~~
- Dokumentation for Text and number widget
- Number min and max value
- proper return value (as int and not as string) for slider - proper return value (as int and not as string) for slider
- Maybe a slider range setting, meanwhile please use *map()* - Maybe a slider range setting, meanwhile please use *map()*
- Improve slider stability
## Documentation ## Documentation

View File

@ -786,3 +786,26 @@
} }
*/ */
/* --------------------------------------------------------------
* Text and number inputs
*--------------------------------------------------------------- */
input {
margin: 0 auto 1.2rem auto;
padding: 2px 5px;
width: 100%;
box-sizing: border-box;
border: none;
border-radius: 4px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.8);
}
input[id^="num"] {
max-width: 6em;
width:auto;
text-align: right;
font-weight: bold;
font-size: 115%;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,42 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from jsmin import jsmin as jsminify ### import always available modules
from htmlmin import minify as htmlminify
from csscompressor import compress as cssminify
import gzip
import sys import sys
import os.path import os.path
import argparse import argparse
import re import re
from glob import glob from glob import glob
### import not always installed modules
missing = []
try:
from jsmin import jsmin as jsminify
except ModuleNotFoundError as e:
missing.append(e)
try:
from htmlmin import minify as htmlminify
except ModuleNotFoundError as e:
missing.append(e)
try:
from csscompressor import compress as cssminify
except ModuleNotFoundError as e:
missing.append(e)
try:
import gzip
except ModuleNotFoundError as e:
missing.append(e)
if len(missing) > 0:
# ERROR: at least one module is missing
for m in missing:
print("Cannot find module '%s'." % m.name)
print("Can't find %s required python module%s. Please install %s. If you're not sure how, a web search" % (len(missing), "s" if len(missing) > 1 else "", "them" if len(missing) > 1 else "it"))
print("for 'python', your operating system/python distribution and 'install modules' should help.")
print("For most people on unix-y systems, this line should work (possibly w/o the '3'):\n pip3 install %s" % " ".join(m.name for m in missing))
print("Here's the long documentation: https://packaging.python.org/tutorials/installing-packages/")
sys.exit(0)
### String template for C header files
TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====( TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====(
{minidata} {minidata}
)====="; )=====";
@ -17,7 +44,9 @@ TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====(
const uint8_t {constant}_GZIP[{gziplen}] PROGMEM = {{ {gzipdata} }}; const uint8_t {constant}_GZIP[{gziplen}] PROGMEM = {{ {gzipdata} }};
''' '''
def parse_arguments(args=None): def parse_arguments(args=None):
""" Command line argument parser definitions """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Prepares ESPUI header files by minifying and gzipping HTML, JS and CSS source files.") description="Prepares ESPUI header files by minifying and gzipping HTML, JS and CSS source files.")
parser.add_argument("--auto", "--all", "-a", dest="auto", action="store_true", parser.add_argument("--auto", "--all", "-a", dest="auto", action="store_true",
@ -36,6 +65,20 @@ def parse_arguments(args=None):
return args return args
def get_context(infile, outfile): def get_context(infile, outfile):
""" This function creates a 'context object': a dictionary containing all the data needed.
Dictionary members:
infile: Full path to the input file or directory as given or autodetected
indir: Full path to the infile parent.
dir: Full path to the input directory tree (indir or parent of indir).
name: Filename of infile excluding extension (i.e. filename up until the first dot)
type: Lowercase extension of infile; one of: html, js, css.
outfile: Full path to the output file or directory as given or autodetected.
outdir: Full path to output directory.
outfilename: Filename of outfile.
minifile: Full path and filename of the intermediary minified file.
constant: C header file constant name derived from infile.
If infile == minifile, the input file already is minified (contains ".min.")
"""
infile = os.path.realpath(infile) infile = os.path.realpath(infile)
dir, name, type = (os.path.basename(os.path.dirname(infile)), os.path.basename(infile).split(os.path.extsep)[0], os.path.basename(infile).split(os.path.extsep)[-1] ) dir, name, type = (os.path.basename(os.path.dirname(infile)), os.path.basename(infile).split(os.path.extsep)[0], os.path.basename(infile).split(os.path.extsep)[-1] )
type = type.strip(".").lower() type = type.strip(".").lower()
@ -58,6 +101,11 @@ def get_context(infile, outfile):
return locals() return locals()
def perform_gzip(c): def perform_gzip(c):
""" Performs GZIP on c['minidata'].
The returned context object will contain additional fields:
gzipdata: Comma-separated string of decimal byte values representing gzipped data.
gziplen: Count of decimal byte values in gzipdata.
"""
compressed = gzip.compress(bytes(c['minidata'], 'utf-8')) compressed = gzip.compress(bytes(c['minidata'], 'utf-8'))
c['gzipdata'] = ','.join([ str(b) for b in compressed ]) c['gzipdata'] = ','.join([ str(b) for b in compressed ])
c['gziplen'] = len(compressed) c['gziplen'] = len(compressed)
@ -65,6 +113,9 @@ def perform_gzip(c):
return c return c
def perform_minify(c): def perform_minify(c):
""" Performs minification on c['infile'].
The returned context object contains the additional field minidata: A string of minified file contents.
"""
with open(c['infile']) as infile: with open(c['infile']) as infile:
minifier = { minifier = {
'css': cssminify, 'css': cssminify,
@ -73,19 +124,27 @@ def perform_minify(c):
}.get(c['type']) or htmlminify }.get(c['type']) or htmlminify
print(" Using %s minifier" % c['type']) print(" Using %s minifier" % c['type'])
c['minidata'] = minifier(infile.read()) c['minidata'] = minifier(infile.read())
return perform_gzip(c) return c
def process_file(infile, outdir, storemini=True): def process_file(infile, outdir, storemini=True):
""" Processes one file """
print("Processing file %s" % infile) print("Processing file %s" % infile)
# Evaluate file and target context
c = get_context(infile, outdir) c = get_context(infile, outdir)
# Minify file data
c = perform_minify(c) c = perform_minify(c)
# Gzip minified data
c = perform_gzip(c)
if storemini: if storemini:
# Write intermediary minified file
if c['infile'] == c['minifile']: if c['infile'] == c['minifile']:
print(" Original file is already minified, refusing to overwrite it") print(" Original file is already minified, refusing to overwrite it")
else: else:
print(" Writing minified file %s" % c['minifile']) print(" Writing minified file %s" % c['minifile'])
with open(c['minifile'], 'w+') as minifile: with open(c['minifile'], 'w+') as minifile:
minifile.write(c['minidata']) minifile.write(c['minidata'])
# Write minified and gzipped data to C header file
with open(c['outfile'], 'w+') as outfile: with open(c['outfile'], 'w+') as outfile:
print(" Using C constant names %s and %s_GZIP" % (c['constant'], c['constant'])) print(" Using C constant names %s and %s_GZIP" % (c['constant'], c['constant']))
print(" Writing C header file %s" % c['outfile']) print(" Writing C header file %s" % c['outfile'])
@ -95,6 +154,10 @@ def filenamefilter(pattern, strings):
return filter(re.compile(pattern).search, strings) return filter(re.compile(pattern).search, strings)
def process_dir(sourcedir, outdir, recursive=True, storemini=True): def process_dir(sourcedir, outdir, recursive=True, storemini=True):
""" Processes a directory tree, recursively. Calls process_file on each HTML/CSS/JS file found.
Skips intermediary minified files. Standalone minified files (i.e. files containing ".min." that
do not have a full version) are processed without minifying again.
"""
pattern = r'/*\.(css|js|htm|html)$' pattern = r'/*\.(css|js|htm|html)$'
files = glob(sourcedir + "/**/*", recursive=True)+glob(sourcedir + "/*") if recursive else glob(sourcedir + "/*") files = glob(sourcedir + "/**/*", recursive=True)+glob(sourcedir + "/*") if recursive else glob(sourcedir + "/*")
files = filenamefilter(pattern, files) files = filenamefilter(pattern, files)
@ -105,6 +168,7 @@ def process_dir(sourcedir, outdir, recursive=True, storemini=True):
process_file(f, outdir, storemini) process_file(f, outdir, storemini)
def check_args(args): def check_args(args):
""" Checks argumental sanity and exits if the arguments are insane. """
abort = 0 abort = 0
if not os.path.exists(args.sources): if not os.path.exists(args.sources):
print("ERROR: Source %s does not exist" % args.sources) print("ERROR: Source %s does not exist" % args.sources)
@ -120,8 +184,12 @@ def check_args(args):
sys.exit(abort) sys.exit(abort)
def main(args): def main(args):
""" main entry point. """
# default source if not given: realpath(../examples/gui/data)
args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "examples", "gui", "data"))) args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "examples", "gui", "data")))
# default target if not given: realpath(../src)
args.target = os.path.realpath(args.target or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "src"))) args.target = os.path.realpath(args.target or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "src")))
# check arguments
check_args(args) check_args(args)
if os.path.isfile(args.sources): if os.path.isfile(args.sources):
print("Source %s is a file, will process one file only." % args.sources) print("Source %s is a file, will process one file only." % args.sources)