diff --git a/.github/workflows/core-arm64-windows-test.yml b/.github/workflows/core-arm64-windows-test.yml index 0eb4e8f8f6..76d273de22 100644 --- a/.github/workflows/core-arm64-windows-test.yml +++ b/.github/workflows/core-arm64-windows-test.yml @@ -119,7 +119,7 @@ jobs: - name: Install meson shell: bash run: | - pip3 install --user meson==1.10.1 + pip3 install --user meson==1.11.0 - name: Run test shell: bash diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index ee7fe7d03d..9eb25a49e7 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Update labels based on changed files - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 + uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" - name: Update labels based on PR title id: labeler - uses: fuxingloh/multi-labeler@f5bd7323b53b0833c1e4ed8d7b797ae995ef75b4 # v2.0.1 + uses: fuxingloh/multi-labeler@bcd50af464202999e57f556b4aefcf05a34abf85 # v5.0.0 with: github-token: ${{secrets.GITHUB_TOKEN}} config-path: .github/multi-labeler.yml diff --git a/HISTORY.md b/HISTORY.md index 462bb9a48d..f2d3cab56b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,48 @@ # Keyman Version History +## 19.0.247 alpha 2026-06-16 + +* chore: update multi-labeler to 5.0.0 (#16100) + +## 19.0.246 alpha 2026-06-15 + +* feat(developer): run project validation from IDE (#16076) +* fix(core): use meson subsystem and needs_exe_wrapper for cross builds on Windows (#16088) +* docs(windows): add context documentation for additional Advanced options (#16089) + +## 19.0.245 alpha 2026-06-10 + +* chore(web): hide KMX keyboard test page (#16083) +* docs(web): remove unnecessary mentioning of Keyman 17 from docs (#16085) +* chore(web): remove outdated `*_load.js` files (#16086) +* fix(web): fix `KeyboardStub.validateForCustomKeyboard` (#16067) + +## 19.0.244 alpha 2026-06-09 + +* refactor(web): extract function, rename variables (#16063) +* refactor(web): reformatting of files (#16066) +* chore(web): improve the KeymanWeb integration documentation (#16064) +* chore(web): more improvements to documentation (#16070) + +## 19.0.243 alpha 2026-06-08 + +* fix(developer): reduce km_core_keyboard_attrs size to 12 (#16075) +* chore(deps): bump minimatch in /core/tests/unit/wasm (#16045) +* chore(deps): bump glob from 10.4.5 to 10.5.0 in /core/tests/unit/wasm (#16046) +* chore(deps-dev): bump js-yaml from 4.1.0 to 4.2.0 in /core/tests/unit/wasm (#16047) +* chore(deps-dev): bump picomatch from 2.3.1 to 2.3.2 in /core/tests/unit/wasm (#16048) +* chore(deps): bump qs and express (#16009) + +## 19.0.242 alpha 2026-06-03 + +* fix(web): fix displaying of keyboard menu (#16061) + +## 19.0.241 alpha 2026-06-02 + +* chore(web): web-core preflight - strip core references (#16040) +* docs: add note on how to use composer on dockerized websites (#16029) +* fix(web): fix race displaying active keyboard in menu (#16042) + ## 19.0.240 alpha 2026-05-28 * chore(web): add filename to link text of manual web tests (#16019) diff --git a/VERSION.md b/VERSION.md index e14cb86f3e..a0b5f4d5f2 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -19.0.241 \ No newline at end of file +19.0.248 \ No newline at end of file diff --git a/common/test/resources/keyboards/test_8568_deadkeys.html b/common/test/resources/keyboards/test_8568_deadkeys.html index 1b4cf31424..054f19b4f8 100644 --- a/common/test/resources/keyboards/test_8568_deadkeys.html +++ b/common/test/resources/keyboards/test_8568_deadkeys.html @@ -36,22 +36,20 @@ + }); + diff --git a/core/cross-arm64.build b/core/cross-arm64.build index 9fd7cc6d14..7bea64992e 100644 --- a/core/cross-arm64.build +++ b/core/cross-arm64.build @@ -1,5 +1,6 @@ [host_machine] system = 'windows' +subsystem = 'windows' cpu_family = 'aarch64' cpu = 'arm64' endian = 'little' diff --git a/core/cross-x64.build b/core/cross-x64.build index df3ab0b5dc..ecc0486e08 100644 --- a/core/cross-x64.build +++ b/core/cross-x64.build @@ -1,5 +1,6 @@ [host_machine] system = 'windows' +subsystem = 'windows' cpu_family = 'x86_64' cpu = 'x86_64' endian = 'little' @@ -11,3 +12,6 @@ ar = 'lib' ld = 'link' strip = 'llvm-strip' pkgconfig = 'pkg-config' + +[properties] +needs_exe_wrapper = false diff --git a/core/tests/unit/wasm/package-lock.json b/core/tests/unit/wasm/package-lock.json index f2c3485da5..b34e01caee 100644 --- a/core/tests/unit/wasm/package-lock.json +++ b/core/tests/unit/wasm/package-lock.json @@ -133,9 +133,9 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -538,9 +538,10 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -572,13 +573,13 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -710,10 +711,20 @@ } }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -770,9 +781,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -932,9 +943,9 @@ } }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { diff --git a/developer/docs/help/reference/kmc/cli/get-started.md b/developer/docs/help/reference/kmc/cli/get-started.md index 348bf4c4b9..2316abef38 100644 --- a/developer/docs/help/reference/kmc/cli/get-started.md +++ b/developer/docs/help/reference/kmc/cli/get-started.md @@ -110,7 +110,7 @@ hamburger menu in the Keyman app. **Web**: copy khmer_angkor.js to your website, then [load it with KeymanWeb][load-keymanweb-keyboard]: ```js -keyman.addKeyboards({ +await keyman.addKeyboards({ id:'khmer_angkor', // The keyboard's unique identification code. name:'Khmer Angkor', // The keyboard's user-readable name. language:{ diff --git a/developer/docs/help/reference/kmc/cli/reference.md b/developer/docs/help/reference/kmc/cli/reference.md index 1d5ed9fc20..662d85a0a3 100644 --- a/developer/docs/help/reference/kmc/cli/reference.md +++ b/developer/docs/help/reference/kmc/cli/reference.md @@ -198,6 +198,13 @@ The following parameters are available: project (which can also be controlled at a project level with the `skipMetadataFiles` option). This option is only valid for compiling projects. +`--publish-only` + +: Skip building component files within a project, and only run the validation + step. Must be combined with `--for-publishing` in order to have an effect. + This option is only valid for compiling projects, and is mostly intended for + use by the IDE. Will fail if build artifacts for components are not present. + ### Examples ```shell diff --git a/developer/src/kmc/README.md b/developer/src/kmc/README.md index 0490998e4d..05fd265a50 100644 --- a/developer/src/kmc/README.md +++ b/developer/src/kmc/README.md @@ -109,7 +109,7 @@ hamburger menu in the Keyman app. **Web**: copy khmer_angkor.js to your website, then [load it with KeymanWeb][load-keymanweb-keyboard]: ```js -keyman.addKeyboards({ +await keyman.addKeyboards({ id:'khmer_angkor', // The keyboard's unique identification code. name:'Khmer Angkor', // The keyboard's user-readable name. language:{ diff --git a/developer/src/kmc/src/commands/build.ts b/developer/src/kmc/src/commands/build.ts index 20f1092a9f..7e21f99f9c 100644 --- a/developer/src/kmc/src/commands/build.ts +++ b/developer/src/kmc/src/commands/build.ts @@ -35,6 +35,7 @@ export function declareBuild(program: Command) { buildCommand.command('file [infile...]', {isDefault: true}) .description(`Compile one or more source files or projects ('file' subcommand is default).`) .option('--for-publishing', 'Verify that project meets @keymanapp repository requirements') + .option('--publish-only', 'Only run the for-publishing validation, skip all other build steps') .addHelpText('after', ` Supported file types: * folder: Keyman project in folder diff --git a/developer/src/kmc/src/commands/buildClasses/BuildKeyboardInfo.ts b/developer/src/kmc/src/commands/buildClasses/BuildKeyboardInfo.ts index 3109038a3a..d3d42f9ce6 100644 --- a/developer/src/kmc/src/commands/buildClasses/BuildKeyboardInfo.ts +++ b/developer/src/kmc/src/commands/buildClasses/BuildKeyboardInfo.ts @@ -49,6 +49,7 @@ export class BuildKeyboardInfo extends BuildActivity { sourcePath: calculateSourcePath(infile), lastCommitDate, forPublishing: !!options.forPublishing, + publishOnly: !!options.publishOnly, }; // Note: should we always ignore the passed-in output filename for .keyboard_info? const outputFilename = project.getOutputFilePath(KeymanFileTypes.Binary.KeyboardInfo); diff --git a/developer/src/kmc/src/commands/buildClasses/BuildModelInfo.ts b/developer/src/kmc/src/commands/buildClasses/BuildModelInfo.ts index f6a44ced5f..7f641a9b8e 100644 --- a/developer/src/kmc/src/commands/buildClasses/BuildModelInfo.ts +++ b/developer/src/kmc/src/commands/buildClasses/BuildModelInfo.ts @@ -75,6 +75,7 @@ export class BuildModelInfo extends BuildActivity { kpsFilename: project.resolveInputFilePath(kps), lastCommitDate, forPublishing: !!options.forPublishing, + publishOnly: !!options.publishOnly, }; // Note: should we always ignore the passed-in output filename for .model_info? diff --git a/developer/src/kmc/src/commands/buildClasses/BuildProject.ts b/developer/src/kmc/src/commands/buildClasses/BuildProject.ts index 82e1347aa5..76fdfe1d04 100644 --- a/developer/src/kmc/src/commands/buildClasses/BuildProject.ts +++ b/developer/src/kmc/src/commands/buildClasses/BuildProject.ts @@ -51,15 +51,17 @@ class ProjectBuilder { } } - // Go through the various file types and build them - for(const builder of buildActivities) { - if(builder.sourceExtension == KeymanFileTypes.Source.Project) { - // We don't support nested projects - continue; - } + if(!this.options.publishOnly) { + // Go through the various file types and build them + for(const builder of buildActivities) { + if(builder.sourceExtension == KeymanFileTypes.Source.Project) { + // We don't support nested projects + continue; + } - if(!await this.buildProjectTargets(builder)) { - return false; + if(!await this.buildProjectTargets(builder)) { + return false; + } } } @@ -113,7 +115,11 @@ class ProjectBuilder { const buildFilename = path.relative(process.cwd(), infile).replace(/\\/g, '/'); const callbacks = new CompilerFileCallbacks(buildFilename, options, this.callbacks); - callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: infile, relativeFilename:buildFilename})); + if(activity.sourceExtension == KeymanFileTypes.Source.Project) { + callbacks.reportMessage(InfrastructureMessages.Info_ValidatingProject({filename: infile, relativeFilename:buildFilename})); + } else { + callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: infile, relativeFilename:buildFilename})); + } fs.mkdirSync(path.dirname(outfile), {recursive:true}); @@ -123,12 +129,19 @@ class ProjectBuilder { // note: command line option here, if set, overrides project setting result = result && !callbacks.hasFailureMessage(this.options.compilerWarningsAsErrors ?? this.project.options.compilerWarningsAsErrors); - if(result) { - callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: infile, relativeFilename:buildFilename})); + if(activity.sourceExtension == KeymanFileTypes.Source.Project) { + if(result) { + callbacks.reportMessage(InfrastructureMessages.Info_ProjectValidatedSuccessfully({filename: infile, relativeFilename:buildFilename})); + } else { + callbacks.reportMessage(InfrastructureMessages.Info_ProjectNotValidatedSuccessfully({filename: infile, relativeFilename:buildFilename})); + } } else { - callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: infile, relativeFilename: buildFilename})); + if(result) { + callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: infile, relativeFilename:buildFilename})); + } else { + callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: infile, relativeFilename: buildFilename})); + } } - return result; } diff --git a/developer/src/kmc/src/messages/infrastructureMessages.ts b/developer/src/kmc/src/messages/infrastructureMessages.ts index d384aa7d86..338af89073 100644 --- a/developer/src/kmc/src/messages/infrastructureMessages.ts +++ b/developer/src/kmc/src/messages/infrastructureMessages.ts @@ -197,5 +197,26 @@ export class InfrastructureMessages { `Failed to generate new project '${def(o.id)}'.`, )}); + // For this message, we override the filename with the passed-in file. A bit of a hack but does the job + static INFO_ValidatingProject = SevInfo | 0x0029; + static Info_ValidatingProject = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m( + this.INFO_ValidatingProject, + `Validating ${def(o.relativeFilename)}`, + )}); + + // For this message, we override the filename with the passed-in file. A bit of a hack but does the job + static INFO_ProjectValidatedSuccessfully = SevInfo | 0x002A; + static Info_ProjectValidatedSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m( + this.INFO_ProjectValidatedSuccessfully, + `${def(o.relativeFilename)} validated successfully.`, + )}); + + // For this message, we override the filename with the passed-in file. A bit of a hack but does the job + static INFO_ProjectNotValidatedSuccessfully = SevInfo | 0x002B; + static Info_ProjectNotValidatedSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m( + this.INFO_ProjectNotValidatedSuccessfully, + `${def(o.relativeFilename)} failed to validate.` + )}); + } diff --git a/developer/src/kmc/src/util/NodeCompilerCallbacks.ts b/developer/src/kmc/src/util/NodeCompilerCallbacks.ts index a92314aa5f..68209d95ce 100644 --- a/developer/src/kmc/src/util/NodeCompilerCallbacks.ts +++ b/developer/src/kmc/src/util/NodeCompilerCallbacks.ts @@ -242,22 +242,26 @@ export class NodeCompilerCallbacks implements CompilerCallbacks { * We treat a few certain infrastructure messages with special colours * @param event * @returns + * Keep in sync with: UfrmMessages.pas, TfrmMessages.Add */ messageSpecialColor(event: CompilerEvent) { switch(event.code) { case InfrastructureMessages.INFO_BuildingFile: case InfrastructureMessages.INFO_CopyingProject: case InfrastructureMessages.INFO_GeneratingProject: + case InfrastructureMessages.INFO_ValidatingProject: return color.whiteBright; case InfrastructureMessages.INFO_FileNotBuiltSuccessfully: case InfrastructureMessages.INFO_ProjectNotBuiltSuccessfully: case InfrastructureMessages.INFO_ProjectNotCopiedSuccessfully: case InfrastructureMessages.INFO_ProjectNotGeneratedSuccessfully: + case InfrastructureMessages.INFO_ProjectNotValidatedSuccessfully: return color.red; case InfrastructureMessages.INFO_FileBuiltSuccessfully: case InfrastructureMessages.INFO_ProjectBuiltSuccessfully: case InfrastructureMessages.INFO_ProjectCopiedSuccessfully: case InfrastructureMessages.INFO_ProjectGeneratedSuccessfully: + case InfrastructureMessages.INFO_ProjectValidatedSuccessfully: return color.green; } return null; diff --git a/developer/src/kmc/src/util/extendedCompilerOptions.ts b/developer/src/kmc/src/util/extendedCompilerOptions.ts index 53f68288f0..b94be88419 100644 --- a/developer/src/kmc/src/util/extendedCompilerOptions.ts +++ b/developer/src/kmc/src/util/extendedCompilerOptions.ts @@ -9,6 +9,12 @@ export interface ExtendedCompilerOptions extends CompilerOptions { * MIT */ forPublishing?: boolean; + /** + * Do not build components, just do the publish phase for the project. This is + * used mostly by Keyman Developer IDE, which will run the .keyboard_info / + * .package_info validation and compilation step if skipMetadataFiles is true. + */ + publishOnly?: boolean; /** * Overrides for message reporting */ @@ -198,6 +204,7 @@ export function commanderOptionsToCompilerOptions(options: any, callbacks: Compi warnDeprecatedCode: options.warnDeprecatedCode, // ExtendedOptions forPublishing: options.forPublishing, + publishOnly: options.publishOnly, messageOverrides: overrides, } } diff --git a/developer/src/server/package.json b/developer/src/server/package.json index 662be2add6..37c92b7f51 100644 --- a/developer/src/server/package.json +++ b/developer/src/server/package.json @@ -13,7 +13,7 @@ "@ngrok/ngrok": "^1.7.0", "@sentry/node": "^7.57.0", "chalk": "^4.1.2", - "express": "^4.22.1", + "express": "^4.22.2", "multer": "^2.1.1", "open": "^8.4.0", "restructure": "^3.0.1", diff --git a/developer/src/tike/compile/Keyman.Developer.System.KmcWrapper.pas b/developer/src/tike/compile/Keyman.Developer.System.KmcWrapper.pas index 168ea8c77d..6c33760ffc 100644 --- a/developer/src/tike/compile/Keyman.Developer.System.KmcWrapper.pas +++ b/developer/src/tike/compile/Keyman.Developer.System.KmcWrapper.pas @@ -17,6 +17,7 @@ type function Run(const parameters: TArray; const path, logFilename: string; Callback: TUtilExecuteCallbackEvent): Boolean; public function Compile(ProjectFile: TProjectFile; const infile, outfile: string; debug: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean; + function CompileForPublishing(ProjectFile: TProjectFile; const projectFilename: string; debug: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean; function Copy(const source, dest, cwd: string; relocateExternal: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean; end; @@ -39,6 +40,39 @@ uses { TKmcWrapper } +function TKmcWrapper.CompileForPublishing( + ProjectFile: TProjectFile; + const projectFilename: string; + debug: Boolean; + Callback: TUtilExecuteCallbackEvent +): Boolean; +var + cmdline: TArray; +begin + cmdline := [ + 'build', + '--log-format', 'tsv', + '--log-level', 'info', + '--for-publishing', + '--publish-only', + projectFilename + ]; + + if Assigned(FGlobalProject) and (FGlobalProject.Options.CompilerWarningsAsErrors) then + cmdline := cmdline + ['--compiler-warnings-as-errors'] + else + cmdline := cmdline + ['--no-compiler-warnings-as-errors']; + + if Assigned(FGlobalProject) and (not FGlobalProject.Options.WarnDeprecatedCode) then + cmdline := cmdline + ['--no-warn-deprecated-code']; + + if debug then + cmdline := cmdline + ['--debug']; + + Result := Run(cmdline, ExtractFileDir(projectFilename), projectFilename, Callback); +end; + + function TKmcWrapper.Compile( ProjectFile: TProjectFile; const infile: string; diff --git a/developer/src/tike/main/Keyman.System.KeymanCore.pas b/developer/src/tike/main/Keyman.System.KeymanCore.pas index 154032c059..89deb6ae6b 100644 --- a/developer/src/tike/main/Keyman.System.KeymanCore.pas +++ b/developer/src/tike/main/Keyman.System.KeymanCore.pas @@ -239,7 +239,7 @@ type km_core_keyboard_attrs = record version_string: pkm_core_cu; id: pkm_core_cu; - default_optons: pkm_core_option_item + default_options: pkm_core_option_item end; pkm_core_keyboard_attrs = ^km_core_keyboard_attrs; diff --git a/developer/src/tike/main/Keyman.System.KeymanCoreDebug.pas b/developer/src/tike/main/Keyman.System.KeymanCoreDebug.pas index 0b5600152b..3c90239173 100644 --- a/developer/src/tike/main/Keyman.System.KeymanCoreDebug.pas +++ b/developer/src/tike/main/Keyman.System.KeymanCoreDebug.pas @@ -186,7 +186,7 @@ initialization Assert(sizeof(km_core_context_item) = 8); Assert(sizeof(km_core_action_item) = 12); Assert(sizeof(km_core_option_item) = 12); - Assert(sizeof(km_core_keyboard_attrs) = 16); + Assert(sizeof(km_core_keyboard_attrs) = 12); Assert(sizeof(km_core_attr) = 16); //keyman_core_api_debug.h: diff --git a/developer/src/tike/main/UfrmMessages.pas b/developer/src/tike/main/UfrmMessages.pas index 9a76254c96..924bec9acd 100644 --- a/developer/src/tike/main/UfrmMessages.pas +++ b/developer/src/tike/main/UfrmMessages.pas @@ -170,6 +170,12 @@ const // ABGR - text on white bg, Colors similar to Light+ VSCode color theme INFO_FileNotBuiltSuccessfully = NAMESPACE_Infrastructure or $0007; INFO_ProjectBuiltSuccessfully = NAMESPACE_Infrastructure or $000B; INFO_ProjectNotBuiltSuccessfully = NAMESPACE_Infrastructure or $000C; + INFO_ProjectCopiedSuccessfully = NAMESPACE_Infrastructure or $0024; + INFO_ProjectNotCopiedSuccessfully = NAMESPACE_Infrastructure or $0025; + INFO_ProjectGeneratedSuccessfully = NAMESPACE_Infrastructure or $0027; + INFO_ProjectNotGeneratedSuccessfully = NAMESPACE_Infrastructure or $0028; + INFO_ProjectValidatedSuccessfully = NAMESPACE_Infrastructure or $002A; + INFO_ProjectNotValidatedSuccessfully = NAMESPACE_Infrastructure or $002B; Segment_Filename = 0; Segment_Filename_Separator = 1; @@ -254,12 +260,18 @@ begin FColor := clBlack; FTextColor := Color_Text; - // Override formatting for 4 known messages + // Override formatting for known messages -- keep in sync with messageSpecialColor() in NodeCompilerCallbacks.ts if (MsgCode = INFO_FileBuiltSuccessfully) or - (MsgCode = INFO_ProjectBuiltSuccessfully) then + (MsgCode = INFO_ProjectBuiltSuccessfully) or + (MsgCode = INFO_ProjectCopiedSuccessfully) or + (MsgCode = INFO_ProjectGeneratedSuccessfully) or + (MsgCode = INFO_ProjectValidatedSuccessfully) then state := plsSuccess else if (MsgCode = INFO_FileNotBuiltSuccessfully) or - (MsgCode = INFO_ProjectNotBuiltSuccessfully) then + (MsgCode = INFO_ProjectNotBuiltSuccessfully) or + (MsgCode = INFO_ProjectNotCopiedSuccessfully) or + (MsgCode = INFO_ProjectNotGeneratedSuccessfully) or + (MsgCode = INFO_ProjectNotValidatedSuccessfully) then state := plsFailure; case state of diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.kpsProjectFileAction.pas b/developer/src/tike/project/Keyman.Developer.System.Project.kpsProjectFileAction.pas index c7a7cafcc5..94cb28c151 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.kpsProjectFileAction.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.kpsProjectFileAction.pas @@ -29,6 +29,8 @@ begin w := TKmcWrapper.Create; try Result := w.Compile(Self, FileName, TargetFilename, False); + if not OwnerProject.Options.SkipMetadataFiles then + Result := Result and w.CompileForPublishing(Self, OwnerProject.FileName, False); // TODO(lowpri): FDebug flag finally w.Free; diff --git a/developer/src/tike/xml/help/contexthelp.xml b/developer/src/tike/xml/help/contexthelp.xml index 646496f5c7..7bada6adbf 100644 --- a/developer/src/tike/xml/help/contexthelp.xml +++ b/developer/src/tike/xml/help/contexthelp.xml @@ -419,11 +419,6 @@

