diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f700f4b..34a99352 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,9 +43,9 @@ jobs: readarray -t ignoresArray <<< $(find ./_includes/locale/strings/keyboards/ -maxdepth 1 -name '*.php' ! -name "en.php" \ -execdir basename {} .php ';') baseURL="http://localhost:8053" - ignoreStr=(" --exclude */downloads/releases/*") + ignoreStr=(" --exclude ${baseURL}*downloads/releases/*") for locale in "${ignoresArray[@]}"; do - ignoreStr+=" --exclude ${baseURL}/$locale/*" + ignoreStr+=" --exclude ${baseURL}/${locale}/*" done echo "ignoreStr: ${ignoreStr[@]}" npx broken-link-checker ${baseURL}/_test --recursive --ordered ---host-requests 50 -e --filter-level 3 ${ignoreStr} | tee blc.log diff --git a/.htaccess b/.htaccess index b24dbb7c..5ae4b331 100644 --- a/.htaccess +++ b/.htaccess @@ -23,15 +23,190 @@ RewriteBase / # Add mime type for apple-app-site-association AddType application/json apple-app-site-association -# Deny crowdin.yml -RewriteRule ^crowdin.yml$ = [F,L] - # Custom error messages (need to pass the original request) -ErrorDocument 404 /_includes/errors/404 +ErrorDocument 404 /_includes/errors/404.php + +RewriteRule "^_includes/errors/404(.php)?$" "/_includes/errors/404.php" [END] + +# ################################################################## +# Reject special and legacy top-level files without i18n +# ################################################################## + +# Any existing file in _common/assets - must come first because it is overridden below otherwise +RewriteCond "%{DOCUMENT_ROOT}/$1/$2" -f +RewriteRule "^(_common/assets)/(.+)$" - [END] + +# +# The following top-level files and folders are not directly visible through URLs: +# +# _common/ (excl. _common/assets/) +# _content/ +# _includes/ +# _scripts/ +# .github/ +# resources/ +# tests/ +# .editorconfig +# .gitattributes +# .gitignore +# .htaccess (this file, not listed explicitly) +# build.sh +# composer.json +# composer.lock +# crowdin.yml +# Dockerfile +# package-lock.json +# package.json +# phpunit.xml +# README.md +# TODO.md +# +RewriteRule "^(_common|_content|_includes|_scripts|.github|resources|tests)(/.*|$)" - [F,END] +RewriteRule "^(.editorconfig|.gitattributes|.gitignore|build.sh|composer.json|composer.lock|crowdin.yml|Dockerfile|package-lock.json|package.json|phpunit.xml|README.md|TODO.md)$" - [F,END] + +# +# The following paths are accessible but controlled by sub-folder .htaccess: +# _legacy/ +# Thus this rule currently has no effect but will come into play if the +# _legacy/.htaccess file is removed. +# +RewriteRule "^(_legacy)(/.*|$)" - [F,END] + +# ################################################################## +# Handle special and legacy top-level files without i18n +# ################################################################## + +# +# The following top-level files and folders do not have i18n redirection, +# but have .php and .md rewrites. They do not have sub-folders. +# _common/assets/ (handled above because _common/ itself is excluded) +# _control/ +# _ie_thunk/ +# _test/ +# +# The following top-level files and folders do not have .php or .md rewrites +# .well-known/ +# cdn/ +# go/ +# robots.txt +# tier.txt +# # apple-app-site-association RewriteRule "^.well-known/apple-app-site-association$" "/.well-known/apple-app-site-association.json" [L] +# Add terminating slash on top-level folders by redirecting +RewriteCond "$1" ^(_control|_ie_thunk|_test|.well-known|go|cdn)$ +RewriteRule "^([^/]+)$" "$1/" [R,L] + +# .php rewrite +RewriteCond "$1" ^(_control|_ie_thunk|_test)$ +RewriteCond "%{DOCUMENT_ROOT}/$1/$2.php" -f +RewriteRule "^([^/]+)/(.+)$" "/$1/$2.php" [END] + +# .md rewrite +RewriteCond "$1" ^(_control|_ie_thunk|_test)$ +RewriteCond "%{DOCUMENT_ROOT}/$1/$2.md" -f +RewriteRule "^([^/]+)/(.+)$" "/_includes/includes/md/mdhost.php?file=$1/$2.md" [END] + +# .md rewrite for folder; no .php rewrite for folder +RewriteCond "$1" ^(_control|_ie_thunk|_test)$ +RewriteCond "%{DOCUMENT_ROOT}/$1/index.md" -f +RewriteRule "^([^/]+)/$" "/_includes/includes/md/mdhost.php?file=$1/index.md" [END] + +# Any existing file in any of those folders or sub folders +RewriteCond "$1" ^(_control|_ie_thunk|_test|.well-known|go|cdn)$ +RewriteCond "%{DOCUMENT_ROOT}/$1/$2" -f +RewriteRule "^([^/]+)/(.+)$" - [END] + +# Top-level files +RewriteCond "$1" ^(robots.txt|tier.txt)$ +RewriteCond "%{DOCUMENT_ROOT}/$1" -f +RewriteRule "^([^/]+)$" - [END] + +# ################################################################## +# Redirections - before rewriting +# ################################################################## + +# ------------------------------------------------------------------ +# PHP and Markdown redirections +# ------------------------------------------------------------------ + +# Remove index.md or index.php and redirect (and stop processing) +RewriteRule "^((.+)/)?index(\.md|\.php)?$" "$1" [R,L] + +# Remove .php extension and redirect +RewriteRule "^(.+)\.php$" "$1" [R,L] +RewriteRule "^(.+)\.md$" "$1" [R,L] + +# ------------------------------------------------------------------ +# For consistency: +# * remove trailing `/` for files if present +# * add trailing `/` for folders if not present +# ------------------------------------------------------------------ + +# +# Note: we don't test the content of the lang path parameter (?:[^/]+)/ +# here; that is managed exclusively in the i18n section later. +# + +# Redirect folder to folder/ for .php +RewriteCond "%{DOCUMENT_ROOT}/_content/$2" -d +RewriteCond "%{DOCUMENT_ROOT}/_content/$2/index.php" -f +RewriteRule "^([^/]+)/(.+[^/])$" "$1/$2/" [R,L] + +# Redirect folder to folder/ for .md +RewriteCond "%{DOCUMENT_ROOT}/_content/$2" -d +RewriteCond "%{DOCUMENT_ROOT}/_content/$2/index.md" -f +RewriteRule "^([^/]+)/(.+[^/])$" "$1/$2/" [R,L] + +# Redirect file/ to file (.md) +RewriteCond "%{DOCUMENT_ROOT}/_content/$2" !-d +RewriteCond "%{DOCUMENT_ROOT}/_content/$2.md" -f +RewriteRule "^([^/]+)/(.+)/$" "$1/$2" [R,L] + +# Redirect file/ to file (.php) +RewriteCond "%{DOCUMENT_ROOT}/_content/$2" !-d +RewriteCond "%{DOCUMENT_ROOT}/_content/$2.php" -f +RewriteRule "^([^/]+)/(.+)/$" "$1/$2" [R,L] + +# +# top-level folders and files +# + +# Redirect folder to folder/ for .php +RewriteCond "%{DOCUMENT_ROOT}/$1" -d +RewriteCond "%{DOCUMENT_ROOT}/$1/index.php" -f +RewriteRule "^(.+[^/])$" "$1/" [R,L] + +# Redirect folder to folder/ for .md +RewriteCond "%{DOCUMENT_ROOT}/$1" -d +RewriteCond "%{DOCUMENT_ROOT}/$1/index.md" -f +RewriteRule "^(.+[^/])$" "$1/" [R,L] + +# Redirect file/ to file (.md) +RewriteCond "%{DOCUMENT_ROOT}/$1" !-d +RewriteCond "%{DOCUMENT_ROOT}/$1.md" -f +RewriteRule "^(.+)/$" "$1" [R,L] + +# Redirect file/ to file (.php) +RewriteCond "%{DOCUMENT_ROOT}/$1" !-d +RewriteCond "%{DOCUMENT_ROOT}/$1.php" -f +RewriteRule "^(.+)/$" "$1" [R,L] + +# ------------------------------------------------------------------ +# Known path redirections +# ------------------------------------------------------------------ + +# Redirect /archive/downloads.php +RewriteRule "^archive/downloads(.php)?$" "/downloads/archive/" [NC,R=301,END,QSA] + +# ios and iphone and ipad to iphone-and-ipad +RewriteRule "^(ios|iphone|ipad)(/.*)?$" "/iphone-and-ipad$2" [NC,R=301,END,QSA] + +# Redirect Android/iOS app to help homepage +RewriteRule "^(android|iphone-and-ipad)/app(.*)$" "https://help.keyman.com/products/$1/" [NC,R=301,END] + # macosx and macos to mac (ignore case) RewriteRule "^(macosx|macos)\b(.*)$" "/mac$2" [NC,R=301,END,QSA] @@ -39,29 +214,22 @@ RewriteRule "^(macosx|macos)\b(.*)$" "/mac$2" [NC,R=301,END,QSA] RewriteRule "^plus.*" "/" [NC,R=301,END,QSA] # Redirect PHP unit tests -RewriteRule "^tests(\/.*)?" "/" [NC,R=301,END,QSA] +RewriteRule "^tests(/.*)?" "/" [NC,R=301,END,QSA] # /donate -> donate.keyman.com -RedirectMatch 301 "^(?i)/donate(\/.*)?" "https://donate.keyman.com" +RedirectMatch 301 "^(?i)/donate(/.*)?" "https://donate.keyman.com" # /privacy -> SIL Privacy policy -RedirectMatch 301 "^(?i)/privacy(\/.*)?" "https://software.sil.org/language-software-privacy-policy/" +RedirectMatch 301 "^(?i)/privacy(/.*)?" "https://software.sil.org/language-software-privacy-policy/" # desktop to windows RewriteRule "^desktop(/.*)?" "/windows$1" [NC,R=301,END,QSA] -# releases-tier/download -# note: the tier is currently ignored -RewriteRule "^downloads/releases/(alpha|beta|stable)/(.+)$" "/downloads/releases/_version_downloads.php?tier=$1&version=$2" [END] - -# releases-download -RewriteRule "^downloads/releases/(.+)$" "/downloads/releases/_version_downloads.php?version=$1" [END] - -# index -RewriteRule "^downloads/releases(\/)?$" "/downloads" [R,END] +# releases-download index +RewriteRule "^downloads/releases(/)?$" "/downloads" [R,END] # CLDR -> LDML -RewriteRule "^cldr(\/)?$" "/ldml" [R=301,END] +RewriteRule "^cldr(/)?$" "/ldml" [R=301,END] # # Keyboard landing pages (TODO) @@ -86,59 +254,14 @@ RewriteRule "^keyboards/(.*)/share(/?)$" "/keyboards/share/$1" [R=301] # /keyboard/{content} to /keyboards/... RewriteRule "^keyboard(/.*)$" "/keyboards$1" [R,END] -# -# Install | Download | Share | bare | .json --> -# - -# /keyboards/install/[id] to /keyboards/install.php -RewriteRule "^keyboards/install/([^/]+)$" "/keyboards/install.php?id=$1" [END,QSA] - -# /keyboards/download/[id] to /keyboards/keyboard.php -# This formerly redirected to a download, but we no longer need it; keep it for -# legacy links -RewriteRule "^keyboards/download/([^/]+)$" "/keyboards/keyboard.php?id=$1" [END,QSA] - -# /keyboards/share/[id] to /keyboards/share.php -# if the keyboard exists in the repo, then share.php will redirect to /keyboards/ -RewriteRule "^keyboards/share/([^/]+)$" "/keyboards/share.php?id=$1" [END,QSA] - -# /keyboards/{id}.json to /keyboards/keyboard.json.php -RewriteRule "^keyboards/(?!keyboard.json)(.*)\.json$" "/keyboards/keyboard.json.php?id=$1" [END] - -# /keyboards/{id} to /keyboards/keyboard.php -RewriteRule "^keyboards/(?!index\.php|install|keyboard|session|share)([^/]+)$" "/keyboards/keyboard.php?id=$1" [END,QSA] - - -# -# Search -# - -# /keyboards?q=... to /keyboards/index.php -# RewriteRule "^keyboards$" "/keyboards/index.php" [L] - -# /keyboards/languages to /keyboards/index.php -RewriteRule "^keyboards/languages/(.*)" "/keyboards/index.php?q=l:id:$1" [END,QSA] - -# /keyboards/download to /keyboards/download.php -RewriteRule "^keyboards/download(.php)?" "/keyboards/download.php" [END,QSA] - -# /keyboards/legacy to /keyboards/keyboard.php -RewriteRule "^keyboards/legacy/(.*)" "/keyboards/keyboard.php?legacy=$1" [END] - -# /keyboards/countries to /keyboards/index.php -RewriteRule "^keyboards/countries/(.*)" "/keyboards/index.php?q=c:id:$1" [END] - # Synonym paths # 10.0 to 15.0 # /1X.0 to /1X landing page -RedirectMatch "^/1([0-5])(\.0)\/?" "/1$1/" - -# ios -RedirectMatch "^/(?!iphone-and-ipad)(ios|iphone|ipad)(\/.*)?" "/iphone-and-ipad$2" +RedirectMatch "^/1([0-5])(\.0)(/?)" "/1$1/" # Connect With Art landing page -RedirectMatch "/connectwithart(\/|$)" "https://sites.google.com/sil.org/connectwithart/home" +RedirectMatch "/connectwithart(/|$)" "https://sites.google.com/sil.org/connectwithart/home" RedirectMatch "^/lt4all(/?)$" "/ldml/lt4all" @@ -180,52 +303,152 @@ RedirectMatch "^/(french|german|italian|spanish|swedish)(/?)$" "/keyboards # dedicated-keyboard-landing pages RedirectMatch 301 "^/(amharic|burmese|cameroon|ethiopic|eurolatin|greek|ipa|sinhala|tamil|tibetan|tigrigna|urdu)(/.*)?$" "/keyboards/h/$1$2" +# ------------------------------------------------------------------ +# i18n redirect --> /file to /file +# ------------------------------------------------------------------ + # -# PHP and Markdown rewriting +# if $1 is a folder or file in /_content, then redirect to currentlang (en?) +# e.g. would redirect windows/download --> en/windows/download/ +RewriteCond "%{DOCUMENT_ROOT}/_content/$1.php" -f [OR] +RewriteCond "%{DOCUMENT_ROOT}/_content/$1.md" -f [OR] +RewriteCond "%{DOCUMENT_ROOT}/_content/$1" -d +RewriteRule "^(.*)$" "en/$1" [R,L] + # +# Paths involving queries (don't match on file/directory) +RewriteRule "^(downloads/releases|keyboards)/(.+)$" "en/$1/$2" [R,L] -# Remove index or index.php and redirect (and stop processing) -RewriteCond "$1" -d -RewriteRule "^((.+)/)?index(\.php)?$" "$1" [R,L] +# ################################################################## +# Rewriting +# ################################################################## -# Remove .php extension and redirect -RewriteCond "$1.php" -f -RewriteCond "$1" !-d -RewriteRule "^(.+)\.php$" "$1" [R,L] +# +# Intentionally not using regex from Validation::validate_bcp47 because we only need lang-script-region triplet +# ^(([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?) +# [NC] for case-insensitive +# Long regex for "BCP-47" codes = $1, rest of URL $2 onward +# + +# +# keyboards Install | Download | Share | bare | .json --> +# + +# /keyboards/install/[id] to /keyboards/install.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/install/([^/]+)$" "/_content/keyboards/install.php?id=$2" [END,QSA] + +# /keyboards/download/[id] to /keyboards/keyboard.php +# This formerly redirected to a download, but we no longer need it; keep it for +# legacy links +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/download/([^/]+)$" "/_content/keyboards/keyboard.php?id=$2" [END,QSA] -# Redirect folder without / to include / -RewriteCond "{DOCUMENT_ROOT}/$1" -d -RewriteCond "{DOCUMENT_ROOT}/$1.php" !-f -RewriteCond "{DOCUMENT_ROOT}/$1.md" !-f -RewriteRule "^(.+[^/])$" "$1/" [R,END] +# /keyboards/share/[id] to /keyboards/share.php +# if the keyboard exists in the repo, then share.php will redirect to /keyboards/ +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/share/([^/]+)$" "/_content/keyboards/share.php?id=$2" [END,QSA] + +# /keyboards/{id}.json to /keyboards/keyboard.json.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/(?!keyboard.json)(.*)\.json$" "/_content/keyboards/keyboard.json.php?id=$2" [END] + +# /keyboards/{id} to /keyboards/keyboard.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/(?!index\.php|install|keyboard|session|share)([^/]+)$" "/_content/keyboards/keyboard.php?id=$2" [END,QSA] # -# PHP rewriting +# keyboards search +# + +# /keyboards/languages to /keyboards/index.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/languages/(.*)" "/_content/keyboards/index.php?q=l:id:$2" [END,QSA] + +# /keyboards/download to /keyboards/download.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/download(.php)?" "/_content/keyboards/download.php" [END,QSA] + +# /keyboards/legacy to /keyboards/keyboard.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/legacy/(.*)" "/_content/keyboards/keyboard.php?legacy=$2" [END] + +# /keyboards/countries to /keyboards/index.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards/countries/(.*)" "/_content/keyboards/index.php?q=c:id:$2" [END] + +# Root keyboard search to pass embed query? +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/keyboards(/)?$" "/_content/keyboards/index.php" [END,QSA] + + +# +# contact/exception +# + +# /contact/exception to /contact/exception.php +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/contact/exception(.php)?$" "/_content/contact/exception.php" [END,QSA] + +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/contact/exception\?id=(.+)$" "/_content/contact/exception?id=$2" [END] + +# +# downloads/releases +# + +# releases-tier/download +# note: the tier is currently ignored +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/downloads/releases/(alpha|beta|stable)/(.+)$" "/_content/downloads/releases/_version_downloads.php?tier=$2&version=$3" [END] + +# releases-download +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/downloads/releases/(.+)$" "/_content/downloads/releases/_version_downloads.php?version=$2" [END] + +# other file types +RewriteCond "%{DOCUMENT_ROOT}/_content/$2" -f +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/(.+)$" "/_content/$2" [END] + +# TODO: do we want en/lao --> en/keyboards/basic_kbdlao? as well as /lao --> ... + +# +# PHP and Markdown rewriting # # TODO: mdhost currently in a different path than help.keyman +############################################## + # Rewrite file to file.md -RewriteCond "%{DOCUMENT_ROOT}/$1.md" -f -RewriteRule "^(.+)$" "/_includes/includes/md/mdhost.php?file=$1.md" [END] +RewriteCond "%{DOCUMENT_ROOT}/_content/$2.md" -f +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/(.+)$" "/_includes/includes/md/mdhost.php?file=_content/$2.md" [END] # Rewrite file to file.php -RewriteCond "%{DOCUMENT_ROOT}/$1.php" -f -RewriteCond "%{DOCUMENT_ROOT}/$1.md" !-f -RewriteRule "^(.+)$" "$1.php" [END] +RewriteCond "%{DOCUMENT_ROOT}/_content/$2.php" -f +RewriteCond "%{DOCUMENT_ROOT}/_content/$2.md" !-f +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/(.+)$" "/_content/$2.php" [END] # Rewrite folder/ to folder/index.md -RewriteCond "%{DOCUMENT_ROOT}/$1/index.md" -f -RewriteRule "^(.+)/$" "/_includes/includes/md/mdhost.php?file=$1/index.md" [END] +RewriteCond "%{DOCUMENT_ROOT}/_content/$2/index.md" -f +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/(.+)/$" "/_includes/includes/md/mdhost.php?file=_content/$2/index.md" [END] # Rewrite folder/ to folder/index.php -RewriteCond "%{DOCUMENT_ROOT}/$1/index.php" -f -RewriteCond "%{DOCUMENT_ROOT}/$1/index.md" !-f -RewriteRule "^(.+)/$" "$1/index.php" [END] - -# Finally, append the terminating slash for folders, given it is no longer -# done automatically because we put DirectorySlash off -RewriteCond %{REQUEST_FILENAME} -d -RewriteRule "^(.*)([^/])$" "$1$2/" [R] +RewriteCond "%{DOCUMENT_ROOT}/_content/$2/index.php" -f +RewriteCond "%{DOCUMENT_ROOT}/_content/$2/index.md" !-f +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/(.+)/$" "/_content/$2/index.php" [END] +# Root page +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)/$" "/_content/index.php" [END] +# Finally, append the terminating slash for folders, given it is no longer +# done automatically because we put DirectorySlash off, for the top-level paths only +RewriteCond "%{DOCUMENT_ROOT}/_content/$2$3" -d +RewriteCond "$1" ^([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?$ [NC] # BCP 47 match +RewriteRule "^([^/]+)(.*)([^/])?$" "$1$2$3/" [R,QSA] diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..c2ba0a5c --- /dev/null +++ b/TODO.md @@ -0,0 +1,62 @@ +Other tasks: + +* PHP upgrade to 8.x +* localizing markdown files + + +Questions for url scheme: + +* URL scheme - very little overlap with langtags (/cdn) +* How do we lay out files in the repo? +* How do we manage relative links? + + +keyman.com/windows --> has link to /linux + +keyman.com/en/windows --> /en/linux +keyman.com/de/windows --> /de/linux + +navigate to keyman.com/linux ->> keyman.com/de/linux (based on geography or by browser lang tag info, by default) + +keyman.com/km/linux --> selects 'km' language, stays there. + + +Fallback? + keyman.com/de/windows --> if no fallback available, use en content, and maybe have a banner saying 'content not yet available in German, please help us translate this!' + + +* transition from existing links? must ensure we have redirections (e.g. /windows --> /en/windows) +* canonical links? +* links embedded in pages on keyman.com: + * should be using relative rather than absolute links (i.e. ../windows rather than /windows) + * Link types: + * dynamic by Javascript + * dynamic links from api.keyman.com data + * dynamic by PHP script / static in HTML (91 .php files) + * static in Markdown (39 files) + * .htaccess redirects and rewrites (16 files) +* external links from other keyman.com sites +* external links from other sites --> should be handled by redirections + + +One plan: +* Move all content pages into a subfolder, including root index.php, e.g. '_content'. All folders except `_common`, `_...`, `.github`, `.well-known`, `cdn`, and `go`, (`resources` and others!) as a starting point. +* In the top-level .htaccess, split out redirects from markdown/php/file extension handling +* Add rewrites for all content pages, to, e.g.: + 1. redirect /windows -> //windows (initially, always redirect to /en/windows) + This could be a static redirect map for the known pages (similar to # per-language landing pages in /.htaccess) + 2. rewrite //windows to /_content/windows?lang= --> redesigning the PHP and Markdown rewriting section of .htaccess to work with localization. + + PSEUDOCODE: + + # Rewrite //... + RewriteCond "$1" !-f + RewriteCond "$1" !-d + RewriteRule "^/([a-z][a-z])/(.+)$/" "/_content/$2?lang=$1" [??? include query string, last] + + Perhaps `([a-z][a-z])` should be a better quality match, e.g. exclude known strings such as cdn,web,go,...? + + 3. rewrite for .md would embed the lang parameter and the appropriate _content path also. + +* Fixup absolute links in _content/ files to relative links +* Fixup absolute links in header files to relative links (make a helper function?) diff --git a/10/index.php b/_content/10/index.php similarity index 100% rename from 10/index.php rename to _content/10/index.php diff --git a/11/index.php b/_content/11/index.php similarity index 98% rename from 11/index.php rename to _content/11/index.php index 9082f394..311ee8e3 100644 --- a/11/index.php +++ b/_content/11/index.php @@ -52,7 +52,7 @@

Keyman Desktop 11

Stable


diff --git a/12/index.php b/_content/12/index.php similarity index 85% rename from 12/index.php rename to _content/12/index.php index 902cfb3a..91db9d88 100644 --- a/12/index.php +++ b/_content/12/index.php @@ -44,8 +44,8 @@

Get Involved

-

The success of Keyman is up to you! Keyman is a community-developed program and your involvement guarantees the ongoing usefulness of Keyman. -There are many ways you can help: get involved in the Keyman project now!

+

The success of Keyman is up to you! Keyman is a community-developed program and your involvement guarantees the ongoing usefulness of Keyman. +There are many ways you can help: get involved in the Keyman project now!

Downloads

diff --git a/12/predictive-text-editor.png b/_content/12/predictive-text-editor.png similarity index 100% rename from 12/predictive-text-editor.png rename to _content/12/predictive-text-editor.png diff --git a/12/predictive-text-ios.png b/_content/12/predictive-text-ios.png similarity index 100% rename from 12/predictive-text-ios.png rename to _content/12/predictive-text-ios.png diff --git a/12/predictive-text-khmer.png b/_content/12/predictive-text-khmer.png similarity index 100% rename from 12/predictive-text-khmer.png rename to _content/12/predictive-text-khmer.png diff --git a/12/predictive-text-settings-android.png b/_content/12/predictive-text-settings-android.png similarity index 100% rename from 12/predictive-text-settings-android.png rename to _content/12/predictive-text-settings-android.png diff --git a/13/index.php b/_content/13/index.php similarity index 83% rename from 13/index.php rename to _content/13/index.php index 27ee3681..f091e322 100644 --- a/13/index.php +++ b/_content/13/index.php @@ -37,8 +37,8 @@

Get Involved

-

The success of Keyman is up to you! Keyman is a community-developed program and your involvement guarantees the ongoing usefulness of Keyman. - There are many ways you can help: get involved in the Keyman project now!

+

The success of Keyman is up to you! Keyman is a community-developed program and your involvement guarantees the ongoing usefulness of Keyman. + There are many ways you can help: get involved in the Keyman project now!

Downloads

diff --git a/13/ios-dark.png b/_content/13/ios-dark.png similarity index 100% rename from 13/ios-dark.png rename to _content/13/ios-dark.png diff --git a/13/share-qr-code.png b/_content/13/share-qr-code.png similarity index 100% rename from 13/share-qr-code.png rename to _content/13/share-qr-code.png diff --git a/14/index.php b/_content/14/index.php similarity index 98% rename from 14/index.php rename to _content/14/index.php index 88688825..29c70214 100644 --- a/14/index.php +++ b/_content/14/index.php @@ -250,5 +250,5 @@

Changes for Keyman Engine

Get Involved

-

There are many ways you can help: get involved in the Keyman project now! +

There are many ways you can help: get involved in the Keyman project now!

diff --git a/14/keyboard_search_khmer.png b/_content/14/keyboard_search_khmer.png similarity index 100% rename from 14/keyboard_search_khmer.png rename to _content/14/keyboard_search_khmer.png diff --git a/14/keyman-engine-changes.md b/_content/14/keyman-engine-changes.md similarity index 100% rename from 14/keyman-engine-changes.md rename to _content/14/keyman-engine-changes.md diff --git a/14/select_language.png b/_content/14/select_language.png similarity index 100% rename from 14/select_language.png rename to _content/14/select_language.png diff --git a/14/slides.svg b/_content/14/slides.svg similarity index 100% rename from 14/slides.svg rename to _content/14/slides.svg diff --git a/14/video.png b/_content/14/video.png similarity index 100% rename from 14/video.png rename to _content/14/video.png diff --git a/14/webinar.md b/_content/14/webinar.md similarity index 99% rename from 14/webinar.md rename to _content/14/webinar.md index f93e7dc7..44882130 100644 --- a/14/webinar.md +++ b/_content/14/webinar.md @@ -2,7 +2,7 @@ title: Keyman 14 Launch Webinar Series --- -[< Back to Keyman 14.0 Home](/14) +[< Back to Keyman 14.0 Home](./) We held a series of webinars all about Keyman 14 between 29 March and 1 April 2021. @@ -224,4 +224,4 @@ class="generic-cta-button" target='_blank'>Join the webinar now!

} -[< Back to Keyman 14.0 Home](/14) +[< Back to Keyman 14.0 Home](./) diff --git a/15/index.php b/_content/15/index.php similarity index 98% rename from 15/index.php rename to _content/15/index.php index b8c36f9f..d891b24d 100644 --- a/15/index.php +++ b/_content/15/index.php @@ -258,5 +258,5 @@

Get Involved

-

There are many ways you can help: get involved in the Keyman project now! +

There are many ways you can help: get involved in the Keyman project now!

diff --git a/about/developers/contributors.md b/_content/about/developers/contributors.md similarity index 100% rename from about/developers/contributors.md rename to _content/about/developers/contributors.md diff --git a/about/developers/index.md b/_content/about/developers/index.md similarity index 100% rename from about/developers/index.md rename to _content/about/developers/index.md diff --git a/about/developers/previous.md b/_content/about/developers/previous.md similarity index 100% rename from about/developers/previous.md rename to _content/about/developers/previous.md diff --git a/about/get-involved.md b/_content/about/get-involved.md similarity index 96% rename from about/get-involved.md rename to _content/about/get-involved.md index b551e1ca..1dde09bd 100644 --- a/about/get-involved.md +++ b/_content/about/get-involved.md @@ -25,11 +25,11 @@ paying staff and contractors, server costs and hardware and software purchases. ## Create a keyboard layout for your language ## {#create-keyboard} Keyman Developer is our comprehensive tool for creating keyboard layouts for every major platform; it is of -course completely free and open source! Go ahead and [download Keyman Developer](/developer/download) +course completely free and open source! Go ahead and [download Keyman Developer](../developer/download) to start creating keyboard layouts today. Once you have created a layout, you can share it online, and if you like, contribute it to the Keyman keyboard repository. -* [Learn about Keyman Developer](/developer) +* [Learn about Keyman Developer](../developer) * [Share your keyboard layouts](https://help.keyman.com/developer/keyboards) ## Localize Keyman for your language ## {#localize-keyman} @@ -51,7 +51,7 @@ We frequently release updates to Keyman. Independent testing and reporting of is you test bug fixes and report issues, you help those who are depending on Keyman to work in their language, many of whom do not have the capacity to test new versions themselves. -* [Download a pre-release version](/downloads/pre-release) +* [Download a pre-release version](../downloads/pre-release) * [Report issues and feature requests](https://github.com/keymanapp/keyman/issues/new/choose) ## Write some code ## {#write-code} @@ -79,6 +79,6 @@ developing software that serves the needs of language communities around the wor introduce yourself — we'd love to meet with you! * [About the Keyman team](team/) -* [Jobs](/jobs) +* [Jobs](../jobs) * [Write to us](https://software.sil.org/about/contact/) * [Send us a tweet or DM on Twitter](https://twitter.com/keyman) diff --git a/about/index.md b/_content/about/index.md similarity index 91% rename from about/index.md rename to _content/about/index.md index 02645bb2..f61e9af2 100644 --- a/about/index.md +++ b/_content/about/index.md @@ -29,7 +29,7 @@ mobile platforms.
-➡️ [Testimonials](/testimonials) +➡️ [Testimonials](../testimonials) ## About the team @@ -50,11 +50,11 @@ Keyman is provided to you free of charge with the support of generous [donors](s ## Get in touch -➡️ [Contact us](/contact) +➡️ [Contact us](../contact) ## About SIL Global - + Keyman is created by SIL Global (formerly SIL International). Partners in Language Development, SIL Global is a faith-based nonprofit organization committed to serving language communities diff --git a/about/list.php b/_content/about/list.php similarity index 100% rename from about/list.php rename to _content/about/list.php diff --git a/about/sponsors/fpcc.svg b/_content/about/sponsors/fpcc.svg similarity index 100% rename from about/sponsors/fpcc.svg rename to _content/about/sponsors/fpcc.svg diff --git a/about/sponsors/index.md b/_content/about/sponsors/index.md similarity index 90% rename from about/sponsors/index.md rename to _content/about/sponsors/index.md index d9d48630..5e4a1480 100644 --- a/about/sponsors/index.md +++ b/_content/about/sponsors/index.md @@ -48,7 +48,7 @@ title: About our sponsors and partners Please contact us if you are interested in sponsoring Keyman. - ➡️ + ➡️

@@ -69,7 +69,7 @@ Indigenous and minority language communities around the world. - Microsoft + Microsoft

Microsoft, through their - +

The National Polytechnic Institute of Cambodia @@ -117,7 +117,7 @@ Indigenous and minority language communities around the world. - Browserstack + Browserstack

We are using BrowserStack to test KeymanWeb @@ -135,7 +135,7 @@ Indigenous and minority language communities around the world. - Sentry + Sentry

Keyman uses Sentry for error monitoring. Thank you to @@ -149,7 +149,7 @@ Indigenous and minority language communities around the world. - 1Password + 1Password

