Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented bi-directional userData. #153

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions dev/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ module.exports = [
"type": "date"
}
},
{
"type": "input",
"id": "password",
"label": "Password Field",
"attributes": {
"type": "password"
}
},
{
"type": "slider",
"messageKey": "slider",
Expand Down
5 changes: 5 additions & 0 deletions dev/custom-fn.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,10 @@ module.exports = function() {
Clay.getItemById('testButton').on('click', handleButtonClick);
});

Clay.on(Clay.EVENTS.BEFORE_SUBMIT, function() {
var password = Clay.getItemById('password').get();
Clay.meta.userData.password = password;
});

console.log('userData: ', Clay.meta.userData);
};
24 changes: 22 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,17 @@ Clay.prototype.generateUrl = function() {
*/
Clay.prototype.getSettings = function(response, convert) {
// Decode and parse config data as JSON
var settings = {};
var payload = {};
response = response.match(/^\{/) ? response : decodeURIComponent(response);

try {
settings = JSON.parse(response);
payload = JSON.parse(response);
} catch (e) {
throw new Error('The provided response was not valid JSON');
}

// flatten the settings for localStorage
var settings = payload.settings;
var settingsStorage = {};
Object.keys(settings).forEach(function(key) {
if (typeof settings[key] === 'object' && settings[key]) {
Expand All @@ -213,6 +214,25 @@ Clay.prototype.getSettings = function(response, convert) {
return convert === false ? settings : Clay.prepareSettingsForAppMessage(settings);
};

/**
* Parse the response from the webviewclosed event data
* @param {string} response
* @returns {Object}
*/
Clay.prototype.getUserData = function(response) {
// Decode and parse config data as JSON
var payload = {};
response = response.match(/^\{/) ? response : decodeURIComponent(response);

try {
payload = JSON.parse(response);
} catch (e) {
throw new Error('The provided response was not valid JSON');
}

return payload.userData;
};

/**
* Updates the settings with the given value(s).
*
Expand Down
15 changes: 14 additions & 1 deletion src/scripts/lib/clay-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ function ClayConfig(settings, config, $rootContainer, meta) {
*/
AFTER_BUILD: 'AFTER_BUILD',

/**
* Called before configuration is returned to app.js. This is when you would set
* properties of of userData to pass back.
* @const
*/
BEFORE_SUBMIT: 'BEFORE_SUBMIT',

/**
* Called if .build() is executed after the page has already been built and
* before the existing content is destroyed
Expand Down Expand Up @@ -210,7 +217,13 @@ function ClayConfig(settings, config, $rootContainer, meta) {
_settings[messageKey].precision = item.precision;
}
});
return _settings;

self.trigger(self.EVENTS.BEFORE_SUBMIT);

return {
settings: _settings,
userData: meta.userData
};
};

// @todo maybe don't do this and force the static method
Expand Down
140 changes: 101 additions & 39 deletions test/spec/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,14 @@ describe('Clay', function() {
stubPebble();
fixture.clay([]);
var logStub = sinon.stub(console, 'log');
var expected = {someSetting: 'value'};
var expected = {settings: {someSetting: 'value'}, userData: {}};

stubMessageKeys(fixture.messageKeysObjToArray(expected));
stubMessageKeys(fixture.messageKeysObjToArray(expected.settings));
Pebble.addEventListener
.withArgs('webviewclosed')
.callArgWith(1, {response: encodeURIComponent(JSON.stringify(expected))});

var expectedAppMessage = fixture.messageKeysExpected(expected);
var expectedAppMessage = fixture.messageKeysExpected(expected.settings);
assert(Pebble.addEventListener.calledWith('webviewclosed'));
assert(Pebble.sendAppMessage.calledWith(expectedAppMessage));

Expand Down Expand Up @@ -269,13 +269,66 @@ describe('Clay', function() {
});
});

describe('.getUserData', function() {
it('it returns the data when input is encoded',
function() {
var clay = fixture.clay([]);
var payload = encodeURIComponent(JSON.stringify({
settings: {},
userData: {
key1: 'value1',
key2: 'value2'
}
}));
var expected = {
key1: 'value1',
key2: 'value2'
};

var result = clay.getUserData(payload);
assert.deepEqual(result, expected);
});

it('it returns the data when input is not encoded',
function() {
var clay = fixture.clay([]);
var unencodedResponse = JSON.stringify({
settings: {},
userData: {
key1: 'value1',
key2: 'value2%7Dbreaks'
}
});
var expected = {
key1: 'value1',
key2: 'value2%7Dbreaks'
};

var result = clay.getUserData(unencodedResponse);
assert.deepEqual(result, expected);
});

it('it logs an error if it is invalid JSON',
function() {
var clay = fixture.clay([]);

assert.throws(function() {
clay.getUserData('not valid JSON');
}, /Not Valid JSON/i);
});

});

describe('.getSettings', function() {
it('it writes to localStorage and returns the data when input is encoded',
function() {
var clay = fixture.clay([]);
var settings = encodeURIComponent(JSON.stringify({
key1: 'value1',
key2: {value: 'value2'}
var payload = encodeURIComponent(JSON.stringify({
settings: {
key1: 'value1',
key2: {value: 'value2'}
},
userData: {}
}));
var expected = {
key1: 'value1',
Expand All @@ -284,7 +337,7 @@ describe('Clay', function() {

stubMessageKeys(fixture.messageKeysObjToArray(expected));

var result = clay.getSettings(settings);
var result = clay.getSettings(payload);
assert.equal(
localStorage.getItem('clay-settings'),
JSON.stringify(expected)
Expand All @@ -295,9 +348,12 @@ describe('Clay', function() {
it('it writes to localStorage and returns the data when input is not encoded',
function() {
var clay = fixture.clay([]);
var settings = JSON.stringify({
key1: 'value1',
key2: {value: 'value2%7Dbreaks'}
var unencodedResponse = JSON.stringify({
settings: {
key1: 'value1',
key2: {value: 'value2%7Dbreaks'}
},
userData: {}
});
var expected = {
key1: 'value1',
Expand All @@ -306,7 +362,7 @@ describe('Clay', function() {

stubMessageKeys(fixture.messageKeysObjToArray(expected));

var result = clay.getSettings(settings);
var result = clay.getSettings(unencodedResponse);
assert.equal(
localStorage.getItem('clay-settings'),
JSON.stringify(expected)
Expand All @@ -328,21 +384,24 @@ describe('Clay', function() {
it('Prepares the settings for sendAppMessage', function() {
var clay = fixture.clay([]);
var response = encodeURIComponent(JSON.stringify({
test1: false,
test2: 'val-2',
test3: true,
test4: ['cb-1', 'cb-3'],
test5: 12345,
test6: [1, 2, 3, 4],
test7: [true, false, true],
test8: {
precision: 2,
value: 12.34
settings: {
test1: false,
test2: 'val-2',
test3: true,
test4: ['cb-1', 'cb-3'],
test5: 12345,
test6: [1, 2, 3, 4],
test7: [true, false, true],
test8: {
precision: 2,
value: 12.34
},
test9: {
precision: 1,
value: [1, 2, 3, 4]
}
},
test9: {
precision: 1,
value: [1, 2, 3, 4]
}
userData: {}
}));
var expected = {
test1: 0,
Expand All @@ -367,22 +426,25 @@ describe('Clay', function() {
it('does not prepare the settings for sendAppMessage if convert is false',
function() {
var clay = fixture.clay([]);
var settings = {
test1: false,
test2: 'val-2',
test3: true,
test4: ['cb-1', 'cb-3'],
test5: 12345,
test6: [1, 2, 3, 4],
test7: [true, false, true],
test8: {
precision: 2,
value: 12.34
}
var payload = {
settings: {
test1: false,
test2: 'val-2',
test3: true,
test4: ['cb-1', 'cb-3'],
test5: 12345,
test6: [1, 2, 3, 4],
test7: [true, false, true],
test8: {
precision: 2,
value: 12.34
}
},
userData: {}
};
var response = encodeURIComponent(JSON.stringify(settings));
var response = encodeURIComponent(JSON.stringify(payload));

assert.deepEqual(clay.getSettings(response, false), settings);
assert.deepEqual(clay.getSettings(response, false), payload.settings);
});
});

Expand Down
33 changes: 21 additions & 12 deletions test/spec/lib/clay-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,23 +331,29 @@ describe('ClayConfig', function() {
var clayConfig = fixtures.clayConfig(config, true, true, settings);

assert.deepEqual(clayConfig.serialize(), {
test1: {value: 'default val'},
test2: {value: 'val-2'},
test3: {value: false},
test4: {value: [false, false, false]},
test5: {value: 12.5, precision: 2}
settings: {
test1: {value: 'default val'},
test2: {value: 'val-2'},
test3: {value: false},
test4: {value: [false, false, false]},
test5: {value: 12.5, precision: 2}
},
userData: {}
});

clayConfig.getItemByMessageKey('test1').set('val-1');
clayConfig.getItemByMessageKey('test3').set(true);
clayConfig.getItemByMessageKey('test4').set([true, false, true]);

assert.deepEqual(clayConfig.serialize(), {
test1: {value: 'val-1'},
test2: {value: 'val-2'},
test3: {value: true},
test4: {value: [true, false, true]},
test5: {value: 12.5, precision: 2}
settings: {
test1: {value: 'val-1'},
test2: {value: 'val-2'},
test3: {value: true},
test4: {value: [true, false, true]},
test5: {value: 12.5, precision: 2}
},
userData: {}
});

// make sure the result of serialize() can actually be fed back in to
Expand Down Expand Up @@ -384,8 +390,11 @@ describe('ClayConfig', function() {

var clayConfig = fixtures.clayConfig(config, true, true, settings);
assert.deepEqual(clayConfig.serialize(), {
test1: {value: 'default val'},
test2: {value: 'val-2'}
settings: {
test1: {value: 'default val'},
test2: {value: 'val-2'}
},
userData: {}
});
});
});
Expand Down