mirror of
https://github.com/pebble-dev/clay.git
synced 2026-09-05 16:47:37 -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.
|
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.
|
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*'))`
|
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
|
```javascript
|
||||||
var Clay = require('clay');
|
var Clay = require('clay');
|
||||||
var clayConfig = require('config.json');
|
var clayConfig = require('config.json');
|
||||||
var clay = new Clay(clayConfig);
|
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
|
8. Next is the fun part. Creating your config page. Edit your `config.json` file using the instructions below
|
||||||
|
|
||||||
# Creating Your Config File
|
# 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
|
## Basic JSON structure
|
||||||
|
|
||||||
@@ -48,8 +31,8 @@ Your root element should be an array. This represents the entire page. Inside th
|
|||||||
#### Example:
|
#### Example:
|
||||||
```javascript
|
```javascript
|
||||||
[
|
[
|
||||||
{ type: 'heading', defaultValue: 'Example Config Page' },
|
{ "type": "heading", "defaultValue": "Example Config Page" },
|
||||||
{ type: 'text', defaultValue: 'Clay makes things easy.' }
|
{ "type": "text", "defaultValue": "Clay makes things easy." }
|
||||||
//... etc etc
|
//... 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:
|
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
|
## 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.
|
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)`
|
### `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
|
#### Properties
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"appKey": "background",
|
"appKey": "sunnyColorTest",
|
||||||
"defaultValue": "00FF00",
|
"defaultValue": "00FF00",
|
||||||
"label": "Sunny Color",
|
"label": "Sunny Color",
|
||||||
"sunlight": true
|
"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} input
|
||||||
* @param {string} [prefix]
|
* @param {string} [prefix]
|
||||||
|
* @private
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function encodeDataUri(input, prefix) {
|
function encodeDataUri(input, prefix) {
|
||||||
@@ -62,17 +63,51 @@ function encodeDataUri(input, prefix) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array} config - the Clay config
|
* @param {Array} config - the Clay config
|
||||||
* @param {function} [customFn] - custom code to run from the config page.
|
* @param {function} [customFn] - Custom code to run from the config page. Will run
|
||||||
* Will run with api as context
|
* 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
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function Clay(config, customFn) {
|
function Clay(config, customFn, options) {
|
||||||
var self = this;
|
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.config = config;
|
||||||
self.customFn = customFn || function() {};
|
self.customFn = customFn || function() {};
|
||||||
self.components = [];
|
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
|
* @private
|
||||||
* @param {Clay~ConfigItem|Array} item
|
* @param {Clay~ConfigItem|Array} item
|
||||||
@@ -93,6 +128,18 @@ function Clay(config, customFn) {
|
|||||||
_registerStandardComponents(self.config);
|
_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) {
|
Clay.prototype.registerComponent = function(component) {
|
||||||
this.components.push(component);
|
this.components.push(component);
|
||||||
};
|
};
|
||||||
@@ -136,12 +183,12 @@ Clay.prototype.generateUrl = function() {
|
|||||||
/**
|
/**
|
||||||
* Parse the response from the webviewclosed event data
|
* Parse the response from the webviewclosed event data
|
||||||
* @param {string} response
|
* @param {string} response
|
||||||
* @returns {{}}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
Clay.prototype.getSettings = function(response) {
|
Clay.prototype.getSettings = function(response) {
|
||||||
// Decode and parse config data as JSON
|
// Decode and parse config data as JSON
|
||||||
var settings = JSON.parse(decodeURIComponent(response));
|
var settings = JSON.parse(decodeURIComponent(response));
|
||||||
// @todo get defaults in here
|
|
||||||
if (!settings) return {};
|
if (!settings) return {};
|
||||||
|
|
||||||
localStorage.setItem('clay-settings', JSON.stringify(settings));
|
localStorage.setItem('clay-settings', JSON.stringify(settings));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ var returnTo = window.returnTo || 'pebblejs://close#';
|
|||||||
var customFn = window.customFn || function() {};
|
var customFn = window.customFn || function() {};
|
||||||
var clayComponents = window.clayComponents || {};
|
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);
|
document.documentElement.classList.add('platform-' + platform);
|
||||||
|
|
||||||
// Register the passed components
|
// Register the passed components
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A Clay config Item
|
* A Clay config Item
|
||||||
* @typedef {object} Clay~ConfigItem
|
* @typedef {Object} Clay~ConfigItem
|
||||||
* @property {string} type
|
* @property {string} type
|
||||||
* @property {string|boolean|number} defaultValue
|
* @property {string|boolean|number} defaultValue
|
||||||
* @property {string} [appKey]
|
* @property {string} [appKey]
|
||||||
* @property {string} [id]
|
* @property {string} [id]
|
||||||
* @property {string} [label]
|
* @property {string} [label]
|
||||||
* @property {object} [attributes]
|
* @property {Object} [attributes]
|
||||||
* @property {Array} [options]
|
* @property {Array} [options]
|
||||||
* @property {Array} [items]
|
* @property {Array} [items]
|
||||||
*/
|
*/
|
||||||
@@ -23,8 +23,8 @@ var manipulators = require('./manipulators');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends ClayEvents
|
* @extends ClayEvents
|
||||||
* @param {{}} settings - setting that were set from a previous session
|
* @param {Object} settings - setting that were set from a previous session
|
||||||
* @param {[]|{}} config
|
* @param {Array|Object} config
|
||||||
* @param {M} $rootContainer
|
* @param {M} $rootContainer
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
@@ -150,7 +150,7 @@ function ClayConfig(settings, config, $rootContainer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
self.getSettings = function() {
|
self.getSettings = function() {
|
||||||
_checkBuilt('getSettings');
|
_checkBuilt('getSettings');
|
||||||
@@ -188,13 +188,13 @@ function ClayConfig(settings, config, $rootContainer) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a component to Clay. This must be called prior to .build();
|
* 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.name - the name of the component
|
||||||
* @param {string} component.template - HTML template to use for 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.set - set manipulator method
|
||||||
* @param {function} component.manipulator.get - get 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
|
* @param {function} [component.initialize] - method to scaffold the component
|
||||||
* @return {boolean} - Returns true if component was registered correctly
|
* @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' ||
|
if (typeof _component.manipulator.set !== 'function' ||
|
||||||
typeof _component.manipulator.get !== 'function') {
|
typeof _component.manipulator.get !== 'function') {
|
||||||
throw new Error('The manipulator must have both a `get` and `set` method');
|
throw new Error('The manipulator must have both a `get` and `set` method');
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ function ClayEvents($eventTarget) {
|
|||||||
/**
|
/**
|
||||||
* Trigger an event.
|
* Trigger an event.
|
||||||
* @param {string} name - a single event name to trigger
|
* @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.
|
* provided the handler does not have custom arguments.
|
||||||
* @returns {ClayEvents}
|
* @returns {ClayEvents}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function ClayItem(config) {
|
|||||||
var _component = componentRegistry[config.type];
|
var _component = componentRegistry[config.type];
|
||||||
|
|
||||||
if (!_component) {
|
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()');
|
'Make sure to register it with ClayConfig.registerComponent()');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ function ClayItem(config) {
|
|||||||
/** @type {string|null} */
|
/** @type {string|null} */
|
||||||
self.appKey = config.appKey || null;
|
self.appKey = config.appKey || null;
|
||||||
|
|
||||||
/** @type {object} */
|
/** @type {Object} */
|
||||||
self.config = config;
|
self.config = config;
|
||||||
|
|
||||||
/** @type {M} */
|
/** @type {M} */
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch update all the properties of an object.
|
* Batch update all the properties of an object.
|
||||||
* @param {object} obj
|
* @param {Object} obj
|
||||||
* @param {object} descriptor
|
* @param {Object} descriptor
|
||||||
* @param {boolean} [descriptor.configurable]
|
* @param {boolean} [descriptor.configurable]
|
||||||
* @param {boolean} [descriptor.enumerable]
|
* @param {boolean} [descriptor.enumerable]
|
||||||
* @param {*} [descriptor.value]
|
* @param {*} [descriptor.value]
|
||||||
|
|||||||
+5
-5
@@ -10,7 +10,7 @@ var componentRegistry = require('../src/scripts/lib/component-registry');
|
|||||||
var idCounter = 0;
|
var idCounter = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string|{}} config
|
* @param {string|Object} config
|
||||||
* @param {boolean} [autoRegister=true]
|
* @param {boolean} [autoRegister=true]
|
||||||
* @returns {Clay~ConfigItem}
|
* @returns {Clay~ConfigItem}
|
||||||
*/
|
*/
|
||||||
@@ -37,7 +37,7 @@ module.exports.configItem = function(config, autoRegister) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string|{}} config
|
* @param {string|Object} config
|
||||||
* @param {boolean} [autoRegister=true]
|
* @param {boolean} [autoRegister=true]
|
||||||
* @returns {ClayItem}
|
* @returns {ClayItem}
|
||||||
*/
|
*/
|
||||||
@@ -46,7 +46,7 @@ module.exports.clayItem = function(config, autoRegister) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {[]} types
|
* @param {Array} types
|
||||||
* @param {boolean} [autoRegister=true]
|
* @param {boolean} [autoRegister=true]
|
||||||
* @returns {*}
|
* @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} [build=true] - run the build method on the result
|
||||||
* @param {boolean} [autoRegister=true]
|
* @param {boolean} [autoRegister=true]
|
||||||
* @param {{}} [settings] - settings to pass to constructor
|
* @param {Object} [settings] - settings to pass to constructor
|
||||||
* @returns {ClayConfig}
|
* @returns {ClayConfig}
|
||||||
*/
|
*/
|
||||||
module.exports.clayConfig = function(types, build, autoRegister, settings) {
|
module.exports.clayConfig = function(types, build, autoRegister, settings) {
|
||||||
|
|||||||
@@ -181,6 +181,23 @@ describe('ClayConfig', function() {
|
|||||||
clayConfig.build();
|
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() {
|
it('only registers the component once', function() {
|
||||||
delete componentRegistry.select;
|
delete componentRegistry.select;
|
||||||
var warnStub = sinon.stub(console, 'warn');
|
var warnStub = sinon.stub(console, 'warn');
|
||||||
|
|||||||
Reference in New Issue
Block a user