Thank you to 1Password for supporting the Keyman team diff --git a/about/sponsors/translation-commons.svg b/_content/about/sponsors/translation-commons.svg similarity index 100% rename from about/sponsors/translation-commons.svg rename to _content/about/sponsors/translation-commons.svg diff --git a/about/sponsors/typotheque.svg b/_content/about/sponsors/typotheque.svg similarity index 100% rename from about/sponsors/typotheque.svg rename to _content/about/sponsors/typotheque.svg diff --git a/about/team/bios/DavidLRowe.md b/_content/about/team/bios/DavidLRowe.md similarity index 100% rename from about/team/bios/DavidLRowe.md rename to _content/about/team/bios/DavidLRowe.md diff --git a/about/team/bios/LornaSIL.md b/_content/about/team/bios/LornaSIL.md similarity index 100% rename from about/team/bios/LornaSIL.md rename to _content/about/team/bios/LornaSIL.md diff --git a/about/team/bios/MakaraSok.md b/_content/about/team/bios/MakaraSok.md similarity index 100% rename from about/team/bios/MakaraSok.md rename to _content/about/team/bios/MakaraSok.md diff --git a/about/team/bios/Markus-SWAG.md b/_content/about/team/bios/Markus-SWAG.md similarity index 100% rename from about/team/bios/Markus-SWAG.md rename to _content/about/team/bios/Markus-SWAG.md diff --git a/about/team/bios/Meng-Heng.md b/_content/about/team/bios/Meng-Heng.md similarity index 100% rename from about/team/bios/Meng-Heng.md rename to _content/about/team/bios/Meng-Heng.md diff --git a/about/team/bios/Nnyny.md b/_content/about/team/bios/Nnyny.md similarity index 100% rename from about/team/bios/Nnyny.md rename to _content/about/team/bios/Nnyny.md diff --git a/about/team/bios/SabineSIL.md b/_content/about/team/bios/SabineSIL.md similarity index 100% rename from about/team/bios/SabineSIL.md rename to _content/about/team/bios/SabineSIL.md diff --git a/about/team/bios/darcywong00.md b/_content/about/team/bios/darcywong00.md similarity index 100% rename from about/team/bios/darcywong00.md rename to _content/about/team/bios/darcywong00.md diff --git a/about/team/bios/ermshiperete.md b/_content/about/team/bios/ermshiperete.md similarity index 100% rename from about/team/bios/ermshiperete.md rename to _content/about/team/bios/ermshiperete.md diff --git a/about/team/bios/glasseyes.md b/_content/about/team/bios/glasseyes.md similarity index 100% rename from about/team/bios/glasseyes.md rename to _content/about/team/bios/glasseyes.md diff --git a/about/team/bios/jahorton.md b/_content/about/team/bios/jahorton.md similarity index 100% rename from about/team/bios/jahorton.md rename to _content/about/team/bios/jahorton.md diff --git a/about/team/bios/markcsinclair.md b/_content/about/team/bios/markcsinclair.md similarity index 100% rename from about/team/bios/markcsinclair.md rename to _content/about/team/bios/markcsinclair.md diff --git a/about/team/bios/mcdurdin.md b/_content/about/team/bios/mcdurdin.md similarity index 100% rename from about/team/bios/mcdurdin.md rename to _content/about/team/bios/mcdurdin.md diff --git a/about/team/bios/rc-swag.md b/_content/about/team/bios/rc-swag.md similarity index 100% rename from about/team/bios/rc-swag.md rename to _content/about/team/bios/rc-swag.md diff --git a/about/team/bios/sgschantz.md b/_content/about/team/bios/sgschantz.md similarity index 100% rename from about/team/bios/sgschantz.md rename to _content/about/team/bios/sgschantz.md diff --git a/about/team/bios/srl295.md b/_content/about/team/bios/srl295.md similarity index 94% rename from about/team/bios/srl295.md rename to _content/about/team/bios/srl295.md index 7de37044..873266fa 100644 --- a/about/team/bios/srl295.md +++ b/_content/about/team/bios/srl295.md @@ -25,7 +25,7 @@ projects, I continue to contribute to Unicode’s Common Locale Data Repository (CLDR), and chair its [Digitally Disadvantaged Languages](https://cldr.unicode.org/ddl) working group. -As for Keyboards, I have been involved in [LDML Keyboards](/ldml) as the CLDR +As for Keyboards, I have been involved in [LDML Keyboards](../../../ldml) as the CLDR spec editor, and have been involved in the implementation of LDML in Keyman, both on the compiler (kmc) and runtime (core) portions. diff --git a/about/team/bios/tombogle.md b/_content/about/team/bios/tombogle.md similarity index 100% rename from about/team/bios/tombogle.md rename to _content/about/team/bios/tombogle.md diff --git a/about/team/bios/tpbaehr.md b/_content/about/team/bios/tpbaehr.md similarity index 100% rename from about/team/bios/tpbaehr.md rename to _content/about/team/bios/tpbaehr.md diff --git a/about/team/contributors.css b/_content/about/team/contributors.css similarity index 100% rename from about/team/contributors.css rename to _content/about/team/contributors.css diff --git a/about/team/index.md b/_content/about/team/index.md similarity index 100% rename from about/team/index.md rename to _content/about/team/index.md diff --git a/about/team/team.css b/_content/about/team/team.css similarity index 100% rename from about/team/team.css rename to _content/about/team/team.css diff --git a/about/team/team.json b/_content/about/team/team.json similarity index 100% rename from about/team/team.json rename to _content/about/team/team.json diff --git a/_content/alpha/index.php b/_content/alpha/index.php new file mode 100644 index 00000000..e9a41f75 --- /dev/null +++ b/_content/alpha/index.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/android/faq/index.php b/_content/android/faq/index.php similarity index 100% rename from android/faq/index.php rename to _content/android/faq/index.php diff --git a/android/index.php b/_content/android/index.php similarity index 93% rename from android/index.php rename to _content/android/index.php index db469c53..c45421ea 100644 --- a/android/index.php +++ b/_content/android/index.php @@ -26,7 +26,7 @@ -

Want to try the Keyman for Android Beta? Learn more

+

Want to try the Keyman for Android Beta? Learn more

@@ -46,7 +46,7 @@

- Create custom Keyman dictionaries with Keyman Developer + Create custom Keyman dictionaries with Keyman Developer and install them to use with your keyboards.

@@ -56,7 +56,7 @@

Now you also have the flexibility of installing Keyman keyboard packages from either online - (like keyman_com ?>/keyboards) or local storage from a new "Settings" panel. + (like keyman_com ?>/keyboards) or local storage from a new "Settings" panel.

@@ -260,7 +260,7 @@

  • Released in two editions: Keyman Free and Keyman Pro
  • Use any Keyman keyboard throughout your entire Android device (Pro Edition only)
  • -
  • Install custom keyboards created with Keyman Developer 9 (free download for Windows)
  • +
  • Install custom keyboards created with Keyman Developer 9 (free download for Windows)
  • Updated keyboard styling
  • Bug fixes
  • @@ -298,7 +298,7 @@

    New in Update 1.2 (22 Apr 2014):


    @@ -314,11 +314,11 @@


    - You can develop your own keyboard layouts for Keyman for Android with Keyman Developer. If you have existing keyboards, they can be ported to Android with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more! + You can develop your own keyboard layouts for Keyman for Android with Keyman Developer. If you have existing keyboards, they can be ported to Android with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more!

    Keyman Engine for Android Documentation

    - Download the latest Keyman Engine for Android + Download the latest Keyman Engine for Android

    \ No newline at end of file diff --git a/_content/beta/index.php b/_content/beta/index.php new file mode 100644 index 00000000..d36917e9 --- /dev/null +++ b/_content/beta/index.php @@ -0,0 +1,3 @@ + diff --git a/bookmarklet/index.php b/_content/bookmarklet/index.php similarity index 100% rename from bookmarklet/index.php rename to _content/bookmarklet/index.php diff --git a/bookmarklet/install-bookmarklet.js b/_content/bookmarklet/install-bookmarklet.js similarity index 100% rename from bookmarklet/install-bookmarklet.js rename to _content/bookmarklet/install-bookmarklet.js diff --git a/contact/exception.php b/_content/contact/exception.php similarity index 100% rename from contact/exception.php rename to _content/contact/exception.php diff --git a/contact/index.php b/_content/contact/index.php similarity index 100% rename from contact/index.php rename to _content/contact/index.php diff --git a/developer/authoring-services.md b/_content/developer/authoring-services.md similarity index 100% rename from developer/authoring-services.md rename to _content/developer/authoring-services.md diff --git a/developer/download.php b/_content/developer/download.php similarity index 84% rename from developer/download.php rename to _content/developer/download.php index b772acab..55853861 100644 --- a/developer/download.php +++ b/_content/developer/download.php @@ -13,15 +13,15 @@ ]); ?>
    -

    Keyman Developer is not compatible with Windows Vista. Please download Keyman Developer 8.0 instead from our archived downloads page.

    +

    Keyman Developer is not compatible with Windows Vista. Please download Keyman Developer 8.0 instead from our archived downloads page.

    -

    Keyman Developer is not compatible with Windows XP. Please download Keyman Developer 8.0 instead from our archived downloads page.

    +

    Keyman Developer is not compatible with Windows XP. Please download Keyman Developer 8.0 instead from our archived downloads page.

    Download Keyman Developer

    - Keyman Developer is compatible with Windows 10 and Windows 11. If you have an older version of Windows, please download an earlier version of Keyman Developer from our archived downloads page. + Keyman Developer is compatible with Windows 10 and Windows 11. If you have an older version of Windows, please download an earlier version of Keyman Developer from our archived downloads page.

    - For kmcomp, please download from our archived downloads page. + For kmcomp, please download from our archived downloads page.

    diff --git a/developer/features.php b/_content/developer/features.php similarity index 99% rename from developer/features.php rename to _content/developer/features.php index 7cb66f0f..9498e0ba 100644 --- a/developer/features.php +++ b/_content/developer/features.php @@ -238,7 +238,7 @@ Keyman Community Site. We love answering questions about Keyman keyboards and Keyman Developer .



    - + \ No newline at end of file diff --git a/developer/index.php b/_content/developer/index.php similarity index 88% rename from developer/index.php rename to _content/developer/index.php index 7bc7e679..f2cf45be 100644 --- a/developer/index.php +++ b/_content/developer/index.php @@ -17,14 +17,14 @@ ?>

    Keyman Developer

    -

    Keyman Developer is the most powerful tool for creating +

    Keyman Developer is the most powerful tool for creating keyboard layouts for any popular platform for any language around the world. Build keyboards layouts for desktop, web, tablet and phone. Optimise your keyboards for each platform, including touch-and-hold keys and alternative layers.

    @@ -32,7 +32,7 @@ -

    Want to try the Keyman Developer Beta? Learn more

    +

    Want to try the Keyman Developer Beta? Learn more

    diff --git a/_content/developer/keymanweb/index.2.0.php b/_content/developer/keymanweb/index.2.0.php new file mode 100644 index 00000000..e899bade --- /dev/null +++ b/_content/developer/keymanweb/index.2.0.php @@ -0,0 +1,2 @@ +KeymanWeb Source Code and Development

    KeymanWeb is an Open Source input method system for the web, supporting both desktops and touch devices. Keyboard layouts for - use with KeymanWeb can be created with the free download Keyman Developer (Windows). + use with KeymanWeb can be created with the free download Keyman Developer (Windows).

    Add KeymanWeb to a Website

    @@ -45,11 +45,11 @@ @@ -97,9 +97,9 @@

    diff --git a/developer/keymanweb/keyboards.php b/_content/developer/keymanweb/keyboards.php similarity index 100% rename from developer/keymanweb/keyboards.php rename to _content/developer/keymanweb/keyboards.php diff --git a/developer/keymanweb/keyboards.txt b/_content/developer/keymanweb/keyboards.txt similarity index 100% rename from developer/keymanweb/keyboards.txt rename to _content/developer/keymanweb/keyboards.txt diff --git a/developer/keymanweb/keymanweb-version.inc.php b/_content/developer/keymanweb/keymanweb-version.inc.php similarity index 100% rename from developer/keymanweb/keymanweb-version.inc.php rename to _content/developer/keymanweb/keymanweb-version.inc.php diff --git a/developer/keymanweb/sample1.php b/_content/developer/keymanweb/sample1.php similarity index 100% rename from developer/keymanweb/sample1.php rename to _content/developer/keymanweb/sample1.php diff --git a/developer/keymanweb/sample2.php b/_content/developer/keymanweb/sample2.php similarity index 100% rename from developer/keymanweb/sample2.php rename to _content/developer/keymanweb/sample2.php diff --git a/downloads/_downloads.php b/_content/downloads/_downloads.php similarity index 100% rename from downloads/_downloads.php rename to _content/downloads/_downloads.php diff --git a/downloads/all-versions/index.php b/_content/downloads/all-versions/index.php similarity index 100% rename from downloads/all-versions/index.php rename to _content/downloads/all-versions/index.php diff --git a/downloads/archive/index.php b/_content/downloads/archive/index.php similarity index 100% rename from downloads/archive/index.php rename to _content/downloads/archive/index.php diff --git a/downloads/archive/legacy-embed.php b/_content/downloads/archive/legacy-embed.php similarity index 100% rename from downloads/archive/legacy-embed.php rename to _content/downloads/archive/legacy-embed.php diff --git a/downloads/archive/static-keys.php b/_content/downloads/archive/static-keys.php similarity index 100% rename from downloads/archive/static-keys.php rename to _content/downloads/archive/static-keys.php diff --git a/downloads/index.php b/_content/downloads/index.php similarity index 100% rename from downloads/index.php rename to _content/downloads/index.php diff --git a/downloads/pre-release/index.php b/_content/downloads/pre-release/index.php similarity index 100% rename from downloads/pre-release/index.php rename to _content/downloads/pre-release/index.php diff --git a/downloads/releases/_version_downloads.php b/_content/downloads/releases/_version_downloads.php similarity index 100% rename from downloads/releases/_version_downloads.php rename to _content/downloads/releases/_version_downloads.php diff --git a/engine/index.php b/_content/engine/index.php similarity index 90% rename from engine/index.php rename to _content/engine/index.php index ac1bb271..fb5f1744 100644 --- a/engine/index.php +++ b/_content/engine/index.php @@ -45,7 +45,7 @@ standalone Keyman Engine for Web (KeymanWeb), you can integrate over 2500 languages to give you and your users the simplest solution to typing on your site possible.

    - You can of course build your own keyboard layouts using Keyman Developer, as well as + You can of course build your own keyboard layouts using Keyman Developer, as well as access our library of hundreds of keyboard layouts covering thousands of languages.

    KeymanWeb Documentation @@ -61,13 +61,13 @@ the world!

    You can develop your own keyboard layouts for Keyman for iOS with - Keyman Developer. If you have existing keyboards, they can be ported to iOS with just + Keyman Developer. If you have existing keyboards, they can be ported to iOS with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more!

    Keyman Engine for iPhone and iPad Documentation
    - Get the Keyman Engine for iOS now + Get the Keyman Engine for iOS now

    Keyman Engine for Android

    @@ -76,13 +76,13 @@ Keyman Engine for Android makes it straightforward to take your app to the world!

    You can develop your own keyboard layouts for Keyman for Android with - Keyman Developer. If you have existing keyboards, they can be ported to Android with just + Keyman Developer. If you have existing keyboards, they can be ported to Android with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more!

    Keyman Engine for Android Documentation
    - Get the Keyman Engine for Android SDK now + Get the Keyman Engine for Android SDK now


    diff --git a/events/iuc38/Lao Roman/index.html b/_content/events/iuc38/Lao Roman/index.html similarity index 100% rename from events/iuc38/Lao Roman/index.html rename to _content/events/iuc38/Lao Roman/index.html diff --git a/events/iuc38/Lao Roman/kmw/build.bat b/_content/events/iuc38/Lao Roman/kmw/build.bat similarity index 100% rename from events/iuc38/Lao Roman/kmw/build.bat rename to _content/events/iuc38/Lao Roman/kmw/build.bat diff --git a/events/iuc38/Lao Roman/kmw/keymanweb.js b/_content/events/iuc38/Lao Roman/kmw/keymanweb.js similarity index 100% rename from events/iuc38/Lao Roman/kmw/keymanweb.js rename to _content/events/iuc38/Lao Roman/kmw/keymanweb.js diff --git a/events/iuc38/Lao Roman/kmw/kmwbase.js b/_content/events/iuc38/Lao Roman/kmw/kmwbase.js similarity index 100% rename from events/iuc38/Lao Roman/kmw/kmwbase.js rename to _content/events/iuc38/Lao Roman/kmw/kmwbase.js diff --git a/events/iuc38/Lao Roman/kmw/kmwosk.js b/_content/events/iuc38/Lao Roman/kmw/kmwosk.js similarity index 100% rename from events/iuc38/Lao Roman/kmw/kmwosk.js rename to _content/events/iuc38/Lao Roman/kmw/kmwosk.js diff --git a/events/iuc38/Lao Roman/kmw/resources/osk/kmwosk.css b/_content/events/iuc38/Lao Roman/kmw/resources/osk/kmwosk.css similarity index 100% rename from events/iuc38/Lao Roman/kmw/resources/osk/kmwosk.css rename to _content/events/iuc38/Lao Roman/kmw/resources/osk/kmwosk.css diff --git a/events/iuc38/Lao Roman/kmw/version.txt b/_content/events/iuc38/Lao Roman/kmw/version.txt similarity index 100% rename from events/iuc38/Lao Roman/kmw/version.txt rename to _content/events/iuc38/Lao Roman/kmw/version.txt diff --git a/events/iuc38/Lao Roman/laoroman-1.0.js b/_content/events/iuc38/Lao Roman/laoroman-1.0.js similarity index 100% rename from events/iuc38/Lao Roman/laoroman-1.0.js rename to _content/events/iuc38/Lao Roman/laoroman-1.0.js diff --git a/events/iuc38/Lao Roman/laoroman-1.0.json b/_content/events/iuc38/Lao Roman/laoroman-1.0.json similarity index 100% rename from events/iuc38/Lao Roman/laoroman-1.0.json rename to _content/events/iuc38/Lao Roman/laoroman-1.0.json diff --git a/events/iuc38/Thai Satellite/jquery1-11-1.min.js b/_content/events/iuc38/Thai Satellite/jquery1-11-1.min.js similarity index 100% rename from events/iuc38/Thai Satellite/jquery1-11-1.min.js rename to _content/events/iuc38/Thai Satellite/jquery1-11-1.min.js diff --git a/events/iuc38/Thai Satellite/thai-full-iphone.png b/_content/events/iuc38/Thai Satellite/thai-full-iphone.png similarity index 100% rename from events/iuc38/Thai Satellite/thai-full-iphone.png rename to _content/events/iuc38/Thai Satellite/thai-full-iphone.png diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.css b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.css similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.css rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.css diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.html b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.html similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.html rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup-full-iphone.html diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup-full.css b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup-full.css similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup-full.css rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup-full.css diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup-full.html b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup-full.html similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup-full.html rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup-full.html diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup.css b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup.css similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup.css rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup.css diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup.html b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup.html similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup.html rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup.html diff --git a/events/iuc38/Thai Satellite/thai-satellite-mockup.js b/_content/events/iuc38/Thai Satellite/thai-satellite-mockup.js similarity index 100% rename from events/iuc38/Thai Satellite/thai-satellite-mockup.js rename to _content/events/iuc38/Thai Satellite/thai-satellite-mockup.js diff --git a/events/iuc38/index.php b/_content/events/iuc38/index.php similarity index 100% rename from events/iuc38/index.php rename to _content/events/iuc38/index.php diff --git a/events/iuc38/keyboardfutures_iuc38.pdf b/_content/events/iuc38/keyboardfutures_iuc38.pdf similarity index 100% rename from events/iuc38/keyboardfutures_iuc38.pdf rename to _content/events/iuc38/keyboardfutures_iuc38.pdf diff --git a/fonts/index.php b/_content/fonts/index.php similarity index 100% rename from fonts/index.php rename to _content/fonts/index.php diff --git a/free/index.md b/_content/free/index.md similarity index 97% rename from free/index.md rename to _content/free/index.md index b77e712a..0d831a6d 100644 --- a/free/index.md +++ b/_content/free/index.md @@ -25,4 +25,4 @@ are also licensed under the MIT License. Copyright for these keyboards and lexical models belongs to many different authors. * [About SIL Global](https://global.sil.org/about/) -* [About Keyman](/about) \ No newline at end of file +* [About Keyman](../about) \ No newline at end of file diff --git a/funding-appeal/index.md b/_content/funding-appeal/index.md similarity index 100% rename from funding-appeal/index.md rename to _content/funding-appeal/index.md diff --git a/funding-appeal/share.md b/_content/funding-appeal/share.md similarity index 100% rename from funding-appeal/share.md rename to _content/funding-appeal/share.md diff --git a/index.php b/_content/index.php similarity index 91% rename from index.php rename to _content/index.php index d318a92b..4a27fd05 100644 --- a/index.php +++ b/_content/index.php @@ -1,4 +1,4 @@ - Keyman helps you type in over 2500 languages on just about any device — Windows, macOS, Linux, iPhone, iPad, Android tablets and phones, and even instantly in your web browser. - Keyman is completely free and open source! + Keyman is completely free and open source!

    @@ -66,7 +66,7 @@ -
    +

    Search over 2500 languages

    " alt="Search button"> @@ -80,7 +80,7 @@ With the world’s most powerful keyboarding engine, intuitive and rapid text input is now possible in your language, and for over 99% of the global population’s mother tongues!

    - + " alt="Hebrew Keyboard bookmarklet" />

    Keyman Bookmarklet

    @@ -159,7 +159,7 @@

    Developer Tools

    - + " alt="Gears" />

    Keyman Engine

    @@ -183,12 +183,12 @@

    About the Keyman team

    - Learn more about the hundreds of people involved in the Keyman project — or join the team yourself! + Learn more about the hundreds of people involved in the Keyman project — or join the team yourself!

    level == 'core'; }); @@ -203,7 +203,7 @@ } else { $img = "https://github.com/{$data[$r]->handle}.png?size=240"; } - echo ""; + echo ""; } ?>
    diff --git a/iphone-and-ipad/index.php b/_content/iphone-and-ipad/index.php similarity index 95% rename from iphone-and-ipad/index.php rename to _content/iphone-and-ipad/index.php index c3a34907..329f4739 100644 --- a/iphone-and-ipad/index.php +++ b/_content/iphone-and-ipad/index.php @@ -26,7 +26,7 @@ -

    Want to try the Keyman for iPhone and iPad Beta? Learn more

    +

    Want to try the Keyman for iPhone and iPad Beta? Learn more

    @@ -232,11 +232,11 @@


    - You can develop your own keyboard layouts for Keyman for iPhone and iPad with Keyman Developer. If you have existing keyboards, they can be ported to iOS with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more! + You can develop your own keyboard layouts for Keyman for iPhone and iPad with Keyman Developer. If you have existing keyboards, they can be ported to iOS with just a recompile. And of course, we include support for touch-oriented features such as touch-and-hold menus, dynamic keyboard layers and more!

    Keyman Engine for iPhone and iPad Documentation

    - Download the latest Keyman Engine for iOS + Download the latest Keyman Engine for iOS

    diff --git a/jobs/brisbane.md b/_content/jobs/brisbane.md similarity index 94% rename from jobs/brisbane.md rename to _content/jobs/brisbane.md index c9ef38e7..9dc7a5b7 100644 --- a/jobs/brisbane.md +++ b/_content/jobs/brisbane.md @@ -17,7 +17,7 @@ We are seeking people like you who are: ## About the event -[Marc Durdin](/about/team/bios/mcdurdin) will be sharing on his experiences working as +[Marc Durdin](../about/team/bios/mcdurdin) will be sharing on his experiences working as a software developer in the majority world — in Thailand, Papua New Guinea, Cambodia, and Laos. Watch the video to learn more about Marc's current context in Cambodia! @@ -68,8 +68,8 @@ Contact: Ross Cruickshank, [ross_cruickshank@sil.org](mailto:ross_cruickshank@si ## More information -* [Keyman Jobs](/jobs) -* [About Keyman](/) +* [Keyman Jobs](./) +* [About Keyman](../about) --- diff --git a/jobs/index.md b/_content/jobs/index.md similarity index 100% rename from jobs/index.md rename to _content/jobs/index.md diff --git a/keyboards/h/amharic/chat/index.php b/_content/keyboards/h/amharic/chat/index.php similarity index 100% rename from keyboards/h/amharic/chat/index.php rename to _content/keyboards/h/amharic/chat/index.php diff --git a/keyboards/h/amharic/index.php b/_content/keyboards/h/amharic/index.php similarity index 95% rename from keyboards/h/amharic/index.php rename to _content/keyboards/h/amharic/index.php index 29977831..986df3ab 100644 --- a/keyboards/h/amharic/index.php +++ b/_content/keyboards/h/amharic/index.php @@ -29,7 +29,7 @@

    Download Now

    - Learn more about Keyman for Windows + Learn more about Keyman for Windows

    Amharic Keyman for macOS

    - Type in Amharic in all your favourite software applications for macOS. Download Keyman + Type in Amharic in all your favourite software applications for macOS. Download Keyman for macOS first

    Download Now

    - Learn more about Keyman for macOS + Learn more about Keyman for macOS

    Amharic Keyman for iPhone

    @@ -96,24 +96,24 @@

    Download an Amharic keyboard on these devices:

diff --git a/keyboards/h/burmese/index.php b/_content/keyboards/h/burmese/index.php similarity index 100% rename from keyboards/h/burmese/index.php rename to _content/keyboards/h/burmese/index.php diff --git a/keyboards/h/cameroon/index.php b/_content/keyboards/h/cameroon/index.php similarity index 100% rename from keyboards/h/cameroon/index.php rename to _content/keyboards/h/cameroon/index.php diff --git a/keyboards/h/ethiopic/index.php b/_content/keyboards/h/ethiopic/index.php similarity index 100% rename from keyboards/h/ethiopic/index.php rename to _content/keyboards/h/ethiopic/index.php diff --git a/keyboards/h/eurolatin/index.php b/_content/keyboards/h/eurolatin/index.php similarity index 100% rename from keyboards/h/eurolatin/index.php rename to _content/keyboards/h/eurolatin/index.php diff --git a/keyboards/h/greek/index.php b/_content/keyboards/h/greek/index.php similarity index 100% rename from keyboards/h/greek/index.php rename to _content/keyboards/h/greek/index.php diff --git a/keyboards/h/ipa/index.php b/_content/keyboards/h/ipa/index.php similarity index 100% rename from keyboards/h/ipa/index.php rename to _content/keyboards/h/ipa/index.php diff --git a/keyboards/h/sinhala/garp/index.php b/_content/keyboards/h/sinhala/garp/index.php similarity index 91% rename from keyboards/h/sinhala/garp/index.php rename to _content/keyboards/h/sinhala/garp/index.php index 81a86e5c..d4e02ece 100644 --- a/keyboards/h/sinhala/garp/index.php +++ b/_content/keyboards/h/sinhala/garp/index.php @@ -35,19 +35,19 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Garp Sinhala Keyman for macOS

- Type in Sinhala in all your favourite software applications for macOS. Download Keyman + Type in Sinhala in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS
@@ -92,25 +92,25 @@

Download a Sinhala keyboard on these devices:

- + .

Bookmarklet

@@ -124,7 +124,7 @@ You can also type Sinhala with:

diff --git a/keyboards/h/sinhala/index.php b/_content/keyboards/h/sinhala/index.php similarity index 100% rename from keyboards/h/sinhala/index.php rename to _content/keyboards/h/sinhala/index.php diff --git a/keyboards/h/sinhala/sinhala.PNG b/_content/keyboards/h/sinhala/sinhala.PNG similarity index 100% rename from keyboards/h/sinhala/sinhala.PNG rename to _content/keyboards/h/sinhala/sinhala.PNG diff --git a/keyboards/h/sinhala/sipon/index.php b/_content/keyboards/h/sinhala/sipon/index.php similarity index 91% rename from keyboards/h/sinhala/sipon/index.php rename to _content/keyboards/h/sinhala/sipon/index.php index 59c00177..c04181ca 100644 --- a/keyboards/h/sinhala/sipon/index.php +++ b/_content/keyboards/h/sinhala/sipon/index.php @@ -35,19 +35,19 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Sipon Phonetic Sinhala Keyman for macOS

- Type in Sinhala in all your favourite software applications for macOS. Download Keyman + Type in Sinhala in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS
@@ -91,25 +91,25 @@

Download a Sinhala keyboard on these devices:

- + .

Bookmarklet

@@ -123,7 +123,7 @@ You can also type Sinhala with:

    -
  • Garp Sinhala - Another phonetic-entry layout for Sinhala.
  • +
  • Garp Sinhala - Another phonetic-entry layout for Sinhala.
diff --git a/keyboards/h/tamil/anjal-paangu/index.php b/_content/keyboards/h/tamil/anjal-paangu/index.php similarity index 93% rename from keyboards/h/tamil/anjal-paangu/index.php rename to _content/keyboards/h/tamil/anjal-paangu/index.php index 28091e83..e074f02c 100644 --- a/keyboards/h/tamil/anjal-paangu/index.php +++ b/_content/keyboards/h/tamil/anjal-paangu/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil Anjal Paangu Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tamil/index.php b/_content/keyboards/h/tamil/index.php similarity index 91% rename from keyboards/h/tamil/index.php rename to _content/keyboards/h/tamil/index.php index 8d3c4cbe..bc2153d3 100644 --- a/keyboards/h/tamil/index.php +++ b/_content/keyboards/h/tamil/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil99 Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

@@ -130,7 +130,7 @@

Type in other Tamil keyboard layouts such as:

    -
  • Thamizha (Tamil99) - Popularly used in eKalappai, this keyboard follows the Tamil99 standard recommended by the Tamil Nadu government.
  • +
  • Thamizha (Tamil99) - Popularly used in eKalappai, this keyboard follows the Tamil99 standard recommended by the Tamil Nadu government.
  • Thamizha (Anjal) - Popularly used in eKalappai, this keyboard follows the Anjal phonetic standard. It’s the easiest to use when learning Tamil.
  • Thamizha (Bamini) - Popularly used in eKalappai, this keyboard follows the Bamini standard common in Sri Lanka, based on old Tamil typewriters.
  • Thamizha (Typewriter) - Popularly used in eKalappai, this keyboard follows the standard Tamil typewriter layout.
  • diff --git a/keyboards/h/tamil/isis/index.php b/_content/keyboards/h/tamil/isis/index.php similarity index 94% rename from keyboards/h/tamil/isis/index.php rename to _content/keyboards/h/tamil/isis/index.php index 3b92bcd4..7598f34d 100644 --- a/keyboards/h/tamil/isis/index.php +++ b/_content/keyboards/h/tamil/isis/index.php @@ -36,19 +36,19 @@

    Download Now

    - Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil (ISIS) Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -91,24 +91,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tamil/new-typewriter/index.php b/_content/keyboards/h/tamil/new-typewriter/index.php similarity index 93% rename from keyboards/h/tamil/new-typewriter/index.php rename to _content/keyboards/h/tamil/new-typewriter/index.php index 42125355..b082e29e 100644 --- a/keyboards/h/tamil/new-typewriter/index.php +++ b/_content/keyboards/h/tamil/new-typewriter/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil New Typewriter Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tamil/suratha-bamuni/index.php b/_content/keyboards/h/tamil/suratha-bamuni/index.php similarity index 93% rename from keyboards/h/tamil/suratha-bamuni/index.php rename to _content/keyboards/h/tamil/suratha-bamuni/index.php index 2bc37388..8a8d452f 100644 --- a/keyboards/h/tamil/suratha-bamuni/index.php +++ b/_content/keyboards/h/tamil/suratha-bamuni/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil Suratha Bamuni Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tamil/visual-media-modular/index.php b/_content/keyboards/h/tamil/visual-media-modular/index.php similarity index 93% rename from keyboards/h/tamil/visual-media-modular/index.php rename to _content/keyboards/h/tamil/visual-media-modular/index.php index 04290ffe..4c1f6a50 100644 --- a/keyboards/h/tamil/visual-media-modular/index.php +++ b/_content/keyboards/h/tamil/visual-media-modular/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil Visual Media (Modular) Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tamil/visual-media-typewriter/index.php b/_content/keyboards/h/tamil/visual-media-typewriter/index.php similarity index 93% rename from keyboards/h/tamil/visual-media-typewriter/index.php rename to _content/keyboards/h/tamil/visual-media-typewriter/index.php index 262e5883..49633229 100644 --- a/keyboards/h/tamil/visual-media-typewriter/index.php +++ b/_content/keyboards/h/tamil/visual-media-typewriter/index.php @@ -35,7 +35,7 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Tamil Visual Media (Typewriter) Keyman for macOS

- Type in Tamil in all your favourite software applications for macOS. Download Keyman + Type in Tamil in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Tamil Keyman for iPhone

@@ -102,24 +102,24 @@

Download a Tamil keyboard on these devices:

- +

Bookmarklet

diff --git a/keyboards/h/tibetan/index.php b/_content/keyboards/h/tibetan/index.php similarity index 100% rename from keyboards/h/tibetan/index.php rename to _content/keyboards/h/tibetan/index.php diff --git a/keyboards/h/tigrigna/eritrean.php b/_content/keyboards/h/tigrigna/eritrean.php similarity index 95% rename from keyboards/h/tigrigna/eritrean.php rename to _content/keyboards/h/tigrigna/eritrean.php index 586b372c..0d8383f6 100644 --- a/keyboards/h/tigrigna/eritrean.php +++ b/_content/keyboards/h/tigrigna/eritrean.php @@ -16,7 +16,7 @@ Type in Tigrigna on iPhone, iPad, Windows, macOS, Linux, and Android. Our Tigrigna keyboards works with Microsoft Word, Photoshop, Facebook, Twitter, email and thousands of other applications.

- Click here for Tigirigna (Ethiopia) + Click here for Tigirigna (Ethiopia)

@@ -65,13 +65,13 @@

Tigrigna Keyman for macOS

- Type in Tigrigna in all your favourite software applications for macOS. Download Keyman + Type in Tigrigna in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS
@@ -87,24 +87,24 @@

Download a Tigrigna keyboard on these devices:

- +

Bookmarklet

@@ -115,7 +115,7 @@

Type in other Ethiopic languages such as:

diff --git a/keyboards/h/tigrigna/index.php b/_content/keyboards/h/tigrigna/index.php similarity index 95% rename from keyboards/h/tigrigna/index.php rename to _content/keyboards/h/tigrigna/index.php index 1679a127..51055485 100644 --- a/keyboards/h/tigrigna/index.php +++ b/_content/keyboards/h/tigrigna/index.php @@ -16,7 +16,7 @@ Type in Tigrigna on iPhone, iPad, Windows, macOS, Linux, and Android. Our Tigrigna keyboards works with Microsoft Word, Photoshop, Facebook, Twitter, email and thousands of other applications.

- Click here for Tigirigna (Eritrea) + Click here for Tigirigna (Eritrea)

@@ -65,13 +65,13 @@

Tigrigna Keyman for macOS

- Type in Tigrigna in all your favourite software applications for macOS. Download Keyman + Type in Tigrigna in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS
@@ -87,24 +87,24 @@

Download a Tigrigna keyboard on these devices:

- +

Bookmarklet

@@ -115,7 +115,7 @@

Type in other Ethiopic languages such as:

diff --git a/keyboards/h/urdu/index.php b/_content/keyboards/h/urdu/index.php similarity index 93% rename from keyboards/h/urdu/index.php rename to _content/keyboards/h/urdu/index.php index d753e529..d49c3b54 100644 --- a/keyboards/h/urdu/index.php +++ b/_content/keyboards/h/urdu/index.php @@ -31,19 +31,19 @@

Download Now

- Learn more about Keyman for Windows + Learn more about Keyman for Windows

Urdu Keyman for macOS

- Type in Urdu in all your favourite software applications for macOS. Download Keyman + Type in Urdu in all your favourite software applications for macOS. Download Keyman for macOS first

Download Now

- Learn more about Keyman for macOS + Learn more about Keyman for macOS

Urdu Keyman for iPhone

@@ -86,24 +86,24 @@

Download an Urdu keyboard on these devices:

\n"; - $linkArray = array( - 'en' => array(Menu::change_ui_language('en'), 'English'), - 'de' => array(Menu::change_ui_language('de'), 'Deutsch'), - 'es' => array(Menu::change_ui_language('es'), 'Español'), - 'fr' => array(Menu::change_ui_language('fr'), 'Français'), - 'km' => array(Menu::change_ui_language('km'), 'ខ្មែរ') - ); + $linkArray = array(); + foreach(DISPLAY_NAMES as $id => $name) { + $linkArray[$id] = array(Menu::change_ui_language($id), $name); + } foreach($linkArray as $id) { echo << ID to handle 3 cases: * ui-language (default) Desktop globe hover * ui-language1 - Desktop globe hover * phone - Mobile list */ private static function render_globe_dropdown($divID = "ui-language"): void { - global $page_is_using_locale; - if (!isset($page_is_using_locale) || !$page_is_using_locale) { - // only render on pages that use localized strings - return; - } - // Phone layout $globeClass = ''; if ($divID === "phone") { ?>
-

" alt="UI globe dropdown" /> Keyboard Search UI

+

" alt="UI globe dropdown" /> Display in:

Keyboards