Choose a help file to include in the keyboard

- -

Compiles the keyboard for KeymanWeb. Two output files will be generated: [filename].js and [filename]_load.js. The KeymanWeb Tutorial - contains more information about the difference between the two output files.

-
-

Tests your KeymanWeb keyboard in an Internet Explorer embedded window

diff --git a/package-lock.json b/package-lock.json index 421e381d88..8975f8c522 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1232,7 +1232,7 @@ "@ngrok/ngrok": "^1.7.0", "@sentry/node": "^7.57.0", "chalk": "^4.1.2", - "express": "^4.22.1", + "express": "^4.22.2", "multer": "^2.1.1", "open": "^8.4.0", "restructure": "^3.0.1", @@ -5301,22 +5301,23 @@ "license": "Apache-2.0" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -5327,6 +5328,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -5335,14 +5337,60 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/brace-expansion": { "version": "1.1.12", @@ -5600,6 +5648,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -6372,6 +6421,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -7832,14 +7882,14 @@ "dev": true }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", + "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", @@ -7858,7 +7908,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", @@ -7908,40 +7958,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/express/node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/express/node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -8666,6 +8682,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -11784,12 +11801,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -11844,6 +11861,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -12272,6 +12290,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12339,14 +12358,16 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14256,7 +14277,7 @@ "@sentry/cli": "^2.31.0", "@zip.js/zip.js": "^2.7.32", "c8": "^7.12.0", - "express": "^4.19.2", + "express": "^4.22.2", "jsdom": "^23.0.1", "promise-status-async": "^1.2.10", "tsx": "^4.19.0" diff --git a/web/docs/engine/guide/adding-keyboards.md b/web/docs/engine/guide/adding-keyboards.md index 221f495de1..957df80270 100644 --- a/web/docs/engine/guide/adding-keyboards.md +++ b/web/docs/engine/guide/adding-keyboards.md @@ -8,8 +8,8 @@ There are multiple ways to add and install keyboards into your KeymanWeb install The most efficient way to utilize a keyboard is to obtain a local copy of it and place this copy in a static location on your website. Once this is done, it can be directly linked into KeymanWeb as follows. -```c -keyman.addKeyboards({ +```typescript +await keyman.addKeyboards({ id:'us', // The keyboard's unique identification code. name:'English', // The keyboard's user-readable name. language:{ @@ -22,7 +22,7 @@ keyman.addKeyboards({ Custom fonts may also be utilized via the `language.font` property. For example: -```c +```typescript font:{ family:'LaoWeb', source:['../font/saysettha_web.ttf','../font/saysettha_web.woff','../font/saysettha_web.eot'] @@ -33,16 +33,16 @@ font:{ To obtain the default Keyman keyboard for a given language, call the following function. -```c -keyman.addKeyboardsForLanguage('Dzongkha'); +```typescript +await keyman.addKeyboardsForLanguage('Dzongkha'); ``` This example would find the default keyboard for the Dzongkha language. This method will fail if the name doesn't perfectly match any language found in the CDN's repository. Alternatively, languages may be looked up via their BCP 47 language code as follows: -```c -keyman.addKeyboards('@he') +```typescript +await keyman.addKeyboards('@he'); ``` The `@` prefix indicates the use of the BCP 47 language code, which in this case corresponds with Hebrew. @@ -51,8 +51,8 @@ The `@` prefix indicates the use of the BCP 47 language code, which in this case To obtain a specific keyboard by name or by keyboard name and language code as a pair, see the following: -```c -keyman.addKeyboards('french','sil_euro_latin@sv','sil_euro_latin@no') +```typescript +await keyman.addKeyboards('french', 'sil_euro_latin@sv', 'sil_euro_latin@no'); ``` This will install three keyboards - one for French (named, quite simply, "French") and two copies of the EuroLatin keyboard - one for Swedish and one for Norwegian. diff --git a/web/docs/engine/guide/examples/__auto-control.html b/web/docs/engine/guide/examples/__auto-control.html index 050e03a9f0..c2a8b472b0 100644 --- a/web/docs/engine/guide/examples/__auto-control.html +++ b/web/docs/engine/guide/examples/__auto-control.html @@ -1,20 +1,17 @@ + - - @@ -28,4 +25,4 @@ Back to Document - \ No newline at end of file + diff --git a/web/docs/engine/guide/examples/__control-by-control.html b/web/docs/engine/guide/examples/__control-by-control.html index 93a481a75f..f694b582ec 100644 --- a/web/docs/engine/guide/examples/__control-by-control.html +++ b/web/docs/engine/guide/examples/__control-by-control.html @@ -1,35 +1,33 @@ + - @@ -38,7 +36,7 @@

Email to (KeymanWeb not enabled)

-

Subject (Defaults to 'English' or 'off' unless on a touch-based device)

+

Subject (Defaults to '(System keyboard)' or 'off' unless on a touch-based device)

Message body (Defaults to 'LaoKeys')

