Skip to content

Commit

Permalink
Merge branch 'pebble#71/bidirectional-user-data' into dist
Browse files Browse the repository at this point in the history
* pebble#71/bidirectional-user-data:
  Implemented bi-directional userData.
  • Loading branch information
jrmobley committed Oct 29, 2016
2 parents aa68169 + d372c99 commit f7cf834
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 54 deletions.
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

0 comments on commit f7cf834

Please sign in to comment.