- + " alt="search button" value="Search" onclick="if(document.getElementById('language-search2').value==''){return false;}"> @@ -137,45 +141,44 @@ private static function render_phone_menu(object $fields): void {
@@ -200,9 +203,9 @@ private static function render_top_menu(object $fields): void { " alt='Header bottom' />
- Keyman is free and open source + Keyman is free and open source -
+
@@ -220,7 +223,7 @@ private static function render_top_menu(object $fields): void {
" alt="Keyman logo" />
- +
@@ -239,7 +242,7 @@ private static function render_top_menu(object $fields): void { \ No newline at end of file diff --git a/_includes/includes/developer-features.php b/_includes/includes/developer-features.php index 08709d21..47b2f852 100644 --- a/_includes/includes/developer-features.php +++ b/_includes/includes/developer-features.php @@ -13,6 +13,6 @@
-
\ No newline at end of file +
diff --git a/_includes/includes/ui/keyboard-details.php b/_includes/includes/ui/keyboard-details.php index d804b881..dd6f94ad 100644 --- a/_includes/includes/ui/keyboard-details.php +++ b/_includes/includes/ui/keyboard-details.php @@ -12,7 +12,7 @@ use \Keyman\Site\com\keyman\Locale; use \Keyman\Site\com\keyman; - Locale::definePageLocale('LOCALE_KEYBOARDS_DETAILS', 'keyboards/details'); + Locale::definePageScope('LOCALE_KEYBOARDS_DETAILS', 'keyboards/details'); $_m_KeyboardDetails = function($id, ...$args) { return Locale::m(LOCALE_KEYBOARDS_DETAILS, $id, ...$args); }; diff --git a/_includes/locale/Locale.php b/_includes/locale/Locale.php index 8d367044..5792fd81 100644 --- a/_includes/locale/Locale.php +++ b/_includes/locale/Locale.php @@ -10,10 +10,18 @@ use \Keyman\Site\Common\KeymanHosts; + // As UI languages get added, we'll need to update this. + define('DISPLAY_NAMES', [ + 'en' => 'English', + 'de' => 'Deutsch', + 'es' => 'Español', + 'fr' => 'Français', + 'km' => 'ខ្មែរ (Khmer)']); + class Locale { public const DEFAULT_LOCALE = 'en'; - // array of the support locales + // array of the support locales // xx-YY locale as specified in crowdin %locale% private static $currentLocales = []; @@ -22,28 +30,75 @@ class Locale { // Each locale is an object? with loaded flag and array of strings private static $strings = []; + private static $invalidLocale = false; + /** * Return the current locales. Fallback to 'en' * @return $currentLocales */ public static function currentLocales() { + if(count(self::$currentLocales) == 0) { + Locale::setLocaleFromURL(); + } return self::$currentLocales; } + /** + * Return the user-selected page locale, which is always embedded at the + * front of the URL path + */ + public static function pageLocale() { + return self::currentLocales()[0]; + } + + /** + * Returns true if the locale determined from the URL is not a known locale, + * based on the list in DISPLAY_NAMES. If we are loaded in a context outside + * localized content, and where the top-level folder name would be valid + * BCP47, e.g. /go/, Locale::invalidLocale() will return true. See root + * /.htaccess for list of all non-localized content where this may arise. + */ + public static function invalidLocale() { + self::currentLocales(); // ensure locale is set + return self::$invalidLocale; + } + + /** + * Set the current locale based on the first path component + * //rest/of/path for the current page URL + */ + private static function setLocaleFromURL() { + // First component of the URL is always the locale + if(preg_match('/^\\/(([a-z]{2,3})(-([A-Za-z]{4}))?(-([a-z]{2}|[0-9]{3}))?)\\//', $_SERVER['REQUEST_URI'], $matches)) { + if(!isset(DISPLAY_NAMES[$matches[1]])) { + // Note: this is an unsupported locale, so we'll end up redirecting in head.php to /en/... + $pageLocale = Locale::DEFAULT_LOCALE; + self::$invalidLocale = true; + } else { + $pageLocale = $matches[1]; + } + } else { + $pageLocale = Locale::DEFAULT_LOCALE; + } + self::setLocale($pageLocale); + } + /** * Set the current locales, with an array of fallbacks, ending in 'en'. * @param $locale - the new current locale (xx-YY as specified in crowdin %locale%) */ - public static function setLocale($locale) { + private static function setLocale($locale) { // Clear current locales - self::$currentLocales == []; + self::$currentLocales = []; if (!empty($locale)) { self::$currentLocales = self::calculateFallbackLocales($locale); } - // Push default fallback locale to the end - array_push(self::$currentLocales, Locale::DEFAULT_LOCALE); + if(!in_array(Locale::DEFAULT_LOCALE, self::$currentLocales)) { + // Push default fallback locale to the end + array_push(self::$currentLocales, Locale::DEFAULT_LOCALE); + } } /** @@ -53,8 +108,8 @@ public static function setLocale($locale) { */ public static function loadDomain($domain) { self::$strings[$domain] = []; - $path = __DIR__ . '/strings/' . $domain . '/*.php'; - $files = glob(__DIR__ . '/strings/' . $domain . '/*.php'); + $path = _KEYMANCOM_INCLUDES . '/locale/strings/' . $domain . '/*.php'; + $files = glob(_KEYMANCOM_INCLUDES . '/locale/strings/' . $domain . '/*.php'); if ($files == false) { return false; } @@ -78,7 +133,7 @@ public static function loadDomain($domain) { */ public static function loadStrings($domain, $locale) { $currentLocaleFilename = sprintf("%s/%s/%s", - __DIR__ . '/strings/', + _KEYMANCOM_INCLUDES . '/locale/strings/', $domain, $locale . '.php'); @@ -88,13 +143,29 @@ public static function loadStrings($domain, $locale) { } } + /** + * Return an array of javascript locales available for the given domain, in + * priority order. + */ + public static function domain_js($domain) { + $root = _KEYMANCOM_INCLUDES . "/locale/strings/$domain"; + $locales = []; + foreach (self::currentLocales() as $locale) { + if(file_exists("$root/$locale.json")) { + array_push($locales, $locale); + } + } + + return $locales; + } + /** * Defines a global variable for page locale strings and also * tells locale system that current page uses locales - * @param $define - + * @param $define - * @param $id - folder containing locale strings, relative to /_includes/locale/strings */ - public static function definePageLocale($define, $id) { + public static function definePageScope($define, $id) { global $page_is_using_locale; $page_is_using_locale = true; define($define, $id); @@ -156,7 +227,7 @@ private static function getString($domain, $id) { } } - // String not found in any localization - + // String not found in any localization - if(KeymanHosts::Instance()->Tier() == KeymanHosts::TIER_DEVELOPMENT) { die('string ' . $id . ' is missing in all the l10ns'); } @@ -164,13 +235,13 @@ private static function getString($domain, $id) { } /** - * Wrapper to lookup localized string for webpage domain. + * Wrapper to lookup localized string for webpage domain. * Formatted string using optional variable args for placeholders * should escape like %1\$s * @param $domain - the PHP file using the localized strings * @param $id - the id for the string * @param $args - optional remaining args to the format string - */ + */ public static function m($domain, $id, ...$args) { $str = self::getString($domain, $id); if (count($args) == 0) { diff --git a/_includes/locale/strings/keyboards/details/en.php b/_includes/locale/strings/keyboards/details/en.php index 22ccde87..3a3b148a 100644 --- a/_includes/locale/strings/keyboards/details/en.php +++ b/_includes/locale/strings/keyboards/details/en.php @@ -137,9 +137,6 @@ "new_search" => "New search", - ## TODO: Previous/Next pagination handled in search.js - - ## Errors # Failed to load keyboard package [ID] diff --git a/_includes/locale/strings/keyboards/details/km.php b/_includes/locale/strings/keyboards/details/km.php index 380b946a..49807a6a 100644 --- a/_includes/locale/strings/keyboards/details/km.php +++ b/_includes/locale/strings/keyboards/details/km.php @@ -89,7 +89,7 @@ "downloads_since" => "ដំឡើងចាប់តាំងពី %1\$s", # Date to start counting downloads - "date_counting" => "October 2019", + "date_counting" => "តុលា​ ២០១៩", "encoding" => "ការអ៊ីនកូដ", diff --git a/_includes/locale/strings/keyboards/en.json b/_includes/locale/strings/keyboards/en.json new file mode 100644 index 00000000..c2bcd24a --- /dev/null +++ b/_includes/locale/strings/keyboards/en.json @@ -0,0 +1,15 @@ +{ + "resultOne": "result", + "resultMore": "results", + "pageNumberOfTotalPages": "page {pageNumber} of {totalPages}.", + "keyboardSearchTitle": "- Keyboard search", + "obsoleteKeyboards": "Obsolete keyboards", + "monthlyDownloadZero": "No recent downloads", + "monthlyDownloadOne": "monthly download", + "monthlyDownloadMore": "monthly downloads", + "notUnicode": "Note: Not a Unicode keyboard", + "designedForPlatform": "Designed for {platform}", + "noMatchesFoundForKeyboard": "No matches found for '{keyboard}'", + "previousPager": "< Previous", + "nextPager": "Next >" +} diff --git a/_includes/locale/strings/keyboards/es.json b/_includes/locale/strings/keyboards/es.json new file mode 100644 index 00000000..70a65bbd --- /dev/null +++ b/_includes/locale/strings/keyboards/es.json @@ -0,0 +1,15 @@ +{ + "resultOne": "resultado", + "resultMore": "resultados", + "pageNumberOfTotalPages": "página {pageNumber} de {totalPages}.", + "keyboardSearchTitle": "- Búsqueda por teclado", + "obsoleteKeyboards": "Teclados obsoletos", + "monthlyDownloadZero": "No hay descargas recientes", + "monthlyDownloadOne": "descarga mensual", + "monthlyDownloadMore": "descargas mensuales", + "notUnicode": "Nota: No es un teclado Unicode", + "designedForPlatform": "Diseñado para {platform}", + "noMatchesFoundForKeyboard": "No se encontraron coincidencias para '{keyboard}'", + "previousPager": "< Anterior", + "nextPager": "Siguente >" +} diff --git a/_includes/locale/strings/keyboards/fr.json b/_includes/locale/strings/keyboards/fr.json new file mode 100644 index 00000000..880a0f99 --- /dev/null +++ b/_includes/locale/strings/keyboards/fr.json @@ -0,0 +1,15 @@ +{ + "resultOne": "résultat", + "resultMore": "résultats", + "pageNumberOfTotalPages": "page {pageNumber} sur {totalPages}.", + "keyboardSearchTitle": "- Recherche au clavier", + "obsoleteKeyboards": "Claviers obsolètes", + "monthlyDownloadZero": "Aucun téléchargement récent", + "monthlyDownloadOne": "téléchargement mensuel", + "monthlyDownloadMore": "téléchargements mensuels", + "notUnicode": "Remarque: Ce n'est pas un clavier Unicode.", + "designedForPlatform": "Conçu pour {platform}", + "noMatchesFoundForKeyboard": "Aucun résultat trouvé pour '{keyboard}'", + "previousPager": "< Précédentes", + "nextPager": "Plus >" +} diff --git a/_includes/locale/strings/keyboards/install/km.php b/_includes/locale/strings/keyboards/install/km.php index 27f64dd4..03d7460f 100644 --- a/_includes/locale/strings/keyboards/install/km.php +++ b/_includes/locale/strings/keyboards/install/km.php @@ -4,14 +4,14 @@ * Keyman is copyright (C) SIL Global. MIT License. * * Default English strings for keyboards/keyboard-install.php - * Don't escape $s when uploading source to crowdin because exports will escape \$s to \\$s + * When exporting strings from crowdin, convert \\$s to \$s */ declare(strict_types=1); return [ # Page Title - "install_page_title" => "%1\$s ក្តារចុច", + "install_page_title" => "%1\$s​ ក្ដារចុច", # {Keyboard} download should start shortly "download_start_shortly" => diff --git a/_includes/locale/strings/keyboards/km.json b/_includes/locale/strings/keyboards/km.json new file mode 100644 index 00000000..cbe861fb --- /dev/null +++ b/_includes/locale/strings/keyboards/km.json @@ -0,0 +1,15 @@ +{ + "resultOne": "លទ្ធផល", + "resultMore": "លទ្ធផល", + "pageNumberOfTotalPages": "ទំព័រ​ទី {pageNumber}​ នៃ {totalPages}។", + "keyboardSearchTitle": "- ស្វែងរកក្ដារចុច", + "obsoleteKeyboards": "ក្ដារចុចបោះបង់ចោល", + "monthlyDownloadZero": "គ្មានការទាញយកថ្មីៗ", + "monthlyDownloadOne": "ចំនួនទាញយកប្រចាំខែ", + "monthlyDownloadMore": "ចំនួនទាញយកទាំងឡាយប្រចាំខែ", + "notUnicode": "ចំណាំ៖​ មិនមែនជាក្ដារចុចយូនីកូដ", + "designedForPlatform": "រចនាសម្រាប់ {platform}", + "noMatchesFoundForKeyboard": "គ្មានឃើញចម្លើយសម្រាប់ {keyboard}", + "previousPager": "< មុន", + "nextPager": "បន្ទាប់ >" +} diff --git a/_includes/locale/strings/keyboards/km.php b/_includes/locale/strings/keyboards/km.php index 8fedcca4..d665723f 100644 --- a/_includes/locale/strings/keyboards/km.php +++ b/_includes/locale/strings/keyboards/km.php @@ -3,7 +3,8 @@ /* * Keyman is copyright (C) SIL Global. MIT License. * - * Default Khmer strings for keyboards/index.php + * Default English strings for keyboards/index.php + * When exporting strings from crowdin, convert \\$s to \$s */ declare(strict_types=1); @@ -42,14 +43,14 @@ # Search box hint: Description "searchbox_description" => "លទ្ធផល​ស្វែងរក​តែងតែ​បង្ហាញ​ជា​បញ្ជី​ក្ដារចុច ។ វាស្វែងរកអំពីឈ្មោះ និងព័ត៌មានលម្អិតរបស់ក្ដារចុច, ឈ្មោះភាសា, ឈ្មោះប្រទេស, និង ឈ្មោះចារឹកនៃក្ដារចុច ។", - + # Search box hint (line 2): "searchbox_hint_2" => "អ្នកអាចភ្ជាប់បុព្វបទទាំងនេះ %1\$s (ឈ្មោះក្ដារចុច) %2\$s (ឈ្មោះភាសា) %3\$s (អក្សរចារឹក, ប្រព័ន្ធសរសេរ) ឫ %4\$s (ឈ្មោះប្រទេស) ដើម្បីធ្វើឱ្យលទ្ធផលស្វែងរកកាន់តែច្បាស់លាស់។ ឧទាហរណ៍ %5\$s ស្វែងរក​នូវ​ក្ដារចុច​សម្រាប់​ភាសា​ទាំងឡាយ​ដែល​ត្រូវបាន​ប្រើប្រាស់​នៅក្នុង​ប្រទេស​ថៃ។", - + # Search box hint (line 3): - "searchbox_hint_3" => - "ការប្រើបុព្វបទ %1\$s ក្នុងការស្វែងរកស្លាកភាសា BCP 47, ឧទាហរណ៍ %2\$s ស្វែងរកភាសា Tigrigna (អេត្យូពី)។" + "searchbox_hint_3" => + "ការប្រើបុព្វបទ %1\$s ក្នុងការស្វែងរកស្លាកភាសា BCP 47, ឧទាហរណ៍ %2\$s ស្វែងរកភាសា Tigrigna (អេត្យូពី)។", ]; diff --git a/_includes/locale/strings/keyboards/share/km.php b/_includes/locale/strings/keyboards/share/km.php index 503caf04..0d11884a 100644 --- a/_includes/locale/strings/keyboards/share/km.php +++ b/_includes/locale/strings/keyboards/share/km.php @@ -4,7 +4,7 @@ * Keyman is copyright (C) SIL Global. MIT License. * * Default English strings for keyboards/keyboard-share.php - * Don't escape $s when uploading source to crowdin because exports will escape \$s to \\$s + * When exporting strings from crowdin, convert \\$s to \$s */ declare(strict_types=1); diff --git a/_scripts/contributors/contributors.mjs b/_scripts/contributors/contributors.mjs index cf314e83..40d61dc0 100644 --- a/_scripts/contributors/contributors.mjs +++ b/_scripts/contributors/contributors.mjs @@ -14,7 +14,7 @@ import { genTeamMarkdownSegment } from "./team.mjs"; // Parse CLI input const program = new Command(); program.name("node .") - .description("Script to generate https://keyman.com/about/team/index.md") + .description("Script to generate https://keyman.com/_content/about/team/index.md") .version("0.1.0") .option("-o, --output ", "output file", "index.md") .option("-g, --github-key ", "github api authentication key (https://github.com/settings/tokens)") @@ -26,7 +26,7 @@ program.parse(process.argv); async function main() { - const teamData = JSON.parse(fs.readFileSync('../../about/team/team.json', 'utf-8')); + const teamData = JSON.parse(fs.readFileSync('../../_content/about/team/team.json', 'utf-8')); const coreTeam = teamData.filter(member => member.level == 'core'); const formerTeam = teamData.filter(member => member.level == 'core-previous'); const coreTeamHandles = coreTeam.map(member => member.handle); diff --git a/_scripts/contributors/run.sh b/_scripts/contributors/run.sh index 3ca07d9f..e7ba9f59 100755 --- a/_scripts/contributors/run.sh +++ b/_scripts/contributors/run.sh @@ -17,16 +17,16 @@ if [[ -z "${GITHUB_TOKEN+x}" ]] || [[ -z "${CROWDIN_TOKEN+x}" ]]; then fi npm ci -node . -g "${GITHUB_TOKEN}" -c "${CROWDIN_TOKEN}" -o "../../about/team/index.md" "$@" +node . -g "${GITHUB_TOKEN}" -c "${CROWDIN_TOKEN}" -o "../../_content/about/team/index.md" "$@" if [[ -z "${GITHUB_ACTIONS+x}" ]]; then echo "Skipping git commit because of local run" else - if ! git diff --exit-code -- ../../about/team/index.md; then + if ! git diff --exit-code -- ../../_content/about/team/index.md; then git config user.email server@keyman.com git config user.name "Keyman Server" git switch -c auto/contributors - git add ../../about/team/index.md + git add ../../_content/about/team/index.md git commit -m "auto: refresh contributors Test-bot: skip" diff --git a/_scripts/contributors/team.mjs b/_scripts/contributors/team.mjs index adac8b15..73620ab1 100644 --- a/_scripts/contributors/team.mjs +++ b/_scripts/contributors/team.mjs @@ -10,7 +10,7 @@ export function genTeamMarkdownSegment(teamData) { for(const member of teamData) { const img = member.img ? `/cdn/dev/img/${member.img}` : `https://github.com/${member.handle}.png?size=240`; - const url = fs.existsSync(`../../about/team/bios/${member.handle}.md`) ? `bios/${member.handle}` : `https://github.com/${member.handle}`; + const url = fs.existsSync(`../../_content/about/team/bios/${member.handle}.md`) ? `bios/${member.handle}` : `https://github.com/${member.handle}`; md += `
diff --git a/_test/blc_test.mjs b/_test/blc_test.mjs deleted file mode 100644 index a9802ecb..00000000 --- a/_test/blc_test.mjs +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Keyman is copyright (C) SIL Global. MIT License. - * - * Setup options and run the broken-link-checker on the site - * @param excludeExternalLinks: boolean to skip external links. Default true - * - * package.json using bhttp 1.2.8 to resolve this exception - * Reference: https://github.com/stevenvachon/broken-link-checker/issues/184 - */ -import * as fs from 'node:fs'; -import { argv } from 'node:process'; -import * as path from 'node:path'; -import blc from 'broken-link-checker'; -import humanizeDuration from 'humanize-duration'; -const { SiteChecker } = blc; - -const KEYMAN_COM_BASE_URL = 'http://localhost:8053'; - -/** - * Searches through ../_includes/locale/strings/keyboards/ for the localized .php files. - * Generate list of excludedKeywords: non-en locales - * @returns string[] - */ -function generateExcludeList() { - // Determine list of "locales" to exclude - const excluded = fs.readdirSync('../_includes/locale/strings/keyboards/') - .filter(file => path.extname(file).toLowerCase() === '.php') - .filter(file => file !== 'en.php') - .map(file => `${KEYMAN_COM_BASE_URL}/${path.basename(file, '.php')}/`); - - return excluded; -} - -/** - * Run the broken link checker test. Prints results while running - * @param excludeExternalLinks {boolean} to skip external links - */ -async function runTest(excludeExternalLinks) { - const options = { - cacheResponses: true, // Check each unique URL once - excludedKeywords: generateExcludeList(), - excludeExternalLinks: excludeExternalLinks, - excludedSchemes: ['market'], - filterLevel: 3, - maintainLinkOrder: true, - maxSocketsPerHost: 50, - recursive: true - }; - console.info(`options: ${JSON.stringify(options, null, 2)}`); - - let startTime = Date.now(); - console.info(`start time: ${new Date(startTime).toISOString()}`); - - const siteChecker = new SiteChecker(options, { - html: (tree, robots, response, pageURL) => { - console.info(`\nGetting links from: ${pageURL}`); - }, - link: (result) => { - //console.info(`${JSON.stringify(result)}`); - if (result.broken) { - const brokenUrl = (result.url.resolved) ? result.url.resolved : result.url.original; - console.error(`├─BROKEN─ ${brokenUrl} because ${result.brokenReason}`); - } else if (result.excluded) { - console.info(`├─EXCLUDED─ ${result.url.resolved} for ${link.excludedReason}`); - } else { - // For troubleshooting valid links - //console.info(`├───OK─── ${result.url.resolved}`); - } - }, - end: () => { - // Summary - console.info(`\nLinks broken: TBD`); - console.info(`\nTime elapsed: ${humanizeDuration(Date.now() - startTime, {largest: 2, round:true})}\n`); - } - }); - - const firstPageUrl = `${KEYMAN_COM_BASE_URL}/_test`; - siteChecker.enqueue(firstPageUrl); -} - -/* - * Setup options and run the broken-link-checker on the site - * @param excludeExternalLinks: boolean to skip external links. Default true - */ -const excludeExternalLinks = argv.length >= 3 ? argv[2].toLowerCase() === 'true' : true; -await runTest(excludeExternalLinks); diff --git a/_test/go.md b/_test/go.md index ed64ed2a..05493431 100644 --- a/_test/go.md +++ b/_test/go.md @@ -64,7 +64,7 @@ showmenu: false ## android ### /go/android/X.Y/download-keyboards/languages -Royce, Scott, and Darcy attending Colloquium on Fonts for Southeast Asian scripts + [download-keyboards/languages](/go/android/16.0/download-keyboards/languages/km) [live: download-keyboards/languages](https://keyman.com/go/android/16.0/download-keyboards/languages/km) diff --git a/_test/index.md b/_test/index.md index be6b99b7..c050effa 100644 --- a/_test/index.md +++ b/_test/index.md @@ -23,15 +23,15 @@ showmenu: false ## Links to Other Test Pages -[/go links](./go) +[go links](go) -[/keyboards links](./keyboards) +[keyboards links](keyboards) -[keyboard language landing links](./language-landing) +[keyboard language landing links](language-landing) -[/_legacy keyboards links](./legacy) +[legacy keyboards links](legacy) -[/well-known links](./well-known) +[well-known links](well-known) ## Link to Main Page diff --git a/alpha/index.php b/alpha/index.php deleted file mode 100644 index 5d2d5042..00000000 --- a/alpha/index.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/android/app/.htaccess b/android/app/.htaccess deleted file mode 100644 index 544cf4cf..00000000 --- a/android/app/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ - -# Redirect /android/app to help.keyman.com -RedirectMatch ".*" "https://help.keyman.com/products/android/" diff --git a/archive/.htaccess b/archive/.htaccess deleted file mode 100644 index 0599591b..00000000 --- a/archive/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ - -# Redirect /archive/downloads.php" -RedirectMatch 301 "/archive/downloads.php" "/downloads/archive/" diff --git a/beta/index.php b/beta/index.php deleted file mode 100644 index 6b70f0ee..00000000 --- a/beta/index.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/build.sh b/build.sh index 5c205d5b..14b78dda 100755 --- a/build.sh +++ b/build.sh @@ -52,9 +52,9 @@ function test_docker_container() { readarray -t ignoresArray <<< $(find ./_includes/locale/strings/keyboards/ -maxdepth 1 -name '*.php' ! -name "en.php" \ -execdir basename {} .php ';') local baseURL="http://localhost:8053" - local ignoreStr=(" --exclude */downloads/releases/*") + local ignoreStr=(" --exclude ${baseURL}*/downloads/releases/*") for locale in "${ignoresArray[@]}"; do - ignoreStr+=" --exclude ${baseURL}/$locale/*" + ignoreStr+=" --exclude ${baseURL}/${locale}/*" done echo "ignoreStr: ${ignoreStr[@]}" npx broken-link-checker ${baseURL}/_test --recursive --ordered ---host-requests 50 -e --filter-level 3 ${ignoreStr} | tee blc.log diff --git a/cdn/dev/js/i18n.mjs b/cdn/dev/js/i18n.mjs new file mode 100644 index 00000000..e3123813 --- /dev/null +++ b/cdn/dev/js/i18n.mjs @@ -0,0 +1,143 @@ +/** + * Keyman is copyright (c) SIL Global. MIT License + * + * Vanilla JS for localizing keyboard search strings without a framework + * Reference: https://medium.com/@mihura.ian/translations-in-vanilla-javascript-c942c2095170 + * + * Domains are loaded by Head::render() with the js_i18n_domains property, e.g. + * + * 'js_i18n_domains' => [ + * 'keyboards' => Locale::domain_js('keyboards'), + * ], + * + */ + +export class I18n { + // domains member has the following structure: + // [ + // { "locale": "fr", "strings": { "key": "value", ... } }, + // { "locale": "en", "strings": { "key": "value", ... } }, + // ... + // ] + static domains = []; + + static _pageLocale; + + /** + * @returns the current page locale based on the URL. Note that the PHP + * Locale.php is responsible for parsing and avoiding invalid locales. + */ + static pageLocale() { + if(!this._pageLocale) { + let langMatch = location.pathname.match(/^\/([^/]+)/); + this._pageLocale = langMatch ? langMatch[1] : 'en'; + } + return this._pageLocale; + } + + /** + * Load the strings for the given domain + * @param {string} domain + * @return {boolean} Status if domain was successfully loaded + */ + static loadDomain(domain) { + + // avoid reporting domain-load errors more than once + I18n.domains[domain] = { locales: [] }; + + const json = document.getElementById('i18n_'+domain)?.text; + if(!json) { + console.error(`i18n domain '${domain}' was not loaded`); + return false; + } + + try { + I18n.domains[domain] = { + locales: JSON.parse(json) + }; + } catch(e) { + // Handle JSON parse errors so we get a functioning page, even if it has + // no localized strings visible + console.error(`Invalid JSON for 'i18n_${domain}': ${e}`); + return false; + } + + return true; + } + + /** + * Navigates inside `obj` with `path` string, + * + * Usage: + * objNavigate({a: {b: {c: 123}}}, "a.b.c") // returns 123 + * + * Fails silently. + * @param {Object} obj + * @param {string} path to navigate into obj + * @return {string} or undefined if variable is not found. + */ + static objNavigate(obj, path){ + if(!obj) return undefined; + var aPath = path.split('.'); + try { + return aPath.reduce((a, v) => a[v], obj); + } catch { + return undefined; + } + }; + + /** + * Interpolates variables wrapped with `{}` in `str` with variables in `obj` + * It will replace what it can, and leave the rest untouched + * + * Usage: + * + * named variables: + * strObjInterpolation("I'm {age} years old!", { age: 29 }); + * + * ordered variables + * strObjInterpolation("The {0} says {1}, {1}, {1}!", ['cow', 'moo']); + * @param {string} str containing interpolated variables wrapped in `{}` + * @param {Object} JSON containing values for the variables + * @return {string} Resulting string where variables are replaced + */ + static strObjInterpolation(str, obj){ + obj = obj || []; + str = str ? str.toString() : ''; + return str.replace( + /{([^{}]*)}/g, + (a, b) => { + const r = obj[b]; + return typeof r === 'string' || typeof r === 'number' ? r : a; + }, + ); + }; + + /** + * Determine the display UI language for the keyboard search + * Navigate the translation JSON + * @param {string} domain of the localized strings + * @param {string} key for the string + * @param {Object} interpolations for optional formatted parameters + * @return {string} localized string + */ + static t(domain, key, interpolations) { + if (!I18n.domains[domain]) { + if(!I18n.loadDomain(domain)) { + return key; + } + } + + // Find best matching string in the available locales + for(const locale of I18n.domains[domain].locales) { + const value = I18n.objNavigate(locale.strings, key); + if(value) { + return I18n.strObjInterpolation(value, interpolations); + } + } + + console.warn(`Missing localization string in '${domain}' for '${key}' in all loaded locales`); + // TODO: log to sentry? + return key; + } +} diff --git a/cdn/dev/keyboard-search/search.js b/cdn/dev/keyboard-search/search.mjs similarity index 86% rename from cdn/dev/keyboard-search/search.js rename to cdn/dev/keyboard-search/search.mjs index e4242fb9..59c9f732 100644 --- a/cdn/dev/keyboard-search/search.js +++ b/cdn/dev/keyboard-search/search.mjs @@ -1,3 +1,8 @@ +import { I18n } from '../js/i18n.mjs'; + +const I18N_DOMAIN = 'keyboards'; +const t = (key, interpolations) => I18n.t(I18N_DOMAIN, key, interpolations); + // Polyfill for String.prototype.includes if (!String.prototype.includes) { @@ -14,12 +19,12 @@ if (!String.prototype.includes) { ///////////////////////////// -if(typeof embed_query == 'undefined') { - var embed_query = ''; +if(typeof window.embed_query == 'undefined') { + window.embed_query = ''; } -var embed_query_q = embed_query == '' ? '' : '?'+embed_query; -var embed_query_x = embed_query == '' ? '' : '&'+embed_query; +var embed_query_q = window.embed_query == '' ? '' : '?'+window.embed_query; +var embed_query_x = window.embed_query == '' ? '' : '&'+window.embed_query; var dynamic_search_timeout = 0; @@ -35,14 +40,15 @@ function getCurrentPath(q, page, obsolete) { obsolete = obsolete ? '&obsolete=1' : ''; page = page > 1 ? 'page='+page : ''; var path = ''; + const base = `/${I18n.pageLocale()}`; if(r && r[1].charAt(0) == 'c') { - path = '/keyboards/countries/'; + path = `${base}/keyboards/countries/`; } else if(r && r[1].charAt(0) == 'l') { - path = '/keyboards/languages/'+r[3]; + path = `${base}/keyboards/languages/${r[3]}`; } else if(q == '') { - path = '/keyboards' + path = `${base}/keyboards/` } else { - path = '/keyboards?q='+encodeURIComponent(q); + path = `${base}/keyboards/?q=${encodeURIComponent(q)}`; } if(page + obsolete == '') { @@ -84,12 +90,12 @@ function wrapSearch(localCounter, updateHistory) { $('#search-box').removeClass('searching'); return false; } - + var base = location.protocol+'//api.'+location.host; // this works on test sites as well as live, assuming we use the host pattern "keyman.com[.localhost]" var url = base+'/search/2.0?p='+page+'&q='+encodeURIComponent(stripCommonWords(q)); - if(embed) { - url += '&platform='+embed; + if(window.embed) { + url += '&platform='+window.embed; } if(obsolete) { @@ -258,25 +264,25 @@ function process_response(q, obsolete, res) { var deprecatedElement = null; $('
').text( - res.context.totalRows + (res.context.totalRows == 1 ? ' result' : ' results') + - (res.context.totalPages < 2 ? '' : '; page '+res.context.pageNumber + ' of '+res.context.totalPages+'.') + res.context.totalRows + ' ' + (res.context.totalRows == 1 ? t('resultOne') : t('resultMore') )+ ' ' + + (res.context.totalPages < 2 ? '' : t('pageNumberOfTotalPages', {pageNumber: res.context.pageNumber, totalPages: res.context.totalPages})) ).appendTo(resultsElement); - document.title = q + ' - Keyboard search'; + document.title = q + ' ' + t('keyboardSearchTitle'); - res.keyboards.forEach(function(kbd) { + for (const kbd of res.keyboards) { if(isKeyboardObsolete(kbd) && !deprecatedElement) { // TODO: make title change depending on whether deprecated keyboards are shown or hidden deprecatedElement = $( - '

Obsolete keyboards

'); + '

' + t('obsoleteKeyboards') + '

'); resultsElement.append(deprecatedElement); } - $keyboardClass = kbd.isDedicatedLandingPage ? 'keyboard keyboardLandingPage' : 'keyboard'; + const keyboardClass = kbd.isDedicatedLandingPage ? 'keyboard keyboardLandingPage' : 'keyboard'; var k = $( - "
"+ + "
"+ "
"+ "
"+ "
"+ @@ -288,22 +294,22 @@ function process_response(q, obsolete, res) { "
"); if(kbd.isDedicatedLandingPage) { - $('.title a', k).text(kbd.name).attr('href', '/keyboards/h'+kbd.id+embed_query_q); + $('.title a', k).text(kbd.name).attr('href', `/${I18n.pageLocale()}/keyboards/h/${kbd.id}${embed_query_q}`); } else { - $('.title a', k).text(kbd.name).attr('href', '/keyboards/'+kbd.id+(kbd.match.tag ? '?bcp47='+kbd.match.tag+embed_query_x : embed_query_q)); + $('.title a', k).text(kbd.name).attr('href', '/' + I18n.pageLocale() + '/keyboards/'+kbd.id+(kbd.match.tag ? '?bcp47='+kbd.match.tag+embed_query_x : embed_query_q)); } if(kbd.isDedicatedLandingPage) { // We won't show the downloads text } else if(kbd.match.downloads == 0) - $('.downloads', k).text('No recent downloads'); + $('.downloads', k).text(t('monthlyDownloadZero')); else if(kbd.match.downloads == 1) - $('.downloads', k).text(kbd.match.downloads+' monthly download'); + $('.downloads', k).text(kbd.match.downloads+' ' + t('monthlyDownloadOne')); else - $('.downloads', k).text(kbd.match.downloads+' monthly downloads'); + $('.downloads', k).text(kbd.match.downloads+' ' + t('monthlyDownloadMore')); if(!kbd.encodings.toString().match(/unicode/)) { - $('.encoding', k).text('Note: Not a Unicode keyboard'); + $('.encoding', k).text(t('notUnicode')); } $('.id', k).text(kbd.id); @@ -331,20 +337,21 @@ function process_response(q, obsolete, res) { // icon-ios // icon-linux // icon-windows - var img = $('').attr('src', '/cdn/dev/keyboard-search/icon-'+i+'.png').attr('title', 'Designed for '+i); + var img = $('').attr('src', '/cdn/dev/keyboard-search/icon-'+i+'.png').attr('title', t('designedForPlatform', {platform: i})); $('.platforms', k).append(img); } } } $('.platforms', k).text(); (deprecatedElement ? deprecatedElement : resultsElement).append(k); - }); + }; if(res.context.totalPages > 1) { - buildPager(res, q, obsolete).appendTo(resultsElement); + const p = buildPager(res, q, obsolete); + p.appendTo(resultsElement); } } else { - $('

').addClass('red').text("No matches found for '"+qq+"'").appendTo(resultsElement); + $('

').addClass('red').text(t('noMatchesFoundForKeyboard', {keyboard: qq})).appendTo(resultsElement); } } @@ -358,7 +365,7 @@ function buildPager(res, q, obsolete) { } } - appendPager(pager, '< Previous', res.context.pageNumber-1); + appendPager(pager, t('previousPager'), res.context.pageNumber-1); if(res.context.pageNumber > 5) { $('...').appendTo(pager); } @@ -368,7 +375,7 @@ function buildPager(res, q, obsolete) { if(res.context.pageNumber < res.context.totalPages - 4) { $('...').appendTo(pager); } - appendPager(pager, 'Next >', res.context.pageNumber+1); + appendPager(pager, t('nextPager'), res.context.pageNumber+1); return pager; } @@ -384,7 +391,7 @@ function goToPage(event, q, page) { return false; } -function do_search() { +export function do_search() { document.f.page.value = 1; search(true); return false; // always return false from search box diff --git a/crowdin.yml b/crowdin.yml index 20c8a423..d7946f58 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -27,6 +27,20 @@ files: # Keyboard search files + # JS files + - source: /_includes/locale/strings/keyboards/en.json + dest: /keyboards/keyboards/en.json + translation: /_includes/locale/strings/keyboards/%locale%.json + languages_mapping: + locale: + # Canonical locales as needed + es-ES: es + de: de + fr: fr + km: km + + # PHP files + - source: /_includes/locale/strings/keyboards/en.php dest: /keyboards/keyboards/en.php translation: /_includes/locale/strings/keyboards/%locale%.php diff --git a/developer/keymanweb/index.2.0.php b/developer/keymanweb/index.2.0.php deleted file mode 100644 index f3d82dcc..00000000 --- a/developer/keymanweb/index.2.0.php +++ /dev/null @@ -1,2 +0,0 @@ - 1) keymanweb._KeyboardStubs.sort(function(a,b){ - var ax,bx; - switch(a['KLC']) - { - case 'eng': ax=0; break; - case 'fra': ax=1; break; - case 'deu': ax=2; break; - default: ax=10; break; - } - switch(b['KLC']) - { - case 'eng': bx=0; break; - case 'fra': bx=1; break; - case 'deu': bx=2; break; - default: bx=10; break; - } - return ax-bx; - }); -*/ - // TODO: Need to distinguish between initial loading of a large number of stubs and any subsequent loading. - // UI initialization should not be needed for each registration, only at end. - // Reload this keyboard if it was the last active keyboard and - // make any changes needed by UI for new keyboard stub - // (Uncommented for Build 360) - keymanweb.doKeyboardRegistered(Pstub['KI'],Pstub['KL'],Pstub['KN'],Pstub['KLC']); - } - - /** - * Get *cached or uncached* keyboard context for a specified range, relative to caret - * - * @param {number} n Number of characters to move back from caret - * @param {number} ln Number of characters to return - * @param {Object} Pelem Element to work with (must be currently focused element) - * @return {string} Context string - * - * Example [abcdef|ghi] as INPUT, with the caret position marked by |: - * KC(2,1,Pelem) == "e" - * KC(3,3,Pelem) == "def" - * KC(10,10,Pelem) == "abcdef" i.e. return as much as possible of the requested string - */ - - keymanweb['KC'] = keymanweb.KC = function(n, ln, Pelem) - { - var v = keymanweb.cachedContext.get(n, ln); - if(v !== null) return v; - - var r = keymanweb.KC_(n, ln, Pelem); - keymanweb.cachedContext.set(n, ln, r); - return r; - } - - /** - * Function KN - * Scope Public - * @param {number} n Length of context to check - * @param {Object} Pelem Element to work with (must be currently focused element) - * @return {boolean} True if length of context is less than or equal to n - * Description Test length of context, return true if the length of the context is less than or equal to n - * - * Example [abc|def] as INPUT, with the caret position marked by |: - * KN(3,Pelem) == TRUE - * KN(2,Pelem) == FALSE - * KN(4,Pelem) == TRUE - */ - keymanweb['KN'] = keymanweb.KN = function(n, Ptarg) // KeyboardNul - { - var cx=this.KC(n+1, n+1, Ptarg); - if(cx === false) return true; else return (cx._kmwLength() < n+1); // I2243 - support nul in context; I3319 - } - - /** - * Function KCM - * Scope Public - * @param {number} n Number of characters to move back from caret - * @param {Object} Ptarg Focused element - * @param {string} val String to match - * @param {number} ln Number of characters to return - * @return {boolean} True if selected context matches val - * Description Test keyboard context for match - */ - keymanweb['KCM'] = keymanweb.KCM = function(n, Ptarg, val, ln) // Keyboard_ContextMatch - { - //KeymanWeb._Debug('KeymanWeb.KCM(n='+n+', Ptarg, val='+val+', ln='+ln+'): return '+(this.KC(n,ln,Ptarg)==val)); - var cx=this.KC(n, ln, Ptarg); - if(cx !== false && cx === val) return true; // I3318 - this._DeadkeyResetMatched(); // I3318 - return false; - } - - /** - * Function KIK - * Scope Public - * @param {Object} e keystroke event - * @return {boolean} true if keypress event - * Description Test if event as a keypress event - */ - keymanweb['KIK'] = keymanweb.KIK = function(e) // Keyboard_IsKeypress - { - if(keymanweb._ActiveKeyboard['KM']) // I1380 - support KIK for positional layouts - return !e.LisVirtualKey; // will now return true for U_xxxx keys, but not for T_xxxx keys - else - return keymanweb._USKeyCodeToCharCode(e) ? true : false; // I1380 - support KIK for positional layouts - //if(e.charCode != 0) != null) - // return e.charCode != 0; - //return e.type == 'keypress'; - } - - /** - * Function KKM - * Scope Public - * @param {Object} e keystroke event - * @param {number} Lruleshift - * @param {number} Lrulekey - * @return {boolean} True if key matches rule - * Description Test keystroke with modifiers against rule - */ - keymanweb['KKM'] = keymanweb.KKM = function(e,Lruleshift,Lrulekey) // Keyboard_KeyMatch - { - var retVal = 0; // I3318 - var keyCode = (e.Lcode == 173 ? 189 : e.Lcode); //I3555 (Firefox hyphen issue) - - if(e.vkCode > 255) keyCode = e.vkCode; // added to support extended (touch-hold) keys for mnemonic layouts - - if(e.LisVirtualKey || keyCode > 255) // added keyCode test for same reason - { - if((Lruleshift & 0x4000) == 0x4000 || (keyCode > 255)) // added keyCode test to support extended keys - { - retVal = ((Lrulekey == keyCode) && ((Lruleshift&0x7F) == e.Lmodifiers)); //I3318, I3555 - } - } - else if((Lruleshift & 0x4000) == 0) - { - retVal = (keyCode == Lrulekey); // I3318, I3555 - } - if(!retVal) this._DeadkeyResetMatched(); // I3318 - return retVal; // I3318 - }; - - /** - * Function KKI - * Scope Public - * @param {number} n - * @param {Object} Ptarg - * @param {string} val - * @param {number} ln - * @return {Object} Object with event's virtual key flag, key code, and modifiers - * Description Get object with extended key event information - */ - keymanweb['KKI'] = keymanweb.KKI = function(e) - { - var ei = {}; - ei['vk'] = e.LisVirtualKey; ei['code'] = e.Lcode; ei['modifiers'] = e.Lmodifiers; - return ei; - }; - - /** - * Function KDM - * Scope Public - * @param {number} n current cursor position - * @param {Object} Ptarg target element - * @param {number} d deadkey - * @return {boolean} True if deadkey found selected context matches val - * Description Match deadkey at current cursor position - */ - keymanweb['KDM'] = keymanweb.KDM = function(n, Ptarg, d) - { - if(keymanweb._DeadKeys.length == 0) return false; // I3318 - - var sp=keymanweb._SelPos(Ptarg); - n = sp - n; - for(var i = 0; i < keymanweb._DeadKeys.length; i++) - if(keymanweb._DeadKeys[i].p == n && keymanweb._DeadKeys[i].d == d) { - keymanweb._DeadKeys[i].matched = 1; return 1; // I3318 - } - this._DeadkeyResetMatched(); // I3318 - - return false; - } - - /** - * Function KBR - * Scope Public - * Description Reset/terminate beep or flash (not currently used: Aug 2011) - */ - keymanweb['KBR'] = keymanweb.KBR = function() // KeyboardBeepReset - { - keymanweb.cachedContext.reset(); - - var Lbo; - keymanweb._BeepTimeout = 0; - for(Lbo=0;Lbo= 0; - } - - /** - * Function KO - * Scope Public - * @param {number} dn number of characters to overwrite - * @param {Object} Pelem element to output to - * @param {string} s string to output - * Description Keyboard output - */ - keymanweb['KO'] = keymanweb.KO = function(dn, Pelem, s) // Keyboard_Output() - { - keymanweb.cachedContext.reset(); - - // KeymanTouch for Android uses direct insertion of the character string - if('oninserttext' in keymanweb) - { - keymanweb['oninserttext'](dn,s); - } - - if(Pelem.body) var Ldoc=Pelem; else var Ldoc=Pelem.ownerDocument; // I1481 - integration with rich editors not working 100% - var Li, Ldv; - - if(Pelem.className.indexOf('keymanweb-input') >= 0) - { - var t=keymanweb.getTextBeforeCaret(Pelem); - if(dn > 0) t=t._kmwSubstr(0,t._kmwLength()-dn)+s; else t=t+s; - keymanweb.setTextBeforeCaret(Pelem,t); - return; - } - - if (keymanweb.legacy) - { - if(dn>0) - Pelem.value=Pelem.value._kmwSubstr(0,Pelem.value._kmwLength()-dn)+s; //I3319 - else - Pelem.value=Pelem.value+s; - } - else if (Ldoc && (Ldv=Ldoc.defaultView) && Ldv.getSelection && - (Ldoc.designMode.toLowerCase() == 'on' || Pelem.contentEditable == 'true' || Pelem.contentEditable == 'plaintext-only' || Pelem.contentEditable === '') - ) // I2457 - support contentEditable elements in mozilla, webkit - { - /* Editable iframe and contentEditable elements for mozilla */ - var _IsEditableIframe = Ldoc.designMode.toLowerCase() == 'on'; - if(_IsEditableIframe) var _CacheableCommands = keymanweb._CacheCommands(Ldoc); - - var Lsel = Ldv.getSelection(); - var LselectionStart = Lsel.focusNode.nodeValue ? Lsel.focusNode.substringData(0,Lsel.focusOffset)._kmwLength() : 0; // I3319 - - if(!Lsel.isCollapsed) Lsel.deleteFromDocument(); // I2134, I2192 - //KeymanWeb._Debug('KO: focusOffset='+Lsel.focusOffset+', dn='+dn+', s='+s+' focusNode.type='+Lsel.focusNode.nodeType+', focusNode.parentNode.tagName='+(Lsel.focusNode.parentNode?Lsel.focusNode.parentNode.tagName:'NULL') ); - - var Lrange = Lsel.getRangeAt(0); - if(dn > 0) { - Lrange.setStart(Lsel.focusNode, Lsel.focusOffset - Lsel.focusNode.nodeValue.substr(0,Lsel.focusOffset)._kmwSubstr(-dn).length); // I3319 - Lrange.deleteContents(); - } - - //KeymanWeb._Debug('KO: focusOffset='+Lsel.focusOffset+', dn='+dn+', s='+s+' focusNode.type='+Lsel.focusNode.nodeType+', focusNode.parentNode.tagName='+(Lsel.focusNode.parentNode?Lsel.focusNode.parentNode.tagName:'NULL') ); - - if(s._kmwLength() > 0) // I2132 - exception if s.length > 0, I3319 - { - if(Lsel.focusNode.nodeType == 3) - { - // I2134, I2192 - // Already in a text node - //KeymanWeb._Debug('KO: Already in a text node, adding "'+s+'": '+Lsel.focusOffset + '-> '+Lsel.toString()); - var LfocusOffset = Lsel.focusOffset; - //KeymanWeb._Debug('KO: node.text="'+Lsel.focusNode.data+'", node.length='+Lsel.focusNode.length); - Lsel.focusNode.insertData(Lsel.focusOffset, s); - try - { - Lsel.extend(Lsel.focusNode, LfocusOffset + s.length); - } - catch(e) - { - // Chrome (through 4.0 at least) throws an exception because it has not synchronised its content with the selection. scrollIntoView synchronises the content for selection - Lsel.focusNode.parentNode.scrollIntoView(); - Lsel.extend(Lsel.focusNode, LfocusOffset + s.length); - } - } - else - { - // Create a new text node - empty control - //KeymanWeb._Debug('KO: Creating a new text node for "'+s+'"'); - var n = Ldoc.createTextNode(s); - Lrange.insertNode(n); - Lsel.extend(n,s.length); - } - } - if(_IsEditableIframe) keymanweb._CacheCommandsReset(Ldoc, _CacheableCommands, null);// I2457 - support contentEditable elements in mozilla, webkit - - Lsel.collapseToEnd(); - - // Adjust deadkey positions - if(dn >= 0) - { - keymanweb._DeadkeyDeleteMatched(); // I3318 - keymanweb._DeadkeyAdjustPos(LselectionStart, -dn + s._kmwLength()); // I3318 - } - } - - // Internet Explorer (including IE9) - else if(Ldoc && (Ldv=Ldoc.selection)) // build 77 - use elem.ownerDocument.selection - { - if(Ldoc.body.isContentEditable || Ldoc.designMode.toLowerCase()=='on') // I1295 - isContentEditable - { - var _CacheableCommands = keymanweb._CacheCommands(Ldoc); - } - - var Lrange = Ldv.createRange(), Ls1; - if(Lrange.text != '') - { - Ldv.clear(); - dn = 0; - } - else Lrange.collapse(true); - - if(dn > 0) { - Lrange.moveStart('character',-2*dn); // I3319 (next four lines - var s0=Lrange.text,s1=s0._kmwSubstr(-dn); - Lrange.collapse(false); //move start back to end - Lrange.moveStart('character',-s1.length); - } - else dn = 0; - - Lrange.text = s; - - if(Ldoc.body.isContentEditable || Ldoc.designMode.toLowerCase()=='on') // I1295 - isContentEditable - { - Lrange.moveStart('character',-s.length); - - keymanweb._CacheCommandsReset(Ldoc, _CacheableCommands,Lrange.select); - Lrange.moveStart('character',s.length); - Lrange.select(); - } - // Adjust deadkey positions - if(dn >= 0) - { - keymanweb._DeadkeyDeleteMatched(); // I3318 - keymanweb._DeadkeyAdjustPos(LselectionStart, -dn + s._kmwLength()); // I3318 - } - - keymanweb._Selection = Ldv.createRange(); - keymanweb._Selection.select(); - keymanweb._Selection.scrollIntoView(); - } - - // Mozilla et al; IE9+ also recognizes setSelectionRange, but does not seem to work in exactly the same way as Mozilla - else if (Pelem.setSelectionRange) - { - var LselectionStart, LselectionEnd; - - if(Pelem._KeymanWebSelectionStart != null) // changed to allow a value of 0 - { - LselectionStart = Pelem._KeymanWebSelectionStart; - LselectionEnd = Pelem._KeymanWebSelectionEnd; - } - else - { - LselectionStart = Pelem.value._kmwCodeUnitToCodePoint(Pelem.selectionStart); // I3319 - LselectionEnd = Pelem.value._kmwCodeUnitToCodePoint(Pelem.selectionEnd); // I3319 - } - - var LscrollTop, LscrollLeft; - if(Pelem.type.toLowerCase() == 'textarea' && typeof(Pelem.scrollTop) != 'undefined') { - LscrollTop = Pelem.scrollTop; LscrollLeft = Pelem.scrollLeft; - } - - if(dn < 0) // Don't delete, leave context alone (dn = -1) - { - Pelem.value = Pelem.value._kmwSubstring(0,LselectionStart) + s + Pelem.value._kmwSubstring(LselectionEnd); //I3319 - dn = 0; - } - else if(LselectionStart < dn) - Pelem.value = s + Pelem.value._kmwSubstring(LselectionEnd); //I3319 - else - Pelem.value = Pelem.value._kmwSubstring(0,LselectionStart-dn) + s + Pelem.value._kmwSubstring(LselectionEnd); //I3319 - - // Adjust deadkey positions - if(dn >= 0) - { - keymanweb._DeadkeyDeleteMatched(); // I3318 - keymanweb._DeadkeyAdjustPos(LselectionStart, -dn + s._kmwLength()); // I3318,I3319 - } - - if (typeof(LscrollTop) != 'undefined') { - Pelem.scrollTop = LscrollTop; - Pelem.scrollLeft = LscrollLeft; - } - var caretPos=LselectionStart-dn+s._kmwLength(); // I3319 - var caretPosUnits=Pelem.value._kmwCodePointToCodeUnit(caretPos); // I3319 - - Pelem.setSelectionRange(caretPosUnits,caretPosUnits); // I3319 - Pelem._KeymanWebSelectionStart = null; Pelem._KeymanWebSelectionEnd = null; - } - - // Refresh element content after change (if needed) - if(typeof(keymanweb.refreshElementContent) == 'function') keymanweb.refreshElementContent(Pelem); - } - - /** - * Function KDO - * Scope Public - * @param {number} Pdn no of character to overwrite (delete) - * @param {Object} Pelem element to output to - * @param {number} Pd deadkey id - * Description Record a deadkey at current cursor position, deleting Pdn characters first - */ - keymanweb['KDO'] = keymanweb.KDO = function(Pdn,Pelem,Pd) - { - keymanweb.cachedContext.reset(); - var Lc = new Object(); - if(Pdn >= 0) keymanweb.KO(Pdn,Pelem,""); //I3318 corrected to >= - Lc.p=keymanweb._SelPos(Pelem); Lc.d=Pd; - keymanweb._DeadKeys=keymanweb._push(keymanweb._DeadKeys,Lc); - -// _DebugDeadKeys(Pelem, 'KDeadKeyOutput: dn='+Pdn+'; deadKey='+Pd); - } - - /** - * Function KIO - * Scope Public - * @param {number} Pdn no of character to overwrite (delete) - * @param {string} Ps string - * @param {numebr} Pn index - * @param {Object} Pelem element to output to - * Description Output a character selected from the string according to the offset in the index array - */ - keymanweb['KIO'] = keymanweb.KIO = function(Pdn,Ps,Pn,Pelem) - { - keymanweb.cachedContext.reset(); - if(keymanweb._AnyIndices[Pn-1] < Ps._kmwLength()) //I3319 - keymanweb.KO(Pdn,Pelem,Ps._kmwCharAt(keymanweb._AnyIndices[Pn-1])); //I3319 - } - -/** - * Function _CacheCommands - * Scope Private - * @param {Object} _Document - * @return {Array.} List of style commands that are cacheable - * Description Build reate list of styles that can be applied in iframes - */ - keymanweb._CacheCommands = function(_Document) // I1204 - style application in IFRAMEs, I2192, I2134, I2192 - { - //var _CacheableBackColor=(_Document.selection?'hilitecolor':'backcolor'); - var _CacheableCommands=[['backcolor',1],['fontname',1],['fontsize',1],['forecolor',1],['bold',0],['italic',0],['strikethrough',0],['subscript',0],['superscript',0],['underline',0]]; - if(_Document.defaultView) keymanweb._push(_CacheableCommands,['hilitecolor',1]); - - for(var n=0;n < _CacheableCommands.length; n++) // I1511 - array prototype extended - { - //KeymanWeb._Debug('Command:'+_CacheableCommands[n][0]); - keymanweb._push(_CacheableCommands[n],_CacheableCommands[n][1] ? _Document.queryCommandValue(_CacheableCommands[n][0]) : _Document.queryCommandState(_CacheableCommands[n][0])); - } - return _CacheableCommands; - } - - /** - * Function _CacheCommandReset - * Scope Private - * @param _Document - * _CacheableCommands - * _func - * @return Nothing - * Description Restore styles in IFRAMEs (??) - */ - keymanweb._CacheCommandsReset = function(_Document, _CacheableCommands, _func) - { - for(var n=0;n < _CacheableCommands.length; n++) // I1511 - array prototype extended - { - //KeymanWeb._Debug('ResetCacheCommand:'+_CacheableCommands[n][0]+'='+_CacheableCommands[n][2]); - if(_CacheableCommands[n][1]) - { - if(_Document.queryCommandValue(_CacheableCommands[n][0]) != _CacheableCommands[n][2]) - { - if(_func)_func(); - _Document.execCommand(_CacheableCommands[n][0], false, _CacheableCommands[n][2]); - } - } - else if(_Document.queryCommandState(_CacheableCommands[n][0]) != _CacheableCommands[n][2]) - {if(_func)_func(); - //KeymanWeb._Debug('executing command '+_CacheableCommand[n][0]); - _Document.execCommand(_CacheableCommands[n][0], false, null); - } - } - } - - /** - * KIFS compares the content of a system store with a string value - * - * @param {number} systemId ID of the system store to test (only TSS_LAYER currently supported) - * @param {string} strValue String value to compare to - * @param {Object} Pelem Currently active element (may be needed by future tests) - * @return {boolean} True if the test succeeds - */ - keymanweb['KIFS'] = keymanweb.KIFS = function(systemId,strValue,Pelem) - { - var result=true; - if(systemId == keymanweb.TSS_LAYER) - result = (osk.layerId === strValue); - else if(systemId == keymanweb.TSS_PLATFORM) - { - var i,constraint,constraints=strValue.split(' '); - for(i=0; i 1) - { - var n,x; - for(n=1;n 7) keymanweb._DivDebug.removeChild(keymanweb._DivDebug.childNodes[0]); - //The above line could be replaced by absolute position checking, but this way is a lot easier (and probably faster) - //and is fine if debug output is always a single line - - } - //Lelem.scrollIntoView(); //***temporarily disabled, JMD 23/12/11 - //keymanweb._DivDebug.innerHTML = keymanweb._DivDebug.innerHTML + '
'+keymanweb._DebugDepth+Ps; - //if(!document.selection) - // keymanweb._DivDebug.scrollTop = (keymanweb._DivDebug.scrollHeight - keymanweb._DivDebug.clientHeight<0 ? 0 : - // keymanweb._DivDebug.scrollHeight - keymanweb._DivDebug.clientHeight); - } - } - - _DebugEnter = function(f) - { - _Debug(f+' ENTER'); - keymanweb._DebugDepth = keymanweb._DebugDepth + '  '; - } - - _DebugExit = function(f) - { - keymanweb._DebugDepth = keymanweb._DebugDepth.slice(0,-12); - _Debug(f+' EXIT'); - } - - _DebugDeadKeys = function(Pelem, Ps) - { - var Lt = "", Li, Lp = 0, Ls, Lj; - if(document.selection) - { - // IE debug - for(Li = 0; Li < keymanweb._DeadKeys.length; Li++) - { - if(keymanweb._DeadKeys[Li].p > Lp) Lp = keymanweb._DeadKeys[Li].p; - } - Ls = keymanweb.KC(Lp+1, Lp+1, Pelem); Lt = ''; - if(Ls !== false && Ls._kmwLength() > Lp) //I3319 - { - /* We want to show the previous character in the context */ - Lt = Lt + Ls._kmwSubstr(0,1); Ls = Ls._kmwSlice(1); //I3319 - } - for(Li = 0; Li <= Ls._kmwLength(); Li++) //I3319 - { - for(Lj = 0; Lj < keymanweb._DeadKeys.length; Lj++) - { - if(keymanweb._DeadKeys[Lj].p == Ls._kmwLength() - Li) Lt = Lt + ''+keymanweb._DeadKeys[Lj].d+''; //I3319 - } - if(Li < Ls._kmwLength()) Lt = Lt + Ls._kmwCharAt(Li); //I3319 - } - - Lt = Lt + ' - '; - for(Li = 0; Li < keymanweb._DeadKeys.length; Li++) - { - Lt = Lt + 'dk['+Li+'] = {pos: '+keymanweb._DeadKeys[Li].p+', deadKey: '+keymanweb._DeadKeys[Li].d+'} '; - } - - _Debug(Ps + ': ' + Lt); - } - else - { - if(!keymanweb._IE) return true; //added test to avoid compiler warning 27/8 JMD - - // Mozilla debug (table formatting removed) - if(Pelem.tagName == 'HTML') Ls = Pelem.innerHTML; else Ls = Pelem.value; Lt = ''; //span style="font-size: 12pt">'; - if(typeof(Ls) === 'undefined') return; - for(Li = 0; Li <= Ls._kmwLength(); Li++) Lt += "<"+Ls._kmwCharAt(Li)+">"; //I3319 - for(Li = 0; Li <= Ls._kmwLength(); Li++) //I3319 - { - for(var Lj = 0; Lj < keymanweb._DeadKeys.length; Lj++) - { - Lt = Lt + '['+keymanweb._DeadKeys[Lj].p+':'+keymanweb._DeadKeys[Lj].d+']'; - } - if(Li < Ls._kmwLength()) Lt = Lt + Ls._kmwCharAt(Li); - } - - //_Debug(Ps + ': ' + Lt); - //Lt = Lt + keymanweb._DebugDepth + '   dk['+Li+'] = {pos: '+keymanweb._DeadKeys[Li].p+', deadKey: '+keymanweb._DeadKeys[Li].d+'}
'; - } - -/* - var Lt = "", Li, Lp = 0; - for(Li = 0; Li < keymanweb._DeadKeys.length; Li++) - { - if(keymanweb._DeadKeys[Li].p > Lp) Lp = keymanweb._DeadKeys[Li].p; - } - - var Ls = keymanweb.KC(Lp, Lp, Pelem); - Lt = keymanweb._DebugDepth + '   Context='+Ls+'
'; - - for(Li = 0; Li < keymanweb._DeadKeys.length; Li++) - { - Lt = Lt + keymanweb._DebugDepth + '   dk['+Li+'] = {pos: '+keymanweb._DeadKeys[Li].p+', deadKey: '+keymanweb._DeadKeys[Li].d+'}
'; - } - _Debug(Ps + '
'+Lt); -*/ - } -})(); - -window['_Debug'] = _Debug; -window['_DebugEnter'] = _DebugEnter; -window['_DebugExit'] = _DebugExit; -window['_DebugDeadKeys'] = _DebugDeadKeys; - -/*----------------------------------------------------------------------------------------------------*/ -/*__ENDDEBUG__*/ diff --git a/events/iuc38/Lao Roman/kmw/kmwdebugstub.js b/events/iuc38/Lao Roman/kmw/kmwdebugstub.js deleted file mode 100644 index dc02587c..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwdebugstub.js +++ /dev/null @@ -1,28 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ -/** - * Debug calls external references - */ - - function _Debug(t){}; - - function _DebugEnter(t){}; - - function _DebugExit(t){}; - - function _DebugDeadKeys(t,u){}; - diff --git a/events/iuc38/Lao Roman/kmw/kmwinit.js b/events/iuc38/Lao Roman/kmw/kmwinit.js deleted file mode 100644 index 365291d3..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwinit.js +++ /dev/null @@ -1,44 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/********************************************************/ -/* */ -/* Automatically initialize keymanweb with defaults */ -/* after the page is fully loaded */ -/* */ -/********************************************************/ - -(function() -{ - // Declare KeymanWeb object - var keymanweb=window['tavultesoft']['keymanweb']; - - if(document.readyState === 'complete') - { - keymanweb.init(null); - } - else - { - var readyStateCheckInterval = window.setInterval(function() { - if (document.readyState === "complete") - { - window.clearInterval(readyStateCheckInterval); - keymanweb.init(null); - } - }, 10); - } -})(); diff --git a/events/iuc38/Lao Roman/kmw/kmwkeymaps.js b/events/iuc38/Lao Roman/kmw/kmwkeymaps.js deleted file mode 100644 index 9188720a..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwkeymaps.js +++ /dev/null @@ -1,172 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/** - * Cross-browser compatibility keymaps - */ -(function() -{ - // Declare KeymanWeb object - var keymanweb=window['tavultesoft']['keymanweb']; - - /* I732 START - 13/03/2007 MCD: Swedish: Start mapping of keystroke to US keyboard #2 */ - var ffie = keymanweb._VKMap_FF_IE = {}; - - //ffie['k109'] = 189; // - // These two number-pad VK rules are *not* correct for more recent FF! JMD 8/11/12 - //ffie['k107'] = 187; // = // FF 3.0 // I2062 - ffie['k61'] = 187; // = // FF 2.0 - ffie['k59'] = 186; // ; - - keymanweb._VKMap_Opera_IE = {}; - - keymanweb._VKMap_Safari_IE = {}; - - // Swedish key map - var kmap = keymanweb._VKMap = {}; - - kmap['se'] = {}; - kmap['se']['k220'] = 192; // ` - kmap['se']['k187'] = 189; // - - kmap['se']['k219'] = 187; // = - kmap['se']['k221'] = 219; // [ - kmap['se']['k186'] = 221; // ] - kmap['se']['k191'] = 220; // \ - kmap['se']['k192'] = 186; // ; - kmap['se']['k189'] = 191; // / - - kmap['uk'] = {}; // I1299 - kmap['uk']['k223'] = 192; // // ` U+00AC (logical not) => ` ~ - kmap['uk']['k192'] = 222; // ' @ => ' " - kmap['uk']['k222'] = 226; // # ~ => K_oE2 // I1504 - UK keyboard mixup #, \ - kmap['uk']['k220'] = 220; // \ | => \ | // I1504 - UK keyboard mixup #, \ - - /* I732 END - 13/03/2007 MCD: Swedish: mapping of keystroke to US keyboard #2 */ - - /* 13/03/2007 MCD: Swedish: Legacy keyboards - map US Key Code to Character Code */ - var s0={},s1={}; - - s0['k192'] = 96; - s0['k49'] = 49; - s0['k50'] = 50; - s0['k51'] = 51; - s0['k52'] = 52; - s0['k53'] = 53; - s0['k54'] = 54; - s0['k55'] = 55; - s0['k56'] = 56; - s0['k57'] = 57; - s0['k48'] = 48; - s0['k189'] = 45; - s0['k187'] = 61; - s0['k81'] = 113; - s0['k87'] = 119; - s0['k69'] = 101; - s0['k82'] = 114; - s0['k84'] = 116; - s0['k89'] = 121; - s0['k85'] = 117; - s0['k73'] = 105; - s0['k79'] = 111; - s0['k80'] = 112; - s0['k219'] = 91; - s0['k221'] = 93; - s0['k220'] = 92; - s0['k65'] = 97; - s0['k83'] = 115; - s0['k68'] = 100; - s0['k70'] = 102; - s0['k71'] = 103; - s0['k72'] = 104; - s0['k74'] = 106; - s0['k75'] = 107; - s0['k76'] = 108; - s0['k186'] = 59; - s0['k222'] = 39; - s0['k90'] = 122; - s0['k88'] = 120; - s0['k67'] = 99; - s0['k86'] = 118; - s0['k66'] = 98; - s0['k78'] = 110; - s0['k77'] = 109; - s0['k188'] = 44; - s0['k190'] = 46; - s0['k191'] = 47; - - s1['k192'] = 126; - s1['k49'] = 33; - s1['k50'] = 64; - s1['k51'] = 35; - s1['k52'] = 36; - s1['k53'] = 37; - s1['k54'] = 94; - s1['k55'] = 38; - s1['k56'] = 42; - s1['k57'] = 40; - s1['k48'] = 41; - s1['k189'] = 95; - s1['k187'] = 43; - s1['k81'] = 81; - s1['k87'] = 87; - s1['k69'] = 69; - s1['k82'] = 82; - s1['k84'] = 84; - s1['k89'] = 89; - s1['k85'] = 85; - s1['k73'] = 73; - s1['k79'] = 79; - s1['k80'] = 80; - s1['k219'] = 123; - s1['k221'] = 125; - s1['k220'] = 124; - s1['k65'] = 65; - s1['k83'] = 83; - s1['k68'] = 68; - s1['k70'] = 70; - s1['k71'] = 71; - s1['k72'] = 72; - s1['k74'] = 74; - s1['k75'] = 75; - s1['k76'] = 76; - s1['k186'] = 58; - s1['k222'] = 34; - s1['k90'] = 90; - s1['k88'] = 88; - s1['k67'] = 67; - s1['k86'] = 86; - s1['k66'] = 66; - s1['k78'] = 78; - s1['k77'] = 77; - s1['k188'] = 60; - s1['k190'] = 62; - s1['k191'] = 63; - - keymanweb._USCharCode = [s0,s1]; - - /** - * Function _USKeyCodeToCharCode - * Scope Private - * @param {Event} Levent KMW event object - * @return {number} Character code - * Description Translate keyboard codes to standard US layout codes - */ - keymanweb._USKeyCodeToCharCode = function(Levent) - { - return keymanweb._USCharCode[Levent.Lmodifiers & 0x10 ? 1 : 0]['k'+Levent.Lcode]; - }; - -})(); diff --git a/events/iuc38/Lao Roman/kmw/kmwlayout.js b/events/iuc38/Lao Roman/kmw/kmwlayout.js deleted file mode 100644 index 6af263f3..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwlayout.js +++ /dev/null @@ -1,307 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -window['dfltLayout'] = { - "desktop": - { - "font":"Tahoma,Helvetica", - "layer":[ - { - "id":"default", - "row":[ - { - "id":"1", - "key":[ - {"id":"K_BKQUOTE"}, - {"id":"K_1"}, - {"id":"K_2"}, - {"id":"K_3"}, - {"id":"K_4"}, - {"id":"K_5"}, - {"id":"K_6"}, - {"id":"K_7"}, - {"id":"K_8"}, - {"id":"K_9"}, - {"id":"K_0"}, - {"id":"K_HYPHEN"}, - {"id":"K_EQUAL"}, - {"id":"K_BKSP","text":"*BkSp*","sp":"1","width":"130"} - ] - }, - { - "id":"2", - "key":[ - {"id":"K_TAB","text":"*Tab*","sp":"1","width":"130"}, - {"id":"K_Q"}, - {"id":"K_W"}, - {"id":"K_E"}, - {"id":"K_R"}, - {"id":"K_T"}, - {"id":"K_Y"}, - {"id":"K_U"}, - {"id":"K_I"}, - {"id":"K_O"}, - {"id":"K_P"}, - {"id":"K_LBRKT"}, - {"id":"K_RBRKT"}, - {"id":"K_BKSLASH"} - ] - }, - { - "id":"3", - "key":[ - {"id":"K_CAPS","text":"*Caps*","sp":"1","width":"165"}, - {"id":"K_A"}, - {"id":"K_S"}, - {"id":"K_D"}, - {"id":"K_F"}, - {"id":"K_G"}, - {"id":"K_H"}, - {"id":"K_J"}, - {"id":"K_K"}, - {"id":"K_L"}, - {"id":"K_COLON"}, - {"id":"K_QUOTE"}, - {"id":"K_ENTER","text":"*Enter*","sp":"1","width":"165"} - ] - }, - { - "id":"4", - "key":[ - {"id":"K_SHIFT","text":"*Shift*","sp":"1","width":"130"}, - {"id":"K_oE2"}, - {"id":"K_Z"}, - {"id":"K_X"}, - {"id":"K_C"}, - {"id":"K_V"}, - {"id":"K_B"}, - {"id":"K_N"}, - {"id":"K_M"}, - {"id":"K_COMMA"}, - {"id":"K_PERIOD"}, - {"id":"K_SLASH"}, - {"id":"K_RSHIFT","text":"*Shift*","sp":"1","width":"130"} - ] - }, - { - "id":"5", - "key":[ - {"id":"K_LCONTROL","text":"*Ctrl*","sp":"1","width":"170"}, - {"id":"K_LALT","text":"*Alt*","sp":"1","width":"160"}, - {"id":"K_SPACE","text":"","width":"770"}, - {"id":"K_ALT","text":"*Alt*","sp":"1","width":"160"}, - {"id":"K_RCONTROL","text":"*Ctrl*","sp":"1","width":"170"} - ] - } - ] - } - ] - }, - "tablet": - { - "font":"Tahoma,Helvetica", - "layer":[ - { - "id":"default", - "row":[ - { - "id":"0", - "key":[ - {"id":"K_1"}, - {"id":"K_2"}, - {"id":"K_3"}, - {"id":"K_4"}, - {"id":"K_5"}, - {"id":"K_6"}, - {"id":"K_7"}, - {"id":"K_8"}, - {"id":"K_9"}, - {"id":"K_0"}, - {"id":"K_HYPHEN"}, - {"id":"K_EQUAL"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"1", - "key":[ - {"id":"K_Q","pad":"25"}, - {"id":"K_W"}, - {"id":"K_E"}, - {"id":"K_R"}, - {"id":"K_T"}, - {"id":"K_Y"}, - {"id":"K_U"}, - {"id":"K_I"}, - {"id":"K_O"}, - {"id":"K_P"}, - {"id":"K_LBRKT"}, - {"id":"K_RBRKT"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"2", - "key":[ - {"id":"K_A","pad":"50"}, - {"id":"K_S"}, - {"id":"K_D"}, - {"id":"K_F"}, - {"id":"K_G"}, - {"id":"K_H"}, - {"id":"K_J"}, - {"id":"K_K"}, - {"id":"K_L"}, - {"id":"K_COLON"}, - {"id":"K_QUOTE"}, - {"id":"K_BKSLASH","width":"90"} - ] - }, - { - "id":"3", - "key":[ - {"id":"K_oE2","width":"90"}, - {"id":"K_Z"}, - {"id":"K_X"}, - {"id":"K_C"}, - {"id":"K_V"}, - {"id":"K_B"}, - {"id":"K_N"}, - {"id":"K_M"}, - {"id":"K_COMMA"}, - {"id":"K_PERIOD"}, - {"id":"K_SLASH"}, - {"id":"K_BKQUOTE"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"4", - "key":[ - {"id":"K_SHIFT","text":"*Shift*","sp":"1","width":"200","sk":[ - {"id":"K_LCONTROL","text":"*Ctrl*","sp":"1","width":"50","nextlayer":"ctrl"}, - {"id":"K_LALT","text":"*Alt*","sp":"1","width":"50","nextlayer":"alt"}, - {"id":"K_ALTGR","text":"*AltGr*","sp":"1","width":"50","nextlayer":"ctrlalt"}] - }, - {"id":"K_LOPT","text":"*Menu*","sp":"1","width":"150"}, - {"id":"K_SPACE","text":"","width":"570"}, - {"id":"K_BKSP","text":"*BkSp*","sp":"1","width":"150"}, - {"id":"K_ENTER","text":"*Enter*","sp":"1","width":"200"} - ] - } - ] - } - ] - }, - "phone": - { - "font":"Tahoma,Helvetica", - "layer":[ - { - "id":"default", - "row":[ - { - "id":"0", - "key":[ - {"id":"K_1"}, - {"id":"K_2"}, - {"id":"K_3"}, - {"id":"K_4"}, - {"id":"K_5"}, - {"id":"K_6"}, - {"id":"K_7"}, - {"id":"K_8"}, - {"id":"K_9"}, - {"id":"K_0"}, - {"id":"K_HYPHEN"}, - {"id":"K_EQUAL"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"1", - "key":[ - {"id":"K_Q","pad":"25"}, - {"id":"K_W"}, - {"id":"K_E"}, - {"id":"K_R"}, - {"id":"K_T"}, - {"id":"K_Y"}, - {"id":"K_U"}, - {"id":"K_I"}, - {"id":"K_O"}, - {"id":"K_P"}, - {"id":"K_LBRKT"}, - {"id":"K_RBRKT"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"2", - "key":[ - {"id":"K_A","pad":"50"}, - {"id":"K_S"}, - {"id":"K_D"}, - {"id":"K_F"}, - {"id":"K_G"}, - {"id":"K_H"}, - {"id":"K_J"}, - {"id":"K_K"}, - {"id":"K_L"}, - {"id":"K_COLON"}, - {"id":"K_QUOTE"}, - {"id":"K_BKSLASH","width":"90"} - ] - }, - { - "id":"3", - "key":[ - {"id":"K_oE2","width":"90"}, - {"id":"K_Z"}, - {"id":"K_X"}, - {"id":"K_C"}, - {"id":"K_V"}, - {"id":"K_B"}, - {"id":"K_N"}, - {"id":"K_M"}, - {"id":"K_COMMA"}, - {"id":"K_PERIOD"}, - {"id":"K_SLASH"}, - {"id":"K_BKQUOTE"}, - {"sp":"10","width":"1"} - ] - }, - { - "id":"4", - "key":[ - {"id":"K_SHIFT","text":"*Shift*","sp":"1","width":"200","sk":[ - {"id":"K_LCONTROL","text":"*Ctrl*","sp":"1","width":"50","nextlayer":"ctrl"}, - {"id":"K_LALT","text":"*Alt*","sp":"1","width":"50","nextlayer":"alt"}, - {"id":"K_ALTGR","text":"*AltGr*","sp":"1","width":"50","nextlayer":"ctrlalt"}] - }, - {"id":"K_LOPT","text":"*Menu*","width":"150","sp":"1"}, - {"id":"K_SPACE","width":"570","text":""}, - {"id":"K_BKSP","text":"*BkSp*","width":"150","sp":"1"}, - {"id":"K_ENTER","text":"*Enter*","width":"200","sp":"1"} - ] - } - ] - } - ] - } - }; - diff --git a/events/iuc38/Lao Roman/kmw/kmwlegacy.js b/events/iuc38/Lao Roman/kmw/kmwlegacy.js deleted file mode 100644 index 5cd85827..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwlegacy.js +++ /dev/null @@ -1,877 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/** - * Declare KeymanWeb variable as the tavultesoft.keymanweb.legacy object - */ -var KeymanWeb = tavultesoft['keymanweb']['legacy'] = {}; - -window['KeymanWeb'] = KeymanWeb; - -KeymanWeb['build'] = __BUILD__; -KeymanWeb['version'] = '1.0'; -KeymanWeb['HelpURL'] = tavultesoft['keymanweb']['helpURL']; - -// Declare external legacy function names as calls to internal functions -(function(keymanweb) -{ - // Declare keymanweb osk, legacy and util objects - var osk=keymanweb['osk'],legacy=keymanweb['legacy'],util=keymanweb['util']; - - if(typeof(window['KeymanWeb_onkeyboardinstalled']) != 'undefined') - keymanweb['addEventListener']('keyboardregistered',window['KeymanWeb_onkeyboardinstalled']); - - if(typeof(window['KeymanWeb_onkeyboardloaded']) != 'undefined') - keymanweb['addEventListener']('keyboardloaded',window['KeymanWeb_onkeyboardloaded']); - - if(typeof(window['KeymanWeb_onkeyboardchange']) != 'undefined') - keymanweb['addEventListener']('keyboardchange',window['KeymanWeb_onkeyboardchange']); - - /** - * Function AttachToControl - * Scope Public - * Parameters Pelem Element to which KMW will be attached - * Returns None - * Description Attaches KMW to control (or IFrame) - */ - legacy['AttachToControl'] = function(Pelem) - { - keymanweb.AttachToControl(Pelem); - } - - /** - * Function IsHelpVisible - * Scope Public - * Parameters None - * Returns True if KMW Help displayed - * Description Test if KMW Help is visible - */ - legacy['IsHelpVisible'] = function() - { - return osk._Visible; - } - - /** - * Function GetEnabled - * Scope Public - * Parameters None - * Returns True if KMW enabled - * Description Test if KMW enabled - */ - legacy['GetEnabled'] = function() - { - return keymanweb._Enabled; - } - - /** - * Function SetEnabled - * Scope Public - * Parameters Pvalue True to enable KMW - * Returns Nothing - * Description Enable or disable KMW - */ - legacy['SetEnabled'] = function(Pvalue) - { - keymanweb.SetEnabled(Pvalue); - } - - /** - * Function ShowHelpAuto - * Scope Public - * Parameters None - * Returns None - * Description Automatically position KMW Help relative to element - */ - legacy['ShowHelpAuto'] = function() - { - osk._UserLocated=false; - osk._Show(); - } - - /** - * Function ShowPinnedHelp - * Scope Public - * Parameters None - * Returns None - * Description Fix position of KMW Help at current position - */ - legacy['ShowPinnedHelp'] = function() - { - osk._UserLocated=true; - osk._Show(-1,-1); - } - - /** - * Function DisableControl - * Scope Public - * Parameters Pelem Element to be disabled - * Returns None - * Description Disable KMW control element - */ - legacy['DisableControl'] = function(Pelem) - { - keymanweb.DisableControl(Pelem); - } - - /** - * Function EnableControl - * Scope Public - * Parameters Pelem Element to be enabled - * Returns None - * Description Enable KMW control element - */ - legacy['EnableControl'] = function(Pelem) - { - keymanweb.EnableControl(Pelem); - } - - /** - * Function SetDefaultKeyboardForControl - * Scope Public - * Parameters Pelem Control element - * Pkbd Keyboard - * Returns None - * Description Set default keyboard for control - */ - legacy['SetDefaultKeyboardForControl'] = function(Pelem,Pkbd) - { - keymanweb.SetDefaultKeyboardForControl(Pelem,Pkbd); - } - - /** - * Function GetHelpPos - * Scope Public - * Parameters None - * Returns Array with Help window position and size - * Description Get position and size of Help window - */ - legacy['GetHelpPos'] = function() - { - return osk['GetPos'](); - } - - /** - * Function SetHelpPos - * Scope Public - * Parameters Px x-coordinate for Help rectangle - * Py y-coordinate for Help rectangle - * Returns None - * Description Set position of Help window - */ - legacy['SetHelpPos'] = function(Px,Py) - { - osk['SetPos'](Px,Py); - } - - /** - * Function SetHelpSize - * Scope Public - * Parameters Pw width of Help window - * Returns None - * Description Set width of Help window - */ - legacy['SetHelpSize'] = function(Pw) - { - osk['SetSize'](Pw); - } - - /** - * Function HelpBox (temporary) - * Scope Private - * Parameters None - * Returns OnScreen Keyboard container DIV element - * Description Lets UI get or set OSK properties - */ - legacy['HelpBox'] = function() - { - return osk._Box; - } - - /** - * Function FocusLastActiveElement - * Scope Public - * Parameters None - * Returns None - * Description Set focus to last active target element - */ - legacy['FocusLastActiveElement'] = function() - { - keymanweb._FocusLastActiveElement(); - } - - /** - * Function GetLastActiveElement - * Scope Public - * Parameters None - * Returns Last active element - * Description Return the last target element active (before KMW activated) - */ - legacy['GetLastActiveElement'] = function() - { - return keymanweb._LastActiveElement; - } - - /** - * Function SetLastActiveElement - * Scope Public - * Parameters e Element - * Returns None - * Description Redefines (or clears) the last active target element - */ - legacy['SetLastActiveElement'] = function(e) - { - keymanweb._LastActiveElement = e; - } - - /** - * Function SetActiveKeyboard - * Scope Public - * Parameters PInternalName - * Returns Nothing - * Description Change active keyboard by (internal) keyboard name - */ - legacy['SetActiveKeyboard'] = function(PInternalName) - { - keymanweb['SetActiveKeyboard'](PInternalName); - } - - /** - * Function GetActiveKeyboard - * Scope Public - * Parameters None - * Returns Name of active keyboard - * Description Return internal name of currently active keyboard - */ - legacy['GetActiveKeyboard'] = function() - { - return keymanweb['GetActiveKeyboard'](); - } - - /** - * Function GetKeyboardDetail - * Scope Public - * Parameters PInternalName Internal name of keyboard - * Returns Details of named keyboard - * Description Return keyboard details - */ - legacy['GetKeyboardDetail'] = function(PInternalName) - { - return keymanweb.GetKeyboardDetail(PInternalName); - } - - /** - * Function GetKeyboards - * Scope Public - * Parameters None - * Returns Array of installed keyboard object details - * Description Return array of installed keyboard details - */ - legacy['GetKeyboards'] = function() - { - return keymanweb['GetKeyboards'](); - } - - /** - * Function HelpIsPinned - * Scope Public - * Parameters none - * Returns true if pinned - * Description Test if Help window is pinned - */ - legacy['HelpIsPinned'] = function() - { - return osk._UserLocated; - } - - /** - * Function Init - * Scope Public - * Parameters None - * Returns Nothing - * Description Initialize KMW window - */ - legacy['Init'] = function() - { - var opt={}; - // Legacy variable initialization - if(typeof(window['KeymanWeb_Root']) == 'undefined') - opt['root']=window['KeymanWeb_Root']; - if(typeof(window['KeymanWeb_AttachType']) == 'undefined') - opt['attachType']=window['KeymanWeb_AttachType']; - if(typeof(window['KeymanWeb_ControlDownColor']) == 'undefined') - opt['controlDownColor']=window['KeymanWeb_ControlDownColor']; - if(typeof(window['KeymanWeb_KeyDownColor']) == 'undefined') - opt['keyDownColor']=window['KeymanWeb_KeyDownColor']; - if(typeof(window['KeymanWeb_KeyHoverColor']) == 'undefined') - opt['keyHoverColor']=window['KeymanWeb_KeyHoverColor']; - if(typeof(window['KeymanWeb_DefaultKeyboardName']) == 'undefined') - opt['defaultKeyboardName']=window['KeymanWeb_DefaultKeyboardName']; - if(typeof(window['KeymanWeb_DefaultKeyboardHelp']) == 'undefined') - opt['defaultKeyboardHelp']=window['KeymanWeb_DefaultKeyboardHelp']; - - keymanweb['init'](opt); - } - - /** - * Function GetAbsoluteX - * Scope Public - * Parameters Pobj - * Returns Absolute x-coordinate (needed for iFrames). - * Description Get absolute x-coordinate of Pobj element - */ - legacy['GetAbsoluteX'] = function(Pobj) - { - return util._GetAbsoluteX(Pobj); - } - -/** - * Function GetAbsoluteY - * Scope Public - * Parameters Pobj - * Returns Absolute y-coordinate (needed for iFrames). - * Description Get absolute y-coordinate of Pobj element - */ - legacy['GetAbsoluteY'] = function(Pobj) - { - return util._GetAbsoluteY(Pobj); - } - - /** - * Function AddStyleSheet - * Scope Public - * Parameters s UI stylesheet - * Returns Nothing - * Description Add style to KMW UI - */ - legacy['AddStyleSheet'] = function(s) - { - util['AddStyleSheet'](s); - } - - /** - * Visual Keyboard Legacy Functions - */ - - /** - * Function Help - * Scope Public - * Parameters None - * Returns None - * Description Show or hide KMW Help window below the KMW window - * (Should never be used except by old floating UI) - * No longer called by float UI. Cleaned up and kept here, - * but will almost certainly never be needed any more. - */ - legacy['Help'] = function() - { - if(osk._Visible) osk._Hide(true); else osk._Show(); - keymanweb['FocusLastActiveElement'](); - } - - /** - * Function GetHelpRect - * Scope Public - * Parameters None - * Returns Rectangle containing KMW Virtual Keyboard - * Description Get rectangle containing KMW Virtual Keyboard - */ - legacy['GetHelpRect'] = function() - { - return osk['GetRectOSK'](); - } - - /** - * Function BuildVisualKeyboard - * Scope Public - * Parameters PInternalName Keyboard name - * PStatic true if OSK to be unselectable - * Returns Modified (html-safe) string - * Description Encode angle brackets and ampersand in text string - */ - legacy['BuildVisualKeyboard'] = function(PInternalName, PStatic) - { - return osk.BuildVisualKeyboard(PInternalName,PStatic); - } - - /** - * Function ShowHelp - * Scope Public - * Parameters Px x-coordinate for Help rectangle - * Py y-coordinate for Help rectangle - * Returns None - * Description Display KMW Help (OSK) at specified position - */ - legacy['ShowHelp'] = function(Px, Py) - { - osk._Show(Px, Py); - } - - /** - * Function HideHelp - * Scope Public - * Parameters None - * Returns None - * Description Hide KMW Help window - */ - legacy['HideHelp'] = function() - { - // Must assert 'hiddenByUser' to ensure correct behaviour with CJK keyboard OSKs - osk._Hide(true); - } - - /** - * Function CreateShim - * Scope Public - * Parameters None - * Returns iFrame element - * Description Create an element to go between KMW and drop down (to fix IE6 bug) - */ - legacy['CreateShim'] = function() - { - return util['CreateShim'](); - } - - /** - * Function ShowShim - * Scope Public - * Parameters Pvkbd Visual keyboard DIV element - * Pframe iframe for Visual Keyboard - * Phelp OSK Help DIV element - * Returns None - * Description Display iFrame under OSK at its currently defined position, to allow OSK to overlap SELECT elements (IE6 fix) - */ - legacy['ShowShim'] = function(Pvkbd,Pframe,Phelp) - { - util['ShowShim'](Pvkbd,Pframe,Phelp); - } - - - /** - * Function HideShim - * Scope Public - * Parameters Pframe iframe for Visual Keyboard - * Returns None - * Description Hide iFrame containing OSK - */ - legacy['HideShim'] = function(Pframe) - { - util['HideShim'](Pframe) - } - - /** - * Function OSKShim - * Scope Public - * Parameters None - * Returns Container DIV for OSK shim - * Description Lets user interface get or set properties of OSK shim element - */ - legacy['OSKShim'] = function() - { - return osk._Shim; - } - - /** - * Function KSF - * Scope Public - * Parameters None - * Returns Nothing - * Description Save keyboard focus - */ - legacy['KSF'] = function() // KeyboardSaveFocus - { - keymanweb.KSF(); - } - - /** - * Function KT - * Scope Public - * Parameters Ptext Text to insert - * PdeadKey Dead key value, if any (???) - * Returns true if inserted - * Description Insert text into active control - */ - legacy['KT'] = function(Ptext,PdeadKey) // KeyboardInsertText - { - return keymanweb.KT(Ptext,PdeadKey); - } - - /** - * Function KR - * Scope Public - * Parameters Pk Keyboard - * Returns Nothing - * Description Register keyboard - */ - legacy['KR'] = function(Pk) - { - return keymanweb.KR(Pk); - } - - /** - * Function KRS - * Scope Public - * Parameters Pstub Keyboard stub - * Returns 1 if already loaded, else null - * Description Insert text into active control - */ - legacy['KRS'] = function(Pstub) /* KeyboardRegisterStub */ - { - return keymanweb.KRS(Pstub); - } - - /** - * Function KC - * Scope Public - * Parameters n Number of characters to move back from caret - * ln Number of characters to return - * Pelem Element to work with (must be currently focused element) - * Returns String of characters being the context of that range - * Description Return keyboard context context for a specified range, relative to caret - * - * Example [abcdef|ghi] as INPUT, with the caret position marked by |: - * KC(2,1,Pelem) == "e" - * KC(3,3,Pelem) == "def" - * KC(10,10,Pelem) == "abcdef" - */ - - legacy['KC'] = function(n, ln, Pelem) /* KeyboardContext */ - { - return keymanweb.KC(n,ln,Pelem); - } - - /** - * Function KN - * Scope Public - * Parameters n Length of context to check - * Pelem Element to work with (must be currently focused element) - * Returns TRUE if length of context is less than or equal to n - * Description Returns TRUE if the length of the context is less than or equal to n - * - * Example [abc|def] as INPUT, with the caret position marked by |: - * KN(3,Pelem) == TRUE - * KN(2,Pelem) == FALSE - * KN(4,Pelem) == TRUE - */ - legacy['KN'] = function(n, Ptarg) // KeyboardNul - { - return keymanweb.KN(n,Ptarg); - } - - /** - * Function KCM - * Scope Public - * Parameters n - * Ptarg - * val - * ln - * Returns TRUE if selected context matches val - * Description Test keyboard context for match - */ - legacy['KCM'] = function(n, Ptarg, val, ln) // Keyboard_ContextMatch - { - return keymanweb.KCM(n,Ptarg,val,ln); - } - - /** - * Function KIK - * Scope Public - * Parameters e - * Returns TRUE if keypress event - * Description Test if event as a keypress event - */ - legacy['KIK'] = function(e) // Keyboard_IsKeypress - { - return keymanweb.KIK(e); - } - - /** - * Function KKM - * Scope Public - * Parameters e keystroke event - * Lruleshift - * Lrulekey - * Returns TRUE if key matches rule - * Description Test keystroke with modifiers against rule - */ - legacy['KKM'] = function(e,Lruleshift,Lrulekey) // Keyboard_KeyMatch - { - return keymanweb.KKM(e,Lruleshift,Lrulekey); - } - - /** - * Function KKI - * Scope Public - * Parameters n - * Ptarg - * val - * ln - * Returns Object with event's virtual key flag, key code, and modifiers - * Description Extended key event information - */ - legacy['KKI'] = function(e) - { - return keymanweb.KKI(e); - } - - /** - * Function KIF - * Scope Public - * Parameters store1 String content of store 1 to compare - * store2 String content of store 2 to compare to - * mode 1 = compare inequality; 2 = compare equality - * Pelem Currently active element - * Returns True if the test succeeds - * Description KIF compares the values of two stores, with binary equality. - */ - legacy['KIF'] = function(store1,store2,mode,Pelem) - { - return keymanweb.KIF(store1,store2,mode,Pelem); - } - - /** - * Function KDM - * Scope Public - * Parameters n current cursor position - * Ptarg target element - * d deadkey - * Returns TRUE if deadkey found selected context matches val - * Description Match deadkey at current cursor position - */ - legacy['KDM'] = function(n, Ptarg, d) - { - return keymanweb.KDM(n,Ptarg,d); - } - - /** - * Function KBR - * Scope Public - * Parameters None - * Returns Nothing - * Description Reset/terminate beep or flash - */ - legacy['KBR'] = function() // KeyboardBeepReset - { - keymanweb.KBR(); - } - - /** - * Function KB - * Scope Public - * Parameters Pelem element to flash - * Returns Nothing - * Description Flash body as substitute for audible beep - */ - legacy['KB'] = function(Pelem) // Keyboard_Beep() - { - keymanweb.KB(Pelem); - } - - /** - * Function KA - * Scope Public - * Parameters n character position (index) - * ch character to find in string - * s 'any' string - * Returns True if character found in 'any' string, sets index accordingly - * Description Test for character matching - */ - legacy['KA'] = function(n,ch,s) // Keyboard_Any() - { - return keymanweb.KA(n,ch,s); - } - - /** - * Function KO - * Scope Public - * Parameters dn number of characters to overwrite - * Pelem element to output to - * s string to output - * Returns Nothing - * Description Keyboard output - */ - legacy['KO'] = function(dn, Pelem, s) // Keyboard_Output() - { - keymanweb.KO(dn,Pelem,s); - } - - /** - * Function KDO - * Scope Public - * Parameters Pdn no of character to overwrite (delete) - * Pelem element to output to - * Pd deadkey id - * Returns Nothing - * Description Output a deadkey at current cursor position, deleting Pdn characters first - */ - legacy['KDO'] = function(Pdn,Pelem,Pd) - { - keymanweb.KDO(Pdn,Pelem,Pd); - } - - /** - * Function KIO - * Scope Public - * Parameters Pdn no of character to overwrite (delete) - * Ps string - * Pn index - * Pelem element to output to - * Returns Nothing - * Description Output a character selected from the string according to the offset in the index array - */ - legacy['KIO'] = function(Pdn,Ps,Pn,Pelem) - { - keymanweb.KIO(Pdn,Ps,Pn,Pelem); - } - - legacy['KSETS'] = function(systemId,store,Pelem) - { - return keymanweb.KSETS(systemId,store,Pelem); - } - - /********************************************/ - /* */ - /* Legacy calls to default User Interface */ - /* */ - /********************************************/ - - /** - * Function ShowInterface - * Scope Public - * Parameters Px x-position for KMW window - * Py y-position for KMW window - * Returns None - * Description Display (default) KMW UI window at specified position, if manual mode - */ - legacy['ShowInterface'] = function(Px, Py) - { - if(keymanweb['ShowInterface']) keymanweb['ShowInterface'](Px, Py); - } - - /** - * Function HideInterface - * Scope Public - * Parameters None - * Returns None - * Description Completely hide (default) KMW UI window - */ - legacy['HideInterface'] = function() - { - if(keymanweb['HideInterface']) keymanweb['HideInterface'](); - } - - /** - * Function IsInterfaceVisible - * Scope Public - * Parameters None - * Returns True if KMW visible - * Description Test if KMW is displayed - */ - legacy['IsInterfaceVisible'] = function() - { - if(keymanweb['IsInterfaceVisible']) return keymanweb['IsInterfaceVisible'](); - else return false; - } - - /** - * Function SetMode - * Scope Public - * Parameters PuiMode UI mode ('manual' or 'automatic') - * Returns None - * Description Set UI mode to show user interface when requested - */ - legacy['SetMode'] = function(PuiMode) - { - if(keymanweb['SetMode']) keymanweb['SetMode'](PuiMode); - } - - /** - * Function GetMode - * Scope Public - * Parameters None - * Returns UI mode 'manual' or 'automatic' - * Description Return current UI mode - */ - legacy['GetMode'] = function() - { - if(keymanweb['GetMode']) return keymanweb['GetMode'](); - else return ''; - } - - legacy['onshowhelp'] = function() - { - var p={}; - osk.doShow(p); - } - - legacy['onoskhidehelp'] = function() - { - var p = {}; - osk.doHide(p); - } - - /** - * Function UserInterface - * Scope Public - * Parameters None - * Returns Container DIV for UI - * Desccription Lets user interface get or set properties of UI container - - legacy['UserInterface'] = function() - { - return keymanweb._DivKeymanWeb; - } - - - * Function UIShim - * Scope Public - * Parameters None - * Returns Container DIV for UI shim - * Desccription Lets user interface get or set properties of UI shim element - * - legacy['UIShim'] = function() - { - return keymanweb._DivKeymanWebShim; - } - - - - * Function HelpIcon - * Scope Public - * Parameters None - * Returns OSK Help icon - * Desccription Lets user interface get or set properties of help icon - - legacy['HelpIcon'] = function() - { - return osk._HelpIcon; - } - - - * Function SelectKeyboard - * Scope Public - * Parameters None - * Returns Keyboard selection container from UI - * Description ***Temporary*** function until SelectKeyboard fully moved into UI code - * - legacy['SelectKeyboard'] = function() - { - return keymanweb._SelectKeyboard; - } - */ - - -})(tavultesoft['keymanweb']); diff --git a/events/iuc38/Lao Roman/kmw/kmwnative.js b/events/iuc38/Lao Roman/kmw/kmwnative.js deleted file mode 100644 index af2dc51d..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwnative.js +++ /dev/null @@ -1,458 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/*****************************************/ -/* */ -/* On-Screen (Visual) Keyboard Code */ -/* */ -/*****************************************/ -(function() -{ - // Declare KeymanWeb object - var keymanweb=window['tavultesoft']['keymanweb'],osk=keymanweb['osk'],util=keymanweb['util'],device=util.device; - var dbg=keymanweb.debug; - - // Force full initialization - keymanweb.fullInitialization = true; - - /** - * Set default device options - * @param {Object} opt device options object - */ - keymanweb.setDefaultDeviceOptions=function(opt) - { - // Element attachment type - if(opt['attachType'] == '') opt['attachType'] = (device.touchable ? 'manual' : 'auto'); - } - - /** - * Customized wait display - * - * @param {string|boolean} s displayed text (or false) - */ - util.wait = function(s) - { - // Keyboards loaded with page are initialized before the page is ready, - // so cannot use the wait indicater (and don't need it, anyway) - // Do not display if a blocking cloud server error has occurred (to prevent multiple errors) - var bg=keymanweb.waiting; - if(typeof(bg) == 'undefined' || bg == null || keymanweb.warned) return; - - var nn=bg.firstChild.childNodes; - if(s) - { - bg.pending=true; - window.setTimeout(function() - { - if(bg.pending) - { - window.scrollTo(0,0); - nn[0].style.display='none'; - nn[1].className='kmw-wait-text'; nn[1].innerHTML=s; - nn[2].style.display='block'; - bg.style.display='block'; - } - },1000); - } - else - { - if(bg.pending) - { - nn[1].innerHTML=''; - bg.pending=false; bg.style.display='none'; - } - } - } - - // Get default style sheet path - keymanweb.getStyleSheetPath=function(ssName) - { - var ssPath = util['getOption']('resources')+'osk/'+ssName; - return ssPath; - } - - /** - * Get keyboard path (relative or absolute) - * KeymanWeb 2 revised keyboard location specification: - * (a) absolute URL (includes ':') - load from specified URL - * (b) relative URL (starts with /, ./, ../) - load with respect to current page - * (c) filename only (anything else) - prepend keyboards option to URL - * (e.g. default keyboards option will be set by Cloud) - * - * @param {string} Lfilename keyboard file name with optional prefix - */ - keymanweb.getKeyboardPath=function(Lfilename) - { - var rx=RegExp('^(([\.]/)|([\.][\.]/)|(/))|(:)'); - return (rx.test(Lfilename) ? '' : keymanweb.options['keyboards']) + Lfilename; - } - - /** - * Notify the user if a requested keyboard fails to load - * - * @param {Object} Ln keyboard stub object - */ - keymanweb.keyboardUnavailable = function(Ln) - { - return window.setTimeout(function() - { - util.wait(false); - var Ps=keymanweb._KeyboardStubs[Ln],kbdName=Ps['KN'],lgName=Ps['KL']; - kbdName=kbdName.replace(/\s*keyboard\s*/i,''); - util.alert('Sorry, the '+kbdName+' keyboard for '+lgName+' is not currently available!',keymanweb.setDfltKeyboard); - // Restore base keyboard if requested keyboard doesn't load - if(Ln > 0) - { - Ps=keymanweb._KeyboardStubs[0]; - keymanweb._SetActiveKeyboard(Ps['KI'],Ps['KLC'],true); - } - },10000); - } - - /** - * Get (uncached) keyboard context for a specified range, relative to caret - * - * @param {number} n Number of characters to move back from caret - * @param {number} ln Number of characters to return - * @param {Object} Pelem Element to work with (must be currently focused element) - * @return {string} Context string - * - * Example [abcdef|ghi] as INPUT, with the caret position marked by |: - * KC(2,1,Pelem) == "e" - * KC(3,3,Pelem) == "def" - * KC(10,10,Pelem) == "abcdef" i.e. return as much as possible of the requested string - */ - keymanweb.KC_ = function(n, ln, Pelem) - { - var Ldv; - if(Pelem.body) var Ldoc=Pelem; else var Ldoc=Pelem.ownerDocument; // I1481 - use Ldoc to get the ownerDocument when no selection is found - - if(device.touchable) - return keymanweb.getTextBeforeCaret(Pelem)._kmwSubstr(-n)._kmwSubstr(0,ln); - - if(keymanweb.legacy) - { - return Pelem.value._kmwSubstr(Pelem.length-n, ln); //I3319 - } - else if(Ldoc && (Ldv=Ldoc.defaultView) && Ldv.getSelection && - (Ldoc.designMode.toLowerCase() == 'on' || Pelem.contentEditable == 'true' || Pelem.contentEditable == 'plaintext-only' || Pelem.contentEditable === '')) // && Pelem.tagName == 'HTML') && Pelem.tagName == 'HTML') - // I2457 - support contentEditable elements in mozilla, webkit - { - /* Mozilla midas html editor and editable elements */ - var Lsel = Ldv.getSelection(); - if(Lsel.focusNode.nodeType == 3) - { - if(Lsel.focusOffset > 2*n) // I3319 SMP extension - return Lsel.focusNode.substringData(Lsel.focusOffset - 2*n, 2*n)._kmwSubstr(-n)._kmwSubstr(0,ln); // I3319 - else - return Lsel.focusNode.substringData(0, Lsel.focusOffset)._kmwSubstr(-n)._kmwSubstr(0,ln); // I3319 - } - else - return ""; - } - else if (Pelem.setSelectionRange) - { - /* Mozilla other controls */ - var LselectionStart, LselectionEnd; - if(Pelem._KeymanWebSelectionStart) - { - LselectionStart = Pelem._KeymanWebSelectionStart; - LselectionEnd = Pelem._KeymanWebSelectionEnd; - //KeymanWeb._Debug('KeymanWeb.KC: _KeymanWebSelectionStart=TRUE LselectionStart='+LselectionStart+'; LselectionEnd='+LselectionEnd); - } - else - { - if(keymanweb._CachedSelectionStart === null || Pelem.selectionStart !== keymanweb._LastCachedSelection) // I3319, KMW-1 - { - keymanweb._LastCachedSelection = Pelem.selectionStart; // KMW-1 - keymanweb._CachedSelectionStart = Pelem.value._kmwCodeUnitToCodePoint(Pelem.selectionStart); // I3319 - keymanweb._CachedSelectionEnd = Pelem.value._kmwCodeUnitToCodePoint(Pelem.selectionEnd); // I3319 - } - LselectionStart = keymanweb._CachedSelectionStart; // I3319 - LselectionEnd = keymanweb._CachedSelectionEnd; // I3319 - } - if(LselectionStart < n) - { -//dbg(n+' '+ln+' '+Pelem.value._kmwSubstring(0,LselectionStart)); - return Pelem.value._kmwSubstr(0,LselectionStart); //I3319, KMW-1 - } -//dbg(n+' '+ln+' '+Pelem.value._kmwSubstring(LselectionStart-n,LselectionStart-n+ln)); - return Pelem.value._kmwSubstring(LselectionStart-n,LselectionStart-n+ln); //I3319, KMW-1 - } - - else if(Ldoc && (Ldv=Ldoc.selection)) // build 77 - use elem.ownerDocument instead of document - // I1481 - use Ldoc to get the ownerDocument when no selection is found - { - /* IE */ - var Lrange = Ldv.createRange(); - //if (Lrange.parentElement() == Pelem) { // build 77 - ignore parent of selection - Lrange.moveStart('character',-2*n); //I3319 - - return Lrange.text._kmwSubstr(-n)._kmwSubstring(0,ln); //I3319 - //} - } - - return ""; - } - - /** - * Align all input fields with underlying elements after a rotation, resize, or change of element font - * and/or set visibility - * - * @param {boolean} align align and make visible, else hide - * - **/ - keymanweb.alignInputs = function(align) - { - if(device.touchable) - { - for(var i=0; i 0) - keymanweb.inputList[i].base.style.visibility='hidden'; - } - else - { - keymanweb.inputList[i].style.visibility='hidden'; - keymanweb.inputList[i].base.style.visibility='visible'; - } - } - } - } - - // Manage popup key highlighting - osk.highlightSubKeys=function(k,x,y) - { - // Test for subkey array, return if none - if(k.subKeys == null) return; - - // Highlight key at touch position (and clear other highlighting) - var i,sk,skBox,x0,y0,x1,y1,onKey; - skBox=document.getElementById('kmw-popup-keys'); - - // Show popup keys immediately if touch moved up towards key array (KMEW-100, Build 353) - if((osk.touchY-y > 5) && skBox == null) - { - if(osk.subkeyDelayTimer) window.clearTimeout(osk.subkeyDelayTimer); - osk.showSubKeys(k); skBox=document.getElementById('kmw-popup-keys'); - } - - for(i=0; i x0 && x < x1 && y > y0 && y < y1); - osk.highlightKey(sk,onKey); - if(onKey) osk.highlightKey(k,false); - } catch(ex){} - } - } - - // Create a keytip DIV if a phone device (Build 349) - osk.createKeyTip=function() - { - if(device.formFactor == 'phone') - { - if(osk.keytip == null) - { - osk.keytip=util._CreateElement('DIV'); - osk.keytip.className='kmw-keytip'; - } - // Always append to _Box (since cleared during OSK Load) - osk._Box.appendChild(osk.keytip); - } - } - - osk.optionKey=function(e,keyName,keyDown) - { - if(keyDown) - { - if(keyName.indexOf('K_LOPT') >= 0) osk.showLanguageMenu(); - else if(keyName.indexOf('K_ROPT') >= 0) - { - keymanweb._IsActivatingKeymanWebUI=0; osk._Hide(true); - keymanweb.hideCaret(); keymanweb._LastActiveElement = 0; - } - } - } - - // Add (or remove) the keytip preview (if KeymanWeb on a phone device) - osk.showKeyTip=function(key,on) - { - if(osk.keytip == null) return; - - if(on) - { - if(key.className.indexOf('kmw-key-default') > 0 - && key.id.indexOf('K_SPACE') < 0 - && key.id.indexOf('popup') < 0) - { - var kc=key.firstChild,kcs=kc.style,kt=osk.keytip,kts=kt.style; - kt.textContent=kc.textContent; - kts.fontFamily=util.getStyleValue(kc,'font-family'); - var px=util.getStyleInt(kc,'font-size'); - if(px != 0) kts.fontSize=(1.5*px)+'px'; - var xLeft=util._GetAbsoluteX(key), - xTop=util._GetAbsoluteY(key), - xWidth=key.offsetWidth; - - // Cannot read height or width of tip, calculate from size of text and padding - var tWidth=(1.5*kc.offsetWidth)+ - util.getStyleInt(kt,'padding-left')+ - util.getStyleInt(kt,'padding-right'), - kmRight=util.getStyleInt(key,'margin-right'), - tHeight=(1.5*kc.offsetHeight)+ - util.getStyleInt(kt,'padding-top')+ - util.getStyleInt(kt,'padding-bottom'), - kmTop=util.getStyleInt(key,'margin-top'); - kts.left=(xLeft-kmRight+(xWidth-tWidth)/2)+'px'; - kts.top=(util._GetAbsoluteY(key)-kmTop-osk._Box.offsetTop-tHeight)+'px'; - kts.display='block'; - } - } - else - { - osk.keytip.style.display='none'; - } - } - - /** - * Use rotation events to adjust OSK and input element positions and scaling as necessary - */ - keymanweb.handleRotationEvents=function() - { - if(device.OS == 'iOS') - util.attachDOMEvent(window,'orientationchange',keymanweb.rotateDevice); - - // Also manage viewport rescaling after rotation on Android - if(device.OS == 'Android') - { - osk.wasVisible=osk.isVisible; - - // Hide OSK at start of rotation - if('onmozorientationchange' in screen) - util.attachDOMEvent(screen,'mozorientationchange',osk.hideNow); - else - util.attachDOMEvent(window,'orientationchange',osk.hideNow); - - // Then align inputs and redisplay the OSK on resize event following rotation - util.attachDOMEvent(window,'resize', - function(){ - keymanweb.alignInputs(true); - osk.hideLanguageList(); - osk._Load(); - if(osk.wasVisible)osk._Show(); - } - ); - } - - //TODO: may be able to recognize start of rotation using accelerometer call... - //util.attachDOMEvent(window,'devicemotion',keymanweb.testRotation); - } - - /** - * Hide the URL bar and resize the OSK after rotation (device dependent) - * - * @param {Event} e event (not used directly) - * - */ - keymanweb.rotateDevice = function(e) // Rewritten for I3363 (Build 301) - { - osk.hideLanguageList(); - - if(!osk._Visible) return; - // Always re-adjust OSK rows for rounding to nearest pixel -// if(osk.ready) -// { - //nLayer=osk.resetRowLengths(); // clear aligned flag for all layers - //osk.adjustRowLengths(nLayer); // adjust lengths in visible layer -// } - - osk.adjustHeights(); - - // Hide the URL bar on Android phones - offset is zero for iPhone, but should not be applied here - if(device.formFactor == 'phone' && device.OS == 'Android') - window.setTimeout(function(){window.scrollTo(0,1);},1000); - } - - /** - * Possible way to detect the start of a rotation and hide the OSK before it is adjusted in size - * - * @param {Object} e accelerometer rotation event - * - keymanweb.testRotation = function(e) - { - var r=e.rotationRate; - if(typeof(r) != 'undefined') - { - dbg(r.alpha+' '+r.beta+' '+r.gamma); - } - } - */ - - /** - * Wait until font is loaded before applying stylesheet - test each 100 ms - * @param {Object} kfd main font descriptor - * @param {Object} ofd secondary font descriptor (OSK only) - * @return {boolean} - */ - osk.waitForFonts=function(kfd,ofd) - { - if(typeof(kfd) == 'undefined' && typeof(ofd) == 'undefined') return true; - - if(typeof(kfd['files']) == 'undefined' && typeof(ofd['files']) == 'undefined') return true; - - - var kReady=util.checkFontDescriptor(kfd),oReady=util.checkFontDescriptor(ofd); - if(kReady && oReady) return true; - - keymanweb.fontCheckTimer=window.setInterval(function() - { - if(util.checkFontDescriptor(kfd) && util.checkFontDescriptor(ofd)) - { - window.clearInterval(keymanweb.fontCheckTimer); - keymanweb.fontCheckTimer=null; - keymanweb.alignInputs(true); - } - },100); - - // Align anyway as best as can if font appears to remain uninstalled after 5 seconds - window.setTimeout(function() - { - if(keymanweb.fontCheckTimer) - { - window.clearInterval(keymanweb.fontCheckTimer); - keymanweb.fontCheckTimer=null; - keymanweb.alignInputs(true); - // Don't notify - this is a management issue, not anything the user needs to deal with - // TODO: Consider having an icon in the OSK with a bubble that indicates missing font - //util.alert('Unable to download the font normally used with '+ks['KN']+'.'); - } - },5000); - return false; - } - - - -})(); diff --git a/events/iuc38/Lao Roman/kmw/kmwreleasestub.js b/events/iuc38/Lao Roman/kmw/kmwreleasestub.js deleted file mode 100644 index 3170adce..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwreleasestub.js +++ /dev/null @@ -1,213 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ -/** - * External references to separately compiled string prototype extensions - */ - -/** - * Prototypes for SMP string function extensions - * - * @param {number} cp0 - * @return {string} - **/ -String.kmwFromCharCode = function(cp0) {}; - -/** - * @param {number} codePointIndex - * @return {number} - **/ -String.prototype.kmwCharCodeAt = function(codePointIndex) {}; - -/** - * @param {string} searchValue - * @param {number} fromIndex - * @return {number} - **/ -String.prototype.kmwIndexOf = function(searchValue, fromIndex) {}; - -/** - * @param {string} searchValue - * @param {number} fromIndex - * @return {number} - **/ -String.prototype.kmwLastIndexOf = function(searchValue, fromIndex) {}; - -/** - * @return {number} - **/ -String.prototype.kmwLength = function() {}; - -/** - * @param {number} beginSlice - * @param {number} endSlice - * @return {string} - **/ -String.prototype.kmwSlice = function(beginSlice, endSlice) {}; - -/** - * @param {number} start - * @param {number=} length - * @return {string} - **/ -String.prototype.kmwSubstr = function(start, length) {}; - -/** - * @param {number} indexA - * @param {number=} indexB - * @return {string} - **/ -String.prototype.kmwSubstring = function(indexA, indexB) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype.kmwNextChar = function(codeUnitIndex) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype.kmwPrevChar = function(codeUnitIndex) {}; - -/** - * @param {number} codePointIndex - * @return {number} - **/ -String.prototype.kmwCodePointToCodeUnit = function(codePointIndex) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype.kmwCodeUnitToCodePoint = function(codeUnitIndex) {}; - -/** - * @param {number} codePointIndex - * @return {string} - **/ -String.prototype.kmwCharAt = function(codePointIndex) {}; - - - -/** - * Prototypes for string function extensions that can be either BMP or SMP - * - * @param {number} cp0 - * @return {string} - **/ -String._kmwFromCharCode = function(cp0) {}; - -/** - * @param {number} codePointIndex - * @return {number} - **/ -String.prototype._kmwCharCodeAt = function(codePointIndex) {}; - -/** - * @param {string} searchValue - * @param {number} fromIndex - * @return {number} - **/ -String.prototype._kmwIndexOf = function(searchValue, fromIndex) {}; - -/** - * @param {string} searchValue - * @param {number} fromIndex - * @return {number} - **/ -String.prototype._kmwLastIndexOf = function(searchValue, fromIndex) {}; - -/** - * @return {number} - **/ -String.prototype._kmwLength = function() {}; - -/** - * @param {string} beginSlice - * @param {string} endSlice - * @return {string} - **/ -String.prototype._kmwSlice = function(beginSlice, endSlice) {}; - -/** - * @param {number} start - * @param {number=} length - * @return {string} - **/ -String.prototype._kmwSubstr = function(start, length) {}; - -/** - * @param {number} indexA - * @param {number=} indexB - * @return {string} - **/ -String.prototype._kmwSubstring = function(indexA, indexB) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype._kmwNextChar = function(codeUnitIndex) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype._kmwPrevChar = function(codeUnitIndex) {}; - -/** - * @param {number} codePointIndex - * @return {number} - **/ -String.prototype._kmwCodePointToCodeUnit = function(codePointIndex) {}; - -/** - * @param {number} codeUnitIndex - * @return {number} - **/ -String.prototype._kmwCodeUnitToCodePoint = function(codeUnitIndex) {}; - -/** - * @param {number} codePointIndex - * @return {string} - **/ -String.prototype._kmwCharAt = function(codePointIndex) {}; - - -/** - * String extension to enable SMP handling only as required - * - * @param {(boolean|number)} bEnable - **/ -String.kmwEnableSupplementaryPlane = function(bEnable) {}; - -/** - * External debug routines are stubbed out, allowing the compiler to remove all references - */ - -/** @nosideeffects */ -function _Debug(t){}; - -/** @nosideeffects */ -function _DebugEnter(t){}; - -/** @nosideeffects */ -function _DebugExit(t){}; - -/** @nosideeffects */ -function _DebugDeadKeys(t,u){}; diff --git a/events/iuc38/Lao Roman/kmw/kmwstring.js b/events/iuc38/Lao Roman/kmw/kmwstring.js deleted file mode 100644 index 7856a9a7..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwstring.js +++ /dev/null @@ -1,439 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/** - * Constructs a string from one or more Unicode character codepoint values - * passed as integer parameters. - * - * @param {number} cp0,... 1 or more Unicode codepoints, e.g. 0x0065, 0x10000 - * @return {string|null} The new String object. - */ -String.kmwFromCharCode = function(cp0) { - var chars = [], i; - for (i = 0; i < arguments.length; i++) { - var c = Number(arguments[i]); - if (!isFinite(c) || c < 0 || c > 0x10FFFF || Math.floor(c) !== c) { - throw new RangeError("Invalid code point " + c); - } - if (c < 0x10000) { - chars.push(c); - } else { - c -= 0x10000; - chars.push((c >> 10) + 0xD800); - chars.push((c % 0x400) + 0xDC00); - } - } - return String.fromCharCode.apply(undefined, chars); -} - -/** - * Returns a number indicating the Unicode value of the character at the given - * code point index, with support for supplementary plane characters. - * - * @param {number} codePointIndex The code point index into the string (not - the code unit index) to return - * @return {number} The Unicode character value - */ -String.prototype.kmwCharCodeAt = function(codePointIndex) { - var str = String(this); - var codeUnitIndex = 0; - - if (codePointIndex < 0 || codePointIndex >= str.length) { - return NaN; - } - - for(var i = 0; i < codePointIndex; i++) { - codeUnitIndex = str.kmwNextChar(codeUnitIndex); - if(codeUnitIndex === null) return NaN; - } - - var first = str.charCodeAt(codeUnitIndex); - if (first >= 0xD800 && first <= 0xDBFF && str.length > codeUnitIndex + 1) { - var second = str.charCodeAt(codeUnitIndex + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { - return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000; - } - } - return first; -} - -/** - * Returns the code point index within the calling String object of the first occurrence - * of the specified value, or -1 if not found. - * - * @param {string} searchValue The value to search for - * @param {number} fromIndex Optional code point index to start searching from - * @return {number} The code point index of the specified search value - */ -String.prototype.kmwIndexOf = function(searchValue, fromIndex) { - var str = String(this); - var codeUnitIndex = str.indexOf(searchValue, fromIndex); - - if(codeUnitIndex < 0) { - return codeUnitIndex; - } - - var codePointIndex = 0; - for(var i = 0; i !== null && i < codeUnitIndex; i = str.kmwNextChar(i)) codePointIndex++; - return codePointIndex; -} - -/** - * Returns the code point index within the calling String object of the last occurrence - * of the specified value, or -1 if not found. - * - * @param {string} searchValue The value to search for - * @param {number} fromIndex Optional code point index to start searching from - * @return {number} The code point index of the specified search value - */ -String.prototype.kmwLastIndexOf = function(searchValue, fromIndex) -{ - var str = String(this); - var codeUnitIndex = str.lastIndexOf(searchValue, fromIndex); - - if(codeUnitIndex < 0) { - return codeUnitIndex; - } - - var codePointIndex = 0; - for(var i = 0; i !== null && i < codeUnitIndex; i = str.kmwNextChar(i)) codePointIndex++; - return codePointIndex; -} - -/** - * Returns the length of the string in code points, as opposed to code units. - * - * @return {number} The length of the string in code points - */ -String.prototype.kmwLength = function() { - var str = String(this); - - if(str.length == 0) return 0; - - for(var i = 0, codeUnitIndex = 0; codeUnitIndex !== null; i++) - codeUnitIndex = str.kmwNextChar(codeUnitIndex); - return i; -} - -/** - * Extracts a section of a string and returns a new string. - * - * @param {number} beginSlice The start code point index in the string to - * extract from - * @param {number} endSlice Optional end code point index in the string - * to extract to - * @return {string} The substring as selected by beginSlice and - * endSlice - */ -String.prototype.kmwSlice = function(beginSlice, endSlice) { - var str = String(this); - var beginSliceCodeUnit = str.kmwCodePointToCodeUnit(beginSlice); - var endSliceCodeUnit = str.kmwCodePointToCodeUnit(endSlice); - if(beginSliceCodeUnit === null || endSliceCodeUnit === null) - return ''; - else - return str.slice(beginSliceCodeUnit, endSliceCodeUnit); -} - -/** - * Returns the characters in a string beginning at the specified location through - * the specified number of characters. - * - * @param {number} start The start code point index in the string to - * extract from - * @param {number} length Optional length to extract - * @return {string} The substring as selected by start and length - */ -String.prototype.kmwSubstr = function(start, length) -{ - var str = String(this); - if(start < 0) - { - start = str.kmwLength() + start; - } - if(start < 0) start = 0; - var startCodeUnit = str.kmwCodePointToCodeUnit(start); - var endCodeUnit = startCodeUnit; - - if(startCodeUnit === null) return ''; - - if(arguments.length < 2) { - endCodeUnit = str.length; - } else { - for(var i = 0; i < length; i++) endCodeUnit = str.kmwNextChar(endCodeUnit); - } - if(endCodeUnit === null) - return str.substring(startCodeUnit); - else - return str.substring(startCodeUnit, endCodeUnit); -} - -/** - * Returns the characters in a string between two indexes into the string. - * - * @param {number} indexA The start code point index in the string to - * extract from - * @param {number} indexB The end code point index in the string to - * extract to - * @return {string} The substring as selected by indexA and indexB - */ -String.prototype.kmwSubstring = function(indexA, indexB) -{ - var str = String(this),indexACodeUnit,indexBCodeUnit; - - if(typeof(indexB) == 'undefined') - { - indexACodeUnit = str.kmwCodePointToCodeUnit(indexA); - indexBCodeUnit = str.length; - } - else - { - if(indexA > indexB) { var c = indexA; indexA = indexB; indexB = c; } - - indexACodeUnit = str.kmwCodePointToCodeUnit(indexA); - indexBCodeUnit = str.kmwCodePointToCodeUnit(indexB); - } - if(isNaN(indexACodeUnit) || indexACodeUnit === null) indexACodeUnit = 0; - if(isNaN(indexBCodeUnit) || indexBCodeUnit === null) indexBCodeUnit = str.length; - - return str.substring(indexACodeUnit, indexBCodeUnit); -} - -/* - Helper functions -*/ - -/** - * Returns the code unit index for the next code point in the string, accounting for - * supplementary pairs - * - * @param {number|null} codeUnitIndex The code unit position to increment - * @return {number|null} The index of the next code point in the string, - * in code units - */ -String.prototype.kmwNextChar = function(codeUnitIndex) { - var str = String(this); - - if(codeUnitIndex === null || codeUnitIndex < 0 || codeUnitIndex >= str.length - 1) { - return null; - } - - var first = str.charCodeAt(codeUnitIndex); - if (first >= 0xD800 && first <= 0xDBFF && str.length > codeUnitIndex + 1) { - var second = str.charCodeAt(codeUnitIndex + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { - if(codeUnitIndex == str.length - 2) { - return null; - } - return codeUnitIndex + 2; - } - } - return codeUnitIndex + 1; -} - -/** - * Returns the code unit index for the previous code point in the string, accounting - * for supplementary pairs - * - * @param {number|null} codeUnitIndex The code unit position to decrement - * @return {number|null} The index of the previous code point in the - * string, in code units -*/ -String.prototype.kmwPrevChar = function(codeUnitIndex) { - var str = String(this); - - if(codeUnitIndex == null || codeUnitIndex <= 0 || codeUnitIndex > str.length) { - return null; - } - - var second = str.charCodeAt(codeUnitIndex - 1); - if (second >= 0xDC00 && second <= 0xDFFF && codeUnitIndex > 1) { - var first = str.charCodeAt(codeUnitIndex - 2); - if(first >= 0xD800 && first <= 0xDBFF) { - return codeUnitIndex - 2; - } - } - return codeUnitIndex - 1; -} - -/** - * Returns the corresponding code unit index to the code point index passed - * - * @param {number|null} codePointIndex A code point index in the string - * @return {number|null} The corresponding code unit index - */ -String.prototype.kmwCodePointToCodeUnit = function(codePointIndex) { - - if(codePointIndex === null) return null; - - var str = String(this); - var codeUnitIndex = 0; - - if(codePointIndex < 0) { - codeUnitIndex = str.length; - for(var i = 0; i > codePointIndex; i--) - codeUnitIndex = str.kmwPrevChar(codeUnitIndex); - return codeUnitIndex; - } - - if(codePointIndex == str.kmwLength()) return str.length; - - for(var i = 0; i < codePointIndex; i++) - codeUnitIndex = str.kmwNextChar(codeUnitIndex); - return codeUnitIndex; -} - -/** - * Returns the corresponding code point index to the code unit index passed - * - * @param {number|null} codeUnitIndex A code unit index in the string - * @return {number|null} The corresponding code point index - */ -String.prototype.kmwCodeUnitToCodePoint = function(codeUnitIndex) { - var str = String(this); - - if(codeUnitIndex === null) - return null; - else if(codeUnitIndex == 0) - return 0; - else if(codeUnitIndex < 0) - return str.substr(codeUnitIndex).kmwLength(); - else - return str.substr(0,codeUnitIndex).kmwLength(); -} - -/** - * Returns the character at a the code point index passed - * - * @param {number} codePointIndex A code point index in the string - * @return {string} The corresponding character - */ -String.prototype.kmwCharAt = function(codePointIndex) { - var str = String(this); - - if(codePointIndex >= 0) return str.kmwSubstr(codePointIndex,1); else return ''; -} - -/** - * String prototype library extensions for basic plane characters, - * to simplify enabling or disabling supplementary plane functionality (I3319) - */ - -/** - * Returns the code unit index for the next code point in the string - * - * @param {number} codeUnitIndex A code point index in the string - * @return {number|null} The corresponding character - */ -String.prototype.kmwBMPNextChar = function(codeUnitIndex) -{ - var str = String(this); - if(codeUnitIndex < 0 || codeUnitIndex >= str.length - 1) { - return null; - } - return codeUnitIndex + 1; -} - -/** - * Returns the code unit index for the previous code point in the string - * - * @param {number} codeUnitIndex A code unit index in the string - * @return {number|null} The corresponding character - */ -String.prototype.kmwBMPPrevChar = function(codeUnitIndex) -{ - var str = String(this); - - if(codeUnitIndex <= 0 || codeUnitIndex > str.length) { - return null; - } - return codeUnitIndex - 1; -} - -/** - * Returns the code unit index for a code point index - * - * @param {number} codePointIndex A code point index in the string - * @return {number} The corresponding character - */ -String.prototype.kmwBMPCodePointToCodeUnit = function(codePointIndex) -{ - return codePointIndex; -} - -/** - * Returns the code point index for a code unit index - * - * @param {number} codeUnitIndex A code point index in the string - * @return {number} The corresponding character - */ -String.prototype.kmwBMPCodeUnitToCodePoint = function(codeUnitIndex) -{ - return codeUnitIndex; -} - -/** - * Returns the length of a BMP string - * - * @return {number} The length in code points - */ -String.prototype.kmwBMPLength = function() -{ - var str = String(this); - return str.length; -} - - -/** - * Returns a substring - * - * @param {number} n - * @param {number} ln - * @return {string} - */ -String.prototype.kmwBMPSubstr = function(n,ln) -{ - var str=String(this); - if(n > -1) - return str.substr(n,ln); - else - return str.substr(str.length+n,-n); -} - -/** - * Enable or disable supplementary plane string handling - * - * @param {boolean} bEnable - */ -String.kmwEnableSupplementaryPlane = function(bEnable) -{ - var p=String.prototype; - String._kmwFromCharCode = bEnable ? String.kmwFromCharCode : String.fromCharCode; - p._kmwCharAt = bEnable ? p.kmwCharAt : p.charAt; - p._kmwCharCodeAt = bEnable ? p.kmwCharCodeAt : p.charCodeAt; - p._kmwIndexOf = bEnable ? p.kmwIndexOf :p.indexOf; - p._kmwLastIndexOf = bEnable ? p.kmwLastIndexOf : p.lastIndexOf ; - p._kmwSlice = bEnable ? p.kmwSlice : p.slice; - p._kmwSubstring = bEnable ? p.kmwSubstring : p.substring; - p._kmwSubstr = bEnable ? p.kmwSubstr : p.kmwBMPSubstr; - p._kmwLength = bEnable ? p.kmwLength : p.kmwBMPLength; - p._kmwNextChar = bEnable ? p.kmwNextChar : p.kmwBMPNextChar; - p._kmwPrevChar = bEnable ? p.kmwPrevChar : p.kmwBMPPrevChar; - p._kmwCodePointToCodeUnit = bEnable ? p.kmwCodePointToCodeUnit : p.kmwBMPCodePointToCodeUnit; - p._kmwCodeUnitToCodePoint = bEnable ? p.kmwCodeUnitToCodePoint : p.kmwBMPCodeUnitToCodePoint; -} - diff --git a/events/iuc38/Lao Roman/kmw/kmwuibutton.js b/events/iuc38/Lao Roman/kmw/kmwuibutton.js deleted file mode 100644 index febb68be..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwuibutton.js +++ /dev/null @@ -1,585 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/********************************/ -/* */ -/* Button User Interface Code */ -/* */ -/********************************/ - -/** - * Do not enclose in an anonymous function, as the compiler may create - * global scope variables to replace true, false, null, whcih can then collide - * with other variables. - * Instead, use the --output-wrapper command during optimization, which will - * add the anonymous function to enclose all code, including those optimized - * variables which would otherwise have global scope. - **/ - -try { - // Declare KeymanWeb, OnScreen keyboard and Util objects - var keymanweb=window['tavultesoft']['keymanweb'],osk=keymanweb['osk'], - util=keymanweb['util'],dbg=keymanweb['debug']; - - // Disable UI for touch devices - if(util['isTouchDevice']()) throw ''; - - // User interface global and variables - keymanweb['ui'] = {}; - var ui=keymanweb['ui']; - ui['name'] = 'button'; - - ui.init = false; - ui.KeyboardSelector = null; - - ui.KeymanWeb_DefaultKeyboardHelp='KeymanWeb is not running. Choose a keyboard from the list'; - ui._KeymanWeb_KbdList = null; - ui._KMWSel = null; - ui._IsHelpVisible = false; - ui._DefaultKeyboardID = ''; - - ui.updateTimer = null; - ui.updateList = true; - - /** - * Highlight the currently active keyboard in the list of keyboards - **/ - ui._ShowSelected = function() - { - var _rv,kbd=keymanweb['getActiveKeyboard'](),lgc=keymanweb['getActiveLanguage'](), - kList = ui._KeymanWeb_KbdList.childNodes, - _r = /^KMWSel_(.*)\$(.*)$/; - - for(var i=1; i= kList.length) i=1; - kList[i].childNodes[0].className = 'selected'; - } - - /** - * Select keyboard by id - * - * @param {Event} _id keyboard selection event - * @return {boolean} - */ - ui._SelectKeyboard = function(_id) - { - if(typeof(_id) == 'object') - { - var t=null; - if((typeof(_id.target) != 'undefined') && _id.target) t=_id.target; - else if((typeof(_id.srcElement) != 'undefined') && _id.srcElement) t=_id.srcElement; - if(t) _id=t.id; - } - - var _r=/^KMWSel_(.*)\$(.*)$/; - var _rv=_r.exec(_id),_lgc='',_name=''; - if(_rv !== null) - { - _name = _rv[1].split('$')[0]; //new code - _lgc = _id.split('$')[1]; - if(ui._KMWSel != null) ui._KMWSel.className = ''; - var _k = document.getElementById(_id); - if(_k) _k.className='selected'; - ui._KMWSel = _k; - keymanweb['setActiveKeyboard'](_name,_lgc); - } - else - _name=null; - - keymanweb['focusLastActiveElement'](); - if(osk['isEnabled']()) osk['show'](true); - - ui._ShowKeyboardButton(_name); - return false; - } - - /** - * Set KMW UI activation state on mouse click - * - * @param {Event} e event - */ - ui._SelectorMouseDown = function(e) - { - var x=keymanweb['getLastActiveElement'](); - - // Set the focus to an input field, to get correct OSK display behaviour - if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); - - if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); - } - - /** - * Set focus on mouse up - * - * @param {Event} e event - */ - ui._SelectorMouseUp = function(e) - { - var x=keymanweb['getLastActiveElement'](); - - // Set the focus to an input field, to get correct OSK display behaviour - if(!x) ui._FocusFirstInput(); else keymanweb['focusLastActiveElement'](); - } - - /** - * Set KMW UI activation state on mouse over - * - * @param {Event} e event - */ - ui._SelectorMouseOver = function(e) - { - // highlight the currently active keyboard - ui._ShowSelected(); - - if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); - document.getElementById("kmwico_li").className="sfhover"; - - // Conditionally display keyboard button - ui._ShowKeyboardButton(); - } - - /** - * Sets the focus to the first input or textarea found on the current page - * to ensure consistent keyboard selection and OSK display behaviour - */ - ui._FocusFirstInput = function() - { - var i,ip=null,tp=null, - iList=document.getElementsByTagName("input"), - tList=document.getElementsByTagName("textarea"); - - for(i=0; i 0) tp = tList[0]; - - if((!ip) && (!tp)) - return; - else if(ip && !tp) - ip.focus(); - else if(tp && !ip) - tp.focus(); - else if(ip.offsetTop < tp.offsetTop) - ip.focus(); - else if(ip.offsetTop > tp.offsetTop) - tp.focus(); - else if(ip.offsetLeft < tp.offsetLeft) - ip.focus(); - else - tp.focus(); - } - - /** - * Clear KMW UI activation state on mouse out - * - * @param {Event} e event - */ - ui._SelectorMouseOut = function(e) - { - if(keymanweb['activatingUI']) keymanweb['activatingUI'](0); - document.getElementById("kmwico_li").className="sfunhover"; - } - - /** - * Disable the button to show/hide the OSK if no active keyboard or active keyboard is CJK (user cannot hide) - * - * @param {?string=} _name current keyboard name - */ - ui._ShowKeyboardButton = function(_name) - { - var kbdName = keymanweb['getActiveKeyboard'](), kbdId=document.getElementById("KMW_Keyboard"); - if(arguments.length > 0) kbdName = _name; - if(kbdId) - { - if((kbdName == '') || keymanweb['isCJK']()) - { - kbdId.className='kmw_disabled'; - } - else - { - kbdId.className = osk['isEnabled']() ? 'kmw_show' : 'kmw_hide'; - } - } - } - - /** - * UI Functions called by KeymanWeb or OSK - */ - osk['addEventListener']('show', - function(oskPosition) - { - var t=keymanweb['getLastActiveElement'](); - if(t) - { - if(!oskPosition['userLocated']) - { - oskPosition['x'] = util['getAbsoluteX'](t); - oskPosition['y'] = util['getAbsoluteY'](t)+t.offsetHeight; - } - } - - ui._ShowKeyboardButton(); - return oskPosition; - }); - /* TODO: why is this still needed??? Does it actually do anything?? */ - osk['addEventListener']('hide', - function(hiddenByUser) - { - if((arguments.length > 0) && hiddenByUser) - { - var _a = document.getElementById('KMW_Keyboard'); - if(_a) _a.className = 'kmw_hide'; - } - }); - - /** - * Show or hide the OSK (always visible for CJK keyboards) - * - * @param {Object} _anchor anchor element (?) - * @return {boolean} - **/ - ui._ShowKeymanWebKeyboard = function(_anchor) - { - var kbdId=document.getElementById("KMW_Keyboard"); - if((kbdId.className!='kmw_disabled') && osk['show']) - { - if(osk['isEnabled']()) osk['hide'](); else osk['show'](true); - } - if(window.event) window.event.returnValue=false; - - keymanweb['focusLastActiveElement'](); - return false; - } - - /** - * Initialize Button User Interface - **/ - ui.Initialize = function() - { - //Never initialize UI before KMW (parameters will be undefined) - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,250); return; - } - - if(ui.init || util['isTouchDevice']()) return; - - ui.init = true; - - util['addStyleSheet'](ui._Appearance); - - ui._KeymanWeb_KbdList = util['createElement']('ul'); - ui._KeymanWeb_KbdList.id = 'KeymanWeb_KbdList'; - - var _elem = document.getElementById('KeymanWebControl'); - if(!_elem) - { - var _elems = document.getElementsByTagName('div'); - for(var _i = 0; _i < _elems.length; _i++) - { - if(_elems[_i].className == 'KeymanWebControl') - { - _elem = _elems[_i]; break; - } - } - } - - // Insert as first child of body if not defined by user - if(!_elem && (document.body != null)) - { - _elem=document.createElement('DIV'); - _elem.id='KeymanWebControl'; - document.body.insertBefore(_elem,document.body.firstChild); - } - - - var imgPath=util['getOption']('resources')+'ui/button/'; - if(_elem) - { - // Append another DIV to follow the main control with clear:both to prevent selection over entire width of window - var dx=document.createElement('DIV'),ds=dx.style; - ds.clear='both'; - _elem.parentNode.insertBefore(dx,_elem.nextSibling); - - var _btn=util['createElement']('img'), _ul=util['createElement']('ul'),_li0=util['createElement']('li'); - _btn.id = 'kmwico_a'; - _btn.src = imgPath+'kmw_button.gif'; - _btn.onclick = function(){return false;} //may want to use this in iOS ***** - _li0.appendChild(_btn); - _li0.id = 'kmwico_li'; - _ul.appendChild(_li0); - _ul.id = 'kmwico'; - _ul.style.display = 'block'; - _elem.appendChild(_ul); - } - // Do not define any UI behaviour if no controller element can be found - else return; - - if(!keymanweb['iOS']) - { - var _li = util['createElement']('li'); - var _a = util['createElement']('a'); - var _img = util['createElement']('img'); - _img.src = imgPath+'kbdicon.gif'; - _a.appendChild(_img); - - var _txt1 = document.createTextNode(' Hide Keyboard'); - var _txt2 = document.createTextNode(' Show Keyboard'); - var _sp1 = util['createElement']('span'); - _sp1.id = 'KMW_KbdVisibleMsg'; - _sp1.appendChild(_txt1); - _a.appendChild(_sp1); - - var _sp2 = util['createElement']('span'); - _sp2.id = 'KMW_KbdHiddenMsg'; - _sp2.appendChild(_txt2); - _a.appendChild(_sp2); - _a.onmousedown = ui._ShowKeymanWebKeyboard; - _a.href = '#'; - _a.id = 'KMW_Keyboard'; - _li.id = 'KMW_ButtonUI_KbdIcon'; - _li.appendChild(_a); - ui._KMWSel = _a; - ui._KeymanWeb_KbdList.appendChild(_li); - } - - var _li1 = util['createElement']('li'); - _li1.id = 'KMW_ButtonUI_KbdList'; - var _a1 = util['createElement']('a'); - _a1.appendChild(document.createTextNode('English')); - - _a1.onclick = ui._SelectKeyboard; - _a1.href = '#'; - _a1.id='KMWSel_$'; - _a1.className='selected'; - _li1.appendChild(_a1); - ui._KMWSel = _a1; - ui._KeymanWeb_KbdList.appendChild(_li1); - - var _kbds = keymanweb['getKeyboards'](), _added = []; - - ui.updateKeyboardList(); - - document.getElementById('kmwico_li').appendChild(ui._KeymanWeb_KbdList); - - var _sfEl = document.getElementById("kmwico_li"); - util['attachDOMEvent'](_sfEl,'mousedown',ui._SelectorMouseDown); - util['attachDOMEvent'](_sfEl,'mouseover',ui._SelectorMouseOver); - util['attachDOMEvent'](_sfEl,'mouseout',ui._SelectorMouseOut); - util['attachDOMEvent'](_sfEl,'mouseup',ui._SelectorMouseUp); - - keymanweb['focusLastActiveElement'](); //TODO: this needs to be extended - if no element is active, try and identify an enabled input element - } - - /** - * Keyboard registration event handler - * - * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, - * thus updating only once when only if multiple keyboards are registered together - */ - keymanweb['addEventListener']('keyboardregistered', - function(p) - { - ui.updateList = true; - if(ui.updateTimer) clearTimeout(ui.updateTimer); - ui.updateTimer = setTimeout(ui.updateKeyboardList,20); - }); - - - /** - * Update the entire menu when keyboards are registered or deregistered - **/ - ui.updateKeyboardList = function() - { - ui.updateList = false; - - if(!ui.init) return; - - // Clear existing list first (first two nodes must be preserved) - for(var i=ui._KeymanWeb_KbdList.childNodes.length; i>2; i--) - ui._KeymanWeb_KbdList.removeChild(ui._KeymanWeb_KbdList.childNodes[i-1]); - - var kbds=keymanweb['getKeyboards'](); - if(kbds.length > 0) - { - for(var i=0; i 26) _t=_t.substr(0,24)+'\u2026'; - _a2.appendChild(document.createTextNode(_t)); - _a2.onclick = ui._SelectKeyboard; - _a2.href = '#'; - _a2.id='KMWSel_'+Lki+'$'+Lklc; - _li2.appendChild(_a2); - ui._KeymanWeb_KbdList.appendChild(_li2); - } - - // Define appearance of this interface - ui._Appearance = - "#kmwico, #kmwkbd {"+ - "vertical-align: middle;"+ - "} "+ - - "#KeymanWebControl {float:left;} "+ - - "#KeymanWebControl * "+ - "{"+ - "letter-spacing: 0px !important;"+ - "line-height: 1li !important;"+ - "white-space: nowrap !important;"+ - "} "+ - - "#KeymanWebControl #kmwico img {"+ - "vertical-align: top;"+ - "padding: 0;"+ - "margin: 0;"+ - "border: none;"+ - "} "+ - - "#KeymanWebControl #kmwico, #kmwico ul {"+ - "padding: 0;"+ - "margin: 0;"+ - "list-style: none;"+ - "} "+ - - "#KeymanWebControl #kmwico_a {"+ - "display: block;"+ - //"border: none !important;"+ - "width: 22px; height: 23px; "+ /* sizes needed for kmw_button.gif */ - "} "+ - - "#KeymanWebControl #kmwico li { "+ - "text-align: left;"+ - "} "+ - - "#KeymanWebControl #kmwico li ul {"+ - "display: block;"+ - "position: absolute;"+ - "left: -5999px;"+ - "border: solid 2px #ad4a28;"+ - "background: white;"+ - "border-radius: 4px;"+ - "box-shadow: 4px 4px 2px #666;"+ - "z-index: 10011;"+ /* above the osk */ - "} "+ - - "#KeymanWebControl #kmwico li.sfunhover ul {"+ - "display: none; left: -5999px;"+ - "} "+ - - "#KeymanWebControl #kmwico li:hover ul, #kmwico li.sfhover ul {"+ - "display: block;"+ - "left: auto;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li {"+ - "float: none;"+ - "padding: 0 !important;"+ - "margin: 0 !important;"+ - "width: 136px !important;"+ - "} "+ - - "#KeymanWebControl #KMW_LanguageName {"+ - "font-weight: bold;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a, #kmwico ul li a:visited {"+ - "display: block;"+ - "padding: 2px 4px !important;"+ - "border: none !important;"+ - // "width: auto;"+ - "color: #404040;"+ - "font-family: Tahoma,Verdana,Arial,sans-serif;"+ - "font-size: 8pt;"+ - "text-decoration: none;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.selected {"+ - "font-weight: bold;"+ - "color: black;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a:hover {"+ - "color: white;"+ - "background-color: #ad4a28;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_disabled, #KeymanWebControl #kmwico ul li a.kmw_disabled:hover {"+ - "color: #c0c0c0; cursor: default;"+ - "background-color: white;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdHiddenMsg, #KeymanWebControl #kmwico ul li a.kmw_disabled span#KMW_KbdVisibleMsg {"+ - "display: none;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_show span#KMW_KbdVisibleMsg {"+ - "display: inline;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdHiddenMsg {"+ - "display: inline;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li a.kmw_hide span#KMW_KbdVisibleMsg {"+ - "display: none;"+ - "} "+ - - "#KeymanWebControl #kmwico ul li#KMW_ButtonUI_KbdIcon {"+ - "border-bottom: solid 1px #ad4a28;"+ - "} "; - - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading - ui.Initialize(); - -} catch(err){} - diff --git a/events/iuc38/Lao Roman/kmw/kmwuifloat.js b/events/iuc38/Lao Roman/kmw/kmwuifloat.js deleted file mode 100644 index 05b8c758..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwuifloat.js +++ /dev/null @@ -1,553 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/********************************/ -/* */ -/* Floating User Interface */ -/* */ -/********************************/ - -/** - * Do not enclose in an anonymous function, as the compiler may create - * global scope variables to replace true, false, null, which can collide - * with other variables. - * Instead, use the --output-wrapper command during optimization, which will - * add the anonymous function to enclose all code, including those optimized - * variables which would otherwise have global scope. - **/ - -try { - - // Declare KeymanWeb, OnScreen keyboard and Util objects - var keymanweb=window['tavultesoft']['keymanweb']; - var util=keymanweb['util']; - var osk=keymanweb['osk']; - var dbg=keymanweb['debug']; - - // Disable UI for touch devices - if(util['isTouchDevice']()) throw ''; - - // User interface global and local variables - keymanweb['ui'] = {}; - var ui=keymanweb['ui']; - ui['name'] = 'float'; - - ui.KeyboardSelector = null; - - ui.outerDiv = null; // replaces DivKeymanWeb - ui.innerDiv = null; // replaces Lkdiv - ui.oskButton = null; // toggles OSK on or off - ui.kbdIcon = null; // keyboard icon within OSK button - ui.selecting = false; // control focus behaviour during selection - ui.updateList = true; // control keyboard list updating - ui.updateTimer = null; // prevent unnecessary list refreshing - ui.floatRight = false; // align left by default - ui.initialized = false; // initialization flag - - /** - * Display or hide the OSK from the OSK icon link - */ - ui.toggleOSK = function() - { - keymanweb['focusLastActiveElement'](); - if(osk['show']) - { - if(osk['isEnabled']()) osk['hide'](); else osk['show'](true); - } - if(window.event) window.event.returnValue=false; - return false; - } - - /** - * Function Initialize - * Scope Private - * Description UI Initialization - **/ - ui.Initialize = function() - { - // Must always initialize after keymanWeb itself, otherwise options are undefined - if(!keymanweb['initialized']) - { - window.setTimeout(ui.Initialize,50); return; - } - - if(ui.initialized || util['isTouchDevice']()) return; - - var imgPath=util['getOption']('resources')+"ui/float/"; - - ui.outerDiv = util['createElement']('DIV'); // Container for UI (visible when KeymanWeb is active) - ui.innerDiv = util['createElement']('DIV'); // inner div for UI - ui.kbdIcon = util['createElement']('IMG'); - ui.outerDiv.innerHTML = "" - + "KeymanWeb"; /* I2081 */ - - var s=ui.outerDiv.style; - s.backgroundColor='white'; s.border='solid 1px black'; s.position='absolute'; s.height='18px'; - s.font='bold 8pt sans-serif'; s.display='none'; s.textAlign='left';s.overflow='hidden'; - - util['attachDOMEvent'](ui.outerDiv,'mousedown',ui._SelectorMouseDown); - util['attachDOMEvent'](ui.outerDiv,'mouseover',ui._SelectorMouseOver); - util['attachDOMEvent'](ui.outerDiv,'mouseout',ui._SelectorMouseOut); - - // Register keymanweb events - ui.registerEvents(); - - // I1476 - Handle SELECT overlapping BEGIN //todo***** make shim div local************** - if (window.createPopup && !('XmlHttpRequest' in window)) ui._Shim = util['createShim'](); - // I1476 - Handle SELECT overlapping END - - ui.kbdIcon.src = imgPath+'kbdicon.gif'; - ui.kbdIcon.title = 'Display visual keyboard'; - - // Set initial OSK button style (off by default) - ui.oskButtonState(false); - - var Lhdiv = util['createElement']('DIV'); - ui.oskButton = Lhdiv; - Lhdiv.onclick = ui.toggleOSK; - Lhdiv.appendChild(ui.kbdIcon); - ui.innerDiv.appendChild(Lhdiv); - ui.outerDiv.appendChild(ui.innerDiv); - document.body.appendChild(ui.outerDiv); - - if(ui._Shim) document.body.appendChild(ui._Shim); // I1476 - Handle SELECT overlapping - - ui.KeyboardSelector = util['createElement']('SELECT'); // ControlSelector - KeymanWeb keyboard selector - - s=ui.KeyboardSelector.style; - s.font='8pt sans-serif'; s.backgroundColor='#f3e5de'; s.border='solid 1px #7B9EBD'; s.height='16px';s.margin='1px 2px 0px 2px'; - s.left='20px'; s.top='0px'; s.position='absolute'; s.maxWidth='150px'; - - util['attachDOMEvent'](ui.KeyboardSelector,'change',ui.SelectKeyboardChange); - util['attachDOMEvent'](ui.KeyboardSelector,'blur',ui.SelectBlur); - - ui.innerDiv.appendChild(ui.KeyboardSelector); //this may need to be moved up.... - - // Check required interface alignment and default keyboard - var opt=util['getOption']('ui'),dfltKeyboard='English'; - if(typeof(opt) == 'object') - { - if(typeof(opt['position']) == 'string' && opt['position'] == 'right') - ui.floatRight = true; - if(typeof(opt['default']) == 'string') - dfltKeyboard = opt['default']; - } - - var Lopt = util['createElement']('OPTION'); - Lopt.value = '-'; - Lopt.innerHTML = dfltKeyboard; - ui.KeyboardSelector.appendChild(Lopt); - Lopt = null; - - // This must be set before updating the keyboard list to prevent recursion! - ui.initialized = true; - - // Update the keyboard list if required - ui.updateKeyboardList(); - - //may also want to initialize style sheet here ?? - } - - /** - * UI removal - resource cleanup - */ - keymanweb['addEventListener']('unloaduserinterface', - function() - { - ui.KeyboardSelector = ui.innerDiv = ui.outerDiv = ui.kbdIcon = null; - }); - - /** - * Update list of keyboards shown by UI - */ - ui.updateKeyboardList = function() - { - // Do nothing unless list requires updating - if(ui.updateList) - { - if(!ui.initialized) ui.Initialize(); - - // Remove current list (except for default element) - var i,opts=ui.KeyboardSelector.getElementsByTagName('OPTION'); - for(i=opts.length; i>1; i--) - { - ui.KeyboardSelector.removeChild(opts[i-1]); - } - - // Loop over installed keyboards and add to selection list - var Ln,Lopt,Lkbds=keymanweb['getKeyboards'](); - - for(Ln=0; Ln 1) ui.updateMenu(sk[0],sk[1]); - }); - - /** - * Keyboard change event handler - * - * Update menu selection and control OSK display appropriately - */ - keymanweb['addEventListener']('keyboardchange', - function(p) - { - // Update the keyboard selector whenever a keyboard is loaded - ui.updateMenu(p['internalName'],p['languageCode']); - - // (Conditionally) display the OSK button, and set the style - ui.addButtonOSK(); - }); - - /** - * Show OSK event handler: show or hide the OSK button (never display if a CJK keyboard) - */ - osk['addEventListener']('show', - function(oskPosition) - { - ui.addButtonOSK(); - return oskPosition; - }); - - /** - * Hide OSK event handler - */ - - osk['addEventListener']('hide', - function(hiddenByUser) - { - if(ui.initialized) ui.oskButtonState(false); - }); - } - - /** - * Function _SelectorMouseDown - * Scope Private - * @param {Object} e event - * Description Set KMW UI activation state on mouse click - */ - ui._SelectorMouseDown = function(e) - { - if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); - } - - /** - * Function _SelectorMouseOver - * Scope Private - * @param {Object} e event - * Description Set KMW UI activation state on mouse over - */ - ui._SelectorMouseOver = function(e) - { - if(keymanweb['activatingUI']) keymanweb['activatingUI'](1); - } - - /** - * Function _SelectorMouseOut - * Scope Private - * @param {Object} e event - * Description Clear KMW UI activation state on mouse out - */ - ui._SelectorMouseOut = function(e) - { - if(keymanweb['activatingUI']) keymanweb['activatingUI'](0); - } - - /** - * Function _SelectKeyboardChange - * Scope Private - * @param {Object} e event - * Description Change active keyboard in response to user selection event - */ - ui.SelectKeyboardChange = function(e) - { - if(ui.KeyboardSelector.value != '-') - { - var i=ui.KeyboardSelector.selectedIndex; - var t=ui.KeyboardSelector.options[i].value.split(':'); - keymanweb['setActiveKeyboard'](t[0],t[1]); - } - else - keymanweb['setActiveKeyboard'](''); - - //if(osk['show']) osk['show'](osk['isEnabled']()); handled by keyboard change event??? - keymanweb['focusLastActiveElement'](); - ui.selecting = true; - } - - /** - * Function _SelectBlur - * Scope Private - * @param {Object} e event - * Description Ensure OSK is hidden when moving focus after reselecting a keyboard - */ - ui.SelectBlur = function(e) - { - if(!ui.selecting) keymanweb['focusLastActiveElement'](); - ui.selecting = false; - } - - /** - * Function ShowInterface - * Scope Private - * @param {number=} Px x-position for KMW window - * @param {number=} Py y-position for KMW window - * Description Display KMW window at specified position - */ - ui.ShowInterface = function(Px, Py) - { - if(!ui.initialized) return; - - var Ls = ui.outerDiv.style; - - if(Px && Py) { - Ls.left = Px + 'px'; - Ls.top = Py + 'px'; - } - Ls.display = 'block'; - - ui.kbdIcon.style.left = ui.KeyboardSelector.offsetWidth + 24 + 'px'; - - // (Conditionally) display the OSK button - ui.addButtonOSK(); - - // Set the language selection to the currently active keyboard, if listed - ui.updateMenu(keymanweb['getActiveKeyboard'](),keymanweb['getActiveLanguage']()); - } - - /** - * Function HideInterface - * Scope Private - * Description Completely hide KMW window - */ - ui.HideInterface = function() - { - if(!ui.initialized) return; - - ui.outerDiv.style.display = 'none'; - util['hideShim'](ui._Shim); // I1476 - Handle SELECT overlapping - } - - - /** - * Function addButtonOSK - * Scope Private - * Description Display the OSK button unless a CJK keyboard (or English) - */ - ui.addButtonOSK = function() - { - if(ui.oskButton != null) - { - if(keymanweb['isCJK']() || (ui.KeyboardSelector.selectedIndex==0)) - { - ui.oskButton.style.display = 'none'; - ui.outerDiv.style.width = ui.KeyboardSelector.offsetWidth+30+'px'; - } - else - { - ui.oskButton.style.display = 'block'; - ui.oskButtonState(osk['isEnabled']()); - ui.outerDiv.style.width = ui.KeyboardSelector.offsetWidth+56+'px'; - } - } - } - //TODO: had to expose properties of params - what does that do? (focus event doesn't normally include these properties?) - keymanweb['addEventListener']('controlfocused', - function(params) - { - if(params['activeControl'] == null || params['activeControl']['LEnabled']) - { - /*if(keymanweb._IsIEEditableIframe(Ltarg)) - Ltarg = Ltarg.ownerDocument.parentWindow.frameElement; - else if(keymanweb._IsMozillaEditableIframe(Ltarg)) - Ltarg = Ltarg.defaultView.frameElement;*/ - if(ui.floatRight) // I1296 - ui.ShowInterface(util['getAbsoluteX'](params.target) + params.target.offsetWidth + 1, util['getAbsoluteY'](params.target) + 1); - else - ui.ShowInterface(util['getAbsoluteX'](params.target), util['getAbsoluteY'](params.target) - - parseInt(util['getStyleValue'](ui.outerDiv,'height'),10) - 2); - } - return true; - }); - - /** - * Function oncontrolblurred - * Scope Public - * @param {Object} params event object - * @return {boolean} - * Description UI code to be executed on losing focus - */ - keymanweb['addEventListener']('controlblurred', - function(params) - { - if(!params['event']) return true; // I2404 - Manage IE events in IFRAMEs - - if(!params['isActivating']) ui.HideInterface(); - - return true; - }); - - /** - * Function _Resize - * Scope Private - * @param {Object} e event object - * @return {boolean} - * Description Display KMW OSK at specified position (returns nothing) - */ - ui._Resize = function(e) - { - if(ui.outerDiv.style.display =='block') - { - var elem = keymanweb['getLastActiveElement'](); - if(ui.floatRight) // I1296 - ui.ShowInterface(util['getAbsoluteX'](elem) + elem.offsetWidth + 1, util['getAbsoluteY'](elem) + 1); - else - ui.ShowInterface(util['getAbsoluteX'](elem) + 1, util['getAbsoluteY'](elem) + elem.offsetHeight + 1); - } - return true; - } - - if(window.addEventListener) - window.addEventListener('resize', ui._Resize, false); - else - window.attachEvent('onresize', ui._Resize); - - // Initialize after KMW is fully initialized, if UI already loaded - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - - // but also call initialization when script loaded, which is after KMW initialization for asynchronous script loading - ui.Initialize(); - -} catch(err){} - -// Do not wrap in an anonymous function - let the closure compiler do that, but -// use try...catch to avoid script errors and only execute if a desktop browser diff --git a/events/iuc38/Lao Roman/kmw/kmwuitoggle.js b/events/iuc38/Lao Roman/kmw/kmwuitoggle.js deleted file mode 100644 index 0529a044..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwuitoggle.js +++ /dev/null @@ -1,743 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/********************************/ -/* */ -/* Toggle User Interface Code */ -/* */ -/********************************/ - -/** - * Do not enclose in an anonymous function, as the compiler may create - * global scope variables to replace true, false, null, which may collide - * with other variables. - * Instead, use the --output-wrapper command during optimization, which will - * add the anonymous function to enclose all code, including those optimized - * variables which would otherwise have global scope. - **/ - -try { - - // Declare KeymanWeb, OnScreen Keyboard and Util objects - var keymanweb=window['tavultesoft']['keymanweb'],osk=keymanweb['osk'],util=keymanweb['util']; - var dbg=keymanweb['debug']; - - // Disable UI for touch devices - if(util['isTouchDevice']()) throw ''; - - // Initialize user interface common variables - var ui=keymanweb['ui'] = { - name: 'toggle', - initialized: false, - shim: null, - controller: null, - oskButton: null, - kbdButton: null, - controllerHovered: false, - keyboards: [], - lastActiveKeyboard: -1, - selectedMenuItem: null, - updateList: true, - updateTimer: null - } - - /** - * Update the KeymanWeb user interface when an input element is focused or blurred - * - * @param {Object} someElement focused element - * @param {(boolean|number)} focusing true if focusing - */ - ui.doFocus = function(someElement,focusing) - { - // This callback must be ignored until UI is initialized, or for touch devices (which can never initialize the UI) - if(!ui.initialized) return; - - if(window.event) someElement=window.event.srcElement; - - if(focusing) - { - ui.controller.style.display = 'block'; - } - else - { - if(!(keymanweb['getUIState']()['activationPending']) && !ui.controllerHovered) - { - ui.controller.style.display = 'none'; - } - } - - /* I2406 - Find an appropriate position for the controller */ - var x, y, w, h, p; - - p = util['getAbsolute'](someElement); x = p['x']; y=p['y']; - if(someElement.parentWindow && someElement.parentWindow.frameElement) - { - w = someElement.parentWindow.frameElement.clientWidth; - h = someElement.parentWindow.frameElement.clientHeight; - } - else if(someElement.defaultView && someElement.defaultView.frameElement) - { - w = someElement.defaultView.frameElement.clientWidth; - h = someElement.defaultView.frameElement.clientHeight; - } - else - { - w = someElement.offsetWidth; - h = someElement.offsetHeight; - } - if(x + w > (window.clientWidth?window.clientWidth:window.innerWidth) + document.documentElement.scrollLeft - ui.controller.offsetWidth - 1) - y += h; - else - { - x += w + 2; - //y += h - ui.controller.offsetHeight - 1; // ui.controller.offsetheight is returned as its prior value, which results in incorrect UI positioning - // so better to set the offset absolutely JMD 11/2/11 - y += h - 29; //prevent UI being positioned *above* the top of the element - } - - if(isNaN(x) || isNaN(y)) return; - ui.controller.style.left = x + 'px'; - ui.controller.style.top = y + 'px'; - } - - keymanweb['addEventListener']('controlfocused',function(params){ui.doFocus(params.target,true);}); - keymanweb['addEventListener']('controlblurred',function(params){ui.doFocus(params.target,false);}); - - osk['addEventListener']('show', - function(oskPosition) - { - // Ensure that the ui.controller is visible if help is displayed - ui.controller.style.display = 'block'; - ui.oskButton._setSelected(true); - -/* The following is probably not needed for KMW2, since OSK position is set by KMW, not by the UI - //TODO: This may not be correct - may need to refer to userLocated argument, not function??? - // Check if OSK position is user-defined, return if so - if (osk['userLocated']()) return oskPosition; - - // Otherwise, return the position with respect to the focussed element - var someElement = keymanweb['getLastActiveElement'](), x, y, w, h, p; - if(someElement != null) - { - p = util['getAbsolute'](someElement); x = p['x']; y = p['y']; - if(someElement.parentWindow && someElement.parentWindow.frameElement) - { - w = someElement.parentWindow.frameElement.clientWidth; - h = someElement.parentWindow.frameElement.clientHeight; - } - else if(someElement.defaultView && someElement.defaultView.frameElement) - { - w = someElement.defaultView.frameElement.clientWidth; - h = someElement.defaultView.frameElement.clientHeight; - } - else - { - w = someElement.offsetWidth; - h = someElement.offsetHeight; - } - //TODO: check the logic of this - it doesn't look right!!! Signs on top, height?? - var r = osk['getRect'](); - x += 32; - if(y + h + (r.height - r.top) > (window.clientHeight?window.clientHeight:window.innerHeight) + document.documentElement.scrollTop && - y - (r.height - r.top) >= document.documentElement.scrollTop) - { - y -= (r.height - r.top); - } - else - y += h; - } - else - { - x = ui.controller.offsetLeft; - y = ui.controller.offsetTop + ui.controller.offsetHeight; - } - oskPosition['x'] = x; - oskPosition['y'] = y; -*/ - return oskPosition; - }); - - osk['addEventListener']('hide', - function(byUser) - { - if(byUser['HiddenByUser']) ui.oskButton._setSelected(false); - }); - - /** - * Toggle the on screen keyboard display - KMW button control event - **/ - ui.switchOsk = function() - { - // Check that user control of OSK is allowed - if((keymanweb['getActiveKeyboard']() == '') || keymanweb['isCJK']() ) return; - - osk['show'](!osk['isEnabled']()); - } - - /** - * Toggle a single keyboard on or off - KMW button control event - **/ - ui.switchSingleKbd = function() - { - var _v = (keymanweb['getActiveKeyboard']() == ''),nLastKbd=0,kbdName='',lgCode=''; - if(_v) - { - if(ui.keyboards.length == 0) return; - if(ui.lastActiveKeyboard < ui.keyboards.length && ui.lastActiveKeyboard >= 0) nLastKbd = ui.lastActiveKeyboard; - kbdName = ui.keyboards[nLastKbd]._InternalName; - lgCode = ui.keyboards[nLastKbd]._LanguageCode; - keymanweb['setActiveKeyboard'](kbdName,lgCode); - ui.lastActiveKeyboard = nLastKbd; - } - else - { - keymanweb['setActiveKeyboard'](''); - } - if(ui.kbdButton) ui.kbdButton._setSelected(_v); - } - - /** - * Switch to the next keyboard in the list - KMW button control event - **/ - ui.switchNextKbd = function() - { - var _v = (keymanweb['getActiveKeyboard']() == ''),kbdName='',lgCode=''; - if(_v) - { - if(ui.keyboards.length == 0) return; - kbdName = ui.keyboards[0]._InternalName; - lgCode = ui.keyboards[0]._LanguageCode; - keymanweb['setActiveKeyboard'](kbdName,lgCode); - ui.lastActiveKeyboard = 0; - } - else - { - if(ui.lastActiveKeyboard == ui.keyboards.length-1) - { - keymanweb['setActiveKeyboard'](''); - _v = false; - } - else - { - kbdName = ui.keyboards[++ui.lastActiveKeyboard]._InternalName; - lgCode = ui.keyboards[ui.lastActiveKeyboard]._LanguageCode; - keymanweb['setActiveKeyboard'](kbdName,lgCode); - _v = true; - } - } - if(ui.kbdButton) ui.kbdButton._setSelected(_v); - } - - /** - * Create a button object for KeymanWeb UI buttons - * - * @constructor - * @param {string} _src - * @param {string} _caption - * @param {boolean} _selected - * @return {Object} - **/ - ui.button = function(_src, _caption, _selected) - { - this._onclick = null; - this._onmouseover = null; - this._onmouseout = null; - this._elem = null; - this._down = false; - this._over = false; - this._selected = _selected; - - /*public*/ this.getElem = function() - { - return this._owningObject._elem; - }; - - /*private*/ this.__updatestyle = function() - { - var ss=this._owningObject._elem.style; - if(this._owningObject._over) - { - ss.margin = '0px'; - if(this._owningObject._selected) { - ss.border = 'solid 1px #ad4a28'; - ss.background = '#dfb4b4'; - } - else { - ss.border = 'solid 1px #dfb4b4'; - ss.background = '#f3e5de'; - } - } - else if(this._owningObject._selected) - { - ss.background = '#f3e5de'; - ss.margin = '0px'; - ss.border = 'solid 1px #ad4a28'; - } - else - { - ss.background = 'none'; - ss.margin = '1px'; - ss.border = 'none'; - } - }; - - /*private*/ this.__mouseover = function() - { - ui.controllerHovered = true; - this._owningObject._over = true; - if(this._owningObject._onmouseover != null) this._owningObject._onmouseover(); - this._owningObject.__updatestyle(); - }; - - /*private*/ this.__mouseout = function() - { - ui.controllerHovered = false; - this._owningObject._over = false; - if(this._owningObject._onmouseout != null) this._owningObject._onmouseout(); - this._owningObject.__updatestyle(); - }; - - /*private*/ this.__click = function() - { - keymanweb['activatingUI'](false); // Clear activating UI flag once click is acknowledged - if(this._owningObject._onclick != null) - return this._owningObject._onclick(); - return false; - }; - - /*private*/ this.__mousedown = function() - { - keymanweb['activatingUI'](true); // Set activating UI flag (to manage focus/blur) on any UI mouse down event - this._owningObject._down = true; - this._owningObject.__updatestyle(); - return false; - }; - - /*private*/ this.__mouseup = function() - { - this._owningObject._down = false; - this._owningObject.__updatestyle(); - }; - - /*public*/ this._setSelected = function(_value) - { - keymanweb['activatingUI'](false); // Always clear activating UI flag after selecting UI - this._owningObject._selected = _value; - this._owningObject.__updatestyle(); - }; - - /*public*/ this._getSelected = function() - { - return this._owningObject._selected; - }; - - /*public*/ this._getOver = function() - { - return this._owningObject._over; - }; - - /*public*/ this._getDown = function() - { - return this._owningObject._down; - }; - - this._owningObject = this; // simplifies meaning of 'this' - - var imgPath=util['getOption']('resources') + 'ui/toggle/'; - var _elemImg = util['createElement']('img'); - this._elem = util['createElement']('div'); - this._elem._owningObject = this; - _elemImg.style.display = 'block'; - _elemImg.src = imgPath + _src; - _elemImg.id = 'KMW_Controller_Img'; - this._elem.style.margin = '0px'; //display = 'inline'; - this._elem.style.width = '24px'; - this._elem.style.height = '24px'; - this._elem.style.zIndex = '10002'; - this._elem.style.lineHeight = '100%'; - this._elem.style.styleFloat = this._elem.style.cssFloat = 'left'; - - _elemImg.title = _caption; - _elemImg.alt = _caption; - this._elem.appendChild(_elemImg); - this._elem.onmouseover = this.__mouseover; - this._elem.onmouseout = this.__mouseout; - this._elem.onmousedown = this.__mousedown; - this._elem.onmouseup = this.__mouseup; - _elemImg._owningObject = this; - _elemImg.onclick = this.__click; - - this.__updatestyle(); - - return this; - }; - - /** - * Function Initialize - * Scope Private - * Description Initialize Toggle User Interface - **/ - ui['initialize'] = ui.Initialize = function() - { - //Never initialize before KMW! - if(!keymanweb['initialized'] || util['isTouchDevice']()) return; - - if(!ui.initialized) // I2403 - Allow toggle design to be loaded twice - { - ui.controller = util['createElement']('div'); - } - else - ui.controller.innerHTML = ''; // I2403 - Allow toggle design to be loaded twice - - var imgPath = util['getOption']('resources')+'ui/toggle/'; - ui.controller.style.background = 'url('+imgPath+'kmwcontroller2x.gif)'; - ui.controller.style.padding = '1px 2px'; - - // Create keyboard list and OSK control buttones, and set initial styles - var v1=util['loadCookie']('KeymanWeb_Keyboard'),kbdEnabledOnLoad=false; - if(typeof(v1['current'])!='undefined') kbdEnabledOnLoad = (v1['current'].indexOf('---') < 0); - ui.kbdButton = new ui.button('kmw_logo_16.gif', 'Use Web Keyboard', kbdEnabledOnLoad); - ui.controller.appendChild(ui.kbdButton.getElem()); - - var v2 = util['loadCookie']('KeymanWeb_OnScreenKeyboard'),oskEnabledOnLoad=true; - if(typeof(v2['visible'])!='undefined') oskEnabledOnLoad=(v2['visible'] == 1); - - // Add keyboard icon - ui.oskButton = new ui.button('kmw_osk_16.gif','Show On Screen Keyboard',oskEnabledOnLoad); - ui.oskButton._onclick = ui.switchOsk; - ui.controller.appendChild(ui.oskButton.getElem()); - - // Hide controller unless already initialized - if(!ui.initialized) ui.controller.style.display = 'none'; - ui.controller.style.zIndex = '10001'; - ui.controller.style.position = 'absolute'; - - // The following three lines prevent the UI from being positioned incorrectly when the page is resized, - // but don't fix the problem completely, as the kbd icon still moves. probably need to insert a DIV - // between the button and the container, and make that DIV fixed height and overflow:hidden - //ui.controller.style.maxHeight = '26px'; - //ui.oskButton.getElem().style.position = 'relative'; - //ui.oskButton.getElem().style.overflow = 'hidden'; - - if(!ui.initialized) // I2403 - Allow toggle design to be loaded more than once if necessary - document.body.appendChild(ui.controller); - - // Set initialized true - ui.initialized = true; // I2403 - Allow toggle design to be loaded more than once if needed - - // Then update the keyboard list if keyboards already loaded (i.e. in page script) - ui.updateKeyboardList(); - - } - - /** - * Function updateKeyboardList - * Scope Private - * Description Rebuild the UI and keyboard list - **/ - ui.updateKeyboardList=function() - { - if(!(keymanweb['initialized'] || ui.initialized)) return; //TODO: may want to restart the timer?? - - ui.updateList = false; - - var _kbds=keymanweb['getKeyboards'](),imgPath=util['getOption']('resources') +'ui/toggle/'; - - // Check the number of installed keyboards to determine whether or not we will have a dropdown - if(_kbds.length > 1) - { - // Multiple keyboards - var _kmw_ctrl_img=document.getElementById('KMW_Controller_Img') - _kmw_ctrl_img.src = imgPath+'kmw_logo_16_down.gif'; - _kmw_ctrl_img.style.width = '100%'; - - ui.controller.style.background = 'url('+imgPath+'kmwcontroller2x.gif)'; - - ui.kbdButton.getElem().id = 'kmwico'; - ui.kbdButton.getElem().style.width = '36px'; - ui.kbdButton._onmouseover = function() - { - ui.keyboardMenu.className="sfhover"; - if(ui.shim) - { - var ss=ui.shim.style; - ss.left = ui.keyboardMenu.style.left; - ss.top = ui.keyboardMenu.style.top; - ss.width = ui.keyboardMenu.offsetWidth+"px"; - ss.height = ui.keyboardMenu.offsetHeight+"px"; - ss.zIndex = ui.keyboardMenu.style.zIndex-1; - ss.display = 'block'; - } - }; - ui.kbdButton._onmouseout = function() - { - ui.keyboardMenu.className="sfunhover"; - if(ui.shim) ui.shim.style.display = 'none'; - }; - ui.kbdButton._onclick = null; - ui.createMenu(); - } - // Single keyboard - else if(_kbds.length == 1) - { - var Lki=_kbds[0]['InternalName']; - var Lklc=_kbds[0]['LanguageCode']; - ui.controller.style.background = 'url('+imgPath+'kmwcontroller2.gif)'; - ui.keyboards.push({_InternalName: Lki, _LanguageCode: Lklc, _Index: 0}); - ui.kbdButton._onclick = ui.switchSingleKbd; - // Must remove menu if keyboards have been removed leaving only a single keyboard - if(typeof(ui.keyboardMenu) != 'undefined') delete ui.keyboardMenu; - } - - // Highlight the last active keyboard - var sk=keymanweb['getSavedKeyboard']().split(':'); - ui.updateMenu(sk[0],sk[1]); - } - - /** - * Keyboard registration event handler - * - * Set a timer to update the UI keyboard list on timeout after each keyboard is registered, - * thus updating only once when only if multiple keyboards are registered together - */ - keymanweb['addEventListener']('keyboardregistered', - function(p) - { - ui.updateList = true; - if(ui.updateTimer) clearTimeout(ui.updateTimer); - ui.updateTimer = setTimeout(ui.updateKeyboardList,200); - }); - - - /** - * Keyboard change event handler - * - * Update menu selection and control OSK display appropriately - */ - keymanweb['addEventListener']('keyboardchange', - function(p) - { - ui.updateMenu(p['internalName'],p['languageCode']); - }); - - /* ---------------------------------------- - Drop down menu - ---------------------------------------- */ - -// var _SelectedMenuItem; - - /** - * Function selecKbd - * Scope Private - * @param {number} _kbd - * Description Select a keyboard from the drop down menu - **/ - ui.selectKbd = function(_kbd) - { - var _name,_lgCode,_index; - if(_kbd < 0) - { - _name = ''; _lgCode='';_index = ''; - } - else - { - _name = ui.keyboards[_kbd]._InternalName; _lgCode = ui.keyboards[_kbd]._LanguageCode; _index = ui.keyboards[_kbd]._Index; - } - keymanweb['setActiveKeyboard'](_name,_lgCode); - keymanweb['focusLastActiveElement'](); - ui.kbdButton._setSelected(_name != ''); - if(_kbd >= 0) ui.lastActiveKeyboard = _kbd; - - return false; - }; - - /** - * Function updateMenu - * Scope Private - * @param {string} kbdName - * @param {?string=} lgCode - * Description Updates the menu selection when a change is required - **/ - ui.updateMenu = function(kbdName,lgCode) - { - var i,_k=document.getElementById('KMWSel_$'); - - for(i=0; i 299 ? '300px' : 'auto');}" : "")+ - ".sfunhover#KeymanWeb_KbdList {"+ - "display: none; left: -999px;"+ - "}"+ - ".sfhover#KeymanWeb_KbdList {"+ - "display: block;"+ - "left: auto;"+ - "}"+ - "#KeymanWeb_KbdList li {"+ - "float: none;"+ - "width: auto;"+ - "padding: 0;"+ - "margin: 0;"+ - "text-align: left;"+ - "}"+ - "#KeymanWeb_KbdList li a {"+ - "display: block; "+ - "padding: 2px 4px;"+ - "color: #404040;"+ - "font-family: Tahoma,Verdana,Arial,sans-serif;"+ - "font-size: 8pt;"+ - "text-decoration: none;"+ - "}"+ - "#KeymanWeb_KbdList li a.selected {"+ - "font-weight: bold;"+ - "color: black;"+ - "}"+ - "#KeymanWeb_KbdList li a:hover {"+ - "color: white;"+ - "background-color: #ad4a28;"+ - "text-decoration: underline;"+ - "}"); - - /** - * Function createMenu - * Scope Private - * Description Create the drop down menu and populate with loaded KeymanWeb keyboards - **/ - ui.createMenu = function() - { - if(typeof(ui.keyboardMenu) == 'undefined') // I2403 - Allow toggle design to be loaded twice - { - if (window.createPopup && !('XmlHttpRequest' in window)) - { - ui.shim = util['createElement']('iframe'); - ui.shim.src = ''; - ui.shim.style.display = 'none'; - ui.shim.style.position = 'absolute'; - ui.shim.style.filter = 'progidXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; - ui.shim.frameBorder = '0'; - ui.shim.scrolling = 'no'; - ui.kbdButton.getElem().appendChild(ui.shim); - } - - ui.keyboardMenu=util['createElement']('ul'); - ui.keyboardMenu.id='KeymanWeb_KbdList'; - ui.keyboardMenu.className='sfunhover'; - } - else ui.keyboardMenu.innerHTML = ''; // I2403 - Allow toggle design to be loaded twice - - var _li=util['createElement']('li'); - var _a=util['createElement']('a'); - _a.innerHTML='English'; - _a.href="#"; - _a.onclick = function() { return ui.selectKbd(-1); }; - _a.id='KMWSel_$'; - _a.className='selected'; - _li.appendChild(_a); - - ui.selectedMenuItem=_a; - ui.keyboardMenu.appendChild(_li); - - var _kbds=keymanweb['getKeyboards'](), _added=[]; - ui.keyboards=[]; - for(var _kbd = 0; _kbd < _kbds.length; _kbd++) - { - var _li1=util['createElement']('li'); - var _a1=util['createElement']('a'); - _a1.innerHTML=_kbds[_kbd]['LanguageName'] + ' - ' + _kbds[_kbd]['Name']; - if(!_added[_kbds[_kbd]['InternalName']]) _added[_kbds[_kbd]['InternalName']]=0; - _added[_kbds[_kbd]['InternalName']]++; - - var _n=_added[_kbds[_kbd]['InternalName']]; - ui.keyboards.push({_InternalName: _kbds[_kbd]['InternalName'], _LanguageCode:_kbds[_kbd]['LanguageCode'], _Index: _n}); - - _a1.href="#"; - _a1.onclick = (function(x) { return function() { return ui.selectKbd(x); } })(ui.keyboards.length-1); - _a1.id='KMWSel_'+_kbds[_kbd]['InternalName']+'$'+_n; - - _li1.appendChild(_a1); - ui.keyboardMenu.appendChild(_li1); - } - - //if(!ui.initialized) // I2403 - Allow toggle design to be loaded twice - if(ui.keyboardMenu.parentNode != ui.kbdButton.getElem()) ui.kbdButton.getElem().appendChild(ui.keyboardMenu); - }; - - keymanweb['addHotKey'](191,0x20,ui.switchSingleKbd); - keymanweb['addHotKey'](191,0x30,ui.switchNextKbd); - keymanweb['addHotKey'](191,0x40,ui.switchOsk); - - // Initialize after KMW is fully initialized - keymanweb['addEventListener']('loaduserinterface',ui.Initialize); - - // but also execute here, for asynchronous UI script loading (occurring after KMW initialization) - ui.Initialize(); - -} catch(ex){} - diff --git a/events/iuc38/Lao Roman/kmw/kmwuitoolbar.js b/events/iuc38/Lao Roman/kmw/kmwuitoolbar.js deleted file mode 100644 index 76dfe3b5..00000000 --- a/events/iuc38/Lao Roman/kmw/kmwuitoolbar.js +++ /dev/null @@ -1,1149 +0,0 @@ -/*** - KeymanWeb 2.0 - Copyright 2014 Tavultesoft Pty Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -***/ - -/********************************/ -/* */ -/* Toolbar User Interface */ -/* */ -/********************************/ - -/** - * Do not enclose in an anonymous function, as the compiler may create - * global scope variables to replace true, false, null, which can collide - * with other variables. - * Instead, use the --output-wrapper command during optimization, which will - * add the anonymous function to enclose all code, including those optimized - * variables which would otherwise have global scope. - **/ - -try { - - // Declare KeymanWeb, OnScreen keyboard and Util objects - var keymanweb=window['tavultesoft']['keymanweb'],osk=keymanweb['osk'],util=keymanweb['util'],dbg=keymanweb['debug']; - - // Disable UI for touch devices - if(util['isTouchDevice']()) throw ''; - - // User interface local variables - keymanweb['ui'] = { - init: false, - toolbarNode: null, - backgroundNode: null, - browseMapNode: null, - keyboardsButtonNode: null, - languageButtonsNode: null, - offButtonNode: null, - offBarNode: null, - oskButtonNode: null, - oskBarNode: null, - selectorNode: null, - regionLanguageListNodes: [], - regionNodes: null, - langKeyboardNodes: [], - langKeyboardListNodes: [], - selectedRegion: 'as', - listedKeyboards: [], - keyboardListPriority: 0, - maxListedKeyboards: 1, - lastActiveControl: null, - selectedKeyboard: null, - selectedLanguage: '', - helpOffsetX: 0, - helpOffsetY: 0, - languages: [], // array of objects { id: , name: , keyboards: } - updateMap: false, // flag to control re-initialization of keyboard map - startTimer: 0, // initialization timer - wait 2 seconds after last stub installed then initialize map - lgText: '' // language name in toolbar - } - - // User Interface object - var ui=keymanweb['ui']; - ui['name'] = 'toolbar'; - - ui.ToolBar_Text = { - Keyboards: 'Languages', - OffTitle: 'Turn off KeymanWeb keyboards', - Off: 'Off', - ShowOSK: 'Show On Screen Keyboard', - LanguageSelector: 'Select language' - }; - - ui.ToolBar_Text['SelectKeyboardPre']='Select '; - ui.ToolBar_Text['SelectKeyboardSuf']='keyboard'; - ui.ToolBar_Text['AltKeyboardsPre']='Alternate keyboards for '; - ui.ToolBar_Text['AltKeyboardsSuf']=''; - - ui.ToolBar_Text['ca']='Central America'; - ui.ToolBar_Text['sa']='South America'; - ui.ToolBar_Text['na']='North America'; - ui.ToolBar_Text['eu']='Europe'; - ui.ToolBar_Text['af']='Africa'; - ui.ToolBar_Text['me']='Middle east'; - ui.ToolBar_Text['as']='Asia'; - ui.ToolBar_Text['oc']='Oceania'; - - - var controller=document.getElementById('KeymanWebControl'); - /** - * Create some of the controls but don't insert them into the document yet - * This does not need or want to prevent loss of focus, so uses document.createElement - * rather than util.createElement. - * - * @param {string} tag - * @param {?string=} id - * @param {?string=} className - * @param {string=} innerHTML - * @return {Node|null} - */ - ui.createNode = function(tag, id, className, innerHTML) - { - //var node = util['createElement'](tag); - var node = document.createElement(tag); - if(id) node.id = id; - if(className) node.className = className; - if(innerHTML) node.innerHTML = innerHTML; - - // The following is OK for IE and for F3.5 and later - should simply be ignored for others - // first tried preventDefault() as suggested by many on web, which worked but interfered with keyboard and OSK enabling - if(tag == 'a' || tag == 'area' || tag == 'map') node.ondragstart = function(){return false;} - return node; - } - - /** - * Initialize toolbar UI - */ - ui['initialize'] = ui.initToolbarUI = function() - { - if(!keymanweb['initialized'] || ui.init) return; - - // Find the controller DIV, insert at top of body if undefined - var e = document.getElementById('KeymanWebControl'); - if(!e) - { - if(document.body == null) - return; - else - { - e=document.createElement('DIV'); - e.id='KeymanWebControl'; - document.body.insertBefore(e,document.body.firstChild); - } - } - - // Hide toolbar until elements fully drawn, to prevent spurious text displays - e.style.visibility='hidden'; e.style.maxHeight='35px'; - - ui.init = true; - - if(util['isTouchDevice']()) return; - - util['linkStyleSheet'](util['getOption']('resources')+'ui/toolbar/kmwuitoolbar.css'); - - ui.regions = {}; - ui.regions['ca'] = {t: ui.ToolBar_Text['ca'], m: '49,52,65,54,68,57,71,56,73,59,75,60,93,61,94,58,97,58,101,59,107,60,114,64,115,68,114,77,104,74,98,75,96,78,95,82,90,81,85,80,82,76,78,74,74,73,65,68,57,61' }, - ui.regions['sa'] = {t: ui.ToolBar_Text['sa'], m: '82,82,95,82,96,78,98,75,104,74,114,77,120,79,124,83,126,87,141,90,142,97,138,103,135,113,127,116,123,124,115,131,112,132,109,138,117,139,140,141,141,146,134,148,114,145,109,148,100,148,91,143,91,130,96,111,89,102,83,95,77,89' }, - ui.regions['na'] = {t: ui.ToolBar_Text['na'], m: '0,3,0,37,24,32,35,37,43,47,49,52,65,54,68,57,71,56,73,59,75,60,93,61,93,57,103,49,118,41,126,41,136,23,148,17,156,14,164,5,164,0,57,0,35,5,25,9,5,8' }, - ui.regions['eu'] = {t: ui.ToolBar_Text['eu'], m: '145,29,146,19,158,14,171,6,187,2,206,1,217,4,227,11,231,16,231,33,227,34,225,35,225,37,227,39,228,44,228,47,227,48,223,46,218,44,215,43,208,43,203,45,202,48,205,52,201,52,195,49,189,50,187,48,177,48,175,49,166,50,147,33' }, - ui.regions['af'] = {t: ui.ToolBar_Text['af'], m: '150,58,158,50,166,50,175,49,177,48,187,48,189,50,195,49,201,52,205,52,207,53,221,75,229,75,231,77,231,85,227,92,232,101,237,106,237,112,227,115,222,118,206,125,199,127,193,127,185,111,183,104,180,87,168,89,153,85,143,71,147,60' }, - ui.regions['me'] = {t: ui.ToolBar_Text['me'], m: '205,52,202,48,203,45,208,43,215,43,218,44,223,46,227,48,232,48,239,48,240,49,239,53,242,60,243,65,237,76,231,77,229,75,221,75,207,53' }, - ui.regions['as'] = {t: ui.ToolBar_Text['as'], m: '219,1,221,6,228,12,231,16,231,33,227,34,225,35,225,37,227,39,229,45,232,48,239,48,240,49,239,53,242,60,243,65,249,70,252,81,259,87,271,87,278,95,289,100,303,101,311,98,320,98,323,98,323,84,311,81,308,73,307,65,317,57,330,50,334,44,348,36,364,38,375,34,375,8,355,8,336,5,292,1,285,0,219,0' }, - ui.regions['oc'] = {t: ui.ToolBar_Text['oc'], m: '288,117,289,107,303,101,311,98,323,98,323,84,333,77,344,73,362,80,369,88,375,96,375,141,352,143,323,142,316,136,310,130,291,130' } - - ui.toolbarNode = ui.createNode('div', 'kmw_controls'); - ui.toolbarNode.style.display='block'; - - var tbNode = ui.createNode('a', 'kmw_controls_start', null, ' '); - //tbNode.href = "http://keyman.com/web/"; - tbNode.href = "http://tavultesoft.com/keymanweb/"; // TODO: change link URL to keyman.com/web as soon as page is ready - tbNode.target="_blank"; - ui.toolbarNode.appendChild(tbNode); - - /* Keyboards button */ - ui.keyboardsButtonNode = ui.createNode('div','kmw_btn_keyboards','kmw_button'); - ui.keyboardsButtonNode.title=ui.ToolBar_Text.LanguageSelector; - var aNode = ui.createNode('a', null, 'kmw_button_a'); - aNode.href='#'; - aNode.onclick = ui.showKeyboardsPopup; - aNode.appendChild(ui.createNode('div', 'kmw_img_keyboards', 'kmw_img')); - aNode.appendChild(ui.createNode('div', null, 'kmw_a', ui.ToolBar_Text.Keyboards)); - aNode.appendChild(ui.createNode('div', null, 'kmw_drop')); - ui.keyboardsButtonNode.appendChild(aNode); - - /* Keyboards popup */ - ui.selectorNode = ui.createNode('div', 'kmw_selector'); - ui.regionsNode = ui.createNode('div', 'kmw_selector_regions'); - var imgNode; - ui.browseMapNode = ui.createNode('div', 'kmw_browsemap'); - imgNode = ui.createNode('img', 'kmw_region_browsemap'); - imgNode.src= util['getOption']('resources')+'ui/toolbar/blank.gif'; - imgNode.useMap = '#kmw_worldgrey16'; - ui.browseMapNode.appendChild(imgNode); - - var areaNode, mapNode = ui.createNode('map', 'kmw_worldgrey16'); - mapNode.name='kmw_worldgrey16'; - for(var i in ui.regions) - { - areaNode = ui.createNode('area'); - areaNode.shape = 'poly'; - areaNode.alt = ''; - areaNode.href = '#'; - areaNode.title = ui.regions[i].t; - areaNode.hidefocus = 'true'; - areaNode.onclick = (function(i) { return function(event) { return ui.selectRegion(event, i); } })(i); - areaNode.onmouseover = (function(i) { return function(event) { return ui.hoverRegion(event, i); } })(i); - areaNode.onmouseout = (function(i) { return function(event) { return ui.unhoverRegion(event, i); } })(i); - areaNode.coords = ui.regions[i].m; - mapNode.appendChild(areaNode); - } - - areaNode = ui.createNode('area'); - areaNode.shape = 'default'; - areaNode.nohref = 'true'; - areaNode.alt = ''; - areaNode.onclick=ui.eventCapture; // do not close map when clicking on ocean! - mapNode.appendChild(areaNode); - ui.browseMapNode.appendChild(mapNode); - ui.regionsNode.appendChild(ui.browseMapNode); - ui.regionNodes = []; - - var listNode = ui.createNode('ul'); - for(i in ui.regions) - { - var itemNode = ui.createNode('li'); - ui.regionNodes[i] = ui.createNode('a', null, null, ui.regions[i].t); - ui.regionNodes[i].href='#'; - ui.regionNodes[i].onclick = (function(i) { return function(event) { return ui.selectRegion(event, i); } })(i); - ui.regionNodes[i].onmouseover = (function(i) { return function(event) { return ui.hoverRegion(event, i); } })(i); - ui.regionNodes[i].onmouseout = (function(i) { return function(event) { return ui.unhoverRegion(event, i); } })(i); - itemNode.appendChild(ui.regionNodes[i]); - listNode.appendChild(itemNode); - } - ui.regionsNode.appendChild(listNode); - ui.selectorNode.appendChild(ui.regionsNode); - ui.keyboardsButtonNode.appendChild(ui.selectorNode); - ui.toolbarNode.appendChild(ui.keyboardsButtonNode); - - // Separator and Keyboard Off Button - ui.toolbarNode.appendChild(ui.offBarNode = ui.createNode('div', 'kmw_bar_off', 'kmw_bar')); - - ui.offButtonNode = ui.createNode('div', 'kmw_btn_off', 'kmw_button_selected'); - aNode = ui.createNode('a', null, 'kmw_button_a'); - aNode.href = '#'; - aNode.onclick = ui.offButtonClickEvent; - aNode.title = ui.ToolBar_Text.OffTitle; - aNode.appendChild(ui.createNode('div', 'kmw_img_off', 'kmw_img')); - aNode.appendChild(ui.createNode('div', null, 'kmw_a', ui.ToolBar_Text.Off)); - ui.offButtonNode.appendChild(aNode); - ui.toolbarNode.appendChild(ui.offButtonNode); - - // Keyboard buttons - ui.toolbarNode.appendChild(ui.languageButtonsNode = ui.createNode('div', 'kmw_control_keyboards', 'kmw_button')); - - // Separator and On Screen Keyboard Button - ui.toolbarNode.appendChild(ui.oskBarNode = ui.createNode('div', 'kmw_bar_osk', 'kmw_bar')); - - ui.oskButtonNode = ui.createNode('div', 'kmw_btn_osk', 'kmw_button');//was 'kmw_button_selected' - aNode = ui.createNode('a', null, 'kmw_button_a'); - aNode.href = '#'; - aNode.onclick = ui.showOSK; - aNode.title = ui.ToolBar_Text.ShowOSK; - aNode.appendChild(ui.createNode('div', 'kmw_img_osk', 'kmw_img')); - //aNode.appendChild(ui.createNode('div', null, 'kmw_a', 'On Screen Keyboard')); - ui.oskButtonNode.appendChild(aNode); - ui.toolbarNode.appendChild(ui.oskButtonNode); - - ui.toolbarNode.appendChild(ui.createNode('div', 'kmw_controls_end', null, ' ')); - - var img = ui.createNode('div'); - img.id = 'kmw_map_preload'; - ui.toolbarNode.appendChild(img); - - ui.toolbarNode.appendChild(ui.createNode('br', null, 'kmw_clear')); - - // Append toolbar node to controller - e.appendChild(ui.toolbarNode); - - // Initialize map array, using a timer to allow restarting if necessary after keyboards loaded - // Note that toolbar will be displayed and enabled on completion of timeout routine - ui.updateMap = true; - if(ui.startTimer) clearTimeout(ui.startTimer); - ui.startTimer = setTimeout(ui.addKeyboardsToMap,2000); - - // Ensure that popups are hidden by clicking elsewhere on document - util['attachDOMEvent'](document.body,'click',ui.hideAllPopups,false); - - // Set Europe to be the default region - ui.selectedRegion = 'eu'; - - // Restore focus - keymanweb['focusLastActiveElement'](); - } - - /** - * Fill the map with available keyboards when the Keyboards selector is clicked - * after all keyboard stubs have been registered - **/ - ui.addKeyboardsToMap = function() - { - // Do nothing unless a keyboard has been installed since map created - if(ui.updateMap) ui.updateMap=false; else return; - - var n = 0; - ui.regionLanguageListNodes = []; - - // Build list of keyboards by region and language - var Keyboards = keymanweb['getKeyboards'](); - - // Sort the keyboards by region and language - Keyboards.sort(ui.sortKeyboards); - - // Always rebuild the map, so remove any previously created language lists - for(n=ui.regionsNode.childNodes.length; n>0; n--) - { - if(ui.regionsNode.childNodes[n-1].className == 'kmw_selector_region') - { - ui.regionsNode.removeChild(ui.regionsNode.childNodes[n-1]); - } - } - - for(var i in ui.regions) - { - - ui.regionLanguageListNodes[i] = ui.createNode('div', null, 'kmw_selector_region'); - var colNode = ui.createNode('div', null, 'kmw_keyboard_col'); - var max = 0, count = 0, languageCode = ''; - - // Get number of languages for the region - for(var j=0; j 0) - { - ui.regionLanguageListNodes[i].appendChild(colNode); - colNode = ui.createNode('div', null, count/max == 3 ? 'kmw_keyboard_col_right' : 'kmw_keyboard_col'); - } - count++; - - // Add the language to the column - var langNode = ui.createNode('div', null, 'kmw_language'); - var aNode = ui.createNode('a', null, null, Keyboards[j]['LanguageName']); - aNode.href='#'; - aNode.onclick = (function(lang) { return function(event) { return ui.selectLanguage(event, lang); }; })(ui.languages[languageCode]); - langNode.appendChild(aNode); - colNode.appendChild(langNode); - - n++; - } - // Finish the last column and close the list - ui.regionLanguageListNodes[i].appendChild(colNode); - ui.regionLanguageListNodes[i].appendChild(ui.createNode('div', null, 'kmw_clear')); - ui.regionsNode.appendChild(ui.regionLanguageListNodes[i]); - } - ui.loadCookie(); - - // Ensure that the correct region has been selected - ui.selectRegion(null, ui.selectedRegion); - ui.enableControls(); - - // Restore focus - keymanweb['focusLastActiveElement'](); - - } - - /** - * Sort keyboards array returned from keymanweb by region and language - * - * @param {Object} a - * @param {Object} b - * @return {number} - **/ - ui.sortKeyboards = function(a,b) - { - if(a['RegionCode'] < b['RegionCode']) return -2; - if(a['RegionCode'] > b['RegionCode']) return 2; - if(a['LanguageName'] < b['LanguageName']) return -1; - if(a['LanguageName'] > b['LanguageName']) return 1; - return 0; - } - - /* KeymanWeb Interfaces */ - - /** - * Function findListedKeyboard - * Scope Private - * @param {Object} lang - * @return {?number} - * Description Test if a keyboard is still shown on the toolbar. Returns index of keyboard in listedKeyboards or null if not found - */ - ui.findListedKeyboard = function(lang) - { - for(var i = 0; i < ui.listedKeyboards.length; i++) - if(ui.listedKeyboards[i].lang.id == lang.id) return i; - return null; - } - - /** - * Add a keyboard to the list of keyboards available for a language - * - * @param {Object} lang - * @param {Object} kbd - **/ - ui.addKeyboardToList = function(lang,kbd) - { - var found = ui.findListedKeyboard(lang); - if(found == null) - { - // Add the button - if(ui.listedKeyboards.length >= ui.maxListedKeyboards) - { - var oldestPriority = 0x7fffffff, oldestFound = null; - - for(var i = 0; i < ui.listedKeyboards.length; i++) - if(ui.listedKeyboards[i].priority < oldestPriority) - { - oldestFound = i; - oldestPriority = ui.listedKeyboards[i].priority; - } - - // delete the oldest used control - if(oldestFound != null) - { - var rk = ui.listedKeyboards[oldestFound]; - ui.langKeyboardListNodes[rk.lang.id] = null; - ui.langKeyboardNodes[rk.lang.id] = null; - ui.languageButtonsNode.removeChild(rk.buttonNode); - if(oldestFound == 0) - ui.listedKeyboards = ui.listedKeyboards.slice(oldestFound + 1); - else if(oldestFound == ui.listedKeyboards.length - 1) - ui.listedKeyboards = ui.listedKeyboards.slice(0, oldestFound); - else - ui.listedKeyboards = ui.listedKeyboards.slice(0, oldestFound).concat(ui.listedKeyboards.slice(oldestFound+1)); - } - } - var buttonNode = ui.createNode('div', null/*'kmw_button_keyboard_'+lang.id*/, 'kmw_button'); - var aNode = ui.createNode('a', null, 'kmw_button_a'+(lang.keyboards.length>1 ? ' kmw_norightgap' : '')); - aNode.href='#'; - - var p1=ui.ToolBar_Text['SelectKeyboardPre']+kbd['Name'],p2=ui.ToolBar_Text['SelectKeyboardSuf']; - if(p1.toLowerCase().indexOf(p2.toLowerCase()) < 0) p1=p1+' '+ p2; - aNode.title = p1; - aNode.onclick = function(event) { return ui.selectLanguage(event, lang) }; - aNode.appendChild(ui.createNode('div', 'kmw_img_kbd', 'kmw_img')); - - ui.lgText=ui.truncate(lang.name,28); - aNode.appendChild(ui.createNode('div', null, 'kmw_a', ui.lgText)); - buttonNode.appendChild(aNode); - - var thisANode = aNode; - - if(lang.keyboards.length > 1) { - aNode = ui.createNode('a', null, 'kmw_button_a kmw_noleftgap'); - aNode.href = '#'; - aNode.title = ui.ToolBar_Text['AltKeyboardsPre']+lang.name+ui.ToolBar_Text['AltKeyboardsSuf']; - aNode.onclick = function(event) { return ui.showKeyboardsForLanguage(event, lang) }; - var divNode = ui.createNode('div', null, 'kmw_a'); - var kbdText=ui.truncate(kbd['Name'].replace(/\s?keyboard/i,''),40-ui.lgText.length); - divNode.appendChild(ui.langKeyboardNodes[lang.id] = ui.createNode('span', null, 'kmw_kbd', kbdText)); - aNode.appendChild(divNode); - aNode.appendChild(ui.createNode('div', null, 'kmw_drop')); - buttonNode.appendChild(aNode); - - ui.langKeyboardListNodes[lang.id] = ui.createNode('ul', null, 'kmw_selector_kbd'); - ui.langKeyboardListNodes[lang.id].style.display='none'; - - for(var n in lang.keyboards) { - var itemNode = ui.createNode('li'); - kbdText = lang.keyboards[n]['Name'].replace(/\s?keyboard/i,''); - aNode = ui.createNode('a', null, null, kbdText); - aNode.href = '#'; - aNode.title = ''; - aNode.onclick = (function(lang,kbd) { return function(event) { return ui.selectKeyboard(event, lang, kbd); } })(lang, lang.keyboards[n]); - - itemNode.appendChild(aNode); - ui.langKeyboardListNodes[lang.id].appendChild(itemNode); - } - buttonNode.appendChild(ui.langKeyboardListNodes[lang.id]); - } - - ui.languageButtonsNode.appendChild(buttonNode); - - var thisLang = lang, thisButtonNode = buttonNode; - ui.listedKeyboards.push({priority: ui.keyboardListPriority++, lang:thisLang, keyboard:kbd, buttonNode:thisButtonNode, aNode:thisANode}); - } - else - { - ui.listedKeyboards[found].priority = ui.keyboardListPriority++; - ui.listedKeyboards[found].keyboard = kbd; - var e = ui.langKeyboardNodes[lang.id]; - if(e) - { - var kbdText=kbd['Name'].replace(/\s?keyboard/i,''); - e.innerHTML = ui.truncate(kbdText,40-ui.lgText.length); - } - if(ui.listedKeyboards[found].aNode) - { - var p1=ui.ToolBar_Text['SelectKeyboardPre']+kbd['Name'],p2=ui.ToolBar_Text['SelectKeyboardSuf']; - if(p1.toLowerCase().indexOf(p2.toLowerCase()) < 0) p1=p1+' '+ p2; - ui.listedKeyboards[found].aNode.title = p1; - } - } - } - - /** - * Truncate a long name and add an ellipsis - * - * @param {string} PName string that may need to be truncated - * @param {number} PLen max non-truncated length - * @return {string} string, truncated with ellipsis if necessary - * - **/ - ui.truncate = function(PName,PLen) - { - if(PName.length <=PLen) return PName; - return PName.substr(0,PLen-1)+'\u2026'; - } - - /** - * Rebuild the entire keyboard list whenever a keyboard is installed - * (without necessarily loading the keyboard) - * - * @param {Object} p Keyboard metadata object - **/ - ui.registerKeyboard = function(p) - { - ui.updateMap = true; - if(ui.startTimer) clearTimeout(ui.startTimer); - ui.startTimer = setTimeout(ui.addKeyboardsToMap,2000); - } - keymanweb['addEventListener']('keyboardregistered',ui.registerKeyboard); - - var keyboardsForLangPopup = null; - - /** - * Function hideKeyboardsForLanguage - * Scope Private - * @param {Object} event - * @return {boolean} - * Description Hide the list of keyboards for this language - **/ - ui.hideKeyboardsForLanguage = function(event) - { - var e = ui.keyboardsForLangPopup; - if(e) e.style.display='none'; - ui.CancelPopupDismissal(ui.hideKeyboardsForLanguage); - return ui.eventCapture(event); - } - - /** - * Display the list of keyboards for this language - * - * @param {Object} event - * @param {Object} lang - * @return {boolean} - * - **/ - ui.showKeyboardsForLanguage = function(event, lang) - { - ui.hideKeyboardsPopup(event); - var e = ui.langKeyboardListNodes[lang.id]; - if(e) - { - if(e.style.display=='block') return ui.hideKeyboardsForLanguage(event); - e.style.display='block'; - ui.keyboardsForLangPopup = e; - ui.SetupPopupDismissal(e, ui.hideKeyboardsForLanguage); - } - return ui.eventCapture(event); - } - - /** - * Select the language, and either select the keyboard (if unique) or display the list of keyboards - * available for this language - * - * @param {Object} event - * @param {Object} lang - * @return {boolean} - **/ - ui.selectLanguage = function(event, lang) - { - var found=ui.findListedKeyboard(lang), kbd = null; - - if(found == null) - kbd = lang.keyboards[0]; - else - kbd = ui.listedKeyboards[found].keyboard; - if(!kbd) return false; - - return ui.selectKeyboard(event,lang,kbd); - } - - /** - * Enable a selected keyboard - * - * @param {Object} event - * @param {Object} lang - * @param {Object} kbd - * @return {boolean} - **/ - ui.selectKeyboard = function(event,lang,kbd) - { - if(ui.selectedLanguage) - { - var found = ui.findListedKeyboard(ui.selectedLanguage); - if(found != null) ui.listedKeyboards[found].buttonNode.className = 'kmw_button'; - } - ui.offButtonNode.className = 'kmw_button'; - ui.selectedLanguage = lang; - ui.selectedKeyboard = kbd; - ui.SelectedLanguage = lang.id; - // Return focus to input area and activate the selected keyboard - ui.setLastFocus(); //*****this seems out of sequence??? - ui.addKeyboardToList(lang,kbd); - keymanweb['setActiveKeyboard'](kbd['InternalName'],lang.id); - ui.listedKeyboards[ui.findListedKeyboard(lang)].buttonNode.className = 'kmw_button_selected'; - - // Always save current state when selecting a keyboard - ui.saveCookie(); - ui.enableControls(); - return ui.hideKeyboardsPopup(event) || ui.hideKeyboardsForLanguage(event); - } - - /** - * Enable all UI controls - * - * @return {boolean} - **/ - ui.enableControls = function() - { - var elems=[ui.offButtonNode, ui.offBarNode, ui.oskButtonNode, ui.oskBarNode],hideOskButton=false; - - if(keymanweb['isCJK'](ui.selectedKeyboard)) hideOskButton = true; - else if(ui.selectedKeyboard == null) hideOskButton = (elems[2].style.display == 'none') - - if(ui.selectedKeyboard != null || ui.listedKeyboards.length > 0) - { - for(var i = 0; i < elems.length; i++) - elems[i].style.display=''; - } - else - { - for(var i = 0; i < elems.length; i++) - elems[i].style.display='none'; - } - - if(hideOskButton) - ui.oskButtonNode.style.display = ui.oskBarNode.style.display = 'none'; - - else if(ui.selectedKeyboard == null) - ui.oskButtonNode.className='kmw_button_disabled'; - //else - // ui.oskButtonNode.className=(osk && osk['isEnabled']() ? 'kmw_button_selected' : 'kmw_button'); - - // Display the toolbar if still hidden - ui.toolbarNode.parentNode.style.visibility='visible'; - return true; - } - - /** - * Restore the focus to the last focused element - **/ - ui.setLastFocus = function() - { - keymanweb['focusLastActiveElement'](); - } - - /** - * Display or hide the OSK according to user control. This will always force - * the focus to the last active element if currently unfocused, which is - * preferable to not having the OSK appear when the OSK button is clicked. - * - * @param {Object} event - * @return {boolean} - **/ - ui.showOSK = function(event) - { - //Toggle OSK on or off - if(osk && keymanweb['getActiveKeyboard']() != '') - { - if(osk['isEnabled']()) osk['hide'](); else osk['show'](true); - } - ui.setLastFocus(); - return ui.eventCapture(event); - } - - /** - * Function offButtonClickEvent - * Scope Private - * @param {Object} event - * @return {boolean} - * Description Update the UI when all keyboards disabled by user - **/ - ui.offButtonClickEvent = function(event) - { - if(ui.toolbarNode.className != 'kmw_controls_disabled') - { - ui.hideKeyboardsForLanguage(null); - if(ui.selectedLanguage) - { - var found = ui.findListedKeyboard(ui.selectedLanguage); - if(found != null) ui.listedKeyboards[found].buttonNode.className = 'kmw_button'; - } - ui.selectedKeyboard = null; - ui.selectedLanguage = null; - ui.SelectedLanguage = ''; - ui.offButtonNode.className = 'kmw_button_selected'; - } - // Return the focus to the input area and set the active keyboard to nothing - ui.setLastFocus(); - keymanweb['setActiveKeyboard']('',''); - - //Save current state when deselecting a keyboard (may not be needed) - ui.saveCookie(); - ui.enableControls(); - return ui.eventCapture(event); - } - - /** - * Function eventCapture - * Scope Private - * @param {Object} event - * @return {boolean} - * Description Browser-independent event capture - **/ - ui.eventCapture = function(event) - { - if(!event) event = window.event; - if(window.event) window.event.returnValue = false; - if(event) event.cancelBubble = true; - - return false; - } - - /** - * Function selectRegion - * Scope Private - * @param {Object} event - * @param {string} region - * @return {boolean} - * Description Select the region for which to list languages - **/ - ui.selectRegion = function(event, region) - { - var e = ui.browseMapNode; - if(!e) return ui.eventCapture(event); - e.className = 'kmw_browsemap_'+region; - if(typeof(ui.regionLanguageListNodes[region]) == 'undefined') - { - ui.updateMap = true; ui.addKeyboardsToMap(); - } - ui.regionLanguageListNodes[region].style.display='block'; - ui.regionNodes[region].className='selected'; - if(ui.selectedRegion != null && ui.selectedRegion != region) - { - ui.regionLanguageListNodes[ui.selectedRegion].style.display='none'; - ui.regionNodes[ui.selectedRegion].className=''; - } - ui.selectedRegion = region; - //ui.saveCookie(); - return ui.eventCapture(event); - } - - /** - * Function unhoverRegion - * Scope Private - * @param {Object} event - * @param {string} region - * @return {boolean} - * Description Remove highlighting from a region - **/ - ui.unhoverRegion = function(event, region) - { - ui.browseMapNode.className = (ui.selectedRegion == null ? '' : 'kmw_browsemap_'+ui.selectedRegion); - ui.regionNodes[region].className=(ui.selectedRegion==region?'selected':''); - return ui.eventCapture(event); - } - - /** - * Function hoverRegion - * Scope Private - * @param {Object} event - * @param {string} region - * @return {boolean} - * Description Highlight a hovered region - **/ - ui.hoverRegion = function(event, region) - { - ui.browseMapNode.className = 'kmw_browsemap_'+region+'_sel'; - ui.regionNodes[region].className='hover'; - return ui.eventCapture(event); - } - - /** - * Function pluck - * Scope Private - * @param {Object} elem - * @param {string} property - * @return {*} - * Description Get the value of an element property - **/ - ui.pluck = function(elem, property) { - return elem.getAttribute ? elem.getAttribute(property) || elem[property] : elem[property]; - }; - - /** - * Function focusControlEvent - * Scope Private - * @param {Object} params Object containing Target element (or frame) - * @return {boolean} - * Description UI code to be executed on receiving focus - */ - ui.focusControlEvent = function(params) - { - if(!ui.init) return true; - - var t=params.target; - if(t.tagName.toLowerCase() == 'textarea' || (t.tagName.toLowerCase() == 'input' && t.type.toLowerCase() == 'text')) - { - ui.lastActiveControl = t; - if(ui.pluck(t, 'kmw_disable')) - { - if(ui.toolbarNode.className != 'kmw_controls_disabled') - ui.toolbarNode.className = 'kmw_controls_disabled'; - } - else - { - if(ui.selectedKeyboard != null) - { - if(keymanweb['isCJK']()) - { - ui.oskButtonNode.style.display = ui.oskBarNode.style.display = 'none'; - } - else - { - ui.oskButtonNode.className = (osk && osk['isEnabled']()) ? 'kmw_button_selected' : 'kmw_button'; - } - } - - if(ui.toolbarNode.className != '') ui.toolbarNode.className = ''; - - var offsetX, offsetY; - if(t.KMW_HelpOffsetX) offsetX = t.KMW_HelpOffsetX; else offsetX = 64; - if(t.KMW_HelpOffsetY) offsetY = t.KMW_HelpOffsetY; else offsetY = 0; - ui.helpOffsetX = util['getAbsoluteX'](t)+offsetX; - ui.helpOffsetY = util['getAbsoluteY'](t)+t.offsetHeight+offsetY; - } - } - return true; - } - keymanweb['addEventListener']('controlfocused',ui.focusControlEvent); - - /** - * Function oncontrolblurred - * Scope Private - * Parameters {Object} params Object containing event - * @return {boolean} - * Description UI code to be executed on losing focus - */ - ui.blurControlEvent = function(params) - { - if(!ui.init) return true; - - // Must disable OSK button when not focused - if(ui.oskButtonNode.style.display != 'none') ui.oskButtonNode.className='kmw_button_disabled'; - - if(!params.event) return true; // I2404 - Manage IE events in IFRAMEs - return true; - } - keymanweb['addEventListener']('controlblurred',ui.blurControlEvent); - - - /** - * UI action required when keyboard changed indirectly - * - * @param {Object} p keyboard selection object - * @return {boolean} - **/ - ui.changeKeyboardEvent = function(p) - { - if(p['indirect']) - { - var kbName=p['internalName'], - lgName=p['languageCode']; - if(lgName != '' && kbName != '') - { - var lg = ui.languages[lgName]; - if(lg != null) - { - for(var j=0; j