I am trying to create a new session to have the session in a database, Postgres. I am trying to use this code, but nothing works, and it is frustrating.
I'm almost sure that I need to send a second argument, but I don't know what it will be!.
my code:
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.April22,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.PostgreSQLSessionStorage(
new URL(process.env.DATABASE_URL)
),
});
error:
┃ file:///Users/blablabla/Documents/Apps/cli_shopify_mayo2022/cli-19may/server/middleware/verify-request.js:25
┃ if (session?.isActive()) {
┃ ^
┃
┃ TypeError: session?.isActive is not a function
┃ at file:///Users/diegotorres/Documents/Apps/cli_shopify_mayo2022/cli-19may/server/middleware/verify-request.js:25:18
┃ at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
┃
┃ Node.js v18.0.0
┃ [nodemon] app crashed - waiting for file changes before starting...
postgres file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostgreSQLSessionStorage = void 0;
var tslib_1 = require("tslib");
var pg_1 = tslib_1.__importDefault(require("pg"));
var session_utils_1 = require("../session-utils");
var defaultPostgreSQLSessionStorageOptions = {
sessionTableName: 'shopify_sessions',
port: 3211,
};
var PostgreSQLSessionStorage = /** #class */ (function () {
function PostgreSQLSessionStorage(dbUrl, opts) {
if (opts === void 0) { opts = {}; }
this.dbUrl = dbUrl;
if (typeof this.dbUrl === 'string') {
this.dbUrl = new URL(this.dbUrl);
}
this.options = tslib_1.__assign(tslib_1.__assign({}, defaultPostgreSQLSessionStorageOptions), opts);
this.ready = this.init();
}
PostgreSQLSessionStorage.withCredentials = function (host, dbName, username, password, opts) {
return new PostgreSQLSessionStorage(new URL("postgres://".concat(encodeURIComponent(username), ":").concat(encodeURIComponent(password), "#").concat(host, "/").concat(encodeURIComponent(dbName))), opts);
};
PostgreSQLSessionStorage.prototype.storeSession = function (session) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var entries, query;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ready];
case 1:
_a.sent();
entries = (0, session_utils_1.sessionEntries)(session);
query = "\n INSERT INTO ".concat(this.options.sessionTableName, "\n (").concat(entries.map(function (_a) {
var _b = tslib_1.__read(_a, 1), key = _b[0];
return key;
}).join(', '), ")\n VALUES (").concat(entries.map(function (_, i) { return "$".concat(i + 1); }).join(', '), ")\n ON CONFLICT (id) DO UPDATE SET ").concat(entries
.map(function (_a) {
var _b = tslib_1.__read(_a, 1), key = _b[0];
return "".concat(key, " = Excluded.").concat(key);
})
.join(', '), ";\n ");
return [4 /*yield*/, this.query(query, entries.map(function (_a) {
var _b = tslib_1.__read(_a, 2), _key = _b[0], value = _b[1];
return value;
}))];
case 2:
_a.sent();
return [2 /*return*/, true];
}
});
});
};
PostgreSQLSessionStorage.prototype.loadSession = function (id) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var query, rows, rawResult;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ready];
case 1:
_a.sent();
query = "\n SELECT * FROM ".concat(this.options.sessionTableName, "\n WHERE id = $1;\n ");
return [4 /*yield*/, this.query(query, [id])];
case 2:
rows = _a.sent();
if (!Array.isArray(rows) || (rows === null || rows === void 0 ? void 0 : rows.length) !== 1)
return [2 /*return*/, undefined];
rawResult = rows[0];
return [2 /*return*/, (0, session_utils_1.sessionFromEntries)(Object.entries(rawResult))];
}
});
});
};
PostgreSQLSessionStorage.prototype.deleteSession = function (id) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var query;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ready];
case 1:
_a.sent();
query = "\n DELETE FROM ".concat(this.options.sessionTableName, "\n WHERE id = $1;\n ");
return [4 /*yield*/, this.query(query, [id])];
case 2:
_a.sent();
return [2 /*return*/, true];
}
});
});
};
PostgreSQLSessionStorage.prototype.disconnect = function () {
return this.client.end();
};
PostgreSQLSessionStorage.prototype.init = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
this.client = new pg_1.default.Client({ connectionString: this.dbUrl.toString() });
return [4 /*yield*/, this.connectClient()];
case 1:
_a.sent();
return [4 /*yield*/, this.createTable()];
case 2:
_a.sent();
return [2 /*return*/];
}
});
});
};
PostgreSQLSessionStorage.prototype.connectClient = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.client.connect()];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
PostgreSQLSessionStorage.prototype.hasSessionTable = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var query, _a, rows;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
query = "\n SELECT * FROM pg_catalog.pg_tables WHERE tablename = $1\n ";
return [4 /*yield*/, this.query(query, [this.options.sessionTableName])];
case 1:
_a = tslib_1.__read.apply(void 0, [_b.sent(), 1]), rows = _a[0];
return [2 /*return*/, Array.isArray(rows) && rows.length === 1];
}
});
});
};
PostgreSQLSessionStorage.prototype.createTable = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var hasSessionTable, query;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.hasSessionTable()];
case 1:
hasSessionTable = _a.sent();
if (!!hasSessionTable) return [3 /*break*/, 3];
query = "\n CREATE TABLE ".concat(this.options.sessionTableName, " (\n id varchar(255) NOT NULL PRIMARY KEY,\n shop varchar(255) NOT NULL,\n state varchar(255) NOT NULL,\n isOnline boolean NOT NULL,\n scope varchar(255),\n accessToken varchar(255)\n )\n ");
return [4 /*yield*/, this.query(query)];
case 2:
_a.sent();
_a.label = 3;
case 3: return [2 /*return*/];
}
});
});
};
PostgreSQLSessionStorage.prototype.query = function (sql, params) {
if (params === void 0) { params = []; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.client.query(sql, params)];
case 1:
result = _a.sent();
return [2 /*return*/, result.rows];
}
});
});
};
return PostgreSQLSessionStorage;
}());
exports.PostgreSQLSessionStorage = PostgreSQLSessionStorage;
so, investigating a bit I found the following file which is where the app breaks
import { Shopify } from "#shopify/shopify-api";
const TEST_GRAPHQL_QUERY = `
{
shop {
name
}
}`;
export default function verifyRequest(app, { returnHeader = true } = {}) {
return async (req, res, next) => {
const session = await Shopify.Utils.loadCurrentSession(
req,
res,
app.get("use-online-tokens")
);
let shop = req.query.shop;
if (session && shop && session.shop !== shop) {
// The current request is for a different shop. Redirect gracefully.
return res.redirect(`/auth?shop=${shop}`);
}
if (session?.isActive()) {
try {
// make a request to make sure oauth has succeeded, retry otherwise
const client = new Shopify.Clients.Graphql(
session.shop,
session.accessToken
);
await client.query({ data: TEST_GRAPHQL_QUERY });
return next();
} catch (e) {
if (
e instanceof Shopify.Errors.HttpResponseError &&
e.response.code === 401
) {
// We only want to catch 401s here, anything else should bubble up
} else {
throw e;
}
}
}
if (returnHeader) {
if (!shop) {
if (session) {
shop = session.shop;
} else if (Shopify.Context.IS_EMBEDDED_APP) {
const authHeader = req.headers.authorization;
const matches = authHeader?.match(/Bearer (.*)/);
if (matches) {
const payload = Shopify.Utils.decodeSessionToken(matches[1]);
shop = payload.dest.replace("https://", "");
}
}
}
if (!shop || shop === "") {
return res
.status(400)
.send(
`Could not find a shop to authenticate with. Make sure you are making your XHR request with App Bridge's authenticatedFetch method.`
);
}
res.status(403);
res.header("X-Shopify-API-Request-Failure-Reauthorize", "1");
res.header(
"X-Shopify-API-Request-Failure-Reauthorize-Url",
`/auth?shop=${shop}`
);
res.end();
} else {
res.redirect(`/auth?shop=${shop}`);
}
};
}
You should use cloneSession from Session
Here is full code from my working project and custom implimentation of postgresql session
// tslint:disable-next-line:no-submodule-imports
import { Session } from '#shopify/shopify-api/dist/auth/session/index.js';
import pg from 'pg';
// tslint:disable-next-line:interface-name
interface SessionInterface {
readonly id: string;
shop: string;
state: string;
isOnline: boolean;
scope?: string;
expires?: Date;
accessToken?: string;
onlineAccessInfo?: any;
isActive(): boolean;
}
// tslint:disable-next-line:interface-name
interface SessionStorage {
/**
* Creates or updates the given session in storage.
*
* #param session Session to store
*/
storeSession(session: SessionInterface): Promise<boolean>;
/**
* Loads a session from storage.
*
* #param id Id of the session to load
*/
loadSession(id: string): Promise<SessionInterface | undefined>;
/**
* Deletes a session from storage.
*
* #param id Id of the session to delete
*/
deleteSession(id: string): Promise<boolean>;
}
function fromEntries<T>(entries: Array<[keyof T, T[keyof T]]>): T {
return entries.reduce(
(acc, [key, value]) => ({ ...acc, [key]: value }),
<T>{}
);
}
function sessionFromEntries(
entries: Array<[string, string | number]>,
): SessionInterface {
const obj = fromEntries(
entries
// tslint:disable-next-line:variable-name
.filter(([_key, value]) => value !== null)
.map(([key, value]) => {
switch (key.toLowerCase()) {
case 'isonline':
return ['isOnline', value];
case 'accesstoken':
return ['accessToken', value];
default:
return [key.toLowerCase(), value];
}
}),
) as any;
if (typeof obj.isOnline === 'string') {
obj.isOnline = obj.isOnline.toString().toLowerCase() === 'true';
} else if (typeof obj.isOnline === 'number') {
obj.isOnline = Boolean(obj.isOnline);
}
if (obj.scope) { obj.scope = obj.scope.toString(); }
return obj;
}
const includedKeys = [
'id',
'shop',
'state',
'isOnline',
'scope',
'accessToken',
];
function sessionEntries(
session: SessionInterface,
): Array<[string, string | number]> {
return Object.entries(session).filter(([key]) => includedKeys.includes(key));
}
// tslint:disable-next-line:interface-name
interface PostgreSQLSessionStorageOptions {
sessionTableName: string;
port: number;
}
const defaultPostgreSQLSessionStorageOptions: PostgreSQLSessionStorageOptions =
{
sessionTableName: 'shopify_sessions',
port: 3211,
};
export class PostgreSQLSessionStorage implements SessionStorage {
public static withCredentials(
host: string,
dbName: string,
username: string,
password: string,
opts: Partial<PostgreSQLSessionStorageOptions>,
) {
return new PostgreSQLSessionStorage(
new URL(
`postgres://${encodeURIComponent(username)}:${encodeURIComponent(
password,
)}#${host}/${encodeURIComponent(dbName)}`,
),
opts,
);
}
public readonly ready: Promise<void>;
private options: PostgreSQLSessionStorageOptions;
private client: pg.Client;
constructor(
private dbUrl: URL,
opts: Partial<PostgreSQLSessionStorageOptions> = {},
) {
if (typeof this.dbUrl === 'string') {
this.dbUrl = new URL(this.dbUrl);
}
this.options = {...defaultPostgreSQLSessionStorageOptions, ...opts};
this.ready = this.init();
}
public async storeSession(session: SessionInterface): Promise<boolean> {
await this.ready;
const entries = sessionEntries(session);
const query = `
INSERT INTO ${this.options.sessionTableName}
(${entries.map(([key]) => key).join(', ')})
VALUES (${entries.map((_, i) => `$${i + 1}`).join(', ')})
ON CONFLICT (id) DO UPDATE SET ${entries
.map(([key]) => `${key} = Excluded.${key}`)
.join(', ')};
`;
await this.query(
query,
// tslint:disable-next-line:variable-name
entries.map(([_key, value]) => value),
);
return true;
}
public async loadSession(id: string): Promise<Session | undefined> {
await this.ready;
const query = `
SELECT * FROM ${this.options.sessionTableName}
WHERE id = $1;
`;
const rows = await this.query(query, [id]);
if (!Array.isArray(rows) || rows?.length !== 1) { return undefined; }
const rawResult = rows[0] as any;
const sessionData = sessionFromEntries(Object.entries(rawResult));
return Session.cloneSession(sessionData, sessionData.id);
}
public async deleteSession(id: string): Promise<boolean> {
await this.ready;
const query = `
DELETE FROM ${this.options.sessionTableName}
WHERE id = $1;
`;
await this.query(query, [id]);
return true;
}
public disconnect(): Promise<void> {
return this.client.end();
}
private async init() {
this.client = new pg.Client({connectionString: this.dbUrl.toString(), ssl: true});
await this.connectClient();
await this.createTable();
}
private async connectClient(): Promise<void> {
await this.client.connect();
}
private async hasSessionTable(): Promise<boolean> {
const query = `
SELECT * FROM pg_catalog.pg_tables WHERE tablename = $1
`;
const [rows] = await this.query(query, [this.options.sessionTableName]);
return Array.isArray(rows) && rows.length === 1;
}
private async createTable() {
const hasSessionTable = await this.hasSessionTable();
if (!hasSessionTable) {
const query = `
CREATE TABLE IF NOT EXISTS ${this.options.sessionTableName} (
id varchar(255) NOT NULL PRIMARY KEY,
shop varchar(255) NOT NULL,
state varchar(255) NOT NULL,
isOnline boolean NOT NULL,
scope varchar(255),
accessToken varchar(255)
)
`;
await this.query(query);
}
}
private async query(sql: string, params: any[] = []): Promise<any> {
const result = await this.client.query(sql, params);
return result.rows;
}
}
Does anyone know why this does not work, what am I doing wrong here. It get stuck after the console.log "after read stream"
I am trying to read a bunch of files, convert it to json and upload with bulkwriter to firestore.
After each 400 document I am calling close to write them to firestore and then I am creating a new bulkwriter
I also tried awaiting bulkWriter.create(eventDoc, {}) but it does not work. It also get stuck and there is no error. Why is this ? the create method returns a promise.
Why can't it be awaited ?
https://googleapis.dev/nodejs/firestore/latest/BulkWriter.html#create
The idea is to process 1 file at the time and it can contains tens of thousands of rows which needs to be uploaded to firestore
I am calling this method in for...of loop and awaiting the processBatch method
Any help highly appreciated
async processBatch(document: string, file: string): Promise<void> {
const db = admin.firestore();
console.log('start: ', document);
let bulkWriter;
const writeBatchLimit = 400;
let documentsInBatch = 0;
let totalInDocument = 0;
const eventsCollectionRef = db.collection('events');
const eventDoc = eventsCollectionRef.doc(document);
return new Promise((resolve, reject) => {
console.log('promise');
bulkWriter = db.bulkWriter();
const csvStream = fs.createReadStream(file);
console.log('after read stream');
bulkWriter.create(eventDoc, {})
.then(result => {
console.log('Successfully: ', result);
csvStream.pipe(csvParser())
.on('data', row => {
console.log('row');
bulkWriter.create(eventDoc.collection('event').doc(), row);
documentsInBatch++;
if (documentsInBatch > writeBatchLimit) {
bulkWriter.close();
totalInDocument = + documentsInBatch;
documentsInBatch = 0;
bulkWriter = db.bulkWriter();
}
})
.on('end', () => {
console.log('file: ', file + ', totalInDocument: ', totalInDocument);
resolve();
});
})
.catch(err => {
console.log('Failed: ', err);
reject();
});
});
}
This seems to work:
async processBatch(document: string, file: string): Promise<void> {
const db = admin.firestore();
console.log(`start: ${document}`);
let bulkWriter;
const writeBatchLimit = 400;
let documentsInBatch = 0;
let numOfBatches = 0;
let totalInDocument = 0;
const eventsCollectionRef = db.collection('events');
const eventDoc = eventsCollectionRef.doc(document);
bulkWriter = db.bulkWriter();
const csvStream = fs.createReadStream(file);
bulkWriter.create(eventDoc, {});
csvStream.pipe(csvParser())
.on('data', row => {
bulkWriter.create(eventDoc.collection('event').doc(), row);
documentsInBatch++;
if (documentsInBatch > writeBatchLimit) {
numOfBatches++;
totalInDocument += documentsInBatch;
documentsInBatch = 0;
bulkWriter.close();
console.log(`Committing batch ${numOfBatches}, cumulative: ${totalInDocument}`);
bulkWriter = db.bulkWriter();
}
})
.on('end', () => {
console.log(`file: ${file}, totalInDocument: ${totalInDocument}`);
});
}
I have this Ionic code. The problem is $ionicLoading.hide(); is not hiding the popup. I cant make the "waiting" icon Disappear
function ($scope, $q, $state, $rootScope, $stateParams, $firebaseArray, $window, $ionicLoading) {
var palabras = $rootScope.textAreaOfrecer.replace(/[.#$/]/g,'').toLowerCase().split(' ');
if($rootScope.flag == 1){
return true;
}else{
$rootScope.flag = 1;
}
console.log("0");
$ionicLoading.show();
setMyNewArray().then( function (){
console.log("3");
$ionicLoading.hide();
$rootScope.flag = 0;
console.log("4");
});
function setMyNewArray() {
var deferred = $q.defer();
console.log("1");
Promise.all(
$scope.solicitudes = palabras.map(palabra => $firebaseArray(firebase.database().ref().child("solCompras").orderByChild("palabras/" +
palabra).equalTo(true) ) )
).then( function (){
$scope.solicitudes = multiDimensionalUnique($scope.solicitudes).reduce(function(prev, curr) {
return prev.concat(curr);
});
console.log("2");
deferred.resolve();
});
return deferred.promise;
}
function multiDimensionalUnique(arr) {
var uniques = [];
var itemsFound = {};
for(var i = 0, l = arr.length; i < l; i++) {
var stringified = JSON.stringify(arr[i]);
if(itemsFound[stringified]) { continue; }
uniques.push(arr[i]);
itemsFound[stringified] = true;
}
return uniques;
}
}
I have changed location of show loader and hide loader.. try it once
function ($scope, $q, $state, $rootScope, $stateParams, $firebaseArray, $window, $ionicLoading) {
var palabras = $rootScope.textAreaOfrecer.replace(/[.#$/]/g,'').toLowerCase().split(' ');
if($rootScope.flag == 1){
return true;
}else{
$rootScope.flag = 1;
}
console.log("0");
setMyNewArray().then( function (){
console.log("3");
$rootScope.flag = 0;
console.log("4");
$ionicLoading.hide(); //use hide here
});
function setMyNewArray() {
$ionicLoading.show(); //use loader here.
var deferred = $q.defer();
console.log("1");
Promise.all(
$scope.solicitudes = palabras.map(palabra => $firebaseArray(firebase.database().ref().child("solCompras").orderByChild("palabras/" +
palabra).equalTo(true) ) )
).then( function (){
$scope.solicitudes = multiDimensionalUnique($scope.solicitudes).reduce(function(prev, curr) {
return prev.concat(curr);
});
console.log("2");
deferred.resolve();
});
return deferred.promise;
}
function multiDimensionalUnique(arr) {
var uniques = [];
var itemsFound = {};
for(var i = 0, l = arr.length; i < l; i++) {
var stringified = JSON.stringify(arr[i]);
if(itemsFound[stringified]) { continue; }
uniques.push(arr[i]);
itemsFound[stringified] = true;
}
return uniques;
}
}
Below code is a copy with minor edits from https://github.com/GoogleChrome/chrome-app-samples/tree/master/serial/ledtoggle. I am able to send a byte and receive a reply. I am not able to get an TimeoutError event in case of reply is not sent by the client. I have set timeout to 50 ms.
this.receiveTimeout = 50;
Entire code follows.
const DEVICE_PATH = 'COM1';
const serial = chrome.serial;
var ab2str = function(buf) {
var bufView = new Uint8Array(buf);
var encodedString = String.fromCharCode.apply(null, bufView);
return decodeURIComponent(escape(encodedString));
};
var str2ab = function(str) {
var encodedString = unescape((str));
var bytes = new Uint8Array(1);
bytes[0] = parseInt(encodedString);
}
return bytes.buffer;
};
var SerialConnection = function() {
this.connectionId = -1;
this.lineBuffer = "";
this.receiveTimeout =50;
this.boundOnReceive = this.onReceive.bind(this);
this.boundOnReceiveError = this.onReceiveError.bind(this);
this.onConnect = new chrome.Event();
this.onReadLine = new chrome.Event();
this.onError = new chrome.Event();
};
SerialConnection.prototype.onConnectComplete = function(connectionInfo) {
if (!connectionInfo) {
log("Connection failed.");
return;
}
this.connectionId = connectionInfo.connectionId;
chrome.serial.onReceive.addListener(this.boundOnReceive);
chrome.serial.onReceiveError.addListener(this.boundOnReceiveError);
this.onConnect.dispatch();
};
SerialConnection.prototype.onReceive = function(receiveInfo) {
if (receiveInfo.connectionId !== this.connectionId) {
return;
}
this.lineBuffer += ab2str(receiveInfo.data);
var index;
while ((index = this.lineBuffer.indexOf('$')) >= 0) {
var line = this.lineBuffer.substr(0, index + 1);
this.onReadLine.dispatch(line);
this.lineBuffer = this.lineBuffer.substr(index + 1);
}
};
SerialConnection.prototype.onReceiveError = function(errorInfo) {
log('Error');
if (errorInfo.connectionId === this.connectionId) {
log('Error');
this.onError.dispatch(errorInfo.error);
log('Error');
}
log('Error');
};
SerialConnection.prototype.connect = function(path) {
serial.connect(path, this.onConnectComplete.bind(this))
};
SerialConnection.prototype.send = function(msg) {
if (this.connectionId < 0) {
throw 'Invalid connection';
}
serial.send(this.connectionId, str2ab(msg), function() {});
};
SerialConnection.prototype.disconnect = function() {
if (this.connectionId < 0) {
throw 'Invalid connection';
}
serial.disconnect(this.connectionId, function() {});
};
var connection = new SerialConnection();
connection.onConnect.addListener(function() {
log('connected to: ' + DEVICE_PATH);
);
connection.onReadLine.addListener(function(line) {
log('read line: ' + line);
});
connection.onError.addListener(function() {
log('Error: ');
});
connection.connect(DEVICE_PATH);
function log(msg) {
var buffer = document.querySelector('#buffer');
buffer.innerHTML += msg + '<br/>';
}
document.querySelector('button').addEventListener('click', function() {
connection.send(2);
});
Maybe I'm reading the code incorrectly, but at no point do you pass receiveTimeout into chrome.serial. The method signature is chrome.serial.connect(string path, ConnectionOptions options, function callback), where options is an optional parameter. You never pass anything into options. Fix that and let us know what happens.
Despite of setting and defining everything in Samsung smart TV SDK 4.0 I am getting this error:
TypeError: 'undefined' is not a function (evaluating 'ime.registIMEKey()')
Please help!
CODE:
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
var wapal_magic =
{
elementIds: new Array(),
inputs: new Array(),
ready: new Array()
};
/////////////////////////
var Input = function (id, previousId, nextId) {
var previousElement = document.getElementById(previousId),
nextElement = document.getElementById(nextId);
var installFocusKeyCallbacks = function () {
ime.setKeyFunc(tvKey.KEY_UP, function (keyCode) {
previousElement.focus();
return false;
});
ime.setKeyFunc(tvKey.KEY_DOWN, function (keyCode) {
nextElement.focus();
return false;
});
ime.setKeyFunc(tvKey.KEY_RETURN, function (keyCode) {
widgetAPI.blockNavigation();
return false;
});
ime.setKeyFunc(tvKey.KEY_EXIT, function (keyCode) {
widgetAPI.blockNavigation();
return false;
});
}
var imeReady = function (imeObject) {
installFocusKeyCallbacks();
wapal_magic.ready(id);
},
ime = new IMEShell(id, imeReady, 'en'),
element = document.getElementById(id);
}
wapal_magic.createInputObjects = function () {
var index,
previousIndex,
nextIndex;
for (index in this.elementIds) {
previousIndex = index - 1;
if (previousIndex < 0) {
previousIndex = wapal_magic.inputs.length - 1;
}
nextIndex = (index + 1) % wapal_magic.inputs.length;
wapal_magic.inputs[index] = new Input(this.elementIds[index],
this.elementIds[previousIndex], this.elementIds[nextIndex]);
}
};
wapal_magic.ready = function (id) {
var ready = true,
i;
for (i in wapal_magic.elementIds) {
if (wapal_magic.elementIds[i] == id) {
wapal_magic.ready[i] = true;
}
if (wapal_magic.ready[i] == false) {
ready = false;
}
}
if (ready) {
document.getElementById("txtInp1").focus();
}
};
////////////////////////
wapal_magic.onLoad = function()
{
// Enable key event processing
//this.enableKeys();
// widgetAPI.sendReadyEvent();
this.initTextBoxes(new Array("txtInp1", "txtInp2"));
};
wapal_magic.initTextBoxes = function(textboxes){
this.elementIds = textboxes;
for(i=0;i<this.elementIds.length;i++){
this.inputs[i]=false;
this.ready[i]=null;
}
this.createInputObjects();
widgetAPI.registIMEKey();
};
wapal_magic.onUnload = function()
{
};
wapal_magic.enableKeys = function()
{
document.getElementById("anchor").focus();
};
wapal_magic.keyDown = function()
{
var keyCode = event.keyCode;
alert("Key pressed: " + keyCode);
switch(keyCode)
{
case tvKey.KEY_RETURN:
case tvKey.KEY_PANEL_RETURN:
alert("RETURN");
widgetAPI.sendReturnEvent();
break;
case tvKey.KEY_LEFT:
alert("LEFT");
break;
case tvKey.KEY_RIGHT:
alert("RIGHT");
break;
case tvKey.KEY_UP:
alert("UP");
break;
case tvKey.KEY_DOWN:
alert("DOWN");
break;
case tvKey.KEY_ENTER:
case tvKey.KEY_PANEL_ENTER:
alert("ENTER");
break;
default:
alert("Unhandled key");
break;
}
};
The registIMEKey method is part of the Plugin API.
var pluginAPI = new Common.API.Plugin();
pluginAPI.registIMEKey();
See: http://www.samsungdforum.com/Guide/ref00006/common_module_plugin_object.html#ref00006-common-module-plugin-object-registimekey
Edit: Updated to add code solution.
widgetAPI no contains method registIMEKey();, it contains in IMEShell.