Merge branch 'develop' into laser_pointer
This commit is contained in:
commit
344bae18a2
|
@ -1,4 +1,5 @@
|
|||
/server/games.backup.json
|
||||
/public/config.js
|
||||
/public/dict/*.dict
|
||||
/public/l10n
|
||||
/.vscode
|
||||
|
|
13
README.md
13
README.md
|
@ -157,3 +157,16 @@ A full example is available in (doc/trivabble-apache-host.conf.sample)[doc/triva
|
|||
|
||||
:warning: Be careful to allow enough concurrent processes / threads / workers on your web server.
|
||||
Each player requires one long-standing connection (XHR, SSE or WebSocket), plus small requests when not using WebSockets.
|
||||
|
||||
## Enable the spell checker
|
||||
|
||||
This is an experimental feature. The process of building the dictionaries takes a lot of disk space.
|
||||
|
||||
Install `aspell` (to have the `word-list-compress` command) and run:
|
||||
|
||||
```sh
|
||||
cd dict-dists-extractor
|
||||
make
|
||||
```
|
||||
|
||||
Then, set `ENABLE_CHECK_SPELLING` to `true` in `public/config.js`.
|
||||
|
|
|
@ -0,0 +1,597 @@
|
|||
# -*- Makefile -*-
|
||||
|
||||
ROOT_DICT = ../public/dict
|
||||
OBJ_DIR = obj
|
||||
|
||||
# 0MB < dictionary size < 10MB
|
||||
SMALL = br ca cy da de en es fr ga hr hy is lv nl no pt sv
|
||||
# 10MB < Dictionary size < 50MB
|
||||
LARGE = bg el eo it pl ro ru sk sl uk
|
||||
# 50MB < dictionary size < 500MB
|
||||
VERY_LARGE = ar cs et fi
|
||||
LANGS = $(SMALL) $(LARGE)
|
||||
|
||||
|
||||
DICT_RULE_PRELUDE = sortuniq() { cat > "$$1"; sort -u -o "$$1" "$$1"; }; \
|
||||
echo Building $@ from $<
|
||||
|
||||
# he and hu: can not be generated
|
||||
# af eu la ms tr xk: no aspell dictionary
|
||||
|
||||
ASPDICT = https://ftp.gnu.org/gnu/aspell/dict/0index.html
|
||||
|
||||
LOWS = $(addsuffix .low,$(LANGS))
|
||||
|
||||
DICTS = $(addsuffix .dict,$(LANGS))
|
||||
|
||||
DEPEND = Makefile
|
||||
#MAKEFLAGS = -s
|
||||
|
||||
.PHONY: all required count clean low
|
||||
|
||||
all: required
|
||||
make $(addprefix check-,$(LANGS))
|
||||
|
||||
$(ROOT_DICT):
|
||||
mkdir $(ROOT_DICT)
|
||||
|
||||
$(OBJ_DIR):
|
||||
mkdir $(OBJ_DIR)
|
||||
|
||||
count:
|
||||
wc -l $(ROOT_DICT)/*
|
||||
|
||||
low: $(LOWS)
|
||||
|
||||
required: ${OBJ_DIR} ${OBJ_DIR}/src.mk ${ROOT_DICT}
|
||||
|
||||
$(OBJ_DIR)/src.mk:
|
||||
echo Creation language table
|
||||
wget $(ASPDICT) -q -O - | \
|
||||
awk 'BEGIN { base="'`dirname $(ASPDICT)`'" } \
|
||||
/<tr><td><a/ { $$0 = gensub(/.*"(.+)".*"(.+)\/(.+)".*/, "\\1 \\2 \\3", "g"); \
|
||||
printf "${OBJ_DIR}/%s.dir: $(OBJ_DIR)/%s\n\n", $$1, $$3; \
|
||||
printf "${OBJ_DIR}/%s:\n", $$3; \
|
||||
printf "\techo Downloading %s dictionary source\n", $$1; \
|
||||
printf "\twget -q %s/%s/%s -O $$@\n\n", base, $$2, $$3 } \
|
||||
/<\/table>/ { exit }' > $@
|
||||
|
||||
include $(wildcard ${OBJ_DIR}/src.mk)
|
||||
|
||||
%.dir:
|
||||
echo Installing $@ dictionary
|
||||
cd "$$(dirname "$@")" && \
|
||||
tar -xjf "$$(basename "$<")" && \
|
||||
cd "$$(basename "$(<:.tar.bz2=)")" && \
|
||||
./configure && \
|
||||
make && \
|
||||
cd .. && \
|
||||
mv "$$(basename "$<" .tar.bz2)" "$$(basename "$@")"
|
||||
|
||||
%.low: %.dir
|
||||
@echo "Building list of word $@"
|
||||
export DICT_NAME="$$(basename "$<" ".dir")"; \
|
||||
aspell --dict-dir="$$(realpath $<)" -d "$$DICT_NAME" dump master "$$DICT_NAME" | \
|
||||
aspell --dict-dir="$$(realpath $<)" -l "$$DICT_NAME" expand | \
|
||||
tr -s '[:space:]' '\n' > "$@" && \
|
||||
LC_ALL=C sort -S28G -u -o "$@" "$@"
|
||||
|
||||
$(OBJ_DIR)/no.low:
|
||||
make $(OBJ_DIR)/nb.low
|
||||
mv $(OBJ_DIR)/nb.low $@
|
||||
|
||||
$(OBJ_DIR)/pt.low:
|
||||
make $(OBJ_DIR)/pt_PT.low
|
||||
mv $(OBJ_DIR)/pt_PT.low $@
|
||||
|
||||
$(ROOT_DICT)/ar.dict: $(OBJ_DIR)/ar.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[ﺏِ ]/ب/g' \
|
||||
-e 's/[ﻍُ]/غ/g' \
|
||||
-e 's/[ﻙ ]/ل/g' \
|
||||
-e 's/[ﻡَ]/م/g' \
|
||||
-e 's/[ﻥَ]/ن/g' \
|
||||
-e 's/[ﻱَﻳّ]/ي/g' | \
|
||||
sortuniq "$@"
|
||||
# ا ل ن ش ا ش ي بِ ي ي ب ا ل ن ش ا ش ي بِ ي ي ب ن ش ا ش ي بِ ي ي ف ا ل ن ش ا ش ي بِ ي ي ف ب ا ل ن ش ا ش ي بِ ي ي ف ب ن ش ا ش ي بِ ي ي ف ك ا ل ن ش ا ش ي بِ ي ي ف ك ن ش ا ش ي بِ ي ي ف ل ل ن ش ا ش ي بِ ي ي ف ل ن ش ا ش ي بِ ي ي ف ن ش ا ش ي بِ ي ي ك ا ل ن ش ا ش ي بِ ي ي ك ن ش ا ش ي بِ ي ي ل ل ن ش ا ش ي بِ ي ي ل ن ش ا ش ي بِ ي ي ن ش ا ش ي بِ ي ي و ا ل ن ش ا ش ي بِ ي ي و ب ا ل ن ش ا ش ي بِ ي ي و ب ن ش ا ش ي بِ ي ي و ك ا ل ن ش ا ش ي بِ ي ي و ك ن ش ا ش ي بِ ي ي و ل ل ن ش ا ش ي بِ ي ي و ل ن ش ا ش ي بِ ي ي و ن ش ا ش ي بِ ي ي
|
||||
|
||||
$(ROOT_DICT)/bg.dict: $(OBJ_DIR)/bg.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
grep -v "^[a-zA-Z]" | \
|
||||
tr '[абвгдежзийклмнопрстуфхцчшщъьюя]' '[АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/br.dict: $(OBJ_DIR)/br.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[-]" | \
|
||||
grep -v "[^c]'" | \
|
||||
grep -v "'[^h]" | \
|
||||
sed -e 's/[àâ]/a/g' \
|
||||
-e 's/[éêè]/e/g' \
|
||||
-e 's/[î]/i/g' \
|
||||
-e 's/[ñ]/n/g' \
|
||||
-e 's/[ô]/o/g' \
|
||||
-e 's/[ûüù]/u/g' | \
|
||||
tr '[abcdefghijklmnopqrstuvwxyz]' '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/ca.dict: $(OBJ_DIR)/ca.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[áàãÁÀ]/a/g' \
|
||||
-e 's/[éèÉÈ]/e/g' \
|
||||
-e 's/[çÇ]/c/g' \
|
||||
-e 's/[íïÍ]/i/g' \
|
||||
-e 's/[ñ]/n/g' \
|
||||
-e 's/[óöòÓÒ]/o/g' \
|
||||
-e 's/[úüùÚ]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/cs.dict: $(OBJ_DIR)/cs.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[äâ]/a/g' \
|
||||
-e 's/[çćĆ]/c/g' \
|
||||
-e 's/[ęë]/e/g' \
|
||||
-e 's/[î]/i/g' \
|
||||
-e 's/[ľĽłĺ]/l/g' \
|
||||
-e 's/[ń]/n/g' \
|
||||
-e 's/[őöŐÖô]/o/g' \
|
||||
-e 's/[śŚ]/s/g' \
|
||||
-e 's/[űüŰÜ]/u/g' \
|
||||
-e 's/[ź]/z/g' | \
|
||||
sed -e 's/á/Á/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' -e 's/ě/Ě/g' \
|
||||
-e 's/í/Í/g' -e 's/ň/Ň/g' -e 's/ó/Ó/g' -e 's/ř/Ř/g' -e 's/š/Š/g' \
|
||||
-e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ů/Ů/g' -e 's/ý/Ý/g' -e 's/ž/Ž/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/cy.dict: $(OBJ_DIR)/cy.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
grep -vi "ph" | \
|
||||
sed -e 's/[âä]/a/g' \
|
||||
-e 's/[êë]/e/g' \
|
||||
-e 's/[îï]/i/g' \
|
||||
-e 's/[ôöò]/o/g' \
|
||||
-e 's/[ûüù]/u/g' \
|
||||
-e 's/[ŵ]/w/g' \
|
||||
-e 's/[ŷ]/y/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/da.dict: $(OBJ_DIR)/da.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[áä]/a/g' \
|
||||
-e 's/[ð]/d/g' \
|
||||
-e 's/[éëè]/e/g' \
|
||||
-e 's/[íì]/i/g' \
|
||||
-e 's/[óöô]/o/g' \
|
||||
-e 's/[ü]/u/g' | \
|
||||
tr '[a-zæøå]' '[A-ZÆØÅ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/de.dict: $(OBJ_DIR)/de.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[âà]/a/g' \
|
||||
-e 's/[éê]/e/g' \
|
||||
-e 's/[ñ]/n/g' \
|
||||
-e 's/[œ]/oe/g' \
|
||||
-e 's/[ß]/ss/g' | \
|
||||
tr '[a-zäöü]' '[A-ZÄÖÜ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/el.dict: $(OBJ_DIR)/el.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[άΆ]/α/g' \
|
||||
-e 's/[ϐ]/β/g' \
|
||||
-e 's/[έΈ]/ε/g' \
|
||||
-e 's/[ήΉ]/η/g' \
|
||||
-e 's/[ίϊΐΊ]/ι/g' \
|
||||
-e 's/[όΌ]/ο/g' \
|
||||
-e 's/[ς]/σ/g' \
|
||||
-e 's/[ΰϋύΎ]/υ/g' \
|
||||
-e 's/[ϕ]/φ/g' \
|
||||
-e 's/[ώΏ]/ω/g' | \
|
||||
tr '[αβγδεζηθικλμνξοπρστυφχψω]' '[ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/en.dict: $(OBJ_DIR)/en.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[áâàäåÅ]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[éêèë]/e/g' \
|
||||
-e 's/[íîï]/i/g' \
|
||||
-e 's/[ñ]/n/g' \
|
||||
-e 's/[óôöøiÖ]/o/g' \
|
||||
-e 's/[úûüùiÜ]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/eo.dict: $(OBJ_DIR)/eo.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'qQwWxXyY-]" | \
|
||||
tr '[a-zĉĝĥĵŝŭ]' '[A-ZĈĜĤĴŜŬ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/es.dict: $(OBJ_DIR)/es.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[áÁ]/a/g' \
|
||||
-e 's/[é]/e/g' \
|
||||
-e 's/[í]/i/g' \
|
||||
-e 's/[ó]/o/g' \
|
||||
-e 's/[úü]/u/g' | \
|
||||
tr '[a-zñ]' '[A-ZÑ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/et.dict: $(OBJ_DIR)/et.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'qwxQWX-]" | \
|
||||
tr '[a-zäöõüšž]' '[A-ZÄÖÕÜŠŽ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/fi.dict: $(OBJ_DIR)/fi.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.':-]" | \
|
||||
tr '[a-zäåöšž]' '[A-ZÄÅÖŠŽ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/fr.dict: $(OBJ_DIR)/fr.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[àâä]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[Ééèêë]/e/g' \
|
||||
-e 's/[ïî]/i/g' \
|
||||
-e 's/[ôö]/o/g' \
|
||||
-e 's/[úùûü]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/ga.dict: $(OBJ_DIR)/ga.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.':-]" | \
|
||||
sed -e 's/[áâãÁ]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[éèÉ]/e/g' \
|
||||
-e 's/[íÍ]/i/g' \
|
||||
-e 's/[óöòÓ]/o/g' \
|
||||
-e 's/[úüÚ]/u/g' | \
|
||||
tr '[a-zñ]' '[A-ZÑ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/he.dict: $(OBJ_DIR)/he.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/hr.dict: $(OBJ_DIR)/hr.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
tr '[a-zćčšž]' '[A-ZĆČŠŽ]' | \
|
||||
sed 's/đ/Đ/g' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/hu.dict: $(OBJ_DIR)/hu.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
tr '[a-záéóöőúüű]' '[A-ZÁÉÓÖŐÚÜŰ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
#grep -v "['ԁԃԂԃ-]"
|
||||
$(ROOT_DICT)/hy.dict: $(OBJ_DIR)/hy.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
sed -e 's/ա/Ա/g' -e 's/բ/Բ/g' -e 's/գ/Գ/g' -e 's/դ/Դ/g' -e 's/ե/Ե/g' \
|
||||
-e 's/զ/Զ/g' -e 's/է/Է/g' -e 's/ը/Ը/g' -e 's/թ/Թ/g' -e 's/ժ/Ժ/g' \
|
||||
-e 's/ի/Ի/g' -e 's/լ/Լ/g' -e 's/խ/Խ/g' -e 's/ծ/Ծ/g' -e 's/կ/Կ/g' \
|
||||
-e 's/հ/Հ/g' -e 's/ձ/Ձ/g' -e 's/ղ/Ղ/g' -e 's/ճ/Ճ/g' -e 's/մ/Մ/g' \
|
||||
-e 's/յ/Յ/g' -e 's/ն/Ն/g' -e 's/շ/Շ/g' -e 's/ո/Ո/g' -e 's/չ/Չ/g' \
|
||||
-e 's/պ/Պ/g' -e 's/ջ/Ջ/g' -e 's/ռ/Ռ/g' -e 's/ս/Ս/g' -e 's/վ/Վ/g' \
|
||||
-e 's/տ/Տ/g' -e 's/ր/Ր/g' -e 's/ց/Ց/g' -e 's/ւ/Ւ/g' -e 's/փ/Փ/g' \
|
||||
-e 's/ք/Ք/g' -e 's/օ/Օ/g' -e 's/ֆ/Ֆ/g' -e 's/ու/ՈՒ/g' \
|
||||
-e "s/'//g" | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/it.dict: $(OBJ_DIR)/it.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
sed -e 's/[àâ]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[éè]/e/g' \
|
||||
-e 's/[ì]/i/g' \
|
||||
-e 's/[òiô]/o/g' \
|
||||
-e 's/[ù]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/is.dict: $(OBJ_DIR)/is.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
tr '[a-záæðéíóöúýþ]' '[A-ZÁÆÐÉÍÓÖÚÝÞ]' | sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/lv.dict: $(OBJ_DIR)/lv.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'-]" | \
|
||||
tr '[a-zāčēģīķļņšūž]' '[A-ZĀČĒĢĪĶĻŅŠŪŽ]' | sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/nl.dict: $(OBJ_DIR)/nl.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[1-9+/' .-]" | \
|
||||
sed -e 's/[áäâàÅ]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[éëèê]/e/g' \
|
||||
-e 's/[íïî]/i/g' \
|
||||
-e 's/[ñ]/n/g' \
|
||||
-e 's/[óöô]/o/g' \
|
||||
-e 's/[úüûùÜ]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/no.dict: $(OBJ_DIR)/no.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[.'\"-]" | \
|
||||
sed -e 's/[áäÄ]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[ð]/d/g' \
|
||||
-e 's/[éëèêÉ]/e/g' \
|
||||
-e 's/[íì]/i/g' \
|
||||
-e 's/[óöôò]/o/g' \
|
||||
-e 's/[ü]/u/g' | \
|
||||
tr '[a-zæøå]' '[A-ZÆØÅ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/pl.dict: $(OBJ_DIR)/pl.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[ä]/a/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[é]/e/g' \
|
||||
-e 's/[i]/i/g' \
|
||||
-e 's/[ö]/o/g' \
|
||||
-e 's/[šŠ]/s/g' \
|
||||
-e 's/[û]/u/g' | \
|
||||
tr '[a-złąęóśżćńź]' '[A-ZŁĄĘÓŚŻĆŃŹ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/pt.dict: $(OBJ_DIR)/pt.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[áãâàÁÂ]/a/g' \
|
||||
-e 's/[éêèÉ]/e/g' \
|
||||
-e 's/[íîÍ]/i/g' \
|
||||
-e 's/[óôõÓ]/o/g' \
|
||||
-e 's/[úüÚ]/u/g' | \
|
||||
tr '[a-zç]' '[A-ZÇ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/ro.dict: $(OBJ_DIR)/ro.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[áâăÂĂ]/a/g' \
|
||||
-e 's/[éè]/e/g' \
|
||||
-e 's/[íîÎ]/i/g' \
|
||||
-e 's/[șȘ]/s/g' \
|
||||
-e 's/[țȚ]/t/g' \
|
||||
-e 's/[ü]/u/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/ru.dict: $(OBJ_DIR)/ru.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/а/А/g' -e 's/б/Б/g' -e 's/в/В/g' -e 's/г/Г/g' -e 's/д/Д/g' \
|
||||
-e 's/е/Е/g' -e 's/ё/Ё/g' -e 's/ж/Ж/g' -e 's/з/З/g' -e 's/и/И/g' \
|
||||
-e 's/й/Й/g' -e 's/к/К/g' -e 's/л/Л/g' -e 's/м/М/g' -e 's/н/Н/g' \
|
||||
-e 's/о/О/g' -e 's/п/П/g' -e 's/р/Р/g' -e 's/с/С/g' -e 's/т/Т/g' \
|
||||
-e 's/у/У/g' -e 's/ф/Ф/g' -e 's/х/Х/g' -e 's/ц/Ц/g' -e 's/ч/Ч/g' \
|
||||
-e 's/ш/Ш/g' -e 's/щ/Щ/g' -e 's/ъ/Ъ/g' -e 's/ы/Ы/g' -e 's/ь/Ь/g' \
|
||||
-e 's/э/Э/g' -e 's/ю/Ю/g' -e 's/я/Я/g' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/sk.dict: $(OBJ_DIR)/sk.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[ë]/e/g' | \
|
||||
sed -e 's/á/Á/g' -e 's/ä/Ä/g' -e 's/č/Č/g' -e 's/ď/Ď/g' -e 's/é/É/g' \
|
||||
-e 's/ě/Ě/g' -e 's/í/Í/g' -e 's/ľ/Ľ/g' -e 's/ĺ/Ĺ/g' -e 's/ň/Ň/g' \
|
||||
-e 's/ô/Ô/g' -e 's/ó/Ó/g' -e 's/ö/Ö/g' -e 's/ŕ/Ŕ/g' -e 's/ř/Ř/g' \
|
||||
-e 's/š/Š/g' -e 's/ť/Ť/g' -e 's/ú/Ú/g' -e 's/ü/Ü/g' -e 's/ý/Ý/g' \
|
||||
-e 's/ž/Ž/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/sl.dict: $(OBJ_DIR)/sl.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[áâȁ]/a/g' \
|
||||
-e 's/[ćĆ]/c/g' \
|
||||
-e 's/[éȇȅ]/e/g' \
|
||||
-e 's/[đĐ]/d/g' \
|
||||
-e 's/[íȋȉ]/i/g' \
|
||||
-e 's/[óȏȍö]/o/g' \
|
||||
-e 's/[ŕȓ]/r/g' \
|
||||
-e 's/[úȗȕü]/u/g' | \
|
||||
sed -e 's/č/Č/g' -e 's/š/Š/g' -e 's/ž/Ž/g' | \
|
||||
tr '[a-z]' '[A-Z]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/sv.dict: $(OBJ_DIR)/sv.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "['-]" | \
|
||||
sed -e 's/[æ]/ae/g' \
|
||||
-e 's/[ç]/c/g' \
|
||||
-e 's/[é]/e/g' \
|
||||
-e 's/[ü]/u/g' | \
|
||||
tr '[a-zåäö]' '[A-ZÅÄÖ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
$(ROOT_DICT)/uk.dict: $(OBJ_DIR)/uk.low $(DEPEND)
|
||||
@$(DICT_RULE_PRELUDE); \
|
||||
cat "$<" | \
|
||||
grep -v '^.$$' | \
|
||||
grep -v "[-]" | \
|
||||
tr '[абвгґдеєжзиіїйклмнопрстуфхцчшщьюя]' '[АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ]' | \
|
||||
sortuniq "$@"
|
||||
|
||||
CHECKER = cat $(1) | \
|
||||
grep -v "^[$(2)]*$$" | egrep -v "$(3)" && exit 1 || echo "$< is correct"
|
||||
|
||||
check-ar:$(ROOT_DICT)/ar.dict
|
||||
$(call CHECKER,$<,ابتثجحخدذرزسشصضطظعغفقكلمنهويءأإؤئآةى,~)
|
||||
|
||||
|
||||
check-bg:$(ROOT_DICT)/bg.dict
|
||||
$(call CHECKER,$<,АОЕИТНПРСВМБДКЛГЪЖЗУЧЯЙХЦШЮФЩЬ,~)
|
||||
|
||||
check-br:$(ROOT_DICT)/br.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVWXYZ,C'H[A-Z]*(C'H)*)
|
||||
|
||||
check-ca:$(ROOT_DICT)/ca.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZ,L·L[A-Z]*(L·L)*)
|
||||
|
||||
check-cs:$(ROOT_DICT)/cs.dict
|
||||
$(call CHECKER,$<,AÁBCČDĎEÉĚFGHIÍJKLMNŇOÓPQRŘSŠTŤUÚŮVWXYÝZŽ,~)
|
||||
|
||||
check-da:$(ROOT_DICT)/da.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ,~)
|
||||
|
||||
check-de:$(ROOT_DICT)/de.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ,~)
|
||||
|
||||
check-el:$(ROOT_DICT)/el.dict
|
||||
$(call CHECKER,$<,ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ,~)
|
||||
|
||||
check-eo:$(ROOT_DICT)/eo.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVZĈĜĤĴŜŬ,~)
|
||||
|
||||
check-es:$(ROOT_DICT)/es.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÑ,~)
|
||||
|
||||
check-et:$(ROOT_DICT)/et.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPRSTUVYZÄÖÕÜŠŽ,~)
|
||||
|
||||
check-fi:$(ROOT_DICT)/fi.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÄÅÖŠŽ,~)
|
||||
|
||||
check-ga:$(ROOT_DICT)/ga.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÑ,~)
|
||||
|
||||
check-he:$(ROOT_DICT)/he.dict
|
||||
$(call CHECKER,$<,אבגדהוזחטיכלמנסעפצקרשת,~)
|
||||
|
||||
check-hr:$(ROOT_DICT)/hr.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZĆČĐŠŽ,~)
|
||||
|
||||
check-hu:$(ROOT_DICT)/hu.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÉÓÖŐÚÜŰ,~)
|
||||
|
||||
check-hy:$(ROOT_DICT)/hy.dict
|
||||
$(call CHECKER,$<,ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՈՒև,~)
|
||||
|
||||
check-is:$(ROOT_DICT)/is.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÆÐÉÍÓÖÚÝÞ,~)
|
||||
|
||||
check-lv:$(ROOT_DICT)/lv.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZĀČĒĢĪĶĻŅŠŪŽ,~)
|
||||
|
||||
check-no:$(ROOT_DICT)/no.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ,~)
|
||||
|
||||
check-pl:$(ROOT_DICT)/pl.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZŁĄĘÓŚŻĆŃŹ,~)
|
||||
|
||||
check-pt:$(ROOT_DICT)/pt.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÇ,~)
|
||||
|
||||
check-ru:$(ROOT_DICT)/ru.dict
|
||||
$(call CHECKER,$<,АБВГДЕЁЖЗИЙКЛлМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ,~)
|
||||
|
||||
check-sk:$(ROOT_DICT)/sk.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÁÄČĎÉĚÍĽĹŇÔÓÖŔŠŤÚÜÝŽ,~)
|
||||
|
||||
check-sl:$(ROOT_DICT)/sl.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZČŠŽ,~)
|
||||
|
||||
check-sv:$(ROOT_DICT)/sv.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ,~)
|
||||
|
||||
check-uk:$(ROOT_DICT)/uk.dict
|
||||
$(call CHECKER,$<,ОАИНВЕІТКРСДЛМУПЗЯЬБГЧХЄЇЙЖЦШЮҐФЩ',~)
|
||||
|
||||
check-%:$(ROOT_DICT)/%.dict
|
||||
$(call CHECKER,$<,ABCDEFGHIJKLMNOPQRSTUVWXYZ,~)
|
||||
|
||||
clean:
|
||||
rm -rf "$(OBJ_DIR)"
|
|
@ -166,8 +166,35 @@ msgstr "Vous avez changé la langue du plateau en {0}"
|
|||
msgid "{0} changed the language of the board to {1}"
|
||||
msgstr "{0} a changé la langue du plateau en {1}"
|
||||
|
||||
msgid "Configuration"
|
||||
msgstr "Options de configuration"
|
||||
msgid "Check spelling for new words"
|
||||
msgstr "Vérifier l'orthographe des mots nouveaux"
|
||||
|
||||
msgid "Incorrect spelling for {0} from {1}"
|
||||
msgstr "Orthographe incorrecte pour {0} parmi {1}"
|
||||
|
||||
msgid "All words are correct: {0}"
|
||||
msgstr "Tous les mots sont corrects : {0}"
|
||||
|
||||
msgid "No new word found"
|
||||
msgstr "Aucun nouveau mot trouvé"
|
||||
|
||||
msgid "Incorrect dictionary file."
|
||||
msgstr "Dictionnaire incorrect."
|
||||
|
||||
msgid "Can't load dictionary file."
|
||||
msgstr "Impossible de charger le dictionnaire"
|
||||
|
||||
msgid "Enable spell checker"
|
||||
msgstr "Activer le vérificateur orthographique"
|
||||
|
||||
msgid "Spell checking requires Trivabble to download a dictionary. Do you confirm?"
|
||||
msgstr "La vérification orthographique nécessite que Trivabble télécharge un dictionnaire. Confirmez-vous ?"
|
||||
|
||||
msgid "Spell checking is based on:"
|
||||
msgstr "La vérification orthographique est basée sur :"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
msgid "Configuration window"
|
||||
msgstr "Fenêtre de configuration"
|
||||
|
|
|
@ -172,7 +172,34 @@ msgstr ""
|
|||
msgid "{0} changed the language of the board to {1}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configuration"
|
||||
msgid "Check spelling for new words"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incorrect spelling for {0} from {1}"
|
||||
msgstr ""
|
||||
|
||||
msgid "All words are correct: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "No new word found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incorrect dictionary file."
|
||||
msgstr ""
|
||||
|
||||
msgid "Can't load dictionary file."
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable spell checker"
|
||||
msgstr ""
|
||||
|
||||
msgid "Spell checking requires Trivabble to download a dictionary. Do you confirm?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Spell checking is based on:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configuration window"
|
||||
|
|
|
@ -17,6 +17,9 @@ window.TrivabbleConf = {
|
|||
// to tweak only if your webserver is shared with other conflicting resources at / ( ex: yunohost integration )
|
||||
APP_PATH: "",
|
||||
|
||||
// Whether the spell checker is enabled (dictionaries must be downloaded on the server before enabling this option)
|
||||
ENABLE_SPELL_CHECKER: false,
|
||||
|
||||
// I don't like trailing commas, here is a nice message for you reading this file :-)
|
||||
HAVE_FUN: true
|
||||
};
|
||||
|
|
|
@ -44,37 +44,24 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="modal-config-dialog">
|
||||
<div class="modal" id="modal-settings-dialog">
|
||||
<div class="modal-content">
|
||||
<h2>
|
||||
<span data-l10n="text-content">Configuration window</span>
|
||||
<span class="modal-button" id="modal-close-btn">×</span>
|
||||
</h2>
|
||||
<span data-l10n="text-content">Settings</span>
|
||||
<span class="modal-button" id="btn-settings-close">×</span>
|
||||
</h2>
|
||||
<div id="prefs">
|
||||
<p><label><input type="checkbox" id="tiles-sound" checked="checked" /><span data-l10n="text-content">Sound of the tiles</span></label></p>
|
||||
<p><label><input type="checkbox" id="msg-sound" checked="checked" /><span data-l10n="text-content">Sound of messages</span></label></p>
|
||||
</div>
|
||||
<hr/>
|
||||
<div id="prefs">
|
||||
<p><label>
|
||||
<span data-l10n="text-content">(fast)</span><input type="range" min="0" max="0" id="double-tap-duration"/><span data-l10n="text-content">(slow)</span>
|
||||
<br/>
|
||||
<span data-l10n="text-content">Double tap duration</span>
|
||||
</label></p>
|
||||
<p><label>
|
||||
<span data-l10n="text-content">(fast)</span><input type="range" min="0" max="0" id="flash-light-duration"/><span data-l10n="text-content">(slow)</span>
|
||||
<br/>
|
||||
<span data-l10n="text-content">Flash light duration</span>
|
||||
</label></p>
|
||||
<p><label>
|
||||
<input type="text" size="6" id="flash-light-color"/>
|
||||
<span data-l10n="text-content">Flash light color</span>
|
||||
</label></p>
|
||||
</div>
|
||||
<p id="enable-spell-checker-outer" style="display:none"><label><input type="checkbox" id="enable-spell-checker" /> <span data-l10n="text-content">Enable spell checker</span></label></p>
|
||||
<p><label><span data-l10n="text-content">(fast)</span><input type="range" min="0" max="0" id="double-tap-duration"/><span data-l10n="text-content">(slow)</span><br/><span data-l10n="text-content">Double tap duration</span></label></p>
|
||||
<p><label><span data-l10n="text-content">(fast)</span><input type="range" min="0" max="0" id="flash-light-duration"/><span data-l10n="text-content">(slow)</span><br/><span data-l10n="text-content">Flash light duration</span></label></p>
|
||||
<p><label><input type="text" size="6" id="flash-light-color"/> <span data-l10n="text-content">Flash light color</span></label></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<div id="content">
|
||||
<table id="board">
|
||||
<tr><td class="corner"></td></tr>
|
||||
</table>
|
||||
|
@ -84,6 +71,7 @@
|
|||
</div>
|
||||
|
||||
<div id="panel">
|
||||
<button id="btn-settings" data-l10n="text-content">Settings</button>
|
||||
<div id="bag"></div>
|
||||
<p><span data-l10n="text-content">Number of tiles in the bag:</span><br /><span id="remaining-letters">102</span><br /><span id="help-bag" data-l10n="text-content">Click on it to take one.</span><a href="#" id="help-clear" style="display:none"></a></p>
|
||||
<table id="participants">
|
||||
|
@ -94,7 +82,8 @@
|
|||
<p id="help-turn" data-l10n="text-content">Who's turn? Click on the Turn button!</p>
|
||||
<button id="clear-rack" class="minibutton" data-l10n="text-content">Put back all the tiles of your rack in the bag</button>
|
||||
<button id="show-rack" class="minibutton" data-l10n="text-content">Show my rack to other players</button>
|
||||
<button id="modal-config-btn" class="text-content" data-l10n="text-content">Configuration</button>
|
||||
<button id="check-spelling" class="minibutton" data-l10n="text-content" style="display:none">Check spelling for new words</button>
|
||||
<p id="info-spell-checking" style="display:none;"><span data-l0n="text-content">Spell checking is based on:</span> <a rel="noopener noreferrer" target="_blank" href="http://aspell.net">Aspell</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -156,6 +156,11 @@ button:hover {
|
|||
cursor:pointer
|
||||
}
|
||||
|
||||
button[disabled=disabled], button:disabled {
|
||||
background:#AFA;
|
||||
cursor:not-allowed;
|
||||
}
|
||||
|
||||
#rack {
|
||||
background:#EEC;
|
||||
font-size:0;
|
||||
|
@ -192,8 +197,12 @@ button:hover {
|
|||
cursor:pointer
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #E3E;
|
||||
.tile.tile-spelling-ok {
|
||||
background-color: #3E3;
|
||||
}
|
||||
|
||||
.tile.tile-spelling-nok {
|
||||
background-color: #E33;
|
||||
}
|
||||
|
||||
.tile.tile-highlight {
|
||||
|
@ -203,6 +212,10 @@ button:hover {
|
|||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #E3E;
|
||||
}
|
||||
|
||||
@keyframes highlight {
|
||||
0% {
|
||||
background:red;
|
||||
|
@ -347,7 +360,8 @@ td.blink {
|
|||
width:165px;
|
||||
height:160px;
|
||||
background:url(bag.svg) no-repeat;
|
||||
background-size:100% 100%
|
||||
background-size:100% 100%;
|
||||
flex:1;
|
||||
}
|
||||
|
||||
#bag:hover {
|
||||
|
@ -502,12 +516,41 @@ td.blink {
|
|||
border-radius: 0.25rem;
|
||||
background-color: lightgray;
|
||||
}
|
||||
.modal-button:hover {
|
||||
|
||||
.modal-button:hover, #btn-settings:hover {
|
||||
background-color: darkgray;
|
||||
}
|
||||
|
||||
.show-modal {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: scale(1.0);
|
||||
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
|
||||
}
|
||||
|
||||
.alert {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#btn-settings {
|
||||
background:lightgray;
|
||||
color:black;
|
||||
font-size:small;
|
||||
border-radius:3px;
|
||||
border:none;
|
||||
margin:0 0 0 auto;
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
#btn-settings:before {
|
||||
content: "⚙️ "
|
||||
}
|
||||
|
||||
#info-spell-checking {
|
||||
font-size:small;
|
||||
color:gray;
|
||||
}
|
||||
|
||||
#info-spell-checking a {
|
||||
color:black;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
setConf("ENABLE_EVENT_SOURCE", true);
|
||||
setConf("MAX_WEBSOCKET_ERRORS", 1);
|
||||
setConf("APP_PATH", "");
|
||||
setConf("ENABLE_SPELL_CHECKER", false);
|
||||
setConf("DOUBLE_TAP_DURATIONS", [650, 1100, 1800, 3000, 5000]);
|
||||
setConf("FLASH_LIGHT_DURATIONS", [800, 1600, 3200]);
|
||||
setConf("FLASH_LIGHT_COLOR", "#E3E");
|
||||
|
@ -62,6 +63,7 @@
|
|||
let scoreOf;
|
||||
let bag;
|
||||
let boardLangSelect;
|
||||
const downloadedDictionaries = {};
|
||||
|
||||
const playerLetters = [];
|
||||
let currentPlayer = "";
|
||||
|
@ -82,6 +84,7 @@
|
|||
let remainingLetters = 0;
|
||||
let needsRestart = false;
|
||||
const gameInProgress = false;
|
||||
let currentTilePlayed = {};
|
||||
|
||||
let eventSource = null;
|
||||
let webSocket = null;
|
||||
|
@ -151,6 +154,61 @@
|
|||
}
|
||||
}
|
||||
|
||||
function getDictionary(code, callback, force) {
|
||||
if (downloadedDictionaries[code]) {
|
||||
if (downloadedDictionaries[code].length) {
|
||||
if (callback) {
|
||||
callback(downloadedDictionaries[code]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME we silently never call the callback here
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force && localStorage.spellCheckerEnabled !== "true") {
|
||||
myConfirm(
|
||||
_("Spell checking requires Trivabble to download a dictionary. Do you confirm?"),
|
||||
function () {
|
||||
localStorage.spellCheckerEnabled = "true";
|
||||
getDictionary(code, callback, true);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid redownloading the dictionary if a download is on its way
|
||||
downloadedDictionaries[code] = [];
|
||||
|
||||
const file = new XMLHttpRequest();
|
||||
file.open("GET", "dict/" + code + ".dict", true);
|
||||
file.onreadystatechange = function () {
|
||||
if (file.readyState === 4) {
|
||||
if (file.status === 200) {
|
||||
try {
|
||||
const dictionary = file.responseText.split("\n");
|
||||
downloadedDictionaries[code] = dictionary;
|
||||
callback(dictionary);
|
||||
return;
|
||||
} catch (e) {
|
||||
delete downloadedDictionaries[code];
|
||||
myAlert(_("Incorrect dictionary file."));
|
||||
}
|
||||
} else {
|
||||
delete downloadedDictionaries[code];
|
||||
myAlert(_("Can't load dictionary file."));
|
||||
}
|
||||
}
|
||||
};
|
||||
file.send();
|
||||
}
|
||||
|
||||
function spellCheckerSettingChecked() {
|
||||
localStorage.spellCheckerEnabled = document.getElementById("enable-spell-checker").checked.toString();
|
||||
initSpellChecker();
|
||||
}
|
||||
|
||||
function removeElem(elem) {
|
||||
elem.parentNode.removeChild(elem);
|
||||
}
|
||||
|
@ -211,6 +269,18 @@
|
|||
movingTile.style.width = "";
|
||||
movingTile.style.height = "";
|
||||
|
||||
/* Keep track of letter */
|
||||
if (moveCMD.from === "rack") {
|
||||
if (moveCMD.to === "board") {
|
||||
currentTilePlayed[moveCMD.indexTo] = "-";
|
||||
}
|
||||
} else {/* moveCMD.from === "board" */
|
||||
if (moveCMD.to === "board") {
|
||||
currentTilePlayed[moveCMD.indexTo] = currentTilePlayed[moveCMD.indexFrom];
|
||||
}
|
||||
delete currentTilePlayed[moveCMD.indexFrom];
|
||||
}
|
||||
|
||||
mouseUp(document, dragTileEnd, true);
|
||||
mouseMove(document, dragTileMove, true);
|
||||
|
||||
|
@ -683,8 +753,6 @@
|
|||
? format(_("You changed the language of the board to {0}"), newLang)
|
||||
: format(_("{0} changed the language of the board to {1}"), msg.sender, newLang)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case "highlightTile": {
|
||||
|
@ -711,6 +779,7 @@
|
|||
tablePlayers[currentPlayer].classList.remove("current-player");
|
||||
}
|
||||
|
||||
currentTilePlayed = {};
|
||||
currentPlayer = player;
|
||||
refreshCurrentPlayer();
|
||||
}
|
||||
|
@ -872,6 +941,9 @@
|
|||
break;
|
||||
case "setCell":
|
||||
setCell(data.indexTo, data.letter, Object.prototype.hasOwnProperty.call(data, "player") && data.player !== localStorage.trivabblePlayerName);
|
||||
if ((data.letter !== "") && (currentTilePlayed[data.indexTo] === "-")) {
|
||||
currentTilePlayed[data.indexTo] = data.letter;
|
||||
}
|
||||
break;
|
||||
case "setRackCell":
|
||||
setRackCell(data.indexTo, data.letter);
|
||||
|
@ -1443,6 +1515,181 @@
|
|||
|
||||
}
|
||||
|
||||
function getLetterFromBoard(row, col) {
|
||||
if ((row < 0) || (row >= 15) || (col < 0) || (col >= 15)) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
const index = (row * 15) + col;
|
||||
const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0];
|
||||
const tile = tilePlaceholder.getElementsByClassName("tile")[0];
|
||||
return tile.firstChild.textContent;
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function searchWordInLine(row, col, incRow, incCol) {
|
||||
const initLetter = getLetterFromBoard(row, col);
|
||||
|
||||
/* Look for first letter in line */
|
||||
while (getLetterFromBoard(row - incRow, col - incCol) !== "") {
|
||||
row -= incRow;
|
||||
col -= incCol;
|
||||
}
|
||||
|
||||
/* Look for last letter in line */
|
||||
const word = {letters: "", row: row, col: col, incRow: incRow, incCol: incCol};
|
||||
let letter;
|
||||
while ((letter = getLetterFromBoard(row, col)) !== "") {
|
||||
word.letters += letter;
|
||||
row += incRow;
|
||||
col += incCol;
|
||||
}
|
||||
return (word.letters === initLetter) ? null : word;
|
||||
}
|
||||
|
||||
function isNewWord(newWord, words) {
|
||||
if (newWord === null) {
|
||||
return false;
|
||||
}
|
||||
for (const k of Object.keys(words)) {
|
||||
if ((words[k].letters === newWord.letters) &&
|
||||
(words[k].row === newWord.row) &&
|
||||
(words[k].col === newWord.col) &&
|
||||
(words[k].incRow === newWord.incRow) &&
|
||||
(words[k].incCol === newWord.incCol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function searchNewWords() {
|
||||
|
||||
const words = [];
|
||||
for (const i of Object.keys(currentTilePlayed)) {
|
||||
|
||||
/* Get board position */
|
||||
const row = Math.floor(i / 15);
|
||||
const col = i % 15;
|
||||
|
||||
/* Look for word in column */
|
||||
const newWordInCol = searchWordInLine(row, col, 1, 0);
|
||||
if (isNewWord(newWordInCol, words)) {
|
||||
words.push(newWordInCol);
|
||||
}
|
||||
|
||||
/* Look for word in row */
|
||||
const newWordInRow = searchWordInLine(row, col, 0, 1);
|
||||
if (isNewWord(newWordInRow, words)) {
|
||||
words.push(newWordInRow);
|
||||
}
|
||||
|
||||
/* Should we look for word in diag? */
|
||||
|
||||
/* If nothing found, it's a one letter word */
|
||||
if ((newWordInCol === null) && (newWordInRow === null)) {
|
||||
words.push({letters: getLetterFromBoard(row, col), row: row, col: col, incRow: 0, incCol: 0});
|
||||
}
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
function modifyTileClass(word, value, action) {
|
||||
|
||||
/* action: true for add, false for remove */
|
||||
|
||||
if (action) {
|
||||
|
||||
/* only for new words */
|
||||
for (let l = 0; l < word.letters.length; l++) {
|
||||
const index = ((word.row + (l * word.incRow)) * 15) + word.col + (l * word.incCol);
|
||||
const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0];
|
||||
const tile = tilePlaceholder.getElementsByClassName("tile")[0];
|
||||
|
||||
tile.classList.add(value);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* tiles on board */
|
||||
for (let index = 0; index < 15 * 15; index++) {
|
||||
const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0];
|
||||
const tile = tilePlaceholder.getElementsByClassName("tile")[0];
|
||||
if (typeof tile !== "undefined") {
|
||||
tile.classList.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
/* tiles on rack */
|
||||
for (const tilePlaceholder of rack.getElementsByClassName("tile-placeholder")) {
|
||||
const tile = tilePlaceholder.getElementsByClassName("tile")[0];
|
||||
if (typeof tile !== "undefined") {
|
||||
tile.classList.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
/* tile on the move */
|
||||
if (movingTile !== null) {
|
||||
movingTile.classList.remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkSpellingClicked() {
|
||||
if (localStorage.spellCheckerEnabled === "false") {
|
||||
return;
|
||||
}
|
||||
|
||||
getDictionary(localStorage.trivabbleBoardLang, checkSpelling);
|
||||
}
|
||||
|
||||
function checkSpelling(dictionary) {
|
||||
const newWords = searchNewWords();
|
||||
if (newWords.length === 0) {
|
||||
myAlert(_("No new word found"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if words are in dictionary */
|
||||
let words = [];
|
||||
let badWords = [];
|
||||
for (const k of Object.keys(newWords)) {
|
||||
const currentWord = newWords[k].letters.replace(/ /gu, "?");
|
||||
if (words.indexOf(currentWord) === -1) {
|
||||
words.push(currentWord);
|
||||
}
|
||||
modifyTileClass(newWords[k], "tile-spelling-ok", true);
|
||||
const pattern = "^" + newWords[k].letters.replace(/ /gu, ".") + "$";
|
||||
const find = dictionary.find(function (word) {
|
||||
return word.match(pattern);
|
||||
});
|
||||
if (!find) {
|
||||
if (badWords.indexOf(currentWord) === -1) {
|
||||
badWords.push(currentWord);
|
||||
}
|
||||
modifyTileClass(newWords[k], "tile-spelling-nok", true);
|
||||
}
|
||||
}
|
||||
setTimeout(
|
||||
function () {
|
||||
modifyTileClass(null, "tile-spelling-ok", false);
|
||||
modifyTileClass(null, "tile-spelling-nok", false);
|
||||
}, 5000);
|
||||
words = words.join(", ").trim();
|
||||
badWords = badWords.join(", ").trim();
|
||||
|
||||
/* Advice on erroneous spelling */
|
||||
if (badWords.length > 0) {
|
||||
const msg = chatMessage("", format(_("Incorrect spelling for {0} from {1}"), badWords, words));
|
||||
msg.classList.add("error");
|
||||
} else {
|
||||
chatMessage("", format(_("All words are correct: {0}"), words));
|
||||
}
|
||||
}
|
||||
|
||||
function highlightTile(e) {
|
||||
let id = this.id;
|
||||
if (id === "") {
|
||||
|
@ -1583,6 +1830,24 @@
|
|||
}
|
||||
}
|
||||
|
||||
function initSpellChecker() {
|
||||
if (Conf.ENABLE_SPELL_CHECKER) {
|
||||
document.getElementById("enable-spell-checker-outer").style.display = "";
|
||||
}
|
||||
|
||||
document.getElementById("enable-spell-checker").onclick = spellCheckerSettingChecked;
|
||||
|
||||
if (!Conf.ENABLE_SPELL_CHECKER || localStorage.spellCheckerEnabled === "false") {
|
||||
document.getElementById("check-spelling").style.display = "none";
|
||||
document.getElementById("enable-spell-checker").checked = false;
|
||||
document.getElementById("info-spell-checking").style.display = "none";
|
||||
} else {
|
||||
document.getElementById("check-spelling").style.display = "";
|
||||
document.getElementById("info-spell-checking").style.display = "";
|
||||
document.getElementById("enable-spell-checker").checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
function translateDuration(x, values) {
|
||||
if (x < 0) {
|
||||
return null;
|
||||
|
@ -1707,9 +1972,9 @@
|
|||
location.reload();
|
||||
}
|
||||
|
||||
function showConfig() {
|
||||
const modal = document.querySelector(".modal");
|
||||
modal.classList.toggle("show-modal");
|
||||
function showSettings() {
|
||||
const modal = document.querySelector(".modal");
|
||||
modal.classList.toggle("show-modal");
|
||||
}
|
||||
|
||||
function initGlobals() {
|
||||
|
@ -1734,10 +1999,11 @@
|
|||
document.getElementById("join-game").onclick = joinGame;
|
||||
document.getElementById("clear-rack").onclick = clearRack;
|
||||
document.getElementById("show-rack").onclick = showRack;
|
||||
document.getElementById("check-spelling").onclick = checkSpellingClicked;
|
||||
helpClear.onclick = clearGame;
|
||||
|
||||
document.getElementById("modal-config-btn").onclick = showConfig;
|
||||
document.getElementById("modal-close-btn").onclick = showConfig;
|
||||
document.getElementById("btn-settings").onclick = showSettings;
|
||||
document.getElementById("btn-settings-close").onclick = showSettings;
|
||||
}
|
||||
|
||||
function initGame() {
|
||||
|
@ -1839,7 +2105,7 @@
|
|||
document.getElementById("board-lang").value = localStorage.trivabbleBoardLang;
|
||||
}
|
||||
|
||||
startGame(localStorage.trivabbleGameNumber, localStorage.trivabbleBoardLang);
|
||||
startGame(localStorage.trivabbleGameNumber);
|
||||
}
|
||||
|
||||
function initLang() {
|
||||
|
@ -1861,6 +2127,7 @@
|
|||
initChat();
|
||||
initGame();
|
||||
initSound();
|
||||
initSpellChecker();
|
||||
initLaserPointer();
|
||||
};
|
||||
|
||||
|
|
|
@ -980,7 +980,8 @@ function handleRequest(request, response) {
|
|||
".ogg": "audio/ogg",
|
||||
".js": "application/javascript; charset=utf-8",
|
||||
".css": "text/css; charset=utf-8",
|
||||
".svg": "image/svg+xml"
|
||||
".svg": "image/svg+xml",
|
||||
".dict": "text/plain"
|
||||
};
|
||||
|
||||
for (const i in mimes) {
|
||||
|
|
Loading…
Reference in New Issue