mirror of
https://github.com/pebble-dev/clay.git
synced 2026-08-28 04:46:57 -04:00
Automatically handle the "showConfiguration" and "webviewclosed" events + other minor code cleanup
This commit is contained in:
@@ -11,35 +11,18 @@ Clay will eventually be built into the Pebble SDK. However while it is still in
|
||||
2. Drop `clay.js` in your project's `src/js` directory.
|
||||
3. Create a JSON file called `config.json` and place it in your `src/js` directory.
|
||||
4. in order for JSON files to work you may need to change the line in your `wscript` from `ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js'))` to `ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js*'))`
|
||||
5. Your `app.js` needs to `require` clay and your config file, then be initialized:
|
||||
5. Your `app.js` needs to `require` clay and your config file, then be initialized. Clay will by default, automatically handle the 'showConfiguration' and 'webviewclosed' events:
|
||||
```javascript
|
||||
var Clay = require('clay');
|
||||
var clayConfig = require('config.json');
|
||||
var clay = new Clay(clayConfig);
|
||||
```
|
||||
6. Now in your `showConfiguration` handler you let clay generate the URL for you. It should look something like:
|
||||
```javascript
|
||||
Pebble.addEventListener('showConfiguration', function(e) {
|
||||
Pebble.openURL(clay.generateUrl());
|
||||
});
|
||||
```
|
||||
7. In order for your Pebble app to receive the configuration, you need to get the settings from Clay. Your `webviewclosed` handler should now look something like:
|
||||
```javascript
|
||||
Pebble.addEventListener('webviewclosed', function(e) {
|
||||
// Send settings to Pebble watchapp
|
||||
Pebble.sendAppMessage(clay.getSettings(e.response), function(e) {
|
||||
console.log('Sent config data to Pebble');
|
||||
}, function() {
|
||||
console.log('Failed to send config data!');
|
||||
console.log(JSON.stringify(e));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
8. Next is the fun part. Creating your config page. Edit your `config.json` file using the instructions below
|
||||
|
||||
# Creating Your Config File
|
||||
|
||||
Clay uses javascript objects (or JSON) to generate the config page for you. The structure of the page is totally up to you, but you do need to follow some basic rules.
|
||||
Clay uses JavaScript objects (or JSON) to generate the config page for you. The structure of the page is totally up to you, but you do need to follow some basic rules.
|
||||
|
||||
## Basic JSON structure
|
||||
|
||||
@@ -48,8 +31,8 @@ Your root element should be an array. This represents the entire page. Inside th
|
||||
#### Example:
|
||||
```javascript
|
||||
[
|
||||
{ type: 'heading', defaultValue: 'Example Config Page' },
|
||||
{ type: 'text', defaultValue: 'Clay makes things easy.' }
|
||||
{ "type": "heading", "defaultValue": "Example Config Page" },
|
||||
{ "type": "text", "defaultValue": "Clay makes things easy." }
|
||||
//... etc etc
|
||||
]
|
||||
```
|
||||
@@ -446,6 +429,48 @@ Each component has a **manipulator.** This is a set of methods used to talk to t
|
||||
|
||||
Clay is built to allow developers to add their own basic interactivity to the config page. This is done in a number of ways:
|
||||
|
||||
## Handling The 'showConfiguration' and 'webviewclosed' Events Manually
|
||||
|
||||
Clay will by default, automatically handle the 'showConfiguration' and 'webviewclosed' events. If you wish to override this behavior and handle the events yourself, pass an object as the 3rd parameter of the Clay constructor with `autoHandleEvents` set to `false`
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
var Clay = require('./clay');
|
||||
var clayConfig = require('./config');
|
||||
var clay = new Clay(clayConfig, null, {autoHandleEvents: false});
|
||||
|
||||
Pebble.addEventListener('showConfiguration', function(e) {
|
||||
Pebble.openURL(clay.generateUrl());
|
||||
});
|
||||
|
||||
Pebble.addEventListener('webviewclosed', function(e) {
|
||||
|
||||
if (e && !e.response) { return; }
|
||||
|
||||
// Send settings to Pebble watchapp
|
||||
Pebble.sendAppMessage(clay.getSettings(e.response), function(e) {
|
||||
console.log('Sent config data to Pebble');
|
||||
}, function() {
|
||||
console.log('Failed to send config data!');
|
||||
console.log(JSON.stringify(e));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### `Clay([Array] config, [function] customFn, [object] options)`
|
||||
|
||||
#### Methods
|
||||
|
||||
| Method | Returns
|
||||
| ---
|
||||
| `Clay(Array] config, [function] customFn=null, [object] options={autoHandleEvents: true})` <br> `config` - an Array representing your config <br> `customFn` - function to be run in the context of the generated page <br> `options.autoHandleEvents` - set to `false` to prevent Clay from automatically handling the "showConfiguration" and "webviewclosed" events | `Clay` - a new instance of Clay
|
||||
| `.registerComponent( [ClayComponent] component )` <br> Registers a custom component. | `void`.
|
||||
| `.generateUrl()` | `string` - The URL to open with `Pebble.openURL()`
|
||||
| `.getSettings(response)` <br> `response` - the response object provided to the "webviewclosed" event | `Object` - hash where the key is the `appKey` and the value is the result from the config page.
|
||||
---
|
||||
|
||||
|
||||
## Custom Function
|
||||
|
||||
When initializing Clay in your `app.js`, you can optionally provide a function that will be copied and run on the generated config page. **IMPORTANT:** This function is injected by running `.toString()` on it. If you are making use of `require` or any other dynamic features, they will not work. You must make sure that everything the function needs to execute is available in the function body itself.
|
||||
@@ -492,7 +517,7 @@ module.exports = function(minified) {
|
||||
|
||||
### `ClayConfig([Object] settings, [Array] config, [$Minified] $rootContainer)`
|
||||
|
||||
This is the main way of talking to your generated config page. A reference to the instance of `ClayConfig` is passed to
|
||||
This is the main way of talking to your generated config page.
|
||||
|
||||
#### Properties
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ module.exports = [
|
||||
},
|
||||
{
|
||||
"type": "color",
|
||||
"appKey": "background",
|
||||
"appKey": "sunnyColorTest",
|
||||
"defaultValue": "00FF00",
|
||||
"label": "Sunny Color",
|
||||
"sunlight": true
|
||||
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@ var standardComponents = require('./src/scripts/components');
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {string} [prefix]
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
function encodeDataUri(input, prefix) {
|
||||
@@ -62,17 +63,51 @@ function encodeDataUri(input, prefix) {
|
||||
|
||||
/**
|
||||
* @param {Array} config - the Clay config
|
||||
* @param {function} [customFn] - custom code to run from the config page.
|
||||
* Will run with api as context
|
||||
* @param {function} [customFn] - Custom code to run from the config page. Will run
|
||||
* with the ClayConfig instance as context
|
||||
* @param {Object} [options] - Additional options to pass to Clay
|
||||
* @param {boolean} [options.autoHandleEvents] - If false, Clay will not
|
||||
* automatically handle the 'showConfiguration' and 'webviewclosed' events
|
||||
* @constructor
|
||||
*/
|
||||
function Clay(config, customFn) {
|
||||
function Clay(config, customFn, options) {
|
||||
var self = this;
|
||||
|
||||
if (!Array.isArray(config)) {
|
||||
throw new Error('config must be an Array');
|
||||
}
|
||||
|
||||
if (customFn && typeof customFn !== 'function') {
|
||||
throw new Error('customFn must be an function or "null"');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
self.config = config;
|
||||
self.customFn = customFn || function() {};
|
||||
self.components = [];
|
||||
|
||||
// Let Clay handle all the magic
|
||||
if (options.autoHandleEvents !== false && Pebble) {
|
||||
|
||||
Pebble.addEventListener('showConfiguration', function(e) {
|
||||
Pebble.openURL(self.generateUrl());
|
||||
});
|
||||
|
||||
Pebble.addEventListener('webviewclosed', function(e) {
|
||||
|
||||
if (e && !e.response) { return; }
|
||||
|
||||
// Send settings to Pebble watchapp
|
||||
Pebble.sendAppMessage(self.getSettings(e.response), function(e) {
|
||||
console.log('Sent config data to Pebble');
|
||||
}, function() {
|
||||
console.log('Failed to send config data!');
|
||||
console.log(JSON.stringify(e));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Clay~ConfigItem|Array} item
|
||||
@@ -93,6 +128,18 @@ function Clay(config, customFn) {
|
||||
_registerStandardComponents(self.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a component to Clay.
|
||||
* @param {Object} component - the clay component to register
|
||||
* @param {string} component.name - the name of the component
|
||||
* @param {string} component.template - HTML template to use for the component
|
||||
* @param {string|Object} component.manipulator - methods to attach to the component
|
||||
* @param {function} component.manipulator.set - set manipulator method
|
||||
* @param {function} component.manipulator.get - get manipulator method
|
||||
* @param {Object} [component.defaults] - template defaults
|
||||
* @param {function} [component.initialize] - method to scaffold the component
|
||||
* @return {boolean} - Returns true if component was registered correctly
|
||||
*/
|
||||
Clay.prototype.registerComponent = function(component) {
|
||||
this.components.push(component);
|
||||
};
|
||||
@@ -136,12 +183,12 @@ Clay.prototype.generateUrl = function() {
|
||||
/**
|
||||
* Parse the response from the webviewclosed event data
|
||||
* @param {string} response
|
||||
* @returns {{}}
|
||||
* @returns {Object}
|
||||
*/
|
||||
Clay.prototype.getSettings = function(response) {
|
||||
// Decode and parse config data as JSON
|
||||
var settings = JSON.parse(decodeURIComponent(response));
|
||||
// @todo get defaults in here
|
||||
|
||||
if (!settings) return {};
|
||||
|
||||
localStorage.setItem('clay-settings', JSON.stringify(settings));
|
||||
|
||||
@@ -12,7 +12,7 @@ var returnTo = window.returnTo || 'pebblejs://close#';
|
||||
var customFn = window.customFn || function() {};
|
||||
var clayComponents = window.clayComponents || {};
|
||||
|
||||
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
||||
var platform = window.navigator.userAgent.match(/android/i) ? 'android' : 'ios';
|
||||
document.documentElement.classList.add('platform-' + platform);
|
||||
|
||||
// Register the passed components
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
/**
|
||||
* A Clay config Item
|
||||
* @typedef {object} Clay~ConfigItem
|
||||
* @typedef {Object} Clay~ConfigItem
|
||||
* @property {string} type
|
||||
* @property {string|boolean|number} defaultValue
|
||||
* @property {string} [appKey]
|
||||
* @property {string} [id]
|
||||
* @property {string} [label]
|
||||
* @property {object} [attributes]
|
||||
* @property {Object} [attributes]
|
||||
* @property {Array} [options]
|
||||
* @property {Array} [items]
|
||||
*/
|
||||
@@ -23,8 +23,8 @@ var manipulators = require('./manipulators');
|
||||
|
||||
/**
|
||||
* @extends ClayEvents
|
||||
* @param {{}} settings - setting that were set from a previous session
|
||||
* @param {[]|{}} config
|
||||
* @param {Object} settings - setting that were set from a previous session
|
||||
* @param {Array|Object} config
|
||||
* @param {M} $rootContainer
|
||||
* @constructor
|
||||
*/
|
||||
@@ -150,7 +150,7 @@ function ClayConfig(settings, config, $rootContainer) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {object}
|
||||
* @returns {Object}
|
||||
*/
|
||||
self.getSettings = function() {
|
||||
_checkBuilt('getSettings');
|
||||
@@ -188,13 +188,13 @@ function ClayConfig(settings, config, $rootContainer) {
|
||||
|
||||
/**
|
||||
* Register a component to Clay. This must be called prior to .build();
|
||||
* @param {{}} component - the clay component to register
|
||||
* @param {Object} component - the clay component to register
|
||||
* @param {string} component.name - the name of the component
|
||||
* @param {string} component.template - HTML template to use for the component
|
||||
* @param {string|{}} component.manipulator - methods to attach to the component
|
||||
* @param {string|Object} component.manipulator - methods to attach to the component
|
||||
* @param {function} component.manipulator.set - set manipulator method
|
||||
* @param {function} component.manipulator.get - get manipulator method
|
||||
* @param {{}} [component.defaults] - template defaults
|
||||
* @param {Object} [component.defaults] - template defaults
|
||||
* @param {function} [component.initialize] - method to scaffold the component
|
||||
* @return {boolean} - Returns true if component was registered correctly
|
||||
*/
|
||||
@@ -217,6 +217,10 @@ ClayConfig.registerComponent = function(component) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!_component.manipulator) {
|
||||
throw new Error('The manipulator must be defined');
|
||||
}
|
||||
|
||||
if (typeof _component.manipulator.set !== 'function' ||
|
||||
typeof _component.manipulator.get !== 'function') {
|
||||
throw new Error('The manipulator must have both a `get` and `set` method');
|
||||
|
||||
@@ -88,7 +88,7 @@ function ClayEvents($eventTarget) {
|
||||
/**
|
||||
* Trigger an event.
|
||||
* @param {string} name - a single event name to trigger
|
||||
* @param {object} [eventObj] - an object to pass to the event handler,
|
||||
* @param {Object} [eventObj] - an object to pass to the event handler,
|
||||
* provided the handler does not have custom arguments.
|
||||
* @returns {ClayEvents}
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ function ClayItem(config) {
|
||||
var _component = componentRegistry[config.type];
|
||||
|
||||
if (!_component) {
|
||||
throw new Error('the component: ' + config.type + ' is not registered. ' +
|
||||
throw new Error('The component: ' + config.type + ' is not registered. ' +
|
||||
'Make sure to register it with ClayConfig.registerComponent()');
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ function ClayItem(config) {
|
||||
/** @type {string|null} */
|
||||
self.appKey = config.appKey || null;
|
||||
|
||||
/** @type {object} */
|
||||
/** @type {Object} */
|
||||
self.config = config;
|
||||
|
||||
/** @type {M} */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
/**
|
||||
* Batch update all the properties of an object.
|
||||
* @param {object} obj
|
||||
* @param {object} descriptor
|
||||
* @param {Object} obj
|
||||
* @param {Object} descriptor
|
||||
* @param {boolean} [descriptor.configurable]
|
||||
* @param {boolean} [descriptor.enumerable]
|
||||
* @param {*} [descriptor.value]
|
||||
|
||||
+5
-5
@@ -10,7 +10,7 @@ var componentRegistry = require('../src/scripts/lib/component-registry');
|
||||
var idCounter = 0;
|
||||
|
||||
/**
|
||||
* @param {string|{}} config
|
||||
* @param {string|Object} config
|
||||
* @param {boolean} [autoRegister=true]
|
||||
* @returns {Clay~ConfigItem}
|
||||
*/
|
||||
@@ -37,7 +37,7 @@ module.exports.configItem = function(config, autoRegister) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string|{}} config
|
||||
* @param {string|Object} config
|
||||
* @param {boolean} [autoRegister=true]
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
@@ -46,7 +46,7 @@ module.exports.clayItem = function(config, autoRegister) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {[]} types
|
||||
* @param {Array} types
|
||||
* @param {boolean} [autoRegister=true]
|
||||
* @returns {*}
|
||||
*/
|
||||
@@ -59,10 +59,10 @@ module.exports.config = function(types, autoRegister) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {[]} types
|
||||
* @param {Array} types
|
||||
* @param {boolean} [build=true] - run the build method on the result
|
||||
* @param {boolean} [autoRegister=true]
|
||||
* @param {{}} [settings] - settings to pass to constructor
|
||||
* @param {Object} [settings] - settings to pass to constructor
|
||||
* @returns {ClayConfig}
|
||||
*/
|
||||
module.exports.clayConfig = function(types, build, autoRegister, settings) {
|
||||
|
||||
@@ -181,6 +181,23 @@ describe('ClayConfig', function() {
|
||||
clayConfig.build();
|
||||
});
|
||||
|
||||
it('throws if there is no manipulator',
|
||||
function(done) {
|
||||
delete componentRegistry.select;
|
||||
var clayConfig = fixtures.clayConfig(['select'], false, false);
|
||||
var _selectComponent = _.copyObj(selectComponent);
|
||||
_selectComponent.manipulator = undefined;
|
||||
|
||||
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
|
||||
assert.throws(function() {
|
||||
clayConfig.registerComponent(_selectComponent);
|
||||
}, /manipulator must be defined/);
|
||||
done();
|
||||
});
|
||||
|
||||
clayConfig.build();
|
||||
});
|
||||
|
||||
it('only registers the component once', function() {
|
||||
delete componentRegistry.select;
|
||||
var warnStub = sinon.stub(console, 'warn');
|
||||
|
||||
Reference in New Issue
Block a user