@@ -46,4 +44,4 @@ Back to Document - \ No newline at end of file + diff --git a/web/docs/engine/guide/examples/__first-example.html b/web/docs/engine/guide/examples/__first-example.html index feb96f4daa..24a58c4891 100644 --- a/web/docs/engine/guide/examples/__first-example.html +++ b/web/docs/engine/guide/examples/__first-example.html @@ -6,15 +6,14 @@ - @@ -23,4 +22,4 @@ Back to Document - \ No newline at end of file + diff --git a/web/docs/engine/guide/examples/__full-manual-control.html b/web/docs/engine/guide/examples/__full-manual-control.html index 5a70c7183f..6313c13518 100644 --- a/web/docs/engine/guide/examples/__full-manual-control.html +++ b/web/docs/engine/guide/examples/__full-manual-control.html @@ -1,45 +1,39 @@ + - diff --git a/web/docs/engine/guide/examples/__manual-control.html b/web/docs/engine/guide/examples/__manual-control.html index 4680400e4d..a1cfa72c83 100644 --- a/web/docs/engine/guide/examples/__manual-control.html +++ b/web/docs/engine/guide/examples/__manual-control.html @@ -1,29 +1,27 @@ + - - - @@ -38,4 +36,4 @@ Back to Document - \ No newline at end of file + diff --git a/web/docs/engine/guide/examples/automatic-control.md b/web/docs/engine/guide/examples/automatic-control.md index c804556e18..d21946aa53 100644 --- a/web/docs/engine/guide/examples/automatic-control.md +++ b/web/docs/engine/guide/examples/automatic-control.md @@ -2,28 +2,28 @@ title: Automatic Mode Example --- -This page shows how to include a local keyboard from an arbitrary location in your website's file structure. +This page shows how to include a local keyboard from an arbitrary location +in your website's file structure. -In this example, we use only the LaoKey keyboard. Please click [this link](./__auto-control.html) to open the test page. +In this example, we use only the LaoKey keyboard. Please click +[this link](./__auto-control.html) to open the test page. ## Code Walkthrough ```html - + @@ -31,8 +31,6 @@ In this example, we use only the LaoKey keyboard. Please click [this link](./__a ``` -As you can see above, the second line in the code snippet above references the LaoKey keyboard loader JavaScript file. This is a small stub file, typically less than 200 bytes, that defines the name and actual location of the real keyboard file (in this case, **laokeys.js**). When a page may reference many keyboards, this saves downloading potentially hundreds of kilobytes of unused Javascript keyboards - the keyboard is downloaded when it is first selected by the user. - ## API References On initialization: [`keyman.init()`](../../reference/core/init). diff --git a/web/docs/engine/guide/examples/control-by-control.md b/web/docs/engine/guide/examples/control-by-control.md index 974338ef1f..b3b0b9b3a5 100644 --- a/web/docs/engine/guide/examples/control-by-control.md +++ b/web/docs/engine/guide/examples/control-by-control.md @@ -2,7 +2,10 @@ title: Control-by-Control Example --- -In this example, a simulated webmail form, the default and permissible keyboard for each control is managed by the web page. We use the automatic mode for simplicity of demonstration. We also link to the CDN for KeymanWeb in this example. Please click [this link](__control-by-control.html) to open the test page. +In this example, a simulated webmail form, the default and permissible keyboard for each control +is managed by the web page. We use the automatic mode for simplicity of demonstration. We also +link to the CDN for KeymanWeb in this example. Please click [this link](__control-by-control.html) +to open the test page. ## Code Walkthrough @@ -10,28 +13,23 @@ Include the following script in the HEAD of your page: ```js ``` @@ -40,18 +38,18 @@ Also include the following HTML code: ```html - - + + - - - - ``` + --- -**Note:** In this example we disabled the first element (`document.f.address`) by API call. A later API call can re-enable KeymanWeb for this control should it fit the page's design. Alternatively, this can be done by instead adding the class `'kmw-disabled'` to the control. This will permanently block KeymanWeb from handling its input. +**Note:** In this example we disabled the first element (`document.f.address`) by API call. A +later API call can re-enable KeymanWeb for this control should it fit the page's design. +Alternatively, this can be done by instead adding the class `'kmw-disabled'` to the control. This +will permanently block KeymanWeb from handling its input. --- diff --git a/web/docs/engine/guide/examples/full-manual-control.md b/web/docs/engine/guide/examples/full-manual-control.md index e9e8d2908a..39be4d34b3 100644 --- a/web/docs/engine/guide/examples/full-manual-control.md +++ b/web/docs/engine/guide/examples/full-manual-control.md @@ -2,7 +2,9 @@ title: Manual Control - Custom Interface --- -In this example, the web page designer has opted for their own user interface instead of the KeymanWeb interface. The keyboards in the selector are populated from the KeymanWeb list of keyboards. Please click [this link](__full-manual-control.html) to open the test page. +In this example, the web page designer has opted for their own user interface instead of the +KeymanWeb interface. The keyboards in the selector are populated from the KeymanWeb list of +keyboards. Please click [this link](__full-manual-control.html) to open the test page. ## Code Walkthrough @@ -12,31 +14,25 @@ Include the following script in the HEAD of your page: + - - - ``` - File: [unified_loader.js](js/unified_loader.js) diff --git a/web/docs/engine/guide/examples/js/devanagari_inscript_load.js b/web/docs/engine/guide/examples/js/devanagari_inscript_load.js deleted file mode 100644 index c2fd4d90fe..0000000000 --- a/web/docs/engine/guide/examples/js/devanagari_inscript_load.js +++ /dev/null @@ -1,2 +0,0 @@ -/*(C) Copyright 1994-2006 Tavultesoft Pty Ltd. All Rights Reserved. Details: keymanweb.com*/ -KeymanWeb.KRS(new Stub_Keyboard_devanagari_inscript()); function Stub_Keyboard_devanagari_inscript() {this.KF="devanagari_inscript.js";this.KI="Keyboard_devanagari_inscript";this.KN="Devanagari (INSCRIPT)";} diff --git a/web/docs/engine/guide/examples/js/european2_load.js b/web/docs/engine/guide/examples/js/european2_load.js deleted file mode 100644 index 96ecc9a9be..0000000000 --- a/web/docs/engine/guide/examples/js/european2_load.js +++ /dev/null @@ -1 +0,0 @@ -KeymanWeb.KRS(new Stub_Keyboard_european2()); function Stub_Keyboard_european2() {this.KF="european2-1.6.js";this.KI="Keyboard_european2";this.KN="EuroLatin2 Keyboard";} \ No newline at end of file diff --git a/web/docs/engine/guide/examples/js/hebrew_load.js b/web/docs/engine/guide/examples/js/hebrew_load.js deleted file mode 100644 index ebcd50e4d0..0000000000 --- a/web/docs/engine/guide/examples/js/hebrew_load.js +++ /dev/null @@ -1,2 +0,0 @@ -/*(C) Copyright 1994-2006 Tavultesoft Pty Ltd. All Rights Reserved. Details: keymanweb.com*/ -KeymanWeb.KRS(new Stub_Keyboard_hebrew()); function Stub_Keyboard_hebrew() {this.KF="hebrew.js";this.KI="Keyboard_hebrew";this.KN="Hebrew";} diff --git a/web/docs/engine/guide/examples/js/keymanwebtest_load.js b/web/docs/engine/guide/examples/js/keymanwebtest_load.js deleted file mode 100644 index c06cbba38e..0000000000 --- a/web/docs/engine/guide/examples/js/keymanwebtest_load.js +++ /dev/null @@ -1,2 +0,0 @@ -/*(C) Copyright 1994-2006 Tavultesoft Pty Ltd. All Rights Reserved. Details: keymanweb.com*/ -KeymanWeb.KRS(new Stub_Keyboard_keymanwebtest()); function Stub_Keyboard_keymanwebtest() {this.KF="keymanwebtest.js";this.KI="Keyboard_keymanwebtest";this.KN="KeymanWeb Test";} diff --git a/web/docs/engine/guide/examples/js/korean_korda_load.js b/web/docs/engine/guide/examples/js/korean_korda_load.js deleted file mode 100644 index 7fa96e4bc0..0000000000 --- a/web/docs/engine/guide/examples/js/korean_korda_load.js +++ /dev/null @@ -1,2 +0,0 @@ -/*(C) Copyright 1994-2006 Tavultesoft Pty Ltd. All Rights Reserved. Details: keymanweb.com*/ -KeymanWeb.KRS(new Stub_Keyboard_korean_korda()); function Stub_Keyboard_korean_korda() {this.KF="korean_korda.js";this.KI="Keyboard_korean_korda";this.KN="Korean (KORDA) - 30 Day Evaluation";} diff --git a/web/docs/engine/guide/examples/js/korean_morse_load.js b/web/docs/engine/guide/examples/js/korean_morse_load.js deleted file mode 100644 index fb7abbdb91..0000000000 --- a/web/docs/engine/guide/examples/js/korean_morse_load.js +++ /dev/null @@ -1,2 +0,0 @@ -/*(C) Copyright 1994-2006 Tavultesoft Pty Ltd. All Rights Reserved. Details: keymanweb.com*/ -KeymanWeb.KRS(new Stub_Keyboard_korean_morse()); function Stub_Keyboard_korean_morse() {this.KF="korean_morse.js";this.KI="Keyboard_korean_morse";this.KN="Korean (Morse) - 30 Day Evaluation";} diff --git a/web/docs/engine/guide/examples/js/laokeys_load.js b/web/docs/engine/guide/examples/js/laokeys_load.js deleted file mode 100644 index 522e21fd5a..0000000000 --- a/web/docs/engine/guide/examples/js/laokeys_load.js +++ /dev/null @@ -1,7 +0,0 @@ -/*(C) Copyright 1994-2021 SIL International. All Rights Reserved. Details: keymanweb.com*/ -keyman.addKeyboards({ - id: "laokeys", - name: "Lao (Phonetic)", - languages:{id:'lo',name:'Lao'}, - filename: "./js/laokeys.js" -}); \ No newline at end of file diff --git a/web/docs/engine/guide/examples/js/unified_loader.js b/web/docs/engine/guide/examples/js/unified_loader.js index 2987ce3413..f4a695d24a 100644 --- a/web/docs/engine/guide/examples/js/unified_loader.js +++ b/web/docs/engine/guide/examples/js/unified_loader.js @@ -1,16 +1,18 @@ -/*(C) Copyright 2021 SIL International. All Rights Reserved. Details: keymanweb.com*/ -function loadKeyboards() { - // Uses an older type of keyboard stub definition. - var KWK={ - "devanagari_inscript":{KN:"Devanagari (INSCRIPT)", KLC:"hi", KL:"Hindi"}, - "european2":{KN:"EuroLatin2", KLC:"en", KL:"English"}, - "hebrew":{KN:"Hebrew", KLC:"he", KL:"Hebrew"}, - "korean_korda":{KN:"Korean (KORDA) - 30 Day Evaluation", KLC:"ko", KL:"Korean"}, - "korean_morse":{KN:"Korean (Morse) - 30 Day Evaluation", KLC:"ko", KL:"Korean"}, - "laokeys":{KN:"Lao (Phonetic)", KLC:"lo", KL:"Lao"} - }; +/* + * Keyman is copyright (C) SIL Global. MIT License. + */ +async function loadKeyboards() { + const keyboardList = [ + { id: 'devanagari_inscript', name: 'Devanagari (INSCRIPT)', languages: { id: 'hi', name: 'Hindi' }, filename: './js/devanagari_inscript.js' }, + { id: 'european2', name: 'EuroLatin2', languages: { id: 'en', name: 'English' }, filename: './js/european2.js' }, + { id: 'hebrew', name: 'Hebrew', languages: { id: 'he', name: 'Hebrew' }, filename: './js/hebrew.js' }, + { id: 'korean_korda', name: 'Korean (KORDA)', languages: { id: 'ko', name: 'Korean' }, filename: './js/korean_korda.js' }, + { id: 'korean_morse', name: 'Korean (Morse)', languages: { id: 'ko', name: 'Korean' }, filename: './js/korean_morse.js' }, + // using a KeyboardStub would allow to customize e.g. which font the keyboard uses + { KF: "./js/laokeys.js", KI: "Keyboard_laokeys", KN: "Lao (Phonetic)", KL: "Lao", KLC: "lo" } + ]; - for(var n in KWK) { - KeymanWeb.registerStub({KF:"./js/" + n+".js", KI:"Keyboard_"+n, KN:KWK[n].KN, KL:KWK[n].KL, KLC:KWK[n].KLC}); - } + return keyman.addKeyboards(keyboardList).catch(function(err) { + console.error('keyman.addKeyboards failed with '+errToString(err)+' for '+JSON.stringify(keyboardList)); + }); } diff --git a/web/docs/engine/guide/examples/manual-control.md b/web/docs/engine/guide/examples/manual-control.md index 1087c518c8..d67db736e9 100644 --- a/web/docs/engine/guide/examples/manual-control.md +++ b/web/docs/engine/guide/examples/manual-control.md @@ -10,21 +10,19 @@ Include the following script in the HEAD of your page: ```js - - + - - - ``` -- File: [laokeys_load.js](js/laokeys_load.js) - And finally, include the control img for KeymanWeb: ```html @@ -61,9 +52,11 @@ And finally, include the control img for KeymanWeb: ## API References On programmatically setting the keyboard: + - [`keyman.setActiveKeyboard()`](../../reference/core/setActiveKeyboard). On managing the visibility of the OSK: + - [`keyman.osk.hide()`](../../reference/osk/hide) - [`keyman.osk.show()`](../../reference/osk/show). diff --git a/web/docs/engine/guide/get-started.md b/web/docs/engine/guide/get-started.md index 8d3cd1baa4..96e7a699f4 100644 --- a/web/docs/engine/guide/get-started.md +++ b/web/docs/engine/guide/get-started.md @@ -22,12 +22,10 @@ The source code for the page may be seen below. diff --git a/web/docs/engine/reference/core/addKeyboards.md b/web/docs/engine/reference/core/addKeyboards.md index fc5e3ce07b..e5f48680a7 100644 --- a/web/docs/engine/reference/core/addKeyboards.md +++ b/web/docs/engine/reference/core/addKeyboards.md @@ -9,7 +9,7 @@ Adds keyboards to KeymanWeb. ## Syntax ```js -keyman.addKeyboards(spec[, spec...]) +await keyman.addKeyboards([spec...]) ``` ### Parameters @@ -179,3 +179,7 @@ The `spec.languages.font` object contains the following members: : `string` optional Font size (in CSS dimensions). If not specified, then `1em` is used. + +### Not passing any parameter + +Not passing any parameter will obtain all Keyman keyboards from the CDN. \ No newline at end of file diff --git a/web/docs/engine/reference/core/addKeyboardsForLanguage.md b/web/docs/engine/reference/core/addKeyboardsForLanguage.md index bf97a06b8d..e3a1e553c7 100644 --- a/web/docs/engine/reference/core/addKeyboardsForLanguage.md +++ b/web/docs/engine/reference/core/addKeyboardsForLanguage.md @@ -9,7 +9,7 @@ Add default or all keyboards for a given language to KeymanWeb. ## Syntax ```js -keyman.addKeyboardsForLanguage(spec[, spec...]) +await keyman.addKeyboardsForLanguage(spec[, spec...]) ``` ### Parameters diff --git a/web/docs/engine/reference/core/getKeyboard.md b/web/docs/engine/reference/core/getKeyboard.md index 0d6f8eb52e..9b728995d0 100644 --- a/web/docs/engine/reference/core/getKeyboard.md +++ b/web/docs/engine/reference/core/getKeyboard.md @@ -8,7 +8,7 @@ Get keyboard meta data for the selected keyboard and language. ## Syntax -```c +```js keyman.getKeyboard(keyboardName, languageCode) ``` @@ -75,5 +75,5 @@ The `keyboard` object contains the following members: : `string` *optional* : The font packaged with the keyboard to properly display specialized OSK characters. -## See also +## See also - [keyman.addKeyboards()](addKeyboards) and its documentation about keyboard specification objects. diff --git a/web/docs/engine/reference/core/getKeyboards.md b/web/docs/engine/reference/core/getKeyboards.md index 8d84521b31..cd8b0f2d9c 100644 --- a/web/docs/engine/reference/core/getKeyboards.md +++ b/web/docs/engine/reference/core/getKeyboards.md @@ -8,7 +8,7 @@ Get details of currently installed keyboards. ## Syntax -```c +```js keyman.getKeyboards() ``` @@ -25,5 +25,5 @@ None. See [keyman.getKeyboard()](getKeyboard) for detail on the returned keyboard specification objects. -## See also +## See also - [keyman.addKeyboards()](addKeyboards) diff --git a/web/docs/engine/reference/interface/registerStub.md b/web/docs/engine/reference/interface/registerStub.md index 2d9c8ef5a8..9dc8e10c34 100644 --- a/web/docs/engine/reference/interface/registerStub.md +++ b/web/docs/engine/reference/interface/registerStub.md @@ -8,13 +8,13 @@ Registers the keyboard stub or returns true if already registered. ## Syntax -```c +```js keyman.interface.registerStub(Pstub); ``` or -```c +```js KeymanWeb.KRS(Pstub); // Shorthand ``` diff --git a/web/docs/engine/reference/layouts.md b/web/docs/engine/reference/layouts.md index df3e3b50c7..56d1e40d62 100644 --- a/web/docs/engine/reference/layouts.md +++ b/web/docs/engine/reference/layouts.md @@ -2,4 +2,6 @@ title: Layout Designer --- -One of the main features of *KeymanWeb 17* is its ability to support distinct, user-customizable layouts for touch-screen keyboards on phones and tablets. *Keyman Developer 17* includes a layout designer to simplify the process of creating custom layouts for any keyboard. +One of the main features of *KeymanWeb* is its ability to support distinct, user-customizable +layouts for touch-screen keyboards on phones and tablets. *Keyman Developer* includes a layout +designer to simplify the process of creating custom layouts for any keyboard. diff --git a/web/docs/engine/reference/layoutspec.md b/web/docs/engine/reference/layoutspec.md index 2cdaec1fff..b9d2353901 100644 --- a/web/docs/engine/reference/layoutspec.md +++ b/web/docs/engine/reference/layoutspec.md @@ -2,13 +2,19 @@ title: Layout Specifications --- -Touch-screen layouts for *KeymanWeb 17* are specified as JSON objects containing a member object for each specified device type. Currently supported device types are *tablet* and *phone*. Layouts for *desktop* computers may also be specified but desktop on-screen keyboard design is normally managed by the -standard *Keyman Developer* on-screen keyboard tool rather than the keyboard layout designer. If the same -layout is appropriate for both *tablet* and *phone* devices only one need be specified, and will be used for either type of device. +Touch-screen layouts for *KeymanWeb* are specified as JSON objects containing a member object for +each specified device type. Currently supported device types are *tablet* and *phone*. Layouts +for *desktop* computers may also be specified but desktop on-screen keyboard design is normally +managed by the standard *Keyman Developer* on-screen keyboard tool rather than the keyboard +layout designer. If the same layout is appropriate for both *tablet* and *phone* devices only one +need be specified, and will be used for either type of device. -File encoding for manually-created layout files may use either UTF-8 or 7-bit ANSI coding, but must not include a BOM. For easier editing and management without requiring special fonts, embedded Unicode characters with values above 127 may use the *\uXXXX* notation. +File encoding for manually-created layout files may use either UTF-8 or 7-bit ANSI coding, but +must not include a BOM. For easier editing and management without requiring special fonts, +embedded Unicode characters with values above 127 may use the *\uXXXX* notation. -For details of the JSON specification, see [The JSON Data Interchange Format(ECMA-404)](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +For details of the JSON specification, see [The JSON Data Interchange +Format(ECMA-404)](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). @@ -249,7 +255,7 @@ Details of key member specifications are given below: - + @@ -330,7 +336,11 @@ Details of key member specifications are given below:
id Each key id must start with >K_ , for keys mapped to standard Keyman virtual key names, e.g. K_HYPHEN , or either U_ or T_ for user-defined names. Keys identified as U_xxxx[_xxxx...] specify one or more Unicode characters in hex format, e.g. U_1363 for the Ethiopic Comma character, and will insert those characters if the key id is not matched by a rule. Other user-defined keys, such as T_ZZZ , will be ignored unless matched by a rule. The key id is required except for key styles 9 or 10 (blank or spacer keys).
-For many keyboards, it is helpful to associate some keyboard layers with physical keyboard modifier states. This is reflected in the layer name, where a layer name of *shift* means that when a key in that layer is touched, the keystroke will be processed as if the keyboard Shift key is held. +For many keyboards, it is helpful to associate some keyboard layers with physical keyboard +modifier states. This is reflected in the layer name, where a layer name of *shift* means that +when a key in that layer is touched, the keystroke will be processed as if the keyboard Shift key +is held. + The special layer names of:   *leftalt* , @@ -364,7 +374,9 @@ The following special key identifiers have been added to simplify layer selectio | K_SHIFTED | 264 | | K_ALTGR | 265 | -A special font is used to provide easily recognizable key graphics for various special purpose keys. The following key text strings will be recognized and cause the appropriate graphic to be used for the key cap instead of the actual text: +A special font is used to provide easily recognizable key graphics for various special purpose +keys. The following key text strings will be recognized and cause the appropriate graphic to be +used for the key cap instead of the actual text: | Text string | Key purpose | |:------------------|:--------------------------------------------------------| diff --git a/web/docs/engine/reference/overview.md b/web/docs/engine/reference/overview.md index 574e704abf..712a20640b 100644 --- a/web/docs/engine/reference/overview.md +++ b/web/docs/engine/reference/overview.md @@ -4,11 +4,14 @@ title: Overview *KeymanWeb* is a cross-browser JavaScript input method solution. -The *KeymanWeb 17 API* provides JavaScript functions to allow a website developer to integrate the use of -*KeymanWeb* multi-lingual keyboard mapping into a website, using either a standard or a custom-designed user-interface. The functions are exposed as API calls to the *KeymanWeb* core, the -*On-Screen Keyboard* module, a *Utility function* library, or one of the standard *User Interface* modules. +The *KeymanWeb API* provides JavaScript functions to allow a website developer to integrate the +use of *KeymanWeb* multi-lingual keyboard mapping into a website, using either a standard or a +custom-designed user-interface. The functions are exposed as API calls to the *KeymanWeb* core, +the *On-Screen Keyboard* module, a *Utility function* library, or one of the standard *User +Interface* modules. -A *KeymanWeb* instance is automatically constructed when you include the compiled KeymanWeb script (kmw-release.js) in your web page source. +A *KeymanWeb* instance is automatically constructed when you include the compiled KeymanWeb +script (kmw-release.js) in your web page source. The *KeymanWeb API* comprises the following objects: diff --git a/web/package.json b/web/package.json index fcc6d76790..5ec0135add 100644 --- a/web/package.json +++ b/web/package.json @@ -107,7 +107,7 @@ "@sentry/cli": "^2.31.0", "@zip.js/zip.js": "^2.7.32", "c8": "^7.12.0", - "express": "^4.19.2", + "express": "^4.22.2", "jsdom": "^23.0.1", "promise-status-async": "^1.2.10", "tsx": "^4.19.0" diff --git a/web/src/.editorconfig b/web/src/.editorconfig deleted file mode 100644 index 34f03b7b15..0000000000 --- a/web/src/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -# top-most EditorConfig file -root = true - -; applies to all files -[*] -indent_style = space - -[*.{java, js, ts, sh, css, html, xml}] -indent_size = 2 - diff --git a/web/src/app/browser/src/context/focusAssistant.ts b/web/src/app/browser/src/context/focusAssistant.ts index accb9b811e..ade72ea65a 100644 --- a/web/src/app/browser/src/context/focusAssistant.ts +++ b/web/src/app/browser/src/context/focusAssistant.ts @@ -149,7 +149,7 @@ export class FocusAssistant extends EventEmitter { * @param {(boolean|number)} state Activate (true,false) */ setMaintainingFocus(state: boolean) { - this.maintainingFocus = state ? true : false; + this.maintainingFocus = !!state; } setFocusTimer(): void { diff --git a/web/src/app/browser/src/keymanEngine.ts b/web/src/app/browser/src/keymanEngine.ts index bf5543e2cd..af3bae2d20 100644 --- a/web/src/app/browser/src/keymanEngine.ts +++ b/web/src/app/browser/src/keymanEngine.ts @@ -257,7 +257,7 @@ export class KeymanEngine extends KeymanEngineBase { - // Ensure that the ui.controller is visible if help is displayed - this.controller.style.display = 'block'; - this.oskButton._setSelected(true); + // Ensure that the ui.controller is visible if help is displayed + this.controller.style.display = 'block'; + this.oskButton._setSelected(true); - return oskPosition; - }); + return oskPosition; + }); osk.addEventListener('hide', (byUser) => { if(byUser['HiddenByUser']) { @@ -542,8 +542,18 @@ if(!keymanweb) { } // Highlight the last active keyboard - const sk=keymanweb.getSavedKeyboard().split(':'); - this.updateMenu(sk[0],sk[1]); + let activeKeyboard = keymanweb.getActiveKeyboard(); + let activeLanguage = ''; + if (activeKeyboard) { + activeLanguage = keymanweb.getActiveLanguage(); + } else { + // savedKeyboard is only correct if we use global keyboard settings, + // otherwise it's set to the first keyboard in the list + const savedKeyboard = keymanweb.getSavedKeyboard().split(':'); + activeKeyboard = savedKeyboard[0]; + activeLanguage = savedKeyboard[1]; + } + this.updateMenu(activeKeyboard, activeLanguage); } /* ---------------------------------------- @@ -555,24 +565,24 @@ if(!keymanweb) { /** * Function selecKbd * Scope Private - * @param {number} _kbd + * @param {number} kbdIndex * Description Select a keyboard from the drop down menu **/ - private async selectKbd(_kbd: number): Promise { - let _name,_lgCode; - if(_kbd < 0) { - _name = ''; - _lgCode=''; + private async selectKbd(kbdIndex: number): Promise { + let name: string, languageCode: string; + if (kbdIndex < 0) { + name = ''; + languageCode = ''; } else { - _name = this.keyboards[_kbd]._InternalName; - _lgCode = this.keyboards[_kbd]._LanguageCode; + name = this.keyboards[kbdIndex]._InternalName; + languageCode = this.keyboards[kbdIndex]._LanguageCode; } - await keymanweb.setActiveKeyboard(_name,_lgCode); + await keymanweb.setActiveKeyboard(name, languageCode); keymanweb.focusLastActiveElement(); - this.kbdButton._setSelected(_name != ''); - if(_kbd >= 0) { - this.lastActiveKeyboard = _kbd; + this.kbdButton._setSelected(name != ''); + if (kbdIndex >= 0) { + this.lastActiveKeyboard = kbdIndex; } return false; @@ -687,6 +697,22 @@ if(!keymanweb) { `; } + private createMenuItem(index: number, id: string, name: string, isSelected: boolean): { li: HTMLLIElement, a: HTMLAnchorElement } { + const li = util.createElement('li'); + const a = util.createElement('a'); + a.innerHTML = name; + a.href = "#"; + a.onclick = ((x) => { + return () => this.selectKbd(x); + })(index); + a.id = id; + if (isSelected) { + a.className = 'selected'; + } + li.appendChild(a); + return { li, a }; + } + /** * Function createMenu * Scope Private @@ -701,38 +727,29 @@ if(!keymanweb) { this.keyboardMenu.innerHTML = ''; // I2403 - Allow toggle design to be loaded twice } - const _li = util.createElement('li'); - const _a = util.createElement('a'); - _a.innerHTML='(System keyboard)'; - _a.href="#"; - _a.onclick = () => { - return this.selectKbd(-1); - }; - _a.id='KMWSel_$'; - _a.className='selected'; - _li.appendChild(_a); + // Add the default (system) keyboard as the first entry in the menu + const { li, a } = this.createMenuItem(-1, 'KMWSel_$', '(System keyboard)', true); + this.selectedMenuItem = a; + this.keyboardMenu.appendChild(li); - this.selectedMenuItem=_a; - this.keyboardMenu.appendChild(_li); - - const _kbds=keymanweb.getKeyboards(), _added: Record = {}; + // Add loaded keyboards to the menu this.keyboards = []; - for(let _kbd = 0; _kbd < _kbds.length; _kbd++) { - const _li1=util.createElement('li'); - const _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]++; + const keyboards = keymanweb.getKeyboards(); + const added: Record = {}; + for (let kbdIndex = 0; kbdIndex < keyboards.length; kbdIndex++) { + if (!added[keyboards[kbdIndex].InternalName]) { + added[keyboards[kbdIndex].InternalName] = 0; + } + added[keyboards[kbdIndex].InternalName]++; - const _n=_added[_kbds[_kbd].InternalName]; - this.keyboards.push({_InternalName: _kbds[_kbd].InternalName, _LanguageCode:_kbds[_kbd].LanguageCode, _Index: _n}); + const kbdInstanceCount = added[keyboards[kbdIndex].InternalName]; + this.keyboards.push({ _InternalName: keyboards[kbdIndex].InternalName, _LanguageCode: keyboards[kbdIndex].LanguageCode, _Index: kbdInstanceCount }); - _a1.href="#"; - _a1.onclick = ((x) => { return () => this.selectKbd(x); })(this.keyboards.length-1); - _a1.id='KMWSel_'+_kbds[_kbd].InternalName+'$'+_n; - - _li1.appendChild(_a1); - this.keyboardMenu.appendChild(_li1); + const { li } = this.createMenuItem(this.keyboards.length - 1, + `KMWSel_${keyboards[kbdIndex].InternalName}\$${kbdInstanceCount}`, + `${keyboards[kbdIndex].LanguageName} - ${keyboards[kbdIndex].Name}`, + false); + this.keyboardMenu.appendChild(li); } //if(!ui.initialized) // I2403 - Allow toggle design to be loaded twice @@ -740,7 +757,6 @@ if(!keymanweb) { this.kbdButton.getElem().appendChild(this.keyboardMenu); } }; - } @@ -795,4 +811,4 @@ if(!keymanweb) { ui.initialize(); } catch(ex){} -} \ No newline at end of file +} diff --git a/web/src/app/ui/kmwuitoolbar.ts b/web/src/app/ui/kmwuitoolbar.ts index cf736777f9..6ed8d82e23 100644 --- a/web/src/app/ui/kmwuitoolbar.ts +++ b/web/src/app/ui/kmwuitoolbar.ts @@ -1150,8 +1150,8 @@ if(!keymanweb) { internalName: string, languageCode: string }) => { // Uses a different format than .getKeyboards(), b/c why not? - // https://help.keyman.com/developer/engine/web/16.0/reference/core/getKeyboards vs - // https://help.keyman.com/developer/engine/web/16.0/reference/events/kmw.keyboardchange + // https://help.keyman.com/developer/engine/web/current-version/reference/core/getKeyboards vs + // https://help.keyman.com/developer/engine/web/current-version/reference/events/kmw.keyboardchange this.lastSelectedKeyboard = null; const kbName=p.internalName, lgName=keymanweb.util.getLanguageCodes(p.languageCode)[0]; diff --git a/web/src/engine/src/keyboard-storage/keyboardStub.ts b/web/src/engine/src/keyboard-storage/keyboardStub.ts index 17877dcfe8..cc48db7a1b 100644 --- a/web/src/engine/src/keyboard-storage/keyboardStub.ts +++ b/web/src/engine/src/keyboard-storage/keyboardStub.ts @@ -182,9 +182,9 @@ export class KeyboardStub extends KeyboardProperties { } } - public validateForCustomKeyboard(): Error { - if(super.validateForCustomKeyboard() || !this.KF || !this.KR) { - return new Error('To use a custom keyboard, you must specify file name, keyboard id, keyboard name, language, language code, and region.'); + public validateForCustomKeyboard(): Error|null { + if(super.validateForCustomKeyboard() || !this.KF) { + return new Error('To use a custom keyboard, you must specify file name, keyboard id, keyboard name, language and language code.'); } else { return null; } diff --git a/web/src/engine/src/keyboard/keyboards/keyboardProperties.ts b/web/src/engine/src/keyboard/keyboards/keyboardProperties.ts index 1a3a9e215a..b9b32b444a 100644 --- a/web/src/engine/src/keyboard/keyboards/keyboardProperties.ts +++ b/web/src/engine/src/keyboard/keyboards/keyboardProperties.ts @@ -255,7 +255,7 @@ export class KeyboardProperties implements KeyboardInternalPropertySpec { return null; } - public validateForCustomKeyboard(): Error { + public validateForCustomKeyboard(): Error|null { if(!this.KI || !this.KN || !this.KL || !this.KLC) { return new Error("To use a custom keyboard, you must specify keyboard id, keyboard name, language and language code."); } else { diff --git a/web/src/engine/src/main/keyboardInterfaceBase.ts b/web/src/engine/src/main/keyboardInterfaceBase.ts index 4f83056103..fbf1d20f24 100644 --- a/web/src/engine/src/main/keyboardInterfaceBase.ts +++ b/web/src/engine/src/main/keyboardInterfaceBase.ts @@ -85,7 +85,6 @@ export class KeyboardInterfaceBase diff --git a/web/src/samples/samplehdr.js b/web/src/samples/samplehdr.js index 129d54fc01..1eedf3a04d 100644 --- a/web/src/samples/samplehdr.js +++ b/web/src/samples/samplehdr.js @@ -1,51 +1,62 @@ -// JavaScript Document samplehdr.js: Keyboard management for KeymanWeb demonstration pages +/* + * Keyman is copyright (C) SIL Global. MIT License. + * + * Keyboard management for KeymanWeb demonstration pages + */ /* - The keyboard name and/or BCP-47 language code must be specified for each keyboard that is to be available. - If the same keyboard is used for several languages, it must be listed for each - language, but the keyboard itself will only be loaded once. - If two (or more) keyboards are to be available for a given language, both must be listed. - Any number of keyboards may be specified in one or more calls. - Keyboard paths may be absolute (with respect to the server root) or relative to the keyboards option path. - The actual keyboard object will be downloaded asynchronously when first selected for use. + The keyboard name and/or BCP-47 language code must be specified for + each keyboard that is to be available. If the same keyboard is used + for several languages, it must be listed for each language, but the + keyboard itself will only be loaded once. If two (or more) keyboards + are to be available for a given language, both must be listed. Any + number of keyboards may be specified in one or more calls. Keyboard + paths may be absolute (with respect to the server root) or relative + to the keyboards option path. The actual keyboard object will be + downloaded asynchronously when first selected for use. - Each argument to addKeyboards() is a string, for example: - european2 loads the current version of the Eurolatin 2 keyboard (for its default language) - european2@fr loads the current version of the Eurolatin 2 keyboard for French - european2@fr@1.2 loads version 1.2 of the Eurolatin 2 keyboard for French + Each argument to addKeyboards() is a string, for example: european2 + loads the current version of the Eurolatin 2 keyboard (for its + default language) european2@fr loads the current version of + the Eurolatin 2 keyboard for French european2@fr@1.2 loads + version 1.2 of the Eurolatin 2 keyboard for French - Argument syntax also supports the following extensions: - @fr load the current version of the default keyboard for French - @fr$ load all available keyboards (current version) for French + Argument syntax also supports the following extensions: @fr + load the current version of the default keyboard for French @fr$ + load all available keyboards (current version) for French - Each call to addKeyboards() requires a single call to the remote server, - (unless all keyboards listed are local and fully specified) so it is better - to use multiple arguments rather than separate function calls. + Each call to addKeyboards() requires a single call to the remote + server, (unless all keyboards listed are local and fully specified) + so it is better to use multiple arguments rather than separate + function calls. - Calling addKeyboards() with no arguments returns a list of *all* available keyboards. - The Toolbar (desktop browser) UI is best suited for allowing users to select - the appropriate language and keyboard in this case. + Calling addKeyboards() with no arguments returns a list of *all* + available keyboards. The Toolbar (desktop browser) UI is best suited + for allowing users to select the appropriate language and keyboard + in this case. - Keyboards may also be specified by language name using addKeyboardsForLanguage() - for example: - keymanweb.addKeyboardsForLanguage('Burmese'); + Keyboards may also be specified by language name using + addKeyboardsForLanguage() for example: + keymanweb.addKeyboardsForLanguage('Burmese'); - Appending $ to the language name will again cause all available keyboards for that - language to be loaded rather than the default keyboard. + Appending $ to the language name will again cause all available + keyboards for that language to be loaded rather than the default + keyboard. - The first call to addKeyboardsForLanguage() makes an additional call to the - keyman API to load the current list of keyboard/language associations. + The first call to addKeyboardsForLanguage() makes an additional call + to the keyman API to load the current list of keyboard/language + associations. - In this example, the following function loads the indicated keyboards, - and is called when the page loads. + In this example, the following function loads the indicated + keyboards, and is called when the page loads. */ function errToString(err) { // Painful? Kinda. But needed on un-updated Android API 21! if(Array.isArray(err)) { - var result = ''; - for(var i = 0; i < err.length; i++) { - var e = err[i]; + let result = ''; + for(let i = 0; i < err.length; i++) { + const e = err[i]; if(e.error instanceof Error) { result += e.error.message + '\n'; } else { @@ -72,44 +83,42 @@ }); } - function loadKeyboards(nestLevel) { - var kmw=keyman; - - var base_prefix = '../'; - var prefix = './'; // The default - when prefix == 0. + async function loadKeyboards(nestLevel) { + const base_prefix = '../'; + let prefix = './'; // The default - when prefix == 0. if(nestLevel !== undefined && nestLevel > 0) { prefix = ''; - for(var i=0; i < nestLevel; i++) { - prefix = prefix + base_prefix; + for(let i=0; i < nestLevel; i++) { + prefix += base_prefix; } } // The first keyboard added will be the default keyboard for touch devices. // For faster loading, it may be best for the default keyboard to be // locally sourced. - doAddKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, + await doAddKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, filename:(prefix + 'us-1.0.js')}); // Add more keyboards to the language menu by: // 1. keyboard name ('french'), // 2. keyboard name and language code ('sil_euro_latin@no,sv'), // 3. or just the BCP-47 language code ('@he'). - kmw.addKeyboards('french', 'sil_euro_latin@no,sv', '@he'); + await keyman.addKeyboards('french', 'sil_euro_latin@no,sv', '@he'); // Add a keyboard by language name. Note that the name must be spelled // correctly, or the keyboard will not be found. (Using BCP-47 codes is // usually easier.) - doAddKeyboardsForLanguage('Dzongkha'); + await doAddKeyboardsForLanguage('Dzongkha'); // Add a fully-specified, locally-sourced, keyboard with custom font - doAddKeyboards({ - id:'lao_2008_basic', - name:'Lao Basic', + await doAddKeyboards({ + id: 'lao_2008_basic', + name: 'Lao Basic', languages: { - id:'lo',name:'Lao',region:'Asia', + id: 'lo', name: 'Lao', region: 'Asia' }, - filename:(prefix + 'lao_2008_basic-1.2.js') + filename: (prefix + 'lao_2008_basic-1.2.js') }); // Note that locally specified keyboards will be listed before keyboards @@ -118,29 +127,31 @@ } // Script to allow a user to add any keyboard to the keyboard menu - function addKeyboard(n) { - var sKbd; + async function addKeyboard(n) { + let sKbd; switch(n) { case 1: sKbd=document.getElementById('kbd_id1').value; - doAddKeyboards(sKbd); + await doAddKeyboards(sKbd); break; case 2: sKbd=document.getElementById('kbd_id2').value.toLowerCase(); - doAddKeyboards('@'+sKbd); + await doAddKeyboards('@'+sKbd); break; case 3: // Add keyboard for comma-separated language name(s) sKbd=document.getElementById('kbd_id3').value; - doAddKeyboardsForLanguage(sKbd); + await doAddKeyboardsForLanguage(sKbd); break; } } // Add keyboard on Enter (as well as pressing button) - function clickOnEnter(e,id) + async function clickOnEnter(e,id) { e = e || window.event; - if(e.keyCode == 13) addKeyboard(id); + if (e.keyCode == 13) { + await addKeyboard(id); + } } diff --git a/web/src/samples/simplest/index.html b/web/src/samples/simplest/index.html index c2ed9fd70b..55b8cb2067 100644 --- a/web/src/samples/simplest/index.html +++ b/web/src/samples/simplest/index.html @@ -36,8 +36,7 @@ diff --git a/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js b/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js index 3375279649..6364832fc4 100644 --- a/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js +++ b/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js @@ -63,7 +63,7 @@ describe('LanguageProcessor', function() { assert.isTrue(languageProcessor.mayPredict); // Some aspects of initialization must wait until after construction and overall - // load of the core. See /web/source/kmwbase.ts, in the final IIFE. + // load of the core. assert.isOk(languageProcessor.lmEngine); }); }); diff --git a/web/src/test/manual/web/attachment-api/index.html b/web/src/test/manual/web/attachment-api/index.html index f904d25f08..331e9d2ab2 100644 --- a/web/src/test/manual/web/attachment-api/index.html +++ b/web/src/test/manual/web/attachment-api/index.html @@ -40,9 +40,10 @@ const attachType = (new URLSearchParams(window.location.search)).get("mode"); var attachText = attachType ? attachType : "default"; - var kmw=window.keyman; - kmw.init({ + keyman.init({ attachType: attachType ? attachType : '' + }).then(function() { + loadKeyboards(1); }); @@ -56,7 +57,7 @@ - +

