diff --git a/common/web/keyboard-processor/src/keyboards/keyboardProperties.ts b/common/web/keyboard-processor/src/keyboards/keyboardProperties.ts index 8495d6253e..e83d1a137f 100644 --- a/common/web/keyboard-processor/src/keyboards/keyboardProperties.ts +++ b/common/web/keyboard-processor/src/keyboards/keyboardProperties.ts @@ -142,6 +142,7 @@ export default class KeyboardProperties implements KeyboardInternalPropertySpec this.KN = other.KN; this.KL = other.KL; this.KLC = other.KLC; + // Do NOT apply fontPath here; the mobile apps will have font issues if you do! this.KFont = other.KFont; this.KOskFont = other.KOskFont; this._displayName = (other instanceof KeyboardProperties) ? other._displayName : other.displayName; diff --git a/developer/src/server/build.sh b/developer/src/server/build.sh index 53585f1df6..c735e26fec 100755 --- a/developer/src/server/build.sh +++ b/developer/src/server/build.sh @@ -124,20 +124,18 @@ fi if (( build_keymanweb )); then pushd "$KEYMAN_ROOT/web/" - ./build.sh --no-minify + ./build.sh build --debug popd fi if (( copy_keymanweb )); then - WEB_SRC="$KEYMAN_ROOT/web/build/app/web/debug" - UI_SRC="$KEYMAN_ROOT/web/build/app/ui/debug" + WEB_SRC="$KEYMAN_ROOT/web/build/publish/debug" DST="$(dirname "$THIS_SCRIPT")/src/site/resource" rm -rf "$DST" mkdir -p "$DST/osk" mkdir -p "$DST/ui" cp "$WEB_SRC/"*.js "$WEB_SRC/"*.js.map "$DST/" - cp "$UI_SRC/"*.js "$UI_SRC/"*.js.map "$DST/" cp -R "$WEB_SRC/osk/"* "$DST/osk/" cp -R "$WEB_SRC/ui/"* "$DST/ui/" cp "$KEYMAN_ROOT/web/LICENSE" "$DST/" diff --git a/developer/src/server/src/site/chargrid.js b/developer/src/server/src/site/chargrid.js index 1ce9206bae..f6c31f2df3 100644 --- a/developer/src/server/src/site/chargrid.js +++ b/developer/src/server/src/site/chargrid.js @@ -73,17 +73,10 @@ function updateLogCursor() { var i, selStart, selLength, selDirection; - if(keyman.isPositionSynthesized()) { // this is an internal function - // For touch devices, we need to ask KMW - selStart = 0; - selLength = 0; - selDirection = 'forward'; - } else { - // For desktop devices, we use the position reported by the textarea control - selStart = ta1.selectionStart; - selLength = ta1.selectionEnd - ta1.selectionStart; - selDirection = ta1.selectionDirection; - } + // We use the position reported by the textarea control + selStart = ta1.selectionStart; + selLength = ta1.selectionEnd - ta1.selectionStart; + selDirection = ta1.selectionDirection; selLength = calculateLengthByCodepoint(ta1.value, selStart, selLength); selStart = calculateLengthByCodepoint(ta1.value, 0, selStart); diff --git a/developer/src/server/src/site/test.js b/developer/src/server/src/site/test.js index 954ac203c4..60a27cc484 100644 --- a/developer/src/server/src/site/test.js +++ b/developer/src/server/src/site/test.js @@ -221,7 +221,7 @@ window.onload = function() { // Create a new on screen keyboard view and tell KeymanWeb that // we are using the targetDevice for context input. - newOSK = new com.keyman.osk.InlinedOSKView(targetDevice, keyman.util.device.coreSpec); + newOSK = new keyman.views.InlinedOSKView(keyman, { device: targetDevice }); keyman.core.contextDevice = targetDevice; keyman.osk = newOSK; @@ -238,11 +238,10 @@ window.onload = function() { keyman.addEventListener('keyboardchange', function(keyboardProperties) { if(newOSK) { keyman.osk = newOSK; - newOSK.activeKeyboard = keyman.core.activeKeyboard; + newOSK.activeKeyboard = keyman.contextManager.activeKeyboard; // Private API refs on both sides } keyboardDropdown.set(keyboardProperties.internalName); window.sessionStorage.setItem('current-keyboard', keyboardProperties.internalName); - keyman.alignInputs(); }); } diff --git a/web/src/app/browser/src/keymanEngine.ts b/web/src/app/browser/src/keymanEngine.ts index d562cb679a..dd994f6a75 100644 --- a/web/src/app/browser/src/keymanEngine.ts +++ b/web/src/app/browser/src/keymanEngine.ts @@ -3,9 +3,6 @@ import { Device as DeviceDetector } from 'keyman/engine/device-detect'; import { getAbsoluteY } from 'keyman/engine/dom-utils'; import { OutputTarget } from 'keyman/engine/element-wrappers'; import { - AnchoredOSKView, - FloatingOSKView, - FloatingOSKViewConfiguration, OSKView, TwoStateActivator, VisualKeyboard @@ -13,6 +10,7 @@ import { import { ErrorStub, KeyboardStub, CloudQueryResult, toPrefixedKeyboardId as prefixed } from 'keyman/engine/package-cache'; import { DeviceSpec, Keyboard, ProcessorInitOptions, extendString } from "@keymanapp/keyboard-processor"; +import * as views from './viewsAnchorpoint.js'; import { BrowserConfiguration, BrowserInitOptionDefaults, BrowserInitOptionSpec } from './configuration.js'; import { default as ContextManager } from './contextManager.js'; import DefaultBrowserRules from './defaultBrowserRules.js'; @@ -88,6 +86,11 @@ export default class KeymanEngine extends KeymanEngineBase { diff --git a/web/src/engine/package-cache/src/keyboardStub.ts b/web/src/engine/package-cache/src/keyboardStub.ts index 2a65cc277f..e36314bf89 100644 --- a/web/src/engine/package-cache/src/keyboardStub.ts +++ b/web/src/engine/package-cache/src/keyboardStub.ts @@ -18,6 +18,36 @@ export type KeyboardAPISpec = (APISimpleKeyboard | APICompoundKeyboard) & { export interface RawKeyboardStub extends KeyboardStub {}; +/* + * Get keyboard path (relative or absolute) + * KeymanWeb 2 revised keyboard location specification: + * (a) absolute URL (includes ':') - load from specified URL + * (b) relative URL (starts with /, ./, ../) - load with respect to current page + * (c) filename only (anything else) - prepend keyboards option to URL + * (e.g. default keyboards option will be set by Cloud) + * + * So, to fully interpret the following regex, it detects the following patterns (at minimum): + * ../file (but not .../file) + * ./file + * /file + * http:// (on the colon) + * hello:world (on the colon) - that one miiiight be less intentional, though. Would 'fall + * over' on attempted use anyway, since it's not a valid path. + * + * Alternative clearer version - '^(\.{0,2}/)|(:)'? + * Unless backslashes should be able to replace dots? + */ +const REGEX_FOR_PRECONFIGURED_PATH=RegExp('^(([\\.]/)|([\\.][\\.]/)|(/))|(:)'); + +function configureFilePathing(path: string, configurationBasePath: string) { + configurationBasePath = configurationBasePath || ''; + if(path && !REGEX_FOR_PRECONFIGURED_PATH.test(path)) { + return configurationBasePath + path; + } else { + return path; + } +} + export default class KeyboardStub extends KeyboardProperties { KR: string; KRC: string; @@ -25,7 +55,9 @@ export default class KeyboardStub extends KeyboardProperties { KP?: string; - public constructor(rawStub: RawKeyboardStub); + // For the first flavor of constructor, note that Developer relies on KMW's path config to complete the paths... + // even though supplying an 'internal'-style stub. + public constructor(rawStub: RawKeyboardStub, keyboardBaseUri?: string, fontBaseUri?: string); public constructor(apiSpec: APISimpleKeyboard & { filename: string }, keyboardBaseUri?: string, fontBaseUri?: string); public constructor(kbdId: string, lngId: string); constructor(arg0: string | RawKeyboardStub | (APISimpleKeyboard & { filename: string }), arg1?: string, arg2?: string) { @@ -34,43 +66,19 @@ export default class KeyboardStub extends KeyboardProperties { let apiSpec = arg0 as APISimpleKeyboard & { filename: string }; apiSpec.id = prefixed(apiSpec.id); super(apiSpec, arg2); - this.KF = apiSpec.filename; + this.KF = configureFilePathing(apiSpec.filename, arg1); this.mapRegion(apiSpec.languages); - - /* - * Get keyboard path (relative or absolute) - * KeymanWeb 2 revised keyboard location specification: - * (a) absolute URL (includes ':') - load from specified URL - * (b) relative URL (starts with /, ./, ../) - load with respect to current page - * (c) filename only (anything else) - prepend keyboards option to URL - * (e.g. default keyboards option will be set by Cloud) - * - * So, to fully interpret the following regex, it detects the following patterns (at minimum): - * ../file (but not .../file) - * ./file - * /file - * http:// (on the colon) - * hello:world (on the colon) - that one miiiight be less intentional, though. Would 'fall - * over' on attempted use anyway, since it's not a valid path. - * - * Alternative clearer version - '^(\.{0,2}/)|(:)'? - * Unless backslashes should be able to replace dots? - */ - let rx=RegExp('^(([\\.]/)|([\\.][\\.]/)|(/))|(:)'); - - arg1 = arg1 || ''; - if(this.KF && !rx.test(this.KF)) { - this.KF = arg1 + this.KF; - } } else { let rawStub = arg0 as RawKeyboardStub; rawStub.KI = prefixed(rawStub.KI); - super(rawStub); + super(rawStub, arg2); - this.KF = rawStub.KF; + this.KF = configureFilePathing(rawStub.KF, arg1); this.KP = rawStub.KP; this.KR = rawStub.KR; this.KRC = rawStub.KRC; + + return; } } else { diff --git a/web/src/test/auto/headless/packages/keyboardStub.js b/web/src/test/auto/headless/packages/keyboardStub.js index 4e9d08500d..af6d3bb683 100644 --- a/web/src/test/auto/headless/packages/keyboardStub.js +++ b/web/src/test/auto/headless/packages/keyboardStub.js @@ -38,6 +38,48 @@ describe("KeyboardStub", () => { }; } + it('construction from internal stub format, partially configured paths', () => { + const rawStub = { + KI: 'dummy', + KN: 'test dummy', + KL: 'English', + KLC: 'en', + KF: 'dummy.js', + // The way font paths are currently handled feels pretty rough and unclear. + // Their paths aren't updated in the same way as the KF entry. + // So... leaving font stuff out of the test for now. + // (Also, Developer doesn't seem to bother specifying font files in its stubs, so it's + // less criitcal.) + }; + + const stub = new KeyboardStub(rawStub, 'http://localhost/keyboards/', 'http://localhost/fonts/'); + + assert.equal(stub.KF, 'http://localhost/keyboards/dummy.js'); + }); + + it('construction from internal stub format, pre-configured paths', () => { + // Based on actual font pathing as hosted by the Android app. + const absolutePath = '/data/user/0/com.tavultesoft.kmapro.debug/app_data/packages/dummy/dummy.ttf'; + + const rawStub = { + KI: 'dummy', + KN: 'test dummy', + KL: 'English', + KLC: 'en', + KF: absolutePath, + // The way font paths are currently handled feels pretty rough and unclear. + // Their paths aren't updated in the same way as the KF entry. + // So... leaving font stuff out of the test for now. + // (Also, Developer doesn't seem to bother specifying font files in its stubs, so it's + // less criitcal.) + }; + + // These components... are not, but that's OK - the test is to ignore them. + const stub = new KeyboardStub(rawStub, 'http://localhost/keyboards/', 'http://localhost/fonts/'); + + assert.equal(stub.KF, absolutePath); + }); + it('merge(): barebones stub + fetched sil_euro_latin@no', async () => { const query = performMockedRequest(`${__dirname}/../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`); await query.promise;