KeymanWeb Sample Page - Attachment API Testing

This page is designed to stress-test the new attachment/enablement API model and its functions.

You are currently testing under the attachment mode. Two other modes are available: diff --git a/web/src/test/manual/web/attachment-api/utilities.js b/web/src/test/manual/web/attachment-api/utilities.js index 5793c12af6..f6c404932e 100644 --- a/web/src/test/manual/web/attachment-api/utilities.js +++ b/web/src/test/manual/web/attachment-api/utilities.js @@ -1,7 +1,6 @@ // Page-global variable definitions. { var inputCounter = 0; -var kmw = keyman; } function generateDiagnosticDiv(elem) { @@ -23,8 +22,8 @@ function generateDiagnosticDiv(elem) { attachBtn.type = 'button'; attachBtn.id = 'attach_' + elemId; attachBtn.onclick = function() { - kmw.attachToControl(document.getElementById(elemId)); - var attached = kmw.isAttached(elem); + keyman.attachToControl(document.getElementById(elemId)); + var attached = keyman.isAttached(elem); document.getElementById('attachment_' + elemId).textContent = " Currently " + (attached ? "attached." : "detached."); const indepLabel = document.getElementById("independence_" + elemId); // does not exist for iframes @@ -40,8 +39,8 @@ function generateDiagnosticDiv(elem) { detachBtn.type = 'button'; detachBtn.id = 'detach_' + elemId; detachBtn.onclick = function() { - kmw.detachFromControl(document.getElementById(elemId)); - var attached = kmw.isAttached(elem); + keyman.detachFromControl(document.getElementById(elemId)); + var attached = keyman.isAttached(elem); document.getElementById('attachment_' + elemId).textContent = " Currently " + (attached ? "attached." : "detached."); const indepLabel = document.getElementById("independence_" + elemId); // does not exist for iframes @@ -58,7 +57,7 @@ function generateDiagnosticDiv(elem) { var attachLabel = document.createElement("a"); attachLabel.id = 'attachment_' + elemId; window.setTimeout(function() { - attachLabel.textContent = " Currently " + (kmw.isAttached(elem) ? "attached." : "detached."); + attachLabel.textContent = " Currently " + (keyman.isAttached(elem) ? "attached." : "detached."); }, attachTimer); div.appendChild(attachLabel); @@ -69,7 +68,7 @@ function generateDiagnosticDiv(elem) { enableBtn.type = 'button'; enableBtn.id = 'enable_' + elemId; enableBtn.onclick = function() { - kmw.enableControl(document.getElementById(elemId)); + keyman.enableControl(document.getElementById(elemId)); }; enableBtn.value = 'Enable'; div.appendChild(enableBtn); @@ -79,7 +78,7 @@ function generateDiagnosticDiv(elem) { disableBtn.type = 'button'; disableBtn.id = 'disable_' + elemId; disableBtn.onclick = function() { - kmw.disableControl(document.getElementById(elemId)); + keyman.disableControl(document.getElementById(elemId)); }; disableBtn.value = 'Disable'; div.appendChild(disableBtn); @@ -107,9 +106,9 @@ function generateDiagnosticDiv(elem) { setBtn.type = 'button'; setBtn.id = 'set_' + elemId; setBtn.onclick = function() { - kmw.setKeyboardForControl(document.getElementById(elemId), 'dzongkha', 'dz'); + keyman.setKeyboardForControl(document.getElementById(elemId), 'dzongkha', 'dz'); - if(kmw.isAttached(elem)) { + if(keyman.isAttached(elem)) { kbdLabel.textContent = " Using independently-tracked keyboard."; } }; @@ -121,9 +120,9 @@ function generateDiagnosticDiv(elem) { clearBtn.type = 'button'; clearBtn.id = 'clear_' + elemId; clearBtn.onclick = function() { - kmw.setKeyboardForControl(document.getElementById(elemId), null, null); + keyman.setKeyboardForControl(document.getElementById(elemId), null, null); - if(kmw.isAttached(elem)) { + if(keyman.isAttached(elem)) { kbdLabel.textContent = " Using globally-selected keyboard."; } }; @@ -133,8 +132,8 @@ function generateDiagnosticDiv(elem) { var kbdLabel = document.createElement("a"); kbdLabel.id = 'independence_' + elemId; window.setTimeout(function () { - if(kmw.isAttached(elem)) { - var attached = kmw.isAttached(elem); + if(keyman.isAttached(elem)) { + var attached = keyman.isAttached(elem); kbdLabel.textContent = attached ? " Using globally-selected keyboard." : ''; } }, 1); diff --git a/web/src/test/manual/web/basic-iframe/index.html b/web/src/test/manual/web/basic-iframe/index.html index 8a935f2cc6..56441455dd 100644 --- a/web/src/test/manual/web/basic-iframe/index.html +++ b/web/src/test/manual/web/basic-iframe/index.html @@ -36,8 +36,9 @@ @@ -46,7 +47,7 @@ - +

KeymanWeb: Test IFrame connectivity

diff --git a/web/src/test/manual/web/build-visual-keyboard/index.html b/web/src/test/manual/web/build-visual-keyboard/index.html index 2845f3db86..b7f2a67e74 100644 --- a/web/src/test/manual/web/build-visual-keyboard/index.html +++ b/web/src/test/manual/web/build-visual-keyboard/index.html @@ -37,8 +37,6 @@ @@ -51,7 +50,7 @@ - +

KeymanWeb Sample Page - Chirality Testing

This page is designed to stress-test the new support for chiral modifiers and state keys.

Be sure to reference the developer console for additional feedback.

diff --git a/web/src/test/manual/web/chirality/utilities.js b/web/src/test/manual/web/chirality/utilities.js index 16c9caaf02..7aea2825dd 100644 --- a/web/src/test/manual/web/chirality/utilities.js +++ b/web/src/test/manual/web/chirality/utilities.js @@ -1,19 +1,17 @@ -function loadKeyboards() -{ - var kmw=keyman; - +async function loadKeyboards() +{ // A testing keyboard handwritten with chirality information. - kmw.addKeyboards({id:'chirality',name:'Chirality Testing', + await keyman.addKeyboards({id:'chirality',name:'Chirality Testing', languages:{ id:'en',name:'English',region:'North America' }, filename:'../../../../../build/test-resources/keyboards/chirality.js' }); - + // A testing keyboard using 10.0 format and the KLS layout specifier // without the 'shift' layer properly defined. - // Add a fully-specified, locally-sourced, keyboard with custom font - kmw.addKeyboards({id:'halfDefined',name:'Undefined Shift Layer Keyboard', + // Add a fully-specified, locally-sourced, keyboard with custom font + await keyman.addKeyboards({id:'halfDefined',name:'Undefined Shift Layer Keyboard', languages:{ id:'en',name:'English',region:'North America' }, diff --git a/web/src/test/manual/web/ckeditor/index.html b/web/src/test/manual/web/ckeditor/index.html index 950f8bcb9b..16de19ba02 100644 --- a/web/src/test/manual/web/ckeditor/index.html +++ b/web/src/test/manual/web/ckeditor/index.html @@ -30,10 +30,9 @@ @@ -44,7 +43,7 @@ - +

KeymanWeb Sample Page - Test CKEditor Integration

Test CKEditor Integration

diff --git a/web/src/test/manual/web/ckeditor/inline.html b/web/src/test/manual/web/ckeditor/inline.html index 463ebf2138..06ec8ca0e5 100644 --- a/web/src/test/manual/web/ckeditor/inline.html +++ b/web/src/test/manual/web/ckeditor/inline.html @@ -30,10 +30,9 @@ @@ -44,7 +43,7 @@ - +

KeymanWeb Sample Page - Test CKEditor Integration

Test CKEditor Integration

diff --git a/web/src/test/manual/web/ckeditor/utilities.js b/web/src/test/manual/web/ckeditor/utilities.js index 2ca0fd324c..8c281e2223 100644 --- a/web/src/test/manual/web/ckeditor/utilities.js +++ b/web/src/test/manual/web/ckeditor/utilities.js @@ -1,15 +1,13 @@ -function loadKeyboards() +async function loadKeyboards() { - var kmw=keyman; - // Add more keyboards to the language menu, by keyboard name, // keyboard name and language code, or just the BCP-47 language code. // We use a different loading pattern here than in the samples version to provide a slightly different set of test cases. - kmw.addKeyboards('french','@he'); - kmw.addKeyboards({id:'sil_euro_latin', name:'SIL EuroLatin', languages: [{id:'no'}, {id:'sv'}]}); // Loads from partial stub instead of the compact string. + await keyman.addKeyboards('french', '@he', + { id: 'sil_euro_latin', name: 'SIL EuroLatin', languages: [{ id: 'no' }, { id: 'sv' }] }); // Loads from partial stub instead of the compact string. // Add a keyboard by language name. Note that the name must be spelled // correctly, or the keyboard will not be found. (Using BCP-47 codes is // usually easier.) - kmw.addKeyboardsForLanguage('Dzongkha'); + await keyman.addKeyboardsForLanguage('Dzongkha'); } \ No newline at end of file diff --git a/web/src/test/manual/web/commonHeader.js b/web/src/test/manual/web/commonHeader.js index 74cb22e1cd..e80368b556 100644 --- a/web/src/test/manual/web/commonHeader.js +++ b/web/src/test/manual/web/commonHeader.js @@ -1,172 +1,122 @@ -// JavaScript Document samplehdr.js: Keyboard management for KeymanWeb demonstration pages - /* - The keyboard name and/or BCP-47 language code must be specified for each keyboard that is to be available. - If the same keyboard is used for several languages, it must be listed for each - language, but the keyboard itself will only be loaded once. - If two (or more) keyboards are to be available for a given language, both must be listed. - Any number of keyboards may be specified in one or more calls. - Keyboard paths may be absolute (with respect to the server root) or relative to the keyboards option path. - The actual keyboard object will be downloaded asynchronously when first selected for use. + * Keyman is copyright (C) SIL Global. MIT License. + */ - Each argument to addKeyboards() is a string, for example: - european2 loads the current version of the Eurolatin 2 keyboard (for its default language) - european2@fr loads the current version of the Eurolatin 2 keyboard for French - european2@fr@1.2 loads version 1.2 of the Eurolatin 2 keyboard for French - - Argument syntax also supports the following extensions: - @fr load the current version of the default keyboard for French - @fr$ load all available keyboards (current version) for French - - Each call to addKeyboards() requires a single call to the remote server, - (unless all keyboards listed are local and fully specified) so it is better - to use multiple arguments rather than separate function calls. - - Calling addKeyboards() with no arguments returns a list of *all* available keyboards. - The Toolbar (desktop browser) UI is best suited for allowing users to select - the appropriate language and keyboard in this case. - - Keyboards may also be specified by language name using addKeyboardsForLanguage() - for example: - keymanweb.addKeyboardsForLanguage('Burmese'); - - Appending $ to the language name will again cause all available keyboards for that - language to be loaded rather than the default keyboard. - - The first call to addKeyboardsForLanguage() makes an additional call to the - keyman API to load the current list of keyboard/language associations. - - In this example, the following function loads the indicated keyboards, - and is called when the page loads. -*/ - - function errToString(err) { - // Painful? Kinda. But needed on un-updated Android API 21! - if(Array.isArray(err)) { - var result = ''; - for(var i = 0; i < err.length; i++) { - var e = err[i]; - if(e.error instanceof Error) { - result += e.error.message + '\n'; - } else { - result += JSON.stringify(e) + '\n'; - } - } - return result; - } - if(err instanceof Error) { - return err.message; - } - return JSON.stringify(err); - } - - function doAddKeyboards(data) { - return keyman.addKeyboards(data).catch(function(err) { - console.error('keyman.addKeyboards failed with '+errToString(err)+' for '+JSON.stringify(data)); - }); - } - - function doAddKeyboardsForLanguage(data) { - return keyman.addKeyboardsForLanguage(data).catch(function(err) { - console.error('keyman.addKeyboardsForLanguage failed with '+errToString(err)+' for '+JSON.stringify(data)); - }); - } - - function loadKeyboards(nestLevel) - { - var kmw=keyman; - - var base_prefix = '../'; - var prefix = './'; // The default - when prefix == 0. - - if(nestLevel !== undefined && nestLevel > 0) { - prefix = ''; - for(var i=0; i < nestLevel; i++) { - prefix = prefix + base_prefix; +function errToString(err) { + // Painful? Kinda. But needed on un-updated Android API 21! + if(Array.isArray(err)) { + let result = ''; + for(let i = 0; i < err.length; i++) { + const e = err[i]; + if(e.error instanceof Error) { + result += e.error.message + '\n'; + } else { + result += JSON.stringify(e) + '\n'; } } - - // The first keyboard added will be the default keyboard for touch devices. - // For faster loading, it may be best for the default keyboard to be - // locally sourced. - doAddKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, - filename:(prefix + 'us-1.0.js')}); - - doAddKeyboards({id:'web_context_tests',name:'Web Context Tests',languages:{id:'en',name:'English'}, - filename:(prefix + 'web_context_tests.js')}); - - doAddKeyboards({id:'test_chirality',name:'test_chirality',languages:{id:'en',name:'English'}, - filename:(prefix + 'test_chirality.js')}); - - doAddKeyboards({id:'obolo_chwerty_6351',name:'obolo_chwerty_6351',languages:{id:'en',name:'English'}, - filename:(prefix + 'obolo_chwerty_6351.js')}); - - doAddKeyboards({id:'gesture_prototyping',name:'Gesture Prototyping',languages:{id:'en',name:'English'}, - filename:(prefix + 'keyboards/gesture_prototyping/build/gesture_prototyping.js')}); - - doAddKeyboards({id:'diacritic_rota',name:'Diacritic 10-key Rota',languages:{id:'en',name:'English'}, - filename:(prefix + 'keyboards/diacritic_rota/build/diacritic_rota.js')}); - - doAddKeyboards({id:'ye_old_ten_key',name:'Classic 10-key',languages:{id:'en',name:'English'}, - filename:(prefix + 'keyboards/ye_old_ten_key/build/ye_old_ten_key.js')}); - - // Add more keyboards to the language menu, by keyboard name, - // keyboard name and language code, or just the BCP-47 language code. - // We use a different loading pattern here than in the samples version to provide a slightly different set of test cases. - doAddKeyboards('french','@he'); - doAddKeyboards('khmer_angkor','@km'); - doAddKeyboards({id:'sil_euro_latin', name:'SIL EuroLatin', languages: [{id:'no'}, {id:'sv'}]}); // Loads from partial stub instead of the compact string. - - // Add a keyboard by language name. Note that the name must be spelled - // correctly, or the keyboard will not be found. (Using BCP-47 codes is - // usually easier.) - doAddKeyboardsForLanguage('Dzongkha'); - - // Add a fully-specified, locally-sourced, keyboard with custom font - doAddKeyboards({id:'lao_2008_basic',name:'Lao Basic', - languages: { - id:'lo',name:'Lao',region:'Asia', - }, - filename:(prefix + 'lao_2008_basic-1.2.js') - }); - - // The following two optional calls should be delayed until language menus are fully loaded: - // (a) a specific mapped input element input is focused, to ensure that the OSK appears - // (b) a specific keyboard is loaded, rather than the keyboard last used. - //window.setTimeout(function(){kmw.setActiveElement('ta1',true);},2500); - //window.setTimeout(function(){kmw.setActiveKeyboard('Keyboard_french','fr');},3000); - - // Note that locally specified keyboards will be listed before keyboards - // requested from the remote server by user interfaces that do not order - // keyboards alphabetically by language. + return result; } + if(err instanceof Error) { + return err.message; + } + return JSON.stringify(err); +} - // Script to allow a user to add any keyboard to the keyboard menu - function addKeyboard(n) - { - var sKbd,kmw=keyman; - switch(n) - { - case 1: - sKbd=document.getElementById('kbd_id1').value; - doAddKeyboards(sKbd); - break; - case 2: - sKbd=document.getElementById('kbd_id2').value.toLowerCase(); - doAddKeyboards('@'+sKbd); - break; - case 3: - // Add keyboard for comma-separated language name(s) - sKbd=document.getElementById('kbd_id3').value; - doAddKeyboardsForLanguage(sKbd); - break; +function doAddKeyboards(data) { + return keyman.addKeyboards(data).catch(function(err) { + console.error('keyman.addKeyboards failed with '+errToString(err)+' for '+JSON.stringify(data)); + }); +} + +function doAddKeyboardsForLanguage(data) { + return keyman.addKeyboardsForLanguage(data).catch(function(err) { + console.error('keyman.addKeyboardsForLanguage failed with '+errToString(err)+' for '+JSON.stringify(data)); + }); +} + +async function loadKeyboards(nestLevel) { + const base_prefix = '../'; + let prefix = './'; // The default - when prefix == 0. + + if(nestLevel !== undefined && nestLevel > 0) { + prefix = ''; + for(let i=0; i < nestLevel; i++) { + prefix += base_prefix; } } - // Add keyboard on Enter (as well as pressing button) - function clickOnEnter(e,id) - { - e = e || window.event; - if(e.keyCode == 13) addKeyboard(id); - } + // The first keyboard added will be the default keyboard for touch devices. + // For faster loading, it may be best for the default keyboard to be + // locally sourced. + await doAddKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, + filename:(prefix + 'us-1.0.js')}); + + await doAddKeyboards({id:'web_context_tests',name:'Web Context Tests',languages:{id:'en',name:'English'}, + filename:(prefix + 'web_context_tests.js')}); + + await doAddKeyboards({id:'test_chirality',name:'test_chirality',languages:{id:'en',name:'English'}, + filename:(prefix + 'test_chirality.js')}); + + await doAddKeyboards({id:'obolo_chwerty_6351',name:'obolo_chwerty_6351',languages:{id:'en',name:'English'}, + filename:(prefix + 'obolo_chwerty_6351.js')}); + + await doAddKeyboards({id:'gesture_prototyping',name:'Gesture Prototyping',languages:{id:'en',name:'English'}, + filename:(prefix + 'keyboards/gesture_prototyping/build/gesture_prototyping.js')}); + + await doAddKeyboards({id:'diacritic_rota',name:'Diacritic 10-key Rota',languages:{id:'en',name:'English'}, + filename:(prefix + 'keyboards/diacritic_rota/build/diacritic_rota.js')}); + + await doAddKeyboards({id:'ye_old_ten_key',name:'Classic 10-key',languages:{id:'en',name:'English'}, + filename:(prefix + 'keyboards/ye_old_ten_key/build/ye_old_ten_key.js')}); + + // Add more keyboards to the language menu, by keyboard name, + // keyboard name and language code, or just the BCP-47 language code. + // We use a different loading pattern here than in the samples version to provide a slightly different set of test cases. + await doAddKeyboards('french','@he'); + await doAddKeyboards('khmer_angkor','@km'); + await doAddKeyboards({id:'sil_euro_latin', name:'SIL EuroLatin', languages: [{id:'no'}, {id:'sv'}]}); // Loads from partial stub instead of the compact string. + + // Add a keyboard by language name. Note that the name must be spelled + // correctly, or the keyboard will not be found. (Using BCP-47 codes is + // usually easier.) + await doAddKeyboardsForLanguage('Dzongkha'); + + // Add a fully-specified, locally-sourced, keyboard with custom font + await doAddKeyboards({ + id: 'lao_2008_basic', + name: 'Lao Basic', + languages: { + id: 'lo', name: 'Lao', region: 'Asia' + }, + filename: (prefix + 'lao_2008_basic-1.2.js') + }); +} + +// Script to allow a user to add any keyboard to the keyboard menu +async function addKeyboard(n) { + let sKbd; + switch(n) { + case 1: + sKbd=document.getElementById('kbd_id1').value; + await doAddKeyboards(sKbd); + break; + case 2: + sKbd=document.getElementById('kbd_id2').value.toLowerCase(); + await doAddKeyboards('@'+sKbd); + break; + case 3: + // Add keyboard for comma-separated language name(s) + sKbd=document.getElementById('kbd_id3').value; + await doAddKeyboardsForLanguage(sKbd); + break; + } +} + +// Add keyboard on Enter (as well as pressing button) +async function clickOnEnter(e,id) { + e = e || window.event; + if (e.keyCode == 13) { + await addKeyboard(id); + } +} diff --git a/web/src/test/manual/web/default-subkey/index.html b/web/src/test/manual/web/default-subkey/index.html index 728355c43b..22f00ef3fe 100644 --- a/web/src/test/manual/web/default-subkey/index.html +++ b/web/src/test/manual/web/default-subkey/index.html @@ -36,11 +36,10 @@ - +

KeymanWeb Testing Page - Desktop UI module Testing

This page is designed to facilitate testing of various aspects of the Toolbar UI for KeymanWeb. Originally developed to help address issue #1275. diff --git a/web/src/test/manual/web/empty-row/index.html b/web/src/test/manual/web/empty-row/index.html index 02953493e9..ee6da66cca 100644 --- a/web/src/test/manual/web/empty-row/index.html +++ b/web/src/test/manual/web/empty-row/index.html @@ -36,18 +36,16 @@ - - + + @@ -47,7 +49,7 @@ - +

KeymanWeb: 'Test case' for proper implementation of the removeKeyboards API function

diff --git a/web/src/test/manual/web/issue103/index.html b/web/src/test/manual/web/issue103/index.html index 35b006e347..53c0447cbd 100644 --- a/web/src/test/manual/web/issue103/index.html +++ b/web/src/test/manual/web/issue103/index.html @@ -36,10 +36,11 @@ @@ -48,7 +49,7 @@ - +

KeymanWeb Sample Page - Keyboard Registration Check

This page is designed to test KeymanWeb's behavior when being told to load a keyboard multiple times, both via diff --git a/web/src/test/manual/web/issue103/samplehdr.js b/web/src/test/manual/web/issue103/samplehdr.js index 36b08861c1..e689bf4b3b 100644 --- a/web/src/test/manual/web/issue103/samplehdr.js +++ b/web/src/test/manual/web/issue103/samplehdr.js @@ -1,70 +1,64 @@ -// Modified version of commonHeader - contains repeated requests for the same language. +/* + * Keyman is copyright (C) SIL Global. MIT License. + * + * Modified version of commonHeader.js - contains repeated requests for the same language. + */ - function loadKeyboards() - { - var kmw=keyman; - - // The first keyboard added will be the default keyboard for touch devices. - // For faster loading, it may be best for the default keyboard to be - // locally sourced. - kmw.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, - filename:'../us-1.0.js'}); - - // Add more keyboards to the language menu, by keyboard name, - // keyboard name and language code, or just the BCP-47 language code. - kmw.addKeyboards('french','european2@sv','european2@sv','european2@sv','european2@sv','european2@sv','european2@sv','european2@no','@he'); - kmw.addKeyboards('@he'); - kmw.addKeyboards('@he'); - - // Add a keyboard by language name. Note that the name must be spelled - // correctly, or the keyboard will not be found. (Using BCP-47 codes is - // usually easier.) - kmw.addKeyboardsForLanguage('Dzongkha'); - - // Add a fully-specified, locally-sourced, keyboard with custom font - kmw.addKeyboards({id:'lao_2008_basic',name:'Lao Basic', - languages:{ - id:'lo',name:'Lao',region:'Asia' - }, - filename:'../lao_2008_basic.js' - }); +async function loadKeyboards() { + await keyman.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, + filename:'../us-1.0.js'}); - // The following two optional calls should be delayed until language menus are fully loaded: - // (a) a specific mapped input element input is focused, to ensure that the OSK appears - // (b) a specific keyboard is loaded, rather than the keyboard last used. - //window.setTimeout(function(){kmw.setActiveElement('ta1',true);},2500); - //window.setTimeout(function(){kmw.setActiveKeyboard('Keyboard_french','fr');},3000); - - // Note that locally specified keyboards will be listed before keyboards - // requested from the remote server by user interfaces that do not order - // keyboards alphabetically by language. - } - - // Script to allow a user to add any keyboard to the keyboard menu - function addKeyboard(n) - { - var sKbd,kmw=keyman; - switch(n) - { - case 1: - sKbd=document.getElementById('kbd_id1').value; - kmw.addKeyboards(sKbd); - break; - case 2: - sKbd=document.getElementById('kbd_id2').value.toLowerCase(); - kmw.addKeyboards('@'+sKbd); - break; - case 3: - sKbd=document.getElementById('kbd_id3').value; - kmw.addKeyboardsForLanguage(sKbd); - break; - } - } - - // Add keyboard on Enter (as well as pressing button) - function clickOnEnter(e,id) - { - e = e || window.event; - if(e.keyCode == 13) addKeyboard(id); - } + // Intentionally request the same keyboard multiple times to test that it + // is not added multiple times and doesn't cause an error. + await keyman.addKeyboards('french', 'european2@sv', 'european2@sv', 'european2@sv', + 'european2@sv', 'european2@sv', 'european2@sv', 'european2@no', '@he'); + await keyman.addKeyboards('@he'); + await keyman.addKeyboards('@he'); // intentional duplicate + + // Add a keyboard by language name. Note that the name must be spelled + // correctly, or the keyboard will not be found. (Using BCP-47 codes is + // usually easier.) + await keyman.addKeyboardsForLanguage('Dzongkha'); + + // Add a fully-specified, locally-sourced, keyboard with custom font + await keyman.addKeyboards({ + id: 'lao_2008_basic', + name: 'Lao Basic', + languages:{ + id: 'lo', + name: 'Lao', + region: 'Asia' + }, + filename: '../lao_2008_basic.js' + }); +} + +// Script to allow a user to add any keyboard to the keyboard menu +async function addKeyboard(n) +{ + let sKbd; + switch(n) + { + case 1: + sKbd=document.getElementById('kbd_id1').value; + await keyman.addKeyboards(sKbd); + break; + case 2: + sKbd=document.getElementById('kbd_id2').value.toLowerCase(); + await keyman.addKeyboards('@'+sKbd); + break; + case 3: + sKbd=document.getElementById('kbd_id3').value; + await keyman.addKeyboardsForLanguage(sKbd); + break; + } +} + +// Add keyboard on Enter (as well as pressing button) +async function clickOnEnter(e,id) { + e = e || window.event; + if (e.keyCode == 13) { + await addKeyboard(id); + } +} diff --git a/web/src/test/manual/web/issue115/index.html b/web/src/test/manual/web/issue115/index.html index cd9afcb8fa..f55d98d382 100644 --- a/web/src/test/manual/web/issue115/index.html +++ b/web/src/test/manual/web/issue115/index.html @@ -36,11 +36,10 @@ diff --git a/web/src/test/manual/web/issue116/index.html b/web/src/test/manual/web/issue116/index.html index d81fb947c0..d8f64d9f74 100644 --- a/web/src/test/manual/web/issue116/index.html +++ b/web/src/test/manual/web/issue116/index.html @@ -36,12 +36,12 @@ diff --git a/web/src/test/manual/web/issue11785/index.html b/web/src/test/manual/web/issue11785/index.html index 5df453aab9..fb51a97bcf 100644 --- a/web/src/test/manual/web/issue11785/index.html +++ b/web/src/test/manual/web/issue11785/index.html @@ -40,9 +40,8 @@ @@ -49,7 +50,7 @@ - +

KeymanWeb Sample Page - Mixed Case of TTF font files

Previously, KMW was not applying .TTF fonts on mobile devices.

See issue #1332 diff --git a/web/src/test/manual/web/issue160/index.html b/web/src/test/manual/web/issue160/index.html index 33219e7fdf..3808341b7d 100644 --- a/web/src/test/manual/web/issue160/index.html +++ b/web/src/test/manual/web/issue160/index.html @@ -36,12 +36,12 @@ diff --git a/web/src/test/manual/web/issue266/index.html b/web/src/test/manual/web/issue266/index.html index 56e52016d7..adf03ffe70 100644 --- a/web/src/test/manual/web/issue266/index.html +++ b/web/src/test/manual/web/issue266/index.html @@ -36,12 +36,12 @@ diff --git a/web/src/test/manual/web/issue271/header.js b/web/src/test/manual/web/issue271/header.js index b0d52effe9..6fd6bec984 100644 --- a/web/src/test/manual/web/issue271/header.js +++ b/web/src/test/manual/web/issue271/header.js @@ -1,7 +1,5 @@ function setActiveKeyboard() { - var kmw=window['keyman'] ? keyman : tavultesoft.keymanweb; - var sKbd = document.getElementById('kbd_id4').value; var sLng = document.getElementById('lang_id4').value; - var result = kmw.setActiveKeyboard("Keyboard_" + sKbd, sLng); + var result = keyman.setActiveKeyboard("Keyboard_" + sKbd, sLng); } \ No newline at end of file diff --git a/web/src/test/manual/web/issue271/index.html b/web/src/test/manual/web/issue271/index.html index fa969195a1..0bf9624779 100644 --- a/web/src/test/manual/web/issue271/index.html +++ b/web/src/test/manual/web/issue271/index.html @@ -36,9 +36,10 @@ @@ -49,7 +50,7 @@ - +

KeymanWeb: Test page for interactions between setActiveKeyboard and the toolbar UI

This version is used to test the interactions of SetActiveKeyboard with the Toolbar UI.

diff --git a/web/src/test/manual/web/issue29/index.html b/web/src/test/manual/web/issue29/index.html index 24a226326c..3f007c9cb4 100644 --- a/web/src/test/manual/web/issue29/index.html +++ b/web/src/test/manual/web/issue29/index.html @@ -36,8 +36,9 @@ @@ -47,7 +48,7 @@ - +

KeymanWeb: Test desktop MutationObserver functionality

diff --git a/web/src/test/manual/web/issue3701/index.html b/web/src/test/manual/web/issue3701/index.html index c27bba6c81..6393f5fe7c 100644 --- a/web/src/test/manual/web/issue3701/index.html +++ b/web/src/test/manual/web/issue3701/index.html @@ -36,11 +36,10 @@ diff --git a/web/src/test/manual/web/issue53/index.html b/web/src/test/manual/web/issue53/index.html index 4c730a3f39..d58dbcfdf4 100644 --- a/web/src/test/manual/web/issue53/index.html +++ b/web/src/test/manual/web/issue53/index.html @@ -36,9 +36,10 @@ @@ -48,7 +49,7 @@ - +

KeymanWeb: Tests layering transitions for keyboards with variable layer sizes.

This test should be run from mobile devices or with Chrome's mobile device emulation settings available within Developer Mode.

diff --git a/web/src/test/manual/web/issue53/issue53.js b/web/src/test/manual/web/issue53/issue53.js index 03d1175866..4cef9371cd 100644 --- a/web/src/test/manual/web/issue53/issue53.js +++ b/web/src/test/manual/web/issue53/issue53.js @@ -1,9 +1,7 @@ function loadKeyboards() { - var kmw=keyman; - // Add a fully-specified, locally-sourced, keyboard. - kmw.addKeyboards({id:'layered_debug_keyboard',name:'Web_Layer_Debugging', + keyman.addKeyboards({id:'layered_debug_keyboard',name:'Web_Layer_Debugging', languages:{ id:'dbg',name:'Debug',region:'North America' }, @@ -14,28 +12,28 @@ function loadKeyboards() // Script to allow a user to add any keyboard to the keyboard menu function addKeyboard(n) { - var sKbd,kmw=keyman; + var sKbd; switch(n) { case 1: sKbd=document.getElementById('kbd_id1').value; - kmw.addKeyboards(sKbd); + keyman.addKeyboards(sKbd); break; case 2: sKbd=document.getElementById('kbd_id2').value.toLowerCase(); - kmw.addKeyboards('@'+sKbd); + keyman.addKeyboards('@'+sKbd); break; case 3: sKbd=document.getElementById('kbd_id3').value; - kmw.addKeyboardsForLanguage(sKbd); + keyman.addKeyboardsForLanguage(sKbd); break; } } function removeKeyboard(n) { - var sKbd=document.getElementById('kbd_id4').value, kmw=keyman; - kmw["removeKeyboards"](sKbd); + var sKbd=document.getElementById('kbd_id4').value; + keyman.removeKeyboards(sKbd); } // Add keyboard on Enter (as well as pressing button) diff --git a/web/src/test/manual/web/issue6005/index.html b/web/src/test/manual/web/issue6005/index.html index 7326f99c7d..9410bed564 100644 --- a/web/src/test/manual/web/issue6005/index.html +++ b/web/src/test/manual/web/issue6005/index.html @@ -40,13 +40,11 @@ const alertType = (new URLSearchParams(window.location.search)).get("useAlerts") != "false"; var alertText = alertType ? 'enabled(default)' : 'disabled'; - var kmw=window.keyman; - - kmw.init({ + keyman.init({ 'attachType': 'auto' }).then(function() { // if mobile device, activate pred text. - if(kmw.util.isTouchDevice()) { + if(keyman.util.isTouchDevice()) { var pageRef = (window.location.protocol == 'file:') ? window.location.href.substr(0, window.location.href.lastIndexOf('/')+1) : window.location.href; @@ -60,24 +58,25 @@ languages: ['en'], path: (pageRef + "prediction-mtnt/nrc.en.mtnt.model.js") }; - kmw.addModel(modelStub1); + keyman.addModel(modelStub1); var modelStub2 = {'id': 'nrc.en.mtnt', languages: ['pny-latn'], // yep. Total cheat for the sake of testing. path: (pageRef + "prediction-mtnt/nrc.en.mtnt.model.js") }; - kmw.addModel(modelStub2); + keyman.addModel(modelStub2); } - }); - kmw.addKeyboards('sil_euro_latin@en', - 'galaxie_hebrew_positional@he', - 'sil_cameroon_qwerty@pny-latn'); - kmw.addKeyboards({ - id:'unmatched_final_group_model_interactions_6005', - name:'"Unmatched Vowel Rule"', - languages:{id:'en',name:'English'}, - filename:('unmatched_final_group_model_interactions_6005.js') - }); + keyman.addKeyboards('sil_euro_latin@en', + 'galaxie_hebrew_positional@he', + 'sil_cameroon_qwerty@pny-latn'); + + keyman.addKeyboards({ + id:'unmatched_final_group_model_interactions_6005', + name:'"Unmatched Vowel Rule"', + languages:{id:'en',name:'English'}, + filename:('unmatched_final_group_model_interactions_6005.js') + }); + }); diff --git a/web/src/test/manual/web/issue62/index.html b/web/src/test/manual/web/issue62/index.html index 23ac9889df..c647b03e88 100644 --- a/web/src/test/manual/web/issue62/index.html +++ b/web/src/test/manual/web/issue62/index.html @@ -36,9 +36,10 @@ @@ -49,7 +50,7 @@ - +

KeymanWeb: Light test for touch-based MutationObserver functionality

diff --git a/web/src/test/manual/web/issue63/index.html b/web/src/test/manual/web/issue63/index.html index 55cee63c97..acb2cdd40f 100644 --- a/web/src/test/manual/web/issue63/index.html +++ b/web/src/test/manual/web/issue63/index.html @@ -36,9 +36,10 @@ @@ -49,7 +50,7 @@ - +

KeymanWeb: Test/stress-test touch-based MutationObserver functionality

diff --git a/web/src/test/manual/web/issue917-context-and-notany/index.html b/web/src/test/manual/web/issue917-context-and-notany/index.html index 251edb9142..f7941b8a0d 100644 --- a/web/src/test/manual/web/issue917-context-and-notany/index.html +++ b/web/src/test/manual/web/issue917-context-and-notany/index.html @@ -36,11 +36,10 @@ diff --git a/web/src/test/manual/web/issue920/index.html b/web/src/test/manual/web/issue920/index.html index b20f536906..03265f30bf 100644 --- a/web/src/test/manual/web/issue920/index.html +++ b/web/src/test/manual/web/issue920/index.html @@ -36,15 +36,10 @@ - +

KeymanWeb Sample Page - deadkeys and multiple groups Testing

See issue #920 for details on what this test is all about. Both ;e and .e should produce ə but ;e uses a deadkey and fails.

diff --git a/web/src/test/manual/web/issue9469/index.html b/web/src/test/manual/web/issue9469/index.html index 78c3a15f95..5c7e33daa3 100644 --- a/web/src/test/manual/web/issue9469/index.html +++ b/web/src/test/manual/web/issue9469/index.html @@ -36,11 +36,10 @@ @@ -48,7 +49,7 @@ - +

KeymanWeb Sample Page - Error Testing page

Pick one of the 'debugging' keyboards to test whether the represented error is handled correctly.

diff --git a/web/src/test/manual/web/mnemonic/index.html b/web/src/test/manual/web/mnemonic/index.html index e0b0f0de79..a77c862219 100644 --- a/web/src/test/manual/web/mnemonic/index.html +++ b/web/src/test/manual/web/mnemonic/index.html @@ -33,24 +33,21 @@ - - diff --git a/web/src/test/manual/web/options-with-save/index.html b/web/src/test/manual/web/options-with-save/index.html index 9f607fd11f..2e69318bbc 100644 --- a/web/src/test/manual/web/options-with-save/index.html +++ b/web/src/test/manual/web/options-with-save/index.html @@ -33,24 +33,21 @@ - - diff --git a/web/src/test/manual/web/osk-event-buttons/index.html b/web/src/test/manual/web/osk-event-buttons/index.html index 92dafcdb4a..95ce7c7707 100644 --- a/web/src/test/manual/web/osk-event-buttons/index.html +++ b/web/src/test/manual/web/osk-event-buttons/index.html @@ -36,8 +36,7 @@ @@ -51,7 +52,7 @@ - +

KeymanWeb Sample Page - Platform Testing

This page is designed to test the Platform statement for consistency. Refer to PR #969.
diff --git a/web/src/test/manual/web/platform/utilities.js b/web/src/test/manual/web/platform/utilities.js index 5c351e0317..bb02bdd6a1 100644 --- a/web/src/test/manual/web/platform/utilities.js +++ b/web/src/test/manual/web/platform/utilities.js @@ -1,8 +1,6 @@ -function loadKeyboards() -{ - var kmw=keyman; - - kmw.addKeyboards({id:'platformtest',name:'Platform Testing', +function loadKeyboards() +{ + keyman.addKeyboards({id:'platformtest',name:'Platform Testing', languages:{ id:'en',name:'English',region:'North America' }, diff --git a/web/src/test/manual/web/pr10506/header.js b/web/src/test/manual/web/pr10506/header.js index 0107af3525..986cc00433 100644 --- a/web/src/test/manual/web/pr10506/header.js +++ b/web/src/test/manual/web/pr10506/header.js @@ -1,11 +1,10 @@ function loadKeyboards() { - var kmw=keyman; - kmw.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, + keyman.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, filename:('../us-1.0.js')}); // Add a fully-specified, locally-sourced, keyboard with custom font - kmw.addKeyboards({id:'dotty_keys',name:'Dotty Keys', + keyman.addKeyboards({id:'dotty_keys',name:'Dotty Keys', languages:{ id:'und',name:'Special',region:'World', font:{family:'DejaVu Dots',source:['./DejaVu-Dots.ttf']} diff --git a/web/src/test/manual/web/pr10506/index.html b/web/src/test/manual/web/pr10506/index.html index 06eae11362..84ff48f868 100644 --- a/web/src/test/manual/web/pr10506/index.html +++ b/web/src/test/manual/web/pr10506/index.html @@ -36,9 +36,10 @@ @@ -49,7 +50,7 @@ - +

KeymanWeb Test Page - Key-cap scaling / font-load delay interactions

To run the test, simply change from the default (English) keyboard to the "Special" keyboard.

When things are working properly, the base keys on the "Special" keyboard should contain diff --git a/web/src/test/manual/web/prediction-mtnt/index.html b/web/src/test/manual/web/prediction-mtnt/index.html index 34f43f3c5b..0e41b5b63a 100644 --- a/web/src/test/manual/web/prediction-mtnt/index.html +++ b/web/src/test/manual/web/prediction-mtnt/index.html @@ -36,16 +36,15 @@ - +

@@ -72,8 +73,8 @@ e.value = e.value + event + ': w.iw='+window.innerWidth+' w.ih='+window.innerHeight+orientText+orient+'\n'; - if(event == 'kmw.ri' || event == 'kmw.rh' || event == 'kmw.re') { - e.value = e.value + ' osk.w=' + keyman.osk.computedWidth + ' osk.h=' + keyman.osk.computedHeight + ' kmw.vs=' + keyman.util.getViewportScale() + '\n'; + if(event == 'keyman.ri' || event == 'keyman.rh' || event == 'keyman.re') { + e.value = e.value + ' osk.w=' + keyman.osk.computedWidth + ' osk.h=' + keyman.osk.computedHeight + ' keyman.vs=' + keyman.util.getViewportScale() + '\n'; } e.scrollTop = e.scrollHeight; @@ -89,22 +90,22 @@ window.addEventListener('orientationchange', function() { doLog('orientationchange-b', false) }, false); window.addEventListener('orientationchange', function() { doLog('orientationchange-c', false) }, true); - var kmw_ri = com.keyman.RotationManager.prototype.initNewRotation; + var keyman_ri = com.keyman.RotationManager.prototype.initNewRotation; com.keyman.RotationManager.prototype.initNewRotation = function() { - doLog('kmw.ri'); - kmw_ri.call(this); + doLog('keyman.ri'); + keyman_ri.call(this); } - var kmw_rh = com.keyman.RotationManager.prototype.iOSEventHandler; + var keyman_rh = com.keyman.RotationManager.prototype.iOSEventHandler; com.keyman.RotationManager.prototype.iOSEventHandler = function() { - doLog('kmw.rh'); - kmw_rh.call(this); + doLog('keyman.rh'); + keyman_rh.call(this); } - var kmw_irh = com.keyman.RotationManager.prototype.resolve; + var keyman_irh = com.keyman.RotationManager.prototype.resolve; com.keyman.RotationManager.prototype.resolve = function() { - doLog('kmw.re'); - kmw_irh.call(this); + doLog('keyman.re'); + keyman_irh.call(this); }

Return to main index. diff --git a/web/src/test/manual/web/sentry-integration/errorhdr.js b/web/src/test/manual/web/sentry-integration/errorhdr.js index f5e4ec283f..27b8869504 100644 --- a/web/src/test/manual/web/sentry-integration/errorhdr.js +++ b/web/src/test/manual/web/sentry-integration/errorhdr.js @@ -1,27 +1,25 @@ -// JavaScript Document samplehdr.js: Keyboard management for KeymanWeb demonstration pages - -/* - This script is designed to test KeymanWeb error message handling. +/* + * Keyman is copyright (C) SIL Global. MIT License. + * + * This script is designed to test KeymanWeb error message handling. */ -function loadKeyboards() { - var kmw=keyman; - +async function loadKeyboards() { // We start by adding a keyboard correctly. It's best to include a 'control' in our experiment. - kmw.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, + await keyman.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'}, filename:'../us-1.0.js'}); - + // Insert a keyboard that cannot be found. - kmw.addKeyboards({id:'lao_2008_basic',name:'wrong-filename', + await keyman.addKeyboards({id:'lao_2008_basic',name:'wrong-filename', languages:{ id:'lo',name:'debugging',region:'Asia', font:{family:'LaoWeb',source:['../font/saysettha_web.ttf','../font/saysettha_web.woff','../font/saysettha_web.eot']} }, filename:'./missing_file.js' // Intentional error - the file doesn't exist, so the @@ -51,7 +52,7 @@ - +

KeymanWeb Sample Page - Shift Testing

See issue #978 for details on what this test is all about.

diff --git a/web/src/test/manual/web/test-updateLayer/utilities.js b/web/src/test/manual/web/test-updateLayer/utilities.js index 41704fa0da..378f44c87e 100644 --- a/web/src/test/manual/web/test-updateLayer/utilities.js +++ b/web/src/test/manual/web/test-updateLayer/utilities.js @@ -1,8 +1,6 @@ -function loadKeyboards() -{ - var kmw=keyman; - - kmw.addKeyboards({id:'rac_balti',name:'RAC Balti', +function loadKeyboards() +{ + keyman.addKeyboards({id:'rac_balti',name:'RAC Balti', languages:{ id:'en',name:'English',region:'North America' }, diff --git a/web/src/test/manual/web/text_selection_tests_9073/index.html b/web/src/test/manual/web/text_selection_tests_9073/index.html index 20bd3cda68..7851186892 100644 --- a/web/src/test/manual/web/text_selection_tests_9073/index.html +++ b/web/src/test/manual/web/text_selection_tests_9073/index.html @@ -20,23 +20,21 @@ + }); + diff --git a/web/src/test/manual/web/unminified - manual.html b/web/src/test/manual/web/unminified - manual.html index dbe7cdae48..5ff0c686e3 100644 --- a/web/src/test/manual/web/unminified - manual.html +++ b/web/src/test/manual/web/unminified - manual.html @@ -36,8 +36,7 @@ diff --git a/web/src/tools/testing/bulk_rendering/renderer_core.ts b/web/src/tools/testing/bulk_rendering/renderer_core.ts index fa90283838..597ef36950 100644 --- a/web/src/tools/testing/bulk_rendering/renderer_core.ts +++ b/web/src/tools/testing/bulk_rendering/renderer_core.ts @@ -326,5 +326,5 @@ export class BatchRenderer { // BatchRenderer's internal state stuff is static on the class and is not exposed with // the line below. // @ts-ignore - window['kmw_renderer'] = new BatchRenderer(); + window['keyman_renderer'] = new BatchRenderer(); })(); \ No newline at end of file diff --git a/web/src/tools/testing/recorder/index.html b/web/src/tools/testing/recorder/index.html index f4a68ba769..a9af8e2029 100644 --- a/web/src/tools/testing/recorder/index.html +++ b/web/src/tools/testing/recorder/index.html @@ -57,6 +57,8 @@ keyman.init({ attachType: 'auto', keyboards: '' + }).then(function () { + loadKeyboards(); }); document.getElementById("body").focus(); @@ -67,7 +69,7 @@ - +
diff --git a/windows/docs/help/basic/config/options.md b/windows/docs/help/basic/config/options.md index 3b4bbd86b0..f4084f6465 100644 --- a/windows/docs/help/basic/config/options.md +++ b/windows/docs/help/basic/config/options.md @@ -180,6 +180,28 @@ To open the Options tab of Keyman Configuration: log on for short and isolated tests as specifically requested by Keyman Technical Support. +- Proxy Settings + + In some environments, you may need to configure proxy settings in + order to download keyboards or updates for Keyman. Check with your + network administrator. More information is available in the + [Proxy Configuration](../../advanced/proxy_config) documentation. + +- Keyman System Settings + + The Keyman System Settings dialog provides access to various low-level + Keyman configuration settings. Generally, these settings do not need + to be changed, unless you instructed to do so by Keyman support staff. + +- Base Keyboard + + The Base Keyboard dialog allows you to select the physical Latin-script + layout of your keyboard, which will allow certain Keyman keyboards to remap + themselves dynamically to match your key caps. + + [Base Keyboard dialog](../../context/base-keyboard) + + ## Related Topics - [Keyman Configuration](../config/)