mirror of
https://github.com/pebble-dev/clay.git
synced 2026-08-31 14:26:45 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
627d35fd0a | ||
|
|
ac5bb205aa | ||
|
|
3386e609a8 | ||
|
|
847c651c2b | ||
|
|
f66cba1816 | ||
|
|
2583effe5e | ||
|
|
2e1e5d5d44 | ||
|
|
6c1bcbdb7d | ||
|
|
c5e29ce638 | ||
|
|
7512b6436b | ||
|
|
1b362a366c | ||
|
|
1a8301b0cc | ||
|
|
79c64e5777 | ||
|
|
8ba0a2caee | ||
|
|
904d6bca55 | ||
|
|
94f4770731 | ||
|
|
fa0e243bf1 | ||
|
|
c7bb67f2ef | ||
|
|
2d1a355b23 | ||
|
|
b606e8f87a | ||
|
|
98fc4a41eb | ||
|
|
7836694b53 | ||
|
|
0866527ea0 | ||
|
|
c1b87080f1 | ||
|
|
b2e9ed2392 | ||
|
|
75548a1c04 | ||
|
|
900b03de1d | ||
|
|
cc0e88598f | ||
|
|
078186cd25 | ||
|
|
b55a4c6c61 | ||
|
|
4dad63ea90 | ||
|
|
6335169e9a | ||
|
|
1bf6db0809 | ||
|
|
4b53d920c7 | ||
|
|
fa3406a809 | ||
|
|
46c0adb62c | ||
|
|
d18170337d | ||
|
|
9c7238d578 | ||
|
|
1a63761e43 | ||
|
|
9c6bb48c7a | ||
|
|
2173ad7c71 | ||
|
|
b8db6c6a90 | ||
|
|
62f0337198 | ||
|
|
eb89496733 | ||
|
|
5d6e070e01 | ||
|
|
ae31f9737f | ||
|
|
6e42537aa1 | ||
|
|
2b14076171 | ||
|
|
55ac8681af | ||
|
|
b5d2615307 | ||
|
|
6742ec84cf | ||
|
|
61d735662e | ||
|
|
050b89f82f | ||
|
|
1b179a603a | ||
|
|
4a6382aa7f | ||
|
|
f0c44c5719 | ||
|
|
2c2076bf69 | ||
|
|
5a67fec99e | ||
|
|
7cadd5fba4 | ||
|
|
6b59844084 | ||
|
|
b3963179d1 | ||
|
|
6a63c40e08 | ||
|
|
f91c525a30 | ||
|
|
19779a627f | ||
|
|
b19ad435df | ||
|
|
5627f789a3 | ||
|
|
1c9a812009 | ||
|
|
939398774d | ||
|
|
361dc99ea5 | ||
|
|
9f2a89a41e | ||
|
|
26df41b25e | ||
|
|
dd6fe54834 | ||
|
|
3cffa3a275 | ||
|
|
a0335be710 | ||
|
|
cabee3ae0b | ||
|
|
940c5e2451 | ||
|
|
870436ddd8 | ||
|
|
c3c8de77fc | ||
|
|
87807f180c | ||
|
|
9e344d527b | ||
|
|
2f9e36bdb2 | ||
|
|
5038e80bf2 | ||
|
|
7a2dbb276f | ||
|
|
3300e98ce2 | ||
|
|
693b795c2b | ||
|
|
ef8ab37eb4 | ||
|
|
118df1d952 | ||
|
|
8d4ff52b0f | ||
|
|
613c41fd6e | ||
|
|
ecac278f63 | ||
|
|
742890ee31 | ||
|
|
f08f11fb6f | ||
|
|
859e2f2767 | ||
|
|
19ad09eb66 | ||
|
|
39056a2868 | ||
|
|
8a2d560482 | ||
|
|
f62f960433 | ||
|
|
8fb67ce08d | ||
|
|
65b952d7f8 | ||
|
|
6c2a335b7c | ||
|
|
f717661eea | ||
|
|
35bdeb7519 | ||
|
|
93b927db63 | ||
|
|
9afdd2adb9 | ||
|
|
5fe87a04de | ||
|
|
7e2b75dd58 | ||
|
|
32e192e938 | ||
|
|
1af2b39db1 | ||
|
|
782eaf82f3 | ||
|
|
41d38e04a7 | ||
|
|
1611599a25 | ||
|
|
842cbc9e84 | ||
|
|
238d0e6a6c | ||
|
|
c5af3baaeb | ||
|
|
2030aa1af7 | ||
|
|
4445cb98cf | ||
|
|
12c420d861 | ||
|
|
dc33aa0b5d | ||
|
|
f200af909b | ||
|
|
6f3873ad6b | ||
|
|
70bb2e9d07 | ||
|
|
a9aaf0b940 | ||
|
|
80eb1506d8 | ||
|
|
68723d36f7 | ||
|
|
c937ee735e | ||
|
|
b553094742 | ||
|
|
f31ffed558 | ||
|
|
3f71f97b8b | ||
|
|
1a6308f621 | ||
|
|
7045c59a72 | ||
|
|
4ffb1018f7 | ||
|
|
e78c09f5be | ||
|
|
d8e73f2674 | ||
|
|
0358e820e6 | ||
|
|
1d821f61c3 | ||
|
|
e2ffa42595 | ||
|
|
3a2dcb187e | ||
|
|
08e3a21429 | ||
|
|
42a613caf4 | ||
|
|
4ff38eb0ba | ||
|
|
b466c48487 | ||
|
|
517d4f84ff | ||
|
|
e04a6c9f87 | ||
|
|
1f0867985d | ||
|
|
d0e5988024 | ||
|
|
d007d48afc | ||
|
|
07a847457f | ||
|
|
9347c9f3d2 | ||
|
|
4ee5a7361c | ||
|
|
dad8b2a025 | ||
|
|
d52f6d4aa2 | ||
|
|
a94eae9a16 | ||
|
|
317f6fd4e8 | ||
|
|
b19b07c47d | ||
|
|
0a2ddab597 | ||
|
|
005ac939b1 | ||
|
|
12b0ae9bd6 | ||
|
|
6f92c0d267 | ||
|
|
756cdc0d9e | ||
|
|
783bc84779 | ||
|
|
e621bbf0bd | ||
|
|
43c5c3cc9f | ||
|
|
d8738e06b2 | ||
|
|
67449ec34e | ||
|
|
5c63b00eda | ||
|
|
79eef99731 | ||
|
|
e5496c62d6 | ||
|
|
b1a6f184ba | ||
|
|
878fea0340 | ||
|
|
1142d1adee | ||
|
|
0873f5eba2 | ||
|
|
0faa585d5f | ||
|
|
3b7c4cda7c | ||
|
|
3839a47f5c | ||
|
|
85503d2846 | ||
|
|
d6ae6faef4 | ||
|
|
2c2f003e15 | ||
|
|
2bd9623ab1 | ||
|
|
9f3c78de17 | ||
|
|
1af5828b18 | ||
|
|
99dc081b69 | ||
|
|
37c64a6e05 | ||
|
|
34d83de59e | ||
|
|
e80a1630f1 | ||
|
|
d0af7b0fac | ||
|
|
1af4dfd8ef | ||
|
|
42fc8f1da4 | ||
|
|
d469d404ab |
@@ -1,4 +1,6 @@
|
|||||||
coverage/
|
coverage/
|
||||||
dist/
|
dist/
|
||||||
tmp/
|
tmp/
|
||||||
|
build/
|
||||||
src/scripts/vendor/
|
src/scripts/vendor/
|
||||||
|
src/js/index.js
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"new-cap": [0],
|
"new-cap": [0],
|
||||||
"max-params": [2, 4],
|
"max-params": [2, 5],
|
||||||
"require-jsdoc": [2, {
|
"require-jsdoc": [2, {
|
||||||
"require": {
|
"require": {
|
||||||
"FunctionDeclaration": true,
|
"FunctionDeclaration": true,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Build CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: ghcr.io/pebble-dev/pebbleos-docker:v1
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up uv
|
||||||
|
uses: astral-sh/setup-uv@v7
|
||||||
|
- run: uv tool install pebble-tool
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run build
|
||||||
|
- run: pebble build
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: clay
|
||||||
|
path: dist.zip
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: Lint CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: 'npm'
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run lint
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Node.js Package
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-npm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: ghcr.io/pebble-dev/pebbleos-docker:v1
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up uv
|
||||||
|
uses: astral-sh/setup-uv@v7
|
||||||
|
- run: uv tool install pebble-tool
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run build
|
||||||
|
- run: pebble sdk install 4.9.127
|
||||||
|
- run: pebble build
|
||||||
|
- name: Update npm
|
||||||
|
run: npm install -g npm@next-11
|
||||||
|
- run: npm publish
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: Test CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: 'npm'
|
||||||
|
- name: Setup Chrome
|
||||||
|
uses: browser-actions/setup-chrome@v2
|
||||||
|
id: setup-chrome
|
||||||
|
with:
|
||||||
|
install-dependencies: true
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run build
|
||||||
|
- name: Run headless test
|
||||||
|
uses: coactions/setup-xvfb@v1
|
||||||
|
with:
|
||||||
|
run: npm run test-travis
|
||||||
|
env:
|
||||||
|
CHROME_BIN: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: Typecheck CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
typecheck:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: 'npm'
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run check:types
|
||||||
+10
-23
@@ -1,31 +1,18 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
coverage
|
/coverage
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
# node-waf configuration
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
/.lock-waf_*_build
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directory
|
# Dependency directory
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||||
node_modules
|
/node_modules
|
||||||
|
/npm-debug.log
|
||||||
|
|
||||||
tmp
|
/tmp/
|
||||||
|
/src/js/index.js
|
||||||
dist
|
/dist.zip
|
||||||
|
/dist/
|
||||||
|
/build/
|
||||||
|
/dist-types/
|
||||||
|
|||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
# We ignore everying except for what is actually used by the pebble tool.
|
||||||
|
/**/*
|
||||||
|
!/dist.zip
|
||||||
|
!/src/**/*
|
||||||
|
!/index.js
|
||||||
|
!/index.d.ts
|
||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
sudo: false
|
|
||||||
node_js:
|
|
||||||
- '4'
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
# Needed to include Chrome in Travis for karma tests
|
|
||||||
- export CHROME_BIN=chromium-browser
|
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- sh -e /etc/init.d/xvfb start
|
|
||||||
|
|
||||||
script: 'npm run test-travis'
|
|
||||||
+198
@@ -0,0 +1,198 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
Thanks for checking out Clay. We accept pull requests from anybody, however we ask
|
||||||
|
that you follow some conventions when contributing to Clay.
|
||||||
|
|
||||||
|
We have set up a
|
||||||
|
[piece-of-cake](https://github.com/pebble-dev/clay/issues?q=is%3Aopen+is%3Aissue+label%3Apiece-of-cake)
|
||||||
|
label in GitHub issues for bugs/features that are easy to implement. These issues are
|
||||||
|
a great place to start for people that are new to the codebase.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [Node](https://nodejs.org) (4.0 and later)
|
||||||
|
- [Google Chrome](www.google.com/chrome) (To run tests)
|
||||||
|
- [Pebble SDK](https://developer.rebble.io/sdk/) (optional)
|
||||||
|
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### 1. Fork, then clone the repo:
|
||||||
|
|
||||||
|
`$ git clone git@github.com:your-username/clay.git`
|
||||||
|
|
||||||
|
### 2. Create a new branch with the following naming convention.
|
||||||
|
|
||||||
|
`#<issue-id>/description-of-change`
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
`#90/support-message-keys`
|
||||||
|
|
||||||
|
If there is currently no GitHub issue open for your proposed contribution,
|
||||||
|
then please make one. This allows us to assign milestones and triage priority.
|
||||||
|
|
||||||
|
### 3. Install the project dependencies.
|
||||||
|
|
||||||
|
`$ npm install`
|
||||||
|
|
||||||
|
### 4. Develop your feature
|
||||||
|
|
||||||
|
Commit as often as you like. Your branch will be squashed when the pull request is merged.
|
||||||
|
|
||||||
|
### 5. Run the tests
|
||||||
|
|
||||||
|
`$ npm run test`
|
||||||
|
|
||||||
|
### 6. Run linting
|
||||||
|
|
||||||
|
`$ npm run lint`
|
||||||
|
|
||||||
|
### 7. Submit your pull request
|
||||||
|
|
||||||
|
In the main comment of the pull request, you must state the GitHub issue that your PR
|
||||||
|
resolves. You do this by using the syntax `Resolves #<issue-id>`. An example of this
|
||||||
|
can be found [here](https://github.com/pebble/clay/pull/81)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Project Structure and Development
|
||||||
|
|
||||||
|
|
||||||
|
## Important Files
|
||||||
|
|
||||||
|
There are two main entry points for Clay - `index.js` and `src/scripts/config-page.js`.
|
||||||
|
|
||||||
|
### index.js
|
||||||
|
|
||||||
|
This is the main entry point for the code that will run in the Pebble app's `src/js/app.js`.
|
||||||
|
It is responsible for serializing the provided config into a data URI that will be opened
|
||||||
|
using `Pebble.openURL()`. It also persists data to `localStorage`.
|
||||||
|
|
||||||
|
### src/scripts/config-page.js
|
||||||
|
|
||||||
|
This is the main entry point for the code that runs on the generated config page,
|
||||||
|
and is responsible for passing the injected config and other components to the
|
||||||
|
`ClayConfig` class.
|
||||||
|
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Use the following command to build Clay during development.
|
||||||
|
|
||||||
|
`$ npm run dev`
|
||||||
|
|
||||||
|
This command packages up `src/scripts/config-page.js` and `dev/dev.js` into the `tmp/` directory
|
||||||
|
so `dev/dev.html` can include them as script tags. This will also watch for changes
|
||||||
|
in the project.
|
||||||
|
|
||||||
|
While developing components and other functionality for Clay, it is much easier to
|
||||||
|
work with the files in the `dev/` directory than on a phone or emulator. Below is
|
||||||
|
an explanation of the files and their purpose.
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|----------|-----|
|
||||||
|
| `dev.html` | Open this page in a browser after running `$ npm run dev`. |
|
||||||
|
| `dev.js` | Injects the components and dependencies into the window the same way `index.js` would. |
|
||||||
|
| `config.js` | Clay config to use as a sandbox for testing components. |
|
||||||
|
| `custom-fn.js` | Clay custom function to be injected by `dev.js`. |
|
||||||
|
| `emulator.html` | Copy of the HTML page that is used to make the Clay compatible with the Pebble SDK emulator. |
|
||||||
|
| `uri-test.html` | Used to stress test URI creation for older browser versions. |
|
||||||
|
|
||||||
|
|
||||||
|
## Testing your change inside of a test project.
|
||||||
|
|
||||||
|
Once your change is ready to be tested in the emulator or on the watch, follow these steps:
|
||||||
|
|
||||||
|
1. From your Clay fork run `$ npm run pebble-build`. This builds Clay to work with the Pebble SDK
|
||||||
|
2. From your test Pebble project, run `$ pebble package install /path/to/your/clay/fork`.
|
||||||
|
This will modify your `package.json` to point directly to your local copy of Clay.
|
||||||
|
3. Run the usual`$ pebble build && pebble install --emulator basalt && pebble emu-app-config` to test your modifications
|
||||||
|
4. If you make modifications to your fork of Clay, you must repeat the above steps.
|
||||||
|
|
||||||
|
|
||||||
|
## Functionality
|
||||||
|
|
||||||
|
Most of the magic happens in the `src/scripts/lib` directory. `config-page.js`
|
||||||
|
initializes a new instance of `ClayConfig` and calls the injected custom function
|
||||||
|
(`window.customFn`) with the `ClayConfig` as its context. This allows developers to
|
||||||
|
add extra functionality to the config page, such as setting values of items dynamically
|
||||||
|
or registering small custom components.
|
||||||
|
|
||||||
|
Once the `ClayConfig` is initialized, we run the `.build()` method. This iterates over
|
||||||
|
the config and injects each item into the page. Each item is an instance of `ClayItem`.
|
||||||
|
It also indexes the items to later be retrieved with `.getAllItems()`,
|
||||||
|
`.getItemByMessageKey()`, `.getItemById()`, `.getItemsByType()`.
|
||||||
|
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Clay enforces 100% test coverage. Chances are, that if you are submitting a pull request,
|
||||||
|
there should be tests for the proposed code changes. Have a look at the other tests in
|
||||||
|
the repository to see some examples of how you should be writing your tests.
|
||||||
|
|
||||||
|
There are two commands to use while writing your tests.
|
||||||
|
|
||||||
|
- `$ npm run test` - Runs all tests once.
|
||||||
|
- `$ npm run test-debug` - Watches for file changes and re-runs all tests when it
|
||||||
|
detects a change. This also leaves an in instance of Google Chrome running.
|
||||||
|
If you click the "Debug" button in the top right of the page, a new tab will open.
|
||||||
|
You can then use the Google Chrome developer tools to debug your tests as they run.
|
||||||
|
Refreshing the page will re-run the tests.
|
||||||
|
|
||||||
|
## Style Guide
|
||||||
|
|
||||||
|
Our style guide is very similar to the
|
||||||
|
[Airbnb style guide.](https://github.com/airbnb/javascript/tree/master/es5) with the
|
||||||
|
following exceptions:
|
||||||
|
|
||||||
|
- When saving a reference to `this` use `self`.
|
||||||
|
```javascript
|
||||||
|
// bad
|
||||||
|
function() {
|
||||||
|
var _this = this;
|
||||||
|
return function() {
|
||||||
|
console.log(_this);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad
|
||||||
|
function() {
|
||||||
|
var that = this;
|
||||||
|
return function() {
|
||||||
|
console.log(that);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
function() {
|
||||||
|
var self = this;
|
||||||
|
return function() {
|
||||||
|
console.log(self);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Don't double name your functions. It makes refactoring more difficult.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// bad
|
||||||
|
var log = function log(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
// good
|
||||||
|
var log = function(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The style guide is enforced using ESLint. Run `$ npm run lint` to ensure you are
|
||||||
|
adhering to the style guide.
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- Chat to us in the `#app-dev` channel on Discord. https://discordapp.com/invite/aRUAYFN
|
||||||
|
- Visit the [Rebble Forums](https://forum.rebble.io/)
|
||||||
|
- Skeet at [@rebble.io](https://bsky.app/profile/rebble.io)
|
||||||
|
- More options at https://developer.rebble.io/community/online/
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
/* eslint-disable quotes */
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"id": "main-heading",
|
||||||
|
"defaultValue": "Clay Test Page",
|
||||||
|
"size": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"defaultValue": "This is config 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "section",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"defaultValue": "This is a section"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "input",
|
||||||
|
"messageKey": "email",
|
||||||
|
"defaultValue": "",
|
||||||
|
"label": "Input Field",
|
||||||
|
"description": "This is a new field",
|
||||||
|
"attributes": {
|
||||||
|
"placeholder": "Placeholder set with attributes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "submit",
|
||||||
|
"defaultValue": "Save"
|
||||||
|
}
|
||||||
|
];
|
||||||
+69
-14
@@ -13,6 +13,17 @@ module.exports = [
|
|||||||
"defaultValue": "Some arbitrary text explaining how this all works. " +
|
"defaultValue": "Some arbitrary text explaining how this all works. " +
|
||||||
"It's cool if this wraps across multiple lines"
|
"It's cool if this wraps across multiple lines"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "section",
|
||||||
|
"capabilities": ["RECT", "MICROPHONE"],
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"defaultValue": "This section is only visible for rectangular devices that" +
|
||||||
|
" have a microphone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "section",
|
"type": "section",
|
||||||
"items": [
|
"items": [
|
||||||
@@ -20,9 +31,14 @@ module.exports = [
|
|||||||
"type": "heading",
|
"type": "heading",
|
||||||
"defaultValue": "This is a section"
|
"defaultValue": "This is a section"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"defaultValue": "This is only visible for aplite",
|
||||||
|
"capabilities": ["APLITE"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "input",
|
"type": "input",
|
||||||
"appKey": "email",
|
"messageKey": "email",
|
||||||
"defaultValue": "",
|
"defaultValue": "",
|
||||||
"label": "Input Field",
|
"label": "Input Field",
|
||||||
"description": "This is a description for the input component. " +
|
"description": "This is a description for the input component. " +
|
||||||
@@ -31,22 +47,58 @@ module.exports = [
|
|||||||
"placeholder": "Placeholder set with attributes"
|
"placeholder": "Placeholder set with attributes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "input",
|
||||||
|
"label": "Time Field",
|
||||||
|
"attributes": {
|
||||||
|
"type": "time"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "input",
|
||||||
|
"label": "Date Field",
|
||||||
|
"attributes": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "slider",
|
||||||
|
"messageKey": "slider",
|
||||||
|
"defaultValue": 0,
|
||||||
|
"label": "Slider",
|
||||||
|
"description": "This is the description for the slider",
|
||||||
|
"min": 0,
|
||||||
|
"max": 30,
|
||||||
|
"step": 0.25
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "toggle",
|
"type": "toggle",
|
||||||
"appKey": "cool_stuff",
|
"messageKey": "cool_stuff",
|
||||||
|
"label": "This is a Toggle",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "toggle",
|
||||||
|
"messageKey": "arrayToggle[0]",
|
||||||
|
"label": "This is a Toggle",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "toggle",
|
||||||
|
"messageKey": "arrayToggle[1]",
|
||||||
"label": "This is a Toggle",
|
"label": "This is a Toggle",
|
||||||
"defaultValue": false
|
"defaultValue": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"appKey": "colorTest",
|
"messageKey": "colorTest",
|
||||||
"defaultValue": "FF0000",
|
"defaultValue": "FF0000",
|
||||||
"label": "Standard Color Picker",
|
"label": "Standard Color Picker",
|
||||||
"sunlight": false
|
"sunlight": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"appKey": "sunnyColorTest",
|
"messageKey": "sunnyColorTest",
|
||||||
"defaultValue": "00FF00",
|
"defaultValue": "00FF00",
|
||||||
"label": "Sunny Color Picker",
|
"label": "Sunny Color Picker",
|
||||||
"sunlight": true
|
"sunlight": true
|
||||||
@@ -70,7 +122,7 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "radiogroup",
|
"type": "radiogroup",
|
||||||
"appKey": "radiogroup-test",
|
"messageKey": "radiogroup-test",
|
||||||
"label": "Radio Group",
|
"label": "Radio Group",
|
||||||
"options": [
|
"options": [
|
||||||
{ "label": "Test thing", "value": "one" },
|
{ "label": "Test thing", "value": "one" },
|
||||||
@@ -80,25 +132,28 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "checkboxgroup",
|
"type": "checkboxgroup",
|
||||||
"appKey": "checkboxgroup-test",
|
"messageKey": "checkboxgroup-test",
|
||||||
"defaultValue": ["quote' \"test", "two"],
|
"defaultValue": [0, 1, 0],
|
||||||
"label": "Checkbox Group",
|
"label": "Checkbox Group",
|
||||||
"options": [
|
"options": [ "First thing", "Another thing", "Final thing" ]
|
||||||
{ "label": "First thing", "value": "three" },
|
|
||||||
{ "label": "Another thing", "value": "two" },
|
|
||||||
{ "label": "Final thing", "value": "three" }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "select",
|
"type": "select",
|
||||||
"appKey": "flavor",
|
"messageKey": "flavor",
|
||||||
"defaultValue": "grape",
|
"defaultValue": "grape",
|
||||||
"label": "Select Menu",
|
"label": "Select Menu",
|
||||||
"options": [
|
"options": [
|
||||||
{ "label": "", "value": "" },
|
{ "label": "", "value": "" },
|
||||||
{ "label": "Berry", "value": "berry" },
|
{ "label": "Berry", "value": "berry" },
|
||||||
{ "label": "This Option is Selected", "value": "grape" },
|
{ "label": "This Option is Selected", "value": "grape" },
|
||||||
{ "label": "Banana", "value": "banana" }
|
{ "label": "Banana", "value": "banana" },
|
||||||
|
{
|
||||||
|
"label": "This is an optgroup",
|
||||||
|
"value": [
|
||||||
|
{ "label": "Peach", "value": "peach" },
|
||||||
|
{ "label": "Mango", "value": "mango" }
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"required": "required"
|
"required": "required"
|
||||||
|
|||||||
+15
-3
@@ -10,15 +10,27 @@ module.exports = function() {
|
|||||||
*/
|
*/
|
||||||
function toggleBackground() {
|
function toggleBackground() {
|
||||||
if (this.get()) {
|
if (this.get()) {
|
||||||
Clay.getItemByAppKey('colorTest').enable();
|
Clay.getItemByMessageKey('colorTest').enable();
|
||||||
} else {
|
} else {
|
||||||
Clay.getItemByAppKey('colorTest').disable();
|
Clay.getItemByMessageKey('colorTest').disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function handleButtonClick() {
|
||||||
|
Clay.config = Clay.meta.userData.config2;
|
||||||
|
Clay.build();
|
||||||
|
}
|
||||||
|
|
||||||
Clay.on(Clay.EVENTS.AFTER_BUILD, function() {
|
Clay.on(Clay.EVENTS.AFTER_BUILD, function() {
|
||||||
var coolStuffToggle = Clay.getItemByAppKey('cool_stuff');
|
var coolStuffToggle = Clay.getItemByMessageKey('cool_stuff');
|
||||||
toggleBackground.call(coolStuffToggle);
|
toggleBackground.call(coolStuffToggle);
|
||||||
coolStuffToggle.on('change', toggleBackground);
|
coolStuffToggle.on('change', toggleBackground);
|
||||||
|
|
||||||
|
Clay.getItemById('testButton').on('click', handleButtonClick);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('userData: ', Clay.meta.userData);
|
||||||
};
|
};
|
||||||
|
|||||||
+17
@@ -5,6 +5,23 @@ window.clayConfig = require('./config.js');
|
|||||||
window.claySettings = {};
|
window.claySettings = {};
|
||||||
window.customFn = require('./custom-fn.js');
|
window.customFn = require('./custom-fn.js');
|
||||||
window.clayComponents = require('../src/scripts/components');
|
window.clayComponents = require('../src/scripts/components');
|
||||||
|
window.clayMeta = require('../test/fixture').meta({
|
||||||
|
activeWatchInfo: {
|
||||||
|
platform: 'basalt',
|
||||||
|
model: 'qemu_platform_basalt',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 3,
|
||||||
|
minor: 10,
|
||||||
|
patch: 2,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userData: {
|
||||||
|
foo: 'bar',
|
||||||
|
config2: require('./config-2')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
||||||
document.documentElement.classList.add('platform-' + platform);
|
document.documentElement.classList.add('platform-' + platform);
|
||||||
|
|||||||
+6
-1
@@ -20,9 +20,14 @@
|
|||||||
|
|
||||||
var returnTo = getQueryParam('return_to');
|
var returnTo = getQueryParam('return_to');
|
||||||
var data = decodeURIComponent(location.hash.substring(1));
|
var data = decodeURIComponent(location.hash.substring(1));
|
||||||
if (data) {
|
|
||||||
|
// Check if we dealing with a base64 encoded URI
|
||||||
|
if (data && data.charAt(0) !== '<') {
|
||||||
data = window.atob(data).replace('$$RETURN_TO$$', returnTo);
|
data = window.atob(data).replace('$$RETURN_TO$$', returnTo);
|
||||||
window.location.href = 'data:text/html;base64,' + encodeURIComponent(window.btoa(data));
|
window.location.href = 'data:text/html;base64,' + encodeURIComponent(window.btoa(data));
|
||||||
|
} else if (data) {
|
||||||
|
data = data.replace('$$RETURN_TO$$', returnTo);
|
||||||
|
window.location.href = 'data:text/html;charset=utf-8,' + encodeURIComponent(data);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
+73
-36
@@ -8,65 +8,71 @@ var stringify = require('stringify');
|
|||||||
var del = require('del');
|
var del = require('del');
|
||||||
var inline = require('gulp-inline');
|
var inline = require('gulp-inline');
|
||||||
var htmlmin = require('gulp-htmlmin');
|
var htmlmin = require('gulp-htmlmin');
|
||||||
var sass = require('gulp-sass');
|
var sass = require('gulp-sass')(require('sass'));
|
||||||
var sourceMaps = require('gulp-sourcemaps');
|
var sourceMaps = require('gulp-sourcemaps');
|
||||||
var autoprefixer = require('gulp-autoprefixer');
|
var autoprefixer = require('gulp-autoprefixer');
|
||||||
var uglify = require('gulp-uglify');
|
var uglify = require('gulp-uglify');
|
||||||
var sassify = require('sassify');
|
|
||||||
var autoprefixify = require('./src/scripts/vendor/autoprefixify');
|
var autoprefixify = require('./src/scripts/vendor/autoprefixify');
|
||||||
var insert = require('gulp-insert');
|
var insert = require('gulp-insert');
|
||||||
|
var clayPackage = require('./package.json');
|
||||||
|
|
||||||
var sassIncludePaths = [].concat(
|
var sassIncludePaths = [].concat(
|
||||||
require('bourbon').includePaths,
|
require('bourbon').includePaths,
|
||||||
'src/styles'
|
'src/styles'
|
||||||
);
|
);
|
||||||
|
|
||||||
var sassifyOptions = {
|
|
||||||
base64Encode: false,
|
|
||||||
sourceMap: false,
|
|
||||||
sourceMapEmbed: false,
|
|
||||||
sourceMapContents: false,
|
|
||||||
outputStyle: 'compact',
|
|
||||||
includePaths: sassIncludePaths
|
|
||||||
};
|
|
||||||
|
|
||||||
var autoprefixerOptions = {
|
var autoprefixerOptions = {
|
||||||
browsers: ['Android 4', 'iOS 8'],
|
browsers: ['Android 4', 'iOS 8'],
|
||||||
cascade: false
|
cascade: false
|
||||||
};
|
};
|
||||||
|
|
||||||
var stringifyOptions = ['.html', '.tpl'];
|
var stringifyOptions = ['.html', '.tpl', '.css'];
|
||||||
var versionMessage = '/* Clay - https://github.com/pebble/clay - Version: ' +
|
var versionMessage = '/* Clay - https://github.com/pebble-dev/clay - Version: ' +
|
||||||
require('./package.json').version +
|
clayPackage.version +
|
||||||
' - Build Date: ' + new Date().toISOString() + ' */\n';
|
' - Build Date: ' + new Date().toISOString() + ' */\n';
|
||||||
|
|
||||||
gulp.task('clean-js', function() {
|
gulp.task('clean-js', function() {
|
||||||
return del(['tmp/config-page.js']);
|
return del(['tmp/config-page.js']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('js', ['clean-js'], function() {
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskJs() {
|
||||||
return browserify('src/scripts/config-page.js', { debug: true })
|
return browserify('src/scripts/config-page.js', { debug: true })
|
||||||
.transform('deamdify')
|
.transform('deamdify')
|
||||||
.bundle()
|
.bundle()
|
||||||
.pipe(source('config-page.js'))
|
.pipe(source('config-page.js'))
|
||||||
.pipe(gulp.dest('./tmp/'));
|
.pipe(gulp.dest('./tmp/'));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
gulp.task('js', gulp.series('clean-js', taskJs));
|
||||||
|
|
||||||
gulp.task('clean-sass', function() {
|
gulp.task('clean-sass', function() {
|
||||||
return del(['tmp/config-page.scss']);
|
return del(['tmp/config-page.scss']);
|
||||||
});
|
});
|
||||||
gulp.task('sass', ['clean-sass'], function() {
|
|
||||||
gulp.src('./src/styles/config-page.scss')
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskSass() {
|
||||||
|
return gulp.src(['./src/styles/config-page.scss',
|
||||||
|
'./src/styles/clay/components/*.scss'])
|
||||||
.pipe(sourceMaps.init())
|
.pipe(sourceMaps.init())
|
||||||
.pipe(sass({
|
.pipe(sass({
|
||||||
includePaths: sassIncludePaths
|
loadPaths: sassIncludePaths
|
||||||
}).on('error', sass.logError))
|
}).on('error', sass.logError))
|
||||||
.pipe(autoprefixer(autoprefixerOptions))
|
.pipe(autoprefixer(autoprefixerOptions))
|
||||||
.pipe(sourceMaps.write('./'))
|
.pipe(sourceMaps.write('./'))
|
||||||
.pipe(gulp.dest('tmp'));
|
.pipe(gulp.dest('tmp'));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task('inlineHtml', ['js', 'sass'], function() {
|
gulp.task('sass', gulp.series('clean-sass', taskSass));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskInlineHtml() {
|
||||||
return gulp.src('src/config-page.html')
|
return gulp.src('src/config-page.html')
|
||||||
.pipe(inline())
|
.pipe(inline())
|
||||||
.pipe(htmlmin({
|
.pipe(htmlmin({
|
||||||
@@ -79,40 +85,71 @@ gulp.task('inlineHtml', ['js', 'sass'], function() {
|
|||||||
minifyCSS: true
|
minifyCSS: true
|
||||||
}))
|
}))
|
||||||
.pipe(gulp.dest('tmp/'));
|
.pipe(gulp.dest('tmp/'));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task('clay', ['inlineHtml'], function() {
|
gulp.task('inlineHtml', gulp.series('js', 'sass', taskInlineHtml));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskClay() {
|
||||||
return browserify('index.js', {
|
return browserify('index.js', {
|
||||||
debug: false,
|
debug: false,
|
||||||
standalone: 'clay'
|
standalone: clayPackage.name
|
||||||
})
|
})
|
||||||
|
.transform('deamdify')
|
||||||
.transform(stringify(stringifyOptions))
|
.transform(stringify(stringifyOptions))
|
||||||
.transform(sassify, sassifyOptions)
|
// .transform(autoprefixify, autoprefixerOptions)
|
||||||
.transform(autoprefixify, autoprefixerOptions)
|
.require(require.resolve('./index'), {expose: clayPackage.name})
|
||||||
.require(require.resolve('./index'), {expose: 'pebble-clay'})
|
.exclude('message_keys')
|
||||||
.bundle()
|
.bundle()
|
||||||
.pipe(source('clay.js'))
|
.pipe(source('index.js'))
|
||||||
.pipe(buffer())
|
.pipe(buffer())
|
||||||
.pipe(uglify())
|
.pipe(uglify({
|
||||||
|
preserveComments: 'license'
|
||||||
|
}))
|
||||||
.pipe(insert.prepend(versionMessage))
|
.pipe(insert.prepend(versionMessage))
|
||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./src/js'));
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('clay', gulp.series('inlineHtml', taskClay));
|
||||||
|
|
||||||
|
// Validates the curated index.d.ts against test/type-checks.ts.
|
||||||
|
// For per-file reference declarations in dist-types/, run: npm run build:types
|
||||||
|
gulp.task('types', function(done) {
|
||||||
|
var exec = require('child_process').exec;
|
||||||
|
exec('npx tsc -p tsconfig.typecheck.json', function(err, stdout, stderr) {
|
||||||
|
if (stdout) { console.log(stdout); }
|
||||||
|
if (stderr) { console.error(stderr); }
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('dev-js', ['js', 'sass'], function() {
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskDevJs() {
|
||||||
return browserify('dev/dev.js', { debug: true })
|
return browserify('dev/dev.js', { debug: true })
|
||||||
.transform(stringify(stringifyOptions))
|
.transform(stringify(stringifyOptions))
|
||||||
.transform('deamdify')
|
.transform('deamdify')
|
||||||
.transform(sassify, sassifyOptions)
|
|
||||||
.transform(autoprefixify, autoprefixerOptions)
|
.transform(autoprefixify, autoprefixerOptions)
|
||||||
|
.ignore('message_keys')
|
||||||
.bundle()
|
.bundle()
|
||||||
.pipe(source('dev.js'))
|
.pipe(source('dev.js'))
|
||||||
.pipe(gulp.dest('./tmp/'));
|
.pipe(gulp.dest('./tmp/'));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task('default', ['clay']);
|
gulp.task('dev-js', gulp.series('js', 'sass', taskDevJs));
|
||||||
|
|
||||||
gulp.task('dev', ['dev-js'], function() {
|
gulp.task('default', gulp.series('clay', 'types'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function taskDev() {
|
||||||
gulp.watch('src/styles/**/*.scss', ['sass']);
|
gulp.watch('src/styles/**/*.scss', ['sass']);
|
||||||
gulp.watch(['src/scripts/**/*.js', 'src/templates/**/*.tpl'], ['js']);
|
gulp.watch(['src/scripts/**/*.js', 'src/templates/**/*.tpl'], ['js']);
|
||||||
gulp.watch(['src/**', 'dev/**/*.js'], ['dev-js']);
|
gulp.watch(['src/**', 'dev/**/*.js'], ['dev-js']);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
gulp.task('dev', gulp.series('dev-js', taskDev));
|
||||||
|
|||||||
Vendored
+313
@@ -0,0 +1,313 @@
|
|||||||
|
/**
|
||||||
|
* TypeScript declarations for @rebble/clay
|
||||||
|
*
|
||||||
|
* A Pebble configuration framework that provides a simple way to generate a
|
||||||
|
* configuration page for Pebble watchapps and watchfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Minimal DOM wrapper type from minified.js */
|
||||||
|
interface M {
|
||||||
|
[index: number]: HTMLElement;
|
||||||
|
length: number;
|
||||||
|
add(child: M | string): M;
|
||||||
|
set(property: string, value?: unknown): M;
|
||||||
|
get(property: string): unknown;
|
||||||
|
select(selector: string): M;
|
||||||
|
on(events: string, handler: (...args: unknown[]) => void): M;
|
||||||
|
each(callback: (element: HTMLElement, index: number) => void): M;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Clay config item as provided in the config array */
|
||||||
|
interface ClayConfigItem {
|
||||||
|
type: string;
|
||||||
|
defaultValue?: string | boolean | number;
|
||||||
|
messageKey?: string;
|
||||||
|
id?: string;
|
||||||
|
label?: string;
|
||||||
|
attributes?: Record<string, unknown>;
|
||||||
|
options?: unknown[];
|
||||||
|
serializeValueAs?: string,
|
||||||
|
items?: ClayConfigItem[];
|
||||||
|
capabilities?: string[];
|
||||||
|
group?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Clay component definition */
|
||||||
|
interface ClayComponent {
|
||||||
|
name: string;
|
||||||
|
template: string;
|
||||||
|
manipulator: string | ClayManipulator;
|
||||||
|
defaults?: Record<string, unknown>;
|
||||||
|
style?: string;
|
||||||
|
initialize?: (this: ClayItem, minified: unknown, clay: ClayConfig) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A manipulator with get and set methods */
|
||||||
|
interface ClayManipulator {
|
||||||
|
get: (this: ClayItem) => unknown;
|
||||||
|
set: (this: ClayItem, value: unknown) => ClayItem;
|
||||||
|
disable?: (this: ClayItem) => ClayItem;
|
||||||
|
enable?: (this: ClayItem) => ClayItem;
|
||||||
|
hide?: (this: ClayItem) => ClayItem;
|
||||||
|
show?: (this: ClayItem) => ClayItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clay meta information populated from the Pebble object */
|
||||||
|
interface ClayMeta {
|
||||||
|
activeWatchInfo: PebbleActiveWatchInfo | null;
|
||||||
|
accountToken: string;
|
||||||
|
watchToken: string;
|
||||||
|
userData: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Watch info from the Pebble API */
|
||||||
|
interface PebbleActiveWatchInfo {
|
||||||
|
platform: string;
|
||||||
|
model: string;
|
||||||
|
language: string;
|
||||||
|
firmware: {
|
||||||
|
major: number;
|
||||||
|
minor: number;
|
||||||
|
patch: number;
|
||||||
|
suffix: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Options for the Clay constructor */
|
||||||
|
interface ClayOptions {
|
||||||
|
autoHandleEvents?: boolean;
|
||||||
|
userData?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Event methods mixed in by ClayEvents */
|
||||||
|
interface ClayEvents {
|
||||||
|
/**
|
||||||
|
* Attach an event listener.
|
||||||
|
* @param events - a space-separated list of events
|
||||||
|
* @param handler - the event handler
|
||||||
|
*/
|
||||||
|
on(events: string, handler: (...args: unknown[]) => void): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given event handler from all registered events.
|
||||||
|
* @param handler - the handler to remove
|
||||||
|
*/
|
||||||
|
off(handler: (...args: unknown[]) => void): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger an event.
|
||||||
|
* @param name - a single event name to trigger
|
||||||
|
* @param eventObj - an object to pass to the event handler
|
||||||
|
*/
|
||||||
|
trigger(name: string, eventObj?: unknown): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A ClayItem represents a single config component in the config page */
|
||||||
|
interface ClayItem extends ClayEvents {
|
||||||
|
/** The item's id from the config, or null */
|
||||||
|
id: string | null;
|
||||||
|
|
||||||
|
/** The item's messageKey from the config, or null */
|
||||||
|
messageKey: string | null;
|
||||||
|
|
||||||
|
/** The raw config for this item */
|
||||||
|
config: ClayConfigItem;
|
||||||
|
|
||||||
|
/** The root DOM element wrapper */
|
||||||
|
$element: M;
|
||||||
|
|
||||||
|
/** The manipulator target DOM element wrapper */
|
||||||
|
$manipulatorTarget: M;
|
||||||
|
|
||||||
|
/** The precision for numeric values */
|
||||||
|
precision?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the component initialiser.
|
||||||
|
* @param clay - the ClayConfig instance
|
||||||
|
*/
|
||||||
|
initialize(clay: ClayConfig): ClayItem;
|
||||||
|
|
||||||
|
/** Get the current value of the item via its manipulator */
|
||||||
|
get(): unknown;
|
||||||
|
|
||||||
|
/** Set the value of the item via its manipulator */
|
||||||
|
set(value: unknown): ClayItem;
|
||||||
|
|
||||||
|
/** Disable the item */
|
||||||
|
disable(): ClayItem;
|
||||||
|
|
||||||
|
/** Enable the item */
|
||||||
|
enable(): ClayItem;
|
||||||
|
|
||||||
|
/** Hide the item */
|
||||||
|
hide(): ClayItem;
|
||||||
|
|
||||||
|
/** Show the item */
|
||||||
|
show(): ClayItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ClayConfig lifecycle event names */
|
||||||
|
interface ClayConfigEvents {
|
||||||
|
readonly BEFORE_BUILD: 'BEFORE_BUILD';
|
||||||
|
readonly AFTER_BUILD: 'AFTER_BUILD';
|
||||||
|
readonly BEFORE_DESTROY: 'BEFORE_DESTROY';
|
||||||
|
readonly AFTER_DESTROY: 'AFTER_DESTROY';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ClayConfig manages the config page and its items */
|
||||||
|
interface ClayConfig extends ClayEvents {
|
||||||
|
/** Meta information from the Pebble object */
|
||||||
|
meta: ClayMeta;
|
||||||
|
|
||||||
|
/** The root container element */
|
||||||
|
$rootContainer: M;
|
||||||
|
|
||||||
|
/** Lifecycle event name constants */
|
||||||
|
EVENTS: ClayConfigEvents;
|
||||||
|
|
||||||
|
/** The config array (may be modified before build) */
|
||||||
|
config: ClayConfigItem | ClayConfigItem[];
|
||||||
|
|
||||||
|
/** Get all items. Must call build() first. */
|
||||||
|
getAllItems(): ClayItem[];
|
||||||
|
|
||||||
|
/** Get an item by its messageKey. Must call build() first. */
|
||||||
|
getItemByMessageKey(messageKey: string): ClayItem;
|
||||||
|
|
||||||
|
/** Get an item by its id. Must call build() first. */
|
||||||
|
getItemById(id: string): ClayItem;
|
||||||
|
|
||||||
|
/** Get all items of a given type. Must call build() first. */
|
||||||
|
getItemsByType(type: string): ClayItem[];
|
||||||
|
|
||||||
|
/** Get all items belonging to a given group. Must call build() first. */
|
||||||
|
getItemsByGroup(group: string): ClayItem[];
|
||||||
|
|
||||||
|
/** Serialise the current settings. Must call build() first. */
|
||||||
|
serialize(): Record<string, { value: unknown; precision?: number }>;
|
||||||
|
|
||||||
|
/** Register a component. Alias for ClayConfig.registerComponent. */
|
||||||
|
registerComponent(component: ClayComponent): boolean;
|
||||||
|
|
||||||
|
/** Destroy the config page and reset items. */
|
||||||
|
destroy(): ClayConfig;
|
||||||
|
|
||||||
|
/** Build the config page. Must be called before get methods. */
|
||||||
|
build(): ClayConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClayConfigConstructor {
|
||||||
|
new (
|
||||||
|
settings: Record<string, unknown>,
|
||||||
|
config: ClayConfigItem | ClayConfigItem[],
|
||||||
|
$rootContainer: M,
|
||||||
|
meta: ClayMeta
|
||||||
|
): ClayConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a component to Clay. Must be called before build().
|
||||||
|
*/
|
||||||
|
registerComponent(component: ClayComponent): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main Clay constructor.
|
||||||
|
*
|
||||||
|
* @param config - the Clay config array
|
||||||
|
* @param customFn - custom code to run from the config page
|
||||||
|
* @param options - additional options
|
||||||
|
*/
|
||||||
|
declare class Clay {
|
||||||
|
constructor(
|
||||||
|
config: ClayConfigItem[],
|
||||||
|
customFn?: ((this: ClayConfig) => void) | null,
|
||||||
|
options?: ClayOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
/** The Clay config array */
|
||||||
|
config: ClayConfigItem[];
|
||||||
|
|
||||||
|
/** The custom function */
|
||||||
|
customFn: (this: ClayConfig) => void;
|
||||||
|
|
||||||
|
/** Registered components */
|
||||||
|
components: Record<string, ClayComponent>;
|
||||||
|
|
||||||
|
/** Meta information populated from the Pebble object */
|
||||||
|
meta: ClayMeta;
|
||||||
|
|
||||||
|
/** The Clay version string */
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a component to Clay.
|
||||||
|
* @param component - the clay component to register
|
||||||
|
*/
|
||||||
|
registerComponent(component: ClayComponent): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the Data URI used by the config page with settings injected.
|
||||||
|
*/
|
||||||
|
generateUrl(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the response from the webviewclosed event data.
|
||||||
|
* @param response - the response string
|
||||||
|
* @param convert - if false, return raw settings without conversion
|
||||||
|
*/
|
||||||
|
getSettings(response: string, convert?: boolean): Record<string, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update settings with the given key/value pair.
|
||||||
|
* @param key - the setting key
|
||||||
|
* @param value - the setting value
|
||||||
|
*/
|
||||||
|
setSettings(key: string, value: unknown): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update settings with the given object.
|
||||||
|
* @param settings - an object of key/value pairs to set
|
||||||
|
*/
|
||||||
|
setSettings(settings: Record<string, unknown>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode content as a data URI.
|
||||||
|
* @param input - the content to encode
|
||||||
|
* @param prefix - the URI prefix
|
||||||
|
*/
|
||||||
|
static encodeDataUri(input: string, prefix?: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value to a type compatible with Pebble.sendAppMessage().
|
||||||
|
*/
|
||||||
|
static prepareForAppMessage(
|
||||||
|
val: unknown
|
||||||
|
): number | string | (number | string)[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Clay settings to a format compatible with Pebble.sendAppMessage().
|
||||||
|
*/
|
||||||
|
static prepareSettingsForAppMessage(
|
||||||
|
settings: Record<string, unknown>
|
||||||
|
): Record<number, number | string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace Clay {
|
||||||
|
export {
|
||||||
|
ClayConfigItem,
|
||||||
|
ClayComponent,
|
||||||
|
ClayManipulator,
|
||||||
|
ClayMeta,
|
||||||
|
PebbleActiveWatchInfo,
|
||||||
|
ClayOptions,
|
||||||
|
ClayEvents,
|
||||||
|
ClayItem,
|
||||||
|
ClayConfig,
|
||||||
|
ClayConfigEvents,
|
||||||
|
ClayConfigConstructor,
|
||||||
|
M,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export = Clay;
|
||||||
@@ -3,14 +3,19 @@
|
|||||||
var configPageHtml = require('./tmp/config-page.html');
|
var configPageHtml = require('./tmp/config-page.html');
|
||||||
var toSource = require('tosource');
|
var toSource = require('tosource');
|
||||||
var standardComponents = require('./src/scripts/components');
|
var standardComponents = require('./src/scripts/components');
|
||||||
|
var deepcopy = require('deepcopy/build/deepcopy.min');
|
||||||
|
var version = require('./package.json').version;
|
||||||
|
var messageKeys = require('message_keys');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array} config - the Clay config
|
* @param {Array} config - the Clay config
|
||||||
* @param {function} [customFn] - Custom code to run from the config page. Will run
|
* @param {function} [customFn] - Custom code to run from the config page. Will run
|
||||||
* with the ClayConfig instance as context
|
* with the ClayConfig instance as context
|
||||||
* @param {Object} [options] - Additional options to pass to Clay
|
* @param {Object} [options] - Additional options to pass to Clay
|
||||||
* @param {boolean} [options.autoHandleEvents] - If false, Clay will not
|
* @param {boolean} [options.autoHandleEvents=true] - If false, Clay will not
|
||||||
* automatically handle the 'showConfiguration' and 'webviewclosed' events
|
* automatically handle the 'showConfiguration' and 'webviewclosed' events
|
||||||
|
* @param {*} [options.userData={}] - Arbitrary data to pass to the config page. Will
|
||||||
|
* be available as `clayConfig.meta.userData`
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function Clay(config, customFn, options) {
|
function Clay(config, customFn, options) {
|
||||||
@@ -26,14 +31,30 @@ function Clay(config, customFn, options) {
|
|||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
self.config = config;
|
self.config = deepcopy(config);
|
||||||
self.customFn = customFn || function() {};
|
self.customFn = customFn || function() {};
|
||||||
self.components = {};
|
self.components = {};
|
||||||
self.meta = {
|
self.meta = {
|
||||||
activeWatchInfo: null,
|
activeWatchInfo: null,
|
||||||
accountToken: '',
|
accountToken: '',
|
||||||
watchToken: ''
|
watchToken: '',
|
||||||
|
userData: {}
|
||||||
};
|
};
|
||||||
|
self.version = version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the meta with data from the Pebble object. Make sure to run this inside
|
||||||
|
* either the "showConfiguration" or "ready" event handler
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function _populateMeta() {
|
||||||
|
self.meta = {
|
||||||
|
activeWatchInfo: Pebble.getActiveWatchInfo && Pebble.getActiveWatchInfo(),
|
||||||
|
accountToken: Pebble.getAccountToken(),
|
||||||
|
watchToken: Pebble.getWatchToken(),
|
||||||
|
userData: deepcopy(options.userData || {})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Let Clay handle all the magic
|
// Let Clay handle all the magic
|
||||||
if (options.autoHandleEvents !== false && typeof Pebble !== 'undefined') {
|
if (options.autoHandleEvents !== false && typeof Pebble !== 'undefined') {
|
||||||
@@ -62,36 +83,50 @@ function Clay(config, customFn, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the meta with data from the Pebble object. Make sure to run this inside
|
* If this function returns true then the callback will be executed
|
||||||
* either the "showConfiguration" or "ready" event handler
|
* @callback _scanConfig_testFn
|
||||||
* @return {void}
|
* @param {Clay~ConfigItem} item
|
||||||
*/
|
*/
|
||||||
function _populateMeta() {
|
|
||||||
self.meta = {
|
|
||||||
activeWatchInfo: Pebble.getActiveWatchInfo && Pebble.getActiveWatchInfo(),
|
|
||||||
accountToken: Pebble.getAccountToken(),
|
|
||||||
watchToken: Pebble.getWatchToken()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @callback _scanConfig_callback
|
||||||
|
* @param {Clay~ConfigItem} item
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan over the config and run the callback if the testFn resolves to true
|
||||||
* @private
|
* @private
|
||||||
* @param {Clay~ConfigItem|Array} item
|
* @param {Clay~ConfigItem|Array} item
|
||||||
|
* @param {_scanConfig_testFn} testFn
|
||||||
|
* @param {_scanConfig_callback} callback
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
function _registerStandardComponents(item) {
|
function _scanConfig(item, testFn, callback) {
|
||||||
if (Array.isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
item.forEach(function(item) {
|
item.forEach(function(item) {
|
||||||
_registerStandardComponents(item);
|
_scanConfig(item, testFn, callback);
|
||||||
});
|
});
|
||||||
} else if (item.type === 'section') {
|
} else if (item.type === 'section') {
|
||||||
_registerStandardComponents(item.items);
|
_scanConfig(item.items, testFn, callback);
|
||||||
} else if (standardComponents[item.type]) {
|
} else if (testFn(item)) {
|
||||||
self.registerComponent(standardComponents[item.type]);
|
callback(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_registerStandardComponents(self.config);
|
// register standard components
|
||||||
|
_scanConfig(self.config, function(item) {
|
||||||
|
return standardComponents[item.type];
|
||||||
|
}, function(item) {
|
||||||
|
self.registerComponent(standardComponents[item.type]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// validate config against teh use of appKeys
|
||||||
|
_scanConfig(self.config, function(item) {
|
||||||
|
return item.appKey;
|
||||||
|
}, function() {
|
||||||
|
throw new Error('appKeys are no longer supported. ' +
|
||||||
|
'Please follow the migration guide to upgrade your project');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,76 +184,196 @@ 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
|
||||||
|
* @param {boolean} [convert=true]
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
Clay.prototype.getSettings = function(response) {
|
Clay.prototype.getSettings = function(response, convert) {
|
||||||
// Decode and parse config data as JSON
|
// Decode and parse config data as JSON
|
||||||
var settings = {};
|
var settings = {};
|
||||||
|
response = response.match(/^\{/) ? response : decodeURIComponent(response);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
settings = JSON.parse(decodeURIComponent(response));
|
settings = JSON.parse(response);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('The provided response was not valid JSON');
|
throw new Error('The provided response was not valid JSON');
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem('clay-settings', JSON.stringify(settings));
|
// flatten the settings for localStorage
|
||||||
return settings;
|
var settingsStorage = {};
|
||||||
|
Object.keys(settings).forEach(function(key) {
|
||||||
|
if (typeof settings[key] === 'object' && settings[key]) {
|
||||||
|
settingsStorage[key] = settings[key].value;
|
||||||
|
} else {
|
||||||
|
settingsStorage[key] = settings[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem('clay-settings', JSON.stringify(settingsStorage));
|
||||||
|
|
||||||
|
return convert === false ? settings : Clay.prepareSettingsForAppMessage(settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the settings with the given value(s).
|
||||||
|
*
|
||||||
|
* @signature `clay.setSettings(key, value)`
|
||||||
|
* @param {String} key - The property to set.
|
||||||
|
* @param {*} value - the value assigned to _key_.
|
||||||
|
* @return {undefined}
|
||||||
|
*
|
||||||
|
* @signature `clay.setSettings(settings)`
|
||||||
|
* @param {Object} settings - an object containing the key/value pairs to be set.
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
Clay.prototype.setSettings = function(key, value) {
|
||||||
|
var settingsStorage = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
settingsStorage = JSON.parse(localStorage.getItem('clay-settings')) || {};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof key === 'object') {
|
||||||
|
var settings = key;
|
||||||
|
Object.keys(settings).forEach(function(key) {
|
||||||
|
settingsStorage[key] = settings[key];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
settingsStorage[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('clay-settings', JSON.stringify(settingsStorage));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} input
|
* @param {string} input
|
||||||
* @param {string} [prefix]
|
* @param {string} [prefix='data:text/html;charset=utf-8,']
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
Clay.encodeDataUri = function(input, prefix) {
|
Clay.encodeDataUri = function(input, prefix) {
|
||||||
prefix = typeof prefix !== 'undefined' ? prefix : 'data:text/html;base64,';
|
prefix = typeof prefix !== 'undefined' ? prefix : 'data:text/html;charset=utf-8,';
|
||||||
|
return prefix + encodeURIComponent(input);
|
||||||
|
};
|
||||||
|
|
||||||
if (window.btoa) {
|
/**
|
||||||
return prefix + encodeURIComponent(window.btoa(input));
|
* Converts the val into a type compatible with Pebble.sendAppMessage().
|
||||||
|
* - Strings will be returned without modification
|
||||||
|
* - Numbers will be returned without modification
|
||||||
|
* - Booleans will be converted to a 0 or 1
|
||||||
|
* - Arrays that contain strings will be returned without modification
|
||||||
|
* eg: ['one', 'two'] becomes ['one', 'two']
|
||||||
|
* - Arrays that contain numbers will be returned without modification
|
||||||
|
* eg: [1, 2] becomes [1, 2]
|
||||||
|
* - Arrays that contain booleans will be converted to a 0 or 1
|
||||||
|
* eg: [true, false] becomes [1, 0]
|
||||||
|
* - Arrays must be single dimensional
|
||||||
|
* - Objects that have a "value" property will apply the above rules to the type of
|
||||||
|
* value. If the value is a number or an array of numbers and the optional
|
||||||
|
* property: "precision" is provided, then the number will be multiplied by 10 to
|
||||||
|
* the power of precision (value * 10 ^ precision) and then floored.
|
||||||
|
* Eg: 1.4567 with a precision set to 3 will become 1456
|
||||||
|
* @param {number|string|boolean|Array|Object} val
|
||||||
|
* @param {number|string|boolean|Array} val.value
|
||||||
|
* @param {number|undefined} [val.precision=0]
|
||||||
|
* @returns {number|string|Array}
|
||||||
|
*/
|
||||||
|
Clay.prepareForAppMessage = function(val) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the decimal place of a number by precision then drop any remaining decimal
|
||||||
|
* places.
|
||||||
|
* @param {number} number
|
||||||
|
* @param {number} precision - number of decimal places to move
|
||||||
|
* @returns {number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function _normalizeToPrecision(number, precision) {
|
||||||
|
return Math.floor(number * Math.pow(10, precision || 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// iOS doesn't have a window so we need to polyfil window.btoa
|
var result;
|
||||||
// extracted from https://github.com/inexorabletash/polyfill
|
|
||||||
var B64_ALPHABET =
|
|
||||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
||||||
input = String(input);
|
|
||||||
var position = 0;
|
|
||||||
var out = [];
|
|
||||||
var o1;
|
|
||||||
var o2;
|
|
||||||
var o3;
|
|
||||||
var e1;
|
|
||||||
var e2;
|
|
||||||
var e3;
|
|
||||||
var e4;
|
|
||||||
|
|
||||||
if (/[^\x00-\xFF]/.test(input)) { throw Error('InvalidCharacterError'); }
|
if (Array.isArray(val)) {
|
||||||
|
result = [];
|
||||||
|
val.forEach(function(item, index) {
|
||||||
|
result[index] = Clay.prepareForAppMessage(item);
|
||||||
|
});
|
||||||
|
} else if (typeof val === 'object' && val) {
|
||||||
|
if (typeof val.value === 'number') {
|
||||||
|
result = _normalizeToPrecision(val.value, val.precision);
|
||||||
|
} else if (Array.isArray(val.value)) {
|
||||||
|
result = val.value.map(function(item) {
|
||||||
|
if (typeof item === 'number') {
|
||||||
|
return _normalizeToPrecision(item, val.precision);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result = Clay.prepareForAppMessage(val.value);
|
||||||
|
}
|
||||||
|
} else if (typeof val === 'boolean') {
|
||||||
|
result = val ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
result = val;
|
||||||
|
}
|
||||||
|
|
||||||
while (position < input.length) {
|
return result;
|
||||||
o1 = input.charCodeAt(position++);
|
};
|
||||||
o2 = input.charCodeAt(position++);
|
|
||||||
o3 = input.charCodeAt(position++);
|
|
||||||
|
|
||||||
// 111111 112222 222233 333333
|
/**
|
||||||
e1 = o1 >> 2;
|
* Converts a Clay settings dict into one that is compatible with
|
||||||
e2 = ((o1 & 0x3) << 4) | (o2 >> 4);
|
* Pebble.sendAppMessage(); It also uses the provided messageKeys to correctly
|
||||||
e3 = ((o2 & 0xf) << 2) | (o3 >> 6);
|
* assign arrays into individual keys
|
||||||
e4 = o3 & 0x3f;
|
* @see {prepareForAppMessage}
|
||||||
|
* @param {Object} settings
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
Clay.prepareSettingsForAppMessage = function(settings) {
|
||||||
|
|
||||||
if (position === input.length + 2) {
|
// flatten settings
|
||||||
e3 = 64;
|
var flatSettings = {};
|
||||||
e4 = 64;
|
Object.keys(settings).forEach(function(key) {
|
||||||
} else if (position === input.length + 1) {
|
var val = settings[key];
|
||||||
e4 = 64;
|
var matches = key.match(/(.+?)(?:\[(\d*)\])?$/);
|
||||||
|
|
||||||
|
if (!matches[2]) {
|
||||||
|
flatSettings[key] = val;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push(B64_ALPHABET.charAt(e1),
|
var position = parseInt(matches[2], 10);
|
||||||
B64_ALPHABET.charAt(e2),
|
key = matches[1];
|
||||||
B64_ALPHABET.charAt(e3),
|
|
||||||
B64_ALPHABET.charAt(e4));
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix + encodeURIComponent(out.join(''));
|
if (typeof flatSettings[key] === 'undefined') {
|
||||||
|
flatSettings[key] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
flatSettings[key][position] = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = {};
|
||||||
|
Object.keys(flatSettings).forEach(function(key) {
|
||||||
|
var messageKey = messageKeys[key];
|
||||||
|
var settingArr = Clay.prepareForAppMessage(flatSettings[key]);
|
||||||
|
settingArr = Array.isArray(settingArr) ? settingArr : [settingArr];
|
||||||
|
|
||||||
|
settingArr.forEach(function(setting, index) {
|
||||||
|
result[messageKey + index] = setting;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// validate the settings
|
||||||
|
Object.keys(result).forEach(function(key) {
|
||||||
|
if (Array.isArray(result[key])) {
|
||||||
|
throw new Error('Clay does not support 2 dimensional arrays for item ' +
|
||||||
|
'values. Make sure you are not attempting to use array ' +
|
||||||
|
'syntax (eg: "myMessageKey[2]") in the messageKey for ' +
|
||||||
|
'components that return an array, such as a checkboxgroup');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Clay;
|
module.exports = Clay;
|
||||||
|
|||||||
Generated
+13777
File diff suppressed because it is too large
Load Diff
+57
-33
@@ -1,72 +1,96 @@
|
|||||||
{
|
{
|
||||||
"name": "pebble-clay",
|
"name": "@rebble/clay",
|
||||||
"version": "0.1.2",
|
"version": "1.1.0",
|
||||||
"description": "Pebble Config Framework",
|
"description": "Pebble Config Framework",
|
||||||
"main": "dist/clay.js",
|
"types": "index.d.ts",
|
||||||
"directories": {
|
|
||||||
"example": "example"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test-travis": "./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --single-run --browsers chromeTravisCI && ./node_modules/.bin/eslint ./",
|
"test-travis": "./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --single-run --browsers chromeTravisCI",
|
||||||
"test-debug": "(export DEBUG=true && ./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --no-single-run)",
|
"test-debug": "(export DEBUG=true && ./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --no-single-run)",
|
||||||
"test": "./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --single-run",
|
"test": "./node_modules/.bin/gulp && ./node_modules/.bin/karma start ./test/karma.conf.js --single-run",
|
||||||
"lint": "./node_modules/.bin/eslint ./",
|
"lint": "./node_modules/.bin/eslint ./",
|
||||||
"build": "gulp",
|
"build": "gulp",
|
||||||
"dev": "gulp dev"
|
"build:types": "tsc -p tsconfig.declarations.json",
|
||||||
|
"check:types": "tsc -p tsconfig.typecheck.json",
|
||||||
|
"dev": "gulp dev",
|
||||||
|
"pebble-clean": "rm -rf tmp src/js/index.js && pebble clean",
|
||||||
|
"pebble-publish": "npm run pebble-clean && npm run build && pebble build && pebble package publish && npm run pebble-clean",
|
||||||
|
"pebble-build": "npm run build && pebble build"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/pebble/clay.git"
|
"url": "git+https://github.com/pebble-dev/clay.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Pebble",
|
"pebble",
|
||||||
"Config"
|
"config",
|
||||||
|
"configuration",
|
||||||
|
"pebble-package"
|
||||||
],
|
],
|
||||||
"author": "Pebble Technology",
|
"author": "Pebble Technology",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/pebble/clay/issues"
|
"url": "https://github.com/pebble-dev/clay/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/pebble/clay#readme",
|
"pebble": {
|
||||||
|
"projectType": "package",
|
||||||
|
"sdkVersion": "3",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"aplite",
|
||||||
|
"basalt",
|
||||||
|
"chalk",
|
||||||
|
"diorite",
|
||||||
|
"emery",
|
||||||
|
"flint",
|
||||||
|
"gabbro"
|
||||||
|
],
|
||||||
|
"resources": {
|
||||||
|
"media": []
|
||||||
|
},
|
||||||
|
"capabilities": [
|
||||||
|
"configurable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/pebble-dev/clay#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^6.3.1",
|
"autoprefixer": "^10.4.23",
|
||||||
"bourbon": "^4.2.6",
|
"bourbon": "^4.2.6",
|
||||||
"browserify": "^13.0.0",
|
"browserify": "^13.0.0",
|
||||||
"browserify-istanbul": "^0.2.1",
|
"browserify-istanbul": "^3.0.1",
|
||||||
"chai": "^3.4.1",
|
"chai": "^3.4.1",
|
||||||
"deamdify": "^0.2.0",
|
"deamdify": "^0.2.0",
|
||||||
|
"deepcopy": "^0.6.1",
|
||||||
"del": "^2.0.2",
|
"del": "^2.0.2",
|
||||||
"eslint": "^1.5.1",
|
"eslint": "^1.5.1",
|
||||||
"eslint-config-pebble": "^1.2.0",
|
"eslint-config-pebble": "^1.2.0",
|
||||||
"eslint-plugin-standard": "^1.3.1",
|
"eslint-plugin-standard": "^1.3.1",
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^5.0.1",
|
||||||
"gulp-autoprefixer": "^3.1.0",
|
"gulp-autoprefixer": "^3.1.0",
|
||||||
"gulp-htmlmin": "^1.3.0",
|
"gulp-htmlmin": "^1.3.0",
|
||||||
"gulp-inline": "0.0.15",
|
"gulp-inline": "^0.1.3",
|
||||||
"gulp-insert": "^0.5.0",
|
"gulp-insert": "^0.5.0",
|
||||||
"gulp-sass": "^2.1.1",
|
"gulp-sass": "^6.0.1",
|
||||||
"gulp-sourcemaps": "^1.6.0",
|
"gulp-sourcemaps": "^1.6.0",
|
||||||
"gulp-uglify": "^1.5.2",
|
"gulp-uglify": "^1.5.2",
|
||||||
"joi": "^6.10.1",
|
"joi": "^6.10.1",
|
||||||
"karma": "^0.13.19",
|
"karma": "^6.4.0",
|
||||||
"karma-browserify": "^5.0.1",
|
"karma-browserify": "^8.1.0",
|
||||||
"karma-chrome-launcher": "^0.2.2",
|
"karma-chrome-launcher": "^3.2.0",
|
||||||
"karma-coverage": "^0.5.3",
|
"karma-coverage": "^2.2.1",
|
||||||
"karma-mocha": "^0.2.1",
|
"karma-mocha": "^2.0.1",
|
||||||
"karma-mocha-reporter": "^1.1.5",
|
"karma-mocha-reporter": "^2.2.5",
|
||||||
"karma-source-map-support": "^1.1.0",
|
"karma-source-map-support": "^1.4.0",
|
||||||
"karma-threshold-reporter": "^0.1.15",
|
"karma-threshold-reporter": "^0.1.15",
|
||||||
"mocha": "^2.3.4",
|
"mocha": "^11.7.5",
|
||||||
"postcss": "^5.0.14",
|
"postcss": "8.5.6",
|
||||||
"require-from-string": "^1.1.0",
|
"require-from-string": "^2.0.2",
|
||||||
"sassify": "^0.9.1",
|
"sass": "^1.94.2",
|
||||||
"sinon": "^1.17.3",
|
"sinon": "^1.17.3",
|
||||||
"stringify": "^3.2.0",
|
"stringify": "^3.2.0",
|
||||||
"through": "^2.3.8",
|
"through": "^2.3.8",
|
||||||
"tosource": "^1.0.0",
|
"tosource": "^1.0.0",
|
||||||
|
"typescript": "6.0.2",
|
||||||
"vinyl-buffer": "^1.0.0",
|
"vinyl-buffer": "^1.0.0",
|
||||||
"vinyl-source-stream": "^1.1.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"watchify": "^3.7.0"
|
"watchify": "^3.11.1"
|
||||||
},
|
}
|
||||||
"dependencies": {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 135 KiB |
@@ -3,7 +3,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'button',
|
name: 'button',
|
||||||
template: require('../../templates/components/button.tpl'),
|
template: require('../../templates/components/button.tpl'),
|
||||||
style: require('../../styles/clay/components/button.scss'),
|
style: require('../../../tmp/button.css'),
|
||||||
manipulator: 'button',
|
manipulator: 'button',
|
||||||
defaults: {
|
defaults: {
|
||||||
primary: false,
|
primary: false,
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'checkboxgroup',
|
name: 'checkboxgroup',
|
||||||
template: require('../../templates/components/checkboxgroup.tpl'),
|
template: require('../../templates/components/checkboxgroup.tpl'),
|
||||||
style: require('../../styles/clay/components/checkboxgroup.scss'),
|
style: require('../../../tmp/checkboxgroup.css'),
|
||||||
manipulator: 'checkboxgroup',
|
manipulator: 'checkboxgroup',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
options: [],
|
options: [],
|
||||||
description: '',
|
description: ''
|
||||||
attributes: {}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+226
-93
@@ -3,123 +3,233 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'color',
|
name: 'color',
|
||||||
template: require('../../templates/components/color.tpl'),
|
template: require('../../templates/components/color.tpl'),
|
||||||
style: require('../../styles/clay/components/color.scss'),
|
style: require('../../../tmp/color.css'),
|
||||||
manipulator: 'color',
|
manipulator: 'color',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
description: ''
|
description: ''
|
||||||
},
|
},
|
||||||
initialize: function(minified) {
|
initialize: function(minified, clay) {
|
||||||
var HTML = minified.HTML;
|
var HTML = minified.HTML;
|
||||||
var self = this;
|
var self = this;
|
||||||
var useSunlight = self.config.sunlight !== false;
|
|
||||||
var sunlightColorMap = {
|
|
||||||
'000000': '000000',
|
|
||||||
'000055': '001e41',
|
|
||||||
'0000aa': '004387',
|
|
||||||
'0000ff': '0068ca',
|
|
||||||
'005500': '2b4a2c',
|
|
||||||
'005555': '27514f',
|
|
||||||
'0055aa': '16638d',
|
|
||||||
'0055ff': '007dce',
|
|
||||||
'00aa00': '5e9860',
|
|
||||||
'00aa55': '5c9b72',
|
|
||||||
'00aaaa': '57a5a2',
|
|
||||||
'00aaff': '4cb4db',
|
|
||||||
'00ff00': '8ee391',
|
|
||||||
'00ff55': '8ee69e',
|
|
||||||
'00ffaa': '8aebc0',
|
|
||||||
'00ffff': '84f5f1',
|
|
||||||
'550000': '4a161b',
|
|
||||||
'550055': '482748',
|
|
||||||
'5500aa': '40488a',
|
|
||||||
'5500ff': '2f6bcc',
|
|
||||||
'555500': '564e36',
|
|
||||||
'555555': '545454',
|
|
||||||
'5555aa': '4f6790',
|
|
||||||
'5555ff': '4180d0',
|
|
||||||
'55aa00': '759a64',
|
|
||||||
'55aa55': '759d76',
|
|
||||||
'55aaaa': '71a6a4',
|
|
||||||
'55aaff': '69b5dd',
|
|
||||||
'55ff00': '9ee594',
|
|
||||||
'55ff55': '9de7a0',
|
|
||||||
'55ffaa': '9becc2',
|
|
||||||
'55ffff': '95f6f2',
|
|
||||||
'aa0000': '99353f',
|
|
||||||
'aa0055': '983e5a',
|
|
||||||
'aa00aa': '955694',
|
|
||||||
'aa00ff': '8f74d2',
|
|
||||||
'aa5500': '9d5b4d',
|
|
||||||
'aa5555': '9d6064',
|
|
||||||
'aa55aa': '9a7099',
|
|
||||||
'aa55ff': '9587d5',
|
|
||||||
'aaaa00': 'afa072',
|
|
||||||
'aaaa55': 'aea382',
|
|
||||||
'aaaaaa': 'ababab',
|
|
||||||
'ffffff': 'ffffff',
|
|
||||||
'aaaaff': 'a7bae2',
|
|
||||||
'aaff00': 'c9e89d',
|
|
||||||
'aaff55': 'c9eaa7',
|
|
||||||
'aaffaa': 'c7f0c8',
|
|
||||||
'aaffff': 'c3f9f7',
|
|
||||||
'ff0000': 'e35462',
|
|
||||||
'ff0055': 'e25874',
|
|
||||||
'ff00aa': 'e16aa3',
|
|
||||||
'ff00ff': 'de83dc',
|
|
||||||
'ff5500': 'e66e6b',
|
|
||||||
'ff5555': 'e6727c',
|
|
||||||
'ff55aa': 'e37fa7',
|
|
||||||
'ff55ff': 'e194df',
|
|
||||||
'ffaa00': 'f1aa86',
|
|
||||||
'ffaa55': 'f1ad93',
|
|
||||||
'ffaaaa': 'efb5b8',
|
|
||||||
'ffaaff': 'ecc3eb',
|
|
||||||
'ffff00': 'ffeeab',
|
|
||||||
'ffff55': 'fff1b5',
|
|
||||||
'ffffaa': 'fff6d3'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string|boolean|number} color
|
* @param {string|boolean|number} color
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function cssColor(color) {
|
function cssColor(color) {
|
||||||
if (color === false) { return 'transparent'; }
|
|
||||||
if (typeof color === 'number') {
|
if (typeof color === 'number') {
|
||||||
color = color.toString(16);
|
color = color.toString(16);
|
||||||
|
} else if (!color) {
|
||||||
|
return 'transparent';
|
||||||
}
|
}
|
||||||
while (color.length < 6) {
|
|
||||||
color = '0' + color;
|
color = padColorString(color);
|
||||||
}
|
|
||||||
|
|
||||||
return '#' + (useSunlight ? sunlightColorMap[color] : color);
|
return '#' + (useSunlight ? sunlightColorMap[color] : color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} color
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function padColorString(color) {
|
||||||
|
color = color.toLowerCase();
|
||||||
|
|
||||||
|
while (color.length < 6) {
|
||||||
|
color = '0' + color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|string} value
|
||||||
|
* @returns {string|*}
|
||||||
|
*/
|
||||||
|
function normalizeColor(value) {
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'number': return padColorString(value.toString(16));
|
||||||
|
case 'string': return value.replace(/^#|^0x/, '');
|
||||||
|
default: return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array.<Array>} layout
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
function flattenLayout(layout) {
|
||||||
|
return layout.reduce(function(a, b) {
|
||||||
|
return a.concat(b);
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HEX color to LAB.
|
||||||
|
* Adapted from: https://github.com/antimatter15/rgb-lab
|
||||||
|
* @param {string} hex
|
||||||
|
* @returns {Array} - [l, a, b]
|
||||||
|
*/
|
||||||
|
function hex2lab(hex) {
|
||||||
|
hex = hex.replace(/^#|^0x/, '');
|
||||||
|
|
||||||
|
var r = parseInt(hex.slice(0, 2), 16) / 255;
|
||||||
|
var g = parseInt(hex.slice(2, 4), 16) / 255;
|
||||||
|
var b = parseInt(hex.slice(4), 16) / 255;
|
||||||
|
|
||||||
|
r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
||||||
|
g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
||||||
|
b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
||||||
|
|
||||||
|
var x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
|
||||||
|
var y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
|
||||||
|
var z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
|
||||||
|
|
||||||
|
x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116;
|
||||||
|
y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116;
|
||||||
|
z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116;
|
||||||
|
|
||||||
|
return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the perceptual color distance between two LAB colors
|
||||||
|
* @param {Array} labA
|
||||||
|
* @param {Array} labB
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function deltaE(labA, labB) {
|
||||||
|
var deltaL = labA[0] - labB[0];
|
||||||
|
var deltaA = labA[1] - labB[1];
|
||||||
|
var deltaB = labA[2] - labB[2];
|
||||||
|
|
||||||
|
return Math.sqrt(Math.pow(deltaL, 2) +
|
||||||
|
Math.pow(deltaA, 2) +
|
||||||
|
Math.pow(deltaB, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the layout based on the connected watch
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
function autoLayout() {
|
||||||
|
var bwWatches = ['aplite', 'diorite', 'flint'];
|
||||||
|
if (!clay.meta.activeWatchInfo ||
|
||||||
|
clay.meta.activeWatchInfo.firmware.major === 2 ||
|
||||||
|
bwWatches.indexOf(clay.meta.activeWatchInfo.platform) > -1 &&
|
||||||
|
!self.config.allowGray) {
|
||||||
|
return standardLayouts.BLACK_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bwWatches.indexOf(clay.meta.activeWatchInfo.platform) > -1 &&
|
||||||
|
self.config.allowGray) {
|
||||||
|
return standardLayouts.GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return standardLayouts.COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|string} color
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
self.roundColorToLayout = function(color) {
|
||||||
|
var itemValue = normalizeColor(color);
|
||||||
|
|
||||||
|
// if the color is not in the layout we will need find the closest match
|
||||||
|
if (colorList.indexOf(itemValue) === -1) {
|
||||||
|
var itemValueLAB = hex2lab(itemValue);
|
||||||
|
var differenceArr = colorList.map(function(color) {
|
||||||
|
var colorLAB = hex2lab(normalizeColor(color));
|
||||||
|
return deltaE(itemValueLAB, colorLAB);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the lowest number from the differenceArray
|
||||||
|
var lowest = Math.min.apply(Math, differenceArr);
|
||||||
|
|
||||||
|
// Get the index for that lowest number
|
||||||
|
var index = differenceArr.indexOf(lowest);
|
||||||
|
itemValue = colorList[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseInt(itemValue, 16);
|
||||||
|
};
|
||||||
|
|
||||||
|
var useSunlight = self.config.sunlight !== false;
|
||||||
|
var sunlightColorMap = {
|
||||||
|
'000000': '000000', '000055': '001e41', '0000aa': '004387', '0000ff': '0068ca',
|
||||||
|
'005500': '2b4a2c', '005555': '27514f', '0055aa': '16638d', '0055ff': '007dce',
|
||||||
|
'00aa00': '5e9860', '00aa55': '5c9b72', '00aaaa': '57a5a2', '00aaff': '4cb4db',
|
||||||
|
'00ff00': '8ee391', '00ff55': '8ee69e', '00ffaa': '8aebc0', '00ffff': '84f5f1',
|
||||||
|
'550000': '4a161b', '550055': '482748', '5500aa': '40488a', '5500ff': '2f6bcc',
|
||||||
|
'555500': '564e36', '555555': '545454', '5555aa': '4f6790', '5555ff': '4180d0',
|
||||||
|
'55aa00': '759a64', '55aa55': '759d76', '55aaaa': '71a6a4', '55aaff': '69b5dd',
|
||||||
|
'55ff00': '9ee594', '55ff55': '9de7a0', '55ffaa': '9becc2', '55ffff': '95f6f2',
|
||||||
|
'aa0000': '99353f', 'aa0055': '983e5a', 'aa00aa': '955694', 'aa00ff': '8f74d2',
|
||||||
|
'aa5500': '9d5b4d', 'aa5555': '9d6064', 'aa55aa': '9a7099', 'aa55ff': '9587d5',
|
||||||
|
'aaaa00': 'afa072', 'aaaa55': 'aea382', 'aaaaaa': 'ababab', 'ffffff': 'ffffff',
|
||||||
|
'aaaaff': 'a7bae2', 'aaff00': 'c9e89d', 'aaff55': 'c9eaa7', 'aaffaa': 'c7f0c8',
|
||||||
|
'aaffff': 'c3f9f7', 'ff0000': 'e35462', 'ff0055': 'e25874', 'ff00aa': 'e16aa3',
|
||||||
|
'ff00ff': 'de83dc', 'ff5500': 'e66e6b', 'ff5555': 'e6727c', 'ff55aa': 'e37fa7',
|
||||||
|
'ff55ff': 'e194df', 'ffaa00': 'f1aa86', 'ffaa55': 'f1ad93', 'ffaaaa': 'efb5b8',
|
||||||
|
'ffaaff': 'ecc3eb', 'ffff00': 'ffeeab', 'ffff55': 'fff1b5', 'ffffaa': 'fff6d3'
|
||||||
|
};
|
||||||
|
|
||||||
/* eslint-disable comma-spacing, no-multi-spaces, max-len,
|
/* eslint-disable comma-spacing, no-multi-spaces, max-len,
|
||||||
standard/array-bracket-even-spacing */
|
standard/array-bracket-even-spacing */
|
||||||
var layout = self.config.layout || [
|
var standardLayouts = {
|
||||||
[false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ],
|
COLOR: [
|
||||||
[false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ],
|
[false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ],
|
||||||
['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'],
|
[false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ],
|
||||||
['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'],
|
['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'],
|
||||||
[false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ],
|
['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'],
|
||||||
['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'],
|
[false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ],
|
||||||
['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'],
|
['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'],
|
||||||
[false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ],
|
['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'],
|
||||||
[false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ]
|
[false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ],
|
||||||
];
|
[false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ]
|
||||||
|
],
|
||||||
|
GRAY: [
|
||||||
|
['000000', 'aaaaaa', 'ffffff']
|
||||||
|
],
|
||||||
|
BLACK_WHITE: [
|
||||||
|
['000000', 'ffffff']
|
||||||
|
]
|
||||||
|
};
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
|
|
||||||
|
var layout = self.config.layout || autoLayout();
|
||||||
|
|
||||||
|
if (typeof layout === 'string') {
|
||||||
|
layout = standardLayouts[layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure layout is a 2D array
|
||||||
|
if (!Array.isArray(layout[0])) {
|
||||||
|
layout = [layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorList = flattenLayout(layout).map(function(item) {
|
||||||
|
return normalizeColor(item);
|
||||||
|
}).filter(function(item) {
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
var grid = '';
|
var grid = '';
|
||||||
var itemWidth = 100 / layout[0].length;
|
var rows = layout.length;
|
||||||
var itemHeight = 100 / layout.length;
|
var cols = 0;
|
||||||
|
layout.forEach(function(row) {
|
||||||
|
cols = row.length > cols ? row.length : cols;
|
||||||
|
});
|
||||||
|
var itemWidth = 100 / cols;
|
||||||
|
var itemHeight = 100 / rows;
|
||||||
var $elem = self.$element;
|
var $elem = self.$element;
|
||||||
|
|
||||||
for (var i = 0; i < layout.length; i++) {
|
for (var i = 0; i < rows; i++) {
|
||||||
for (var j = 0; j < layout[i].length; j++) {
|
for (var j = 0; j < cols; j++) {
|
||||||
|
|
||||||
var color = layout[i][j];
|
var color = normalizeColor(layout[i][j]);
|
||||||
var selectable = (color ? ' selectable' : '');
|
var selectable = (color ? ' selectable' : '');
|
||||||
|
|
||||||
var roundedTL = (i === 0 && j === 0) || i === 0 && !layout[i][j - 1] ||
|
var roundedTL = (i === 0 && j === 0) || i === 0 && !layout[i][j - 1] ||
|
||||||
@@ -146,7 +256,7 @@ module.exports = {
|
|||||||
grid += '<i ' +
|
grid += '<i ' +
|
||||||
'class="color-box ' + selectable + roundedTL + roundedTR + roundedBL +
|
'class="color-box ' + selectable + roundedTL + roundedTR + roundedBL +
|
||||||
roundedBR + '" ' +
|
roundedBR + '" ' +
|
||||||
'data-value="' + parseInt(color, 16) + '" ' +
|
(color ? 'data-value="' + parseInt(color, 16) + '" ' : '') +
|
||||||
'style="' +
|
'style="' +
|
||||||
'width:' + itemWidth + '%; ' +
|
'width:' + itemWidth + '%; ' +
|
||||||
'height:' + itemHeight + '%; ' +
|
'height:' + itemHeight + '%; ' +
|
||||||
@@ -155,13 +265,34 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$elem.select('.color-box-container').add(HTML(grid));
|
// on very small layouts the boxes end up huge. The following adds extra padding
|
||||||
|
// to prevent them from being so big.
|
||||||
|
var extraPadding = 0;
|
||||||
|
if (cols === 3) {
|
||||||
|
extraPadding = 5;
|
||||||
|
}
|
||||||
|
if (cols === 2) {
|
||||||
|
extraPadding = 8;
|
||||||
|
}
|
||||||
|
var vPadding = (extraPadding * itemWidth / itemHeight) + '%';
|
||||||
|
var hPadding = extraPadding + '%';
|
||||||
|
$elem.select('.color-box-container')
|
||||||
|
.add(HTML(grid))
|
||||||
|
.set('$paddingTop', vPadding)
|
||||||
|
.set('$paddingRight', hPadding)
|
||||||
|
.set('$paddingBottom', vPadding)
|
||||||
|
.set('$paddingLeft', hPadding);
|
||||||
|
|
||||||
|
$elem.select('.color-box-wrap').set(
|
||||||
|
'$paddingBottom',
|
||||||
|
(itemWidth / itemHeight * 100) + '%'
|
||||||
|
);
|
||||||
|
|
||||||
var $valueDisplay = $elem.select('.value');
|
var $valueDisplay = $elem.select('.value');
|
||||||
var $picker = $elem.select('.picker-wrap');
|
var $picker = $elem.select('.picker-wrap');
|
||||||
var disabled = self.$manipulatorTarget.get('disabled');
|
var disabled = self.$manipulatorTarget.get('disabled');
|
||||||
|
|
||||||
$elem.select('label').on('click', function(ev) {
|
$elem.select('label').on('click', function() {
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
$picker.set('show'); // toggle visibility
|
$picker.set('show'); // toggle visibility
|
||||||
}
|
}
|
||||||
@@ -191,5 +322,7 @@ module.exports = {
|
|||||||
disabled = false;
|
disabled = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// expose layout for testing
|
||||||
|
self._layout = layout;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ module.exports = {
|
|||||||
toggle: require('./toggle'),
|
toggle: require('./toggle'),
|
||||||
radiogroup: require('./radiogroup'),
|
radiogroup: require('./radiogroup'),
|
||||||
checkboxgroup: require('./checkboxgroup'),
|
checkboxgroup: require('./checkboxgroup'),
|
||||||
button: require('./button')
|
button: require('./button'),
|
||||||
|
slider: require('./slider')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'input',
|
name: 'input',
|
||||||
template: require('../../templates/components/input.tpl'),
|
template: require('../../templates/components/input.tpl'),
|
||||||
style: require('../../styles/clay/components/input.scss'),
|
style: require('../../../tmp/input.css'),
|
||||||
manipulator: 'val',
|
manipulator: 'val',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
|
serializeValueAs: 'string',
|
||||||
description: '',
|
description: '',
|
||||||
attributes: {}
|
attributes: {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'radiogroup',
|
name: 'radiogroup',
|
||||||
template: require('../../templates/components/radiogroup.tpl'),
|
template: require('../../templates/components/radiogroup.tpl'),
|
||||||
style: require('../../styles/clay/components/radiogroup.scss'),
|
style: require('../../../tmp/radiogroup.css'),
|
||||||
manipulator: 'radiogroup',
|
manipulator: 'radiogroup',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
options: [],
|
options: [],
|
||||||
|
serializeValueAs: 'string',
|
||||||
description: '',
|
description: '',
|
||||||
attributes: {}
|
attributes: {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'select',
|
name: 'select',
|
||||||
template: require('../../templates/components/select.tpl'),
|
template: require('../../templates/components/select.tpl'),
|
||||||
style: require('../../styles/clay/components/select.scss'),
|
style: require('../../../tmp/select.css'),
|
||||||
manipulator: 'val',
|
manipulator: 'val',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
options: [],
|
options: [],
|
||||||
|
serializeValueAs: 'string',
|
||||||
description: '',
|
description: '',
|
||||||
attributes: {}
|
attributes: {}
|
||||||
},
|
},
|
||||||
@@ -17,7 +18,7 @@ module.exports = {
|
|||||||
var $value = self.$element.select('.value');
|
var $value = self.$element.select('.value');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the HTML value of the component to match the slected option's label
|
* Updates the HTML value of the component to match the selected option's label
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
function setValueDisplay() {
|
function setValueDisplay() {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'slider',
|
||||||
|
template: require('../../templates/components/slider.tpl'),
|
||||||
|
style: require('../../../tmp/slider.css'),
|
||||||
|
manipulator: 'slider',
|
||||||
|
defaults: {
|
||||||
|
label: '',
|
||||||
|
description: '',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
attributes: {}
|
||||||
|
},
|
||||||
|
initialize: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var $value = self.$element.select('.value');
|
||||||
|
var $valuePad = self.$element.select('.value-pad');
|
||||||
|
var $slider = self.$manipulatorTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value display
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function setValueDisplay() {
|
||||||
|
var value = self.get().toFixed(self.precision);
|
||||||
|
$value.set('value', value);
|
||||||
|
$valuePad.set('innerHTML', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var step = $slider.get('step');
|
||||||
|
step = step.toString(10).split('.')[1];
|
||||||
|
self.precision = step ? step.length : 0;
|
||||||
|
|
||||||
|
self.on('change', setValueDisplay);
|
||||||
|
$slider.on('|input', setValueDisplay);
|
||||||
|
setValueDisplay();
|
||||||
|
|
||||||
|
$value.on('|input', function() {
|
||||||
|
$valuePad.set('innerHTML', this.get('value'));
|
||||||
|
});
|
||||||
|
|
||||||
|
$value.on('|change', function() {
|
||||||
|
self.set(this.get('value'));
|
||||||
|
setValueDisplay();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'submit',
|
name: 'submit',
|
||||||
template: require('../../templates/components/submit.tpl'),
|
template: require('../../templates/components/submit.tpl'),
|
||||||
style: require('../../styles/clay/components/submit.scss'),
|
style: require('../../../tmp/submit.css'),
|
||||||
manipulator: 'button',
|
manipulator: 'button',
|
||||||
defaults: {
|
defaults: {
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'toggle',
|
name: 'toggle',
|
||||||
template: require('../../templates/components/toggle.tpl'),
|
template: require('../../templates/components/toggle.tpl'),
|
||||||
style: require('../../styles/clay/components/toggle.scss'),
|
style: require('../../../tmp/toggle.css'),
|
||||||
manipulator: 'checked',
|
manipulator: 'checked',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: '',
|
label: '',
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ var clayConfig = new ClayConfig(settings, config, $mainForm, clayMeta);
|
|||||||
$mainForm.on('submit', function() {
|
$mainForm.on('submit', function() {
|
||||||
// Set the return URL depending on the runtime environment
|
// Set the return URL depending on the runtime environment
|
||||||
location.href = returnTo +
|
location.href = returnTo +
|
||||||
encodeURIComponent(JSON.stringify(clayConfig.getSettings()));
|
encodeURIComponent(JSON.stringify(clayConfig.serialize()));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Run the custom function in the context of the ClayConfig
|
// Run the custom function in the context of the ClayConfig
|
||||||
|
|||||||
+112
-40
@@ -5,12 +5,13 @@
|
|||||||
* @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} [messageKey]
|
||||||
* @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]
|
||||||
|
* @property {Array} [capabilities]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var HTML = require('../vendor/minified').HTML;
|
var HTML = require('../vendor/minified').HTML;
|
||||||
@@ -33,10 +34,22 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var _settings = _.copyObj(settings);
|
var _settings = _.copyObj(settings);
|
||||||
var _items = [];
|
var _items;
|
||||||
var _itemsById = {};
|
var _itemsById;
|
||||||
var _itemsByAppKey = {};
|
var _itemsByMessageKey;
|
||||||
var _isBuilt = false;
|
var _isBuilt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the item arrays and objects
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function _initializeItems() {
|
||||||
|
_items = [];
|
||||||
|
_itemsById = {};
|
||||||
|
_itemsByMessageKey = {};
|
||||||
|
_isBuilt = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add item(s) to the config
|
* Add item(s) to the config
|
||||||
@@ -49,34 +62,36 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
item.forEach(function(item) {
|
item.forEach(function(item) {
|
||||||
_addItems(item, $container);
|
_addItems(item, $container);
|
||||||
});
|
});
|
||||||
} else if (item.type === 'section') {
|
} else if (utils.includesCapability(meta.activeWatchInfo, item.capabilities)) {
|
||||||
var $wrapper = HTML('<div class="section">');
|
if (item.type === 'section') {
|
||||||
$container.add($wrapper);
|
var $wrapper = HTML('<div class="section">');
|
||||||
_addItems(item.items, $wrapper);
|
$container.add($wrapper);
|
||||||
} else {
|
_addItems(item.items, $wrapper);
|
||||||
var _item = _.copyObj(item);
|
} else {
|
||||||
_item.clayId = _items.length;
|
var _item = _.copyObj(item);
|
||||||
|
_item.clayId = _items.length;
|
||||||
|
|
||||||
var clayItem = new ClayItem(_item).initialize(self);
|
var clayItem = new ClayItem(_item).initialize(self);
|
||||||
|
|
||||||
if (_item.id) {
|
if (_item.id) {
|
||||||
_itemsById[_item.id] = clayItem;
|
_itemsById[_item.id] = clayItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_item.messageKey) {
|
||||||
|
_itemsByMessageKey[_item.messageKey] = clayItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
_items.push(clayItem);
|
||||||
|
|
||||||
|
// set the value of the item via the manipulator to ensure consistency
|
||||||
|
var value = typeof _settings[_item.messageKey] !== 'undefined' ?
|
||||||
|
_settings[_item.messageKey] :
|
||||||
|
_item.defaultValue;
|
||||||
|
|
||||||
|
clayItem.set(typeof value !== 'undefined' ? value : '');
|
||||||
|
|
||||||
|
$container.add(clayItem.$element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_item.appKey) {
|
|
||||||
_itemsByAppKey[_item.appKey] = clayItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
_items.push(clayItem);
|
|
||||||
|
|
||||||
// set the value of the item via the manipulator to ensure consistency
|
|
||||||
var value = typeof _settings[_item.appKey] !== 'undefined' ?
|
|
||||||
_settings[_item.appKey] :
|
|
||||||
(_item.defaultValue || '');
|
|
||||||
|
|
||||||
clayItem.set(value);
|
|
||||||
|
|
||||||
$container.add(clayItem.$element);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +112,7 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.meta = meta;
|
self.meta = meta;
|
||||||
|
self.$rootContainer = $rootContainer;
|
||||||
|
|
||||||
self.EVENTS = {
|
self.EVENTS = {
|
||||||
/**
|
/**
|
||||||
@@ -111,7 +127,21 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
* value set
|
* value set
|
||||||
* @const
|
* @const
|
||||||
*/
|
*/
|
||||||
AFTER_BUILD: 'AFTER_BUILD'
|
AFTER_BUILD: 'AFTER_BUILD',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called if .build() is executed after the page has already been built and
|
||||||
|
* before the existing content is destroyed
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
BEFORE_DESTROY: 'BEFORE_DESTROY',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called if .build() is executed after the page has already been built and after
|
||||||
|
* the existing content is destroyed
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
AFTER_DESTROY: 'AFTER_DESTROY'
|
||||||
};
|
};
|
||||||
utils.updateProperties(self.EVENTS, {writable: false});
|
utils.updateProperties(self.EVENTS, {writable: false});
|
||||||
|
|
||||||
@@ -124,12 +154,12 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} appKey
|
* @param {string} messageKey
|
||||||
* @returns {ClayItem}
|
* @returns {ClayItem}
|
||||||
*/
|
*/
|
||||||
self.getItemByAppKey = function(appKey) {
|
self.getItemByMessageKey = function(messageKey) {
|
||||||
_checkBuilt('getItemByAppKey');
|
_checkBuilt('getItemByMessageKey');
|
||||||
return _itemsByAppKey[appKey];
|
return _itemsByMessageKey[messageKey];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,13 +182,33 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} group
|
||||||
|
* @returns {Array.<ClayItem>}
|
||||||
|
*/
|
||||||
|
self.getItemsByGroup = function(group) {
|
||||||
|
_checkBuilt('getItemsByGroup');
|
||||||
|
return _items.filter(function(item) {
|
||||||
|
return item.config.group === group;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
self.getSettings = function() {
|
self.serialize = function() {
|
||||||
_checkBuilt('getSettings');
|
_checkBuilt('serialize');
|
||||||
_.eachObj(_itemsByAppKey, function(appKey, item) {
|
|
||||||
_settings[appKey] = utils.prepareForAppMessage(item.get());
|
_settings = {};
|
||||||
|
|
||||||
|
_.eachObj(_itemsByMessageKey, function(messageKey, item) {
|
||||||
|
_settings[messageKey] = {
|
||||||
|
value: item.get()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.precision) {
|
||||||
|
_settings[messageKey].precision = item.precision;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return _settings;
|
return _settings;
|
||||||
};
|
};
|
||||||
@@ -166,18 +216,40 @@ function ClayConfig(settings, config, $rootContainer, meta) {
|
|||||||
// @todo maybe don't do this and force the static method
|
// @todo maybe don't do this and force the static method
|
||||||
self.registerComponent = ClayConfig.registerComponent;
|
self.registerComponent = ClayConfig.registerComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empties the root container
|
||||||
|
* @returns {ClayConfig}
|
||||||
|
*/
|
||||||
|
self.destroy = function() {
|
||||||
|
var el = $rootContainer[0];
|
||||||
|
self.trigger(self.EVENTS.BEFORE_DESTROY);
|
||||||
|
while (el.firstChild) {
|
||||||
|
el.removeChild(el.firstChild);
|
||||||
|
}
|
||||||
|
_initializeItems();
|
||||||
|
self.trigger(self.EVENTS.AFTER_DESTROY);
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the config page. This must be run before any of the get methods can be run
|
* Build the config page. This must be run before any of the get methods can be run
|
||||||
|
* If you call this method after the page has already been built, teh page will be
|
||||||
|
* destroyed and built again.
|
||||||
* @returns {ClayConfig}
|
* @returns {ClayConfig}
|
||||||
*/
|
*/
|
||||||
self.build = function() {
|
self.build = function() {
|
||||||
|
if (_isBuilt) {
|
||||||
|
self.destroy();
|
||||||
|
}
|
||||||
self.trigger(self.EVENTS.BEFORE_BUILD);
|
self.trigger(self.EVENTS.BEFORE_BUILD);
|
||||||
_addItems(config, $rootContainer);
|
_addItems(self.config, $rootContainer);
|
||||||
_isBuilt = true;
|
_isBuilt = true;
|
||||||
self.trigger(self.EVENTS.AFTER_BUILD);
|
self.trigger(self.EVENTS.AFTER_BUILD);
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_initializeItems();
|
||||||
|
|
||||||
// attach event methods
|
// attach event methods
|
||||||
ClayEvents.call(self, $rootContainer);
|
ClayEvents.call(self, $rootContainer);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function ClayItem(config) {
|
|||||||
self.id = config.id || null;
|
self.id = config.id || null;
|
||||||
|
|
||||||
/** @type {string|null} */
|
/** @type {string|null} */
|
||||||
self.appKey = config.appKey || null;
|
self.messageKey = config.messageKey || null;
|
||||||
|
|
||||||
/** @type {Object} */
|
/** @type {Object} */
|
||||||
self.config = config;
|
self.config = config;
|
||||||
@@ -59,7 +59,7 @@ function ClayItem(config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// attach event methods
|
// attach event methods
|
||||||
ClayEvents.call(self, self.$element);
|
ClayEvents.call(self, self.$manipulatorTarget);
|
||||||
|
|
||||||
// attach the manipulator methods to the clayItem
|
// attach the manipulator methods to the clayItem
|
||||||
_.eachObj(_component.manipulator, function(methodName, method) {
|
_.eachObj(_component.manipulator, function(methodName, method) {
|
||||||
|
|||||||
@@ -73,10 +73,19 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
val: {
|
val: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.$manipulatorTarget.get('value');
|
let value = this.$manipulatorTarget.get('value');
|
||||||
|
switch (this.config.serializeValueAs) {
|
||||||
|
case 'integer':
|
||||||
|
let integerValue = Math.trunc(Number.parseInt(value, 10));
|
||||||
|
return Number.isNaN(integerValue) ? 0 : integerValue;
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
set: function(value) {
|
set: function(value) {
|
||||||
if (this.get() === value.toString(10)) { return this; }
|
let currentValue = this.$manipulatorTarget.get('value');
|
||||||
|
if (typeof currentValue !== 'undefined' &&
|
||||||
|
currentValue === value.toString(10)) { return this; }
|
||||||
this.$manipulatorTarget.set('value', value);
|
this.$manipulatorTarget.set('value', value);
|
||||||
return this.trigger('change');
|
return this.trigger('change');
|
||||||
},
|
},
|
||||||
@@ -85,6 +94,21 @@ module.exports = {
|
|||||||
hide: hide,
|
hide: hide,
|
||||||
show: show
|
show: show
|
||||||
},
|
},
|
||||||
|
slider: {
|
||||||
|
get: function() {
|
||||||
|
return parseFloat(this.$manipulatorTarget.get('value'));
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
var initVal = this.get();
|
||||||
|
this.$manipulatorTarget.set('value', value);
|
||||||
|
if (this.get() === initVal) { return this; }
|
||||||
|
return this.trigger('change');
|
||||||
|
},
|
||||||
|
disable: disable,
|
||||||
|
enable: enable,
|
||||||
|
hide: hide,
|
||||||
|
show: show
|
||||||
|
},
|
||||||
checked: {
|
checked: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.$manipulatorTarget.get('checked');
|
return this.$manipulatorTarget.get('checked');
|
||||||
@@ -101,12 +125,21 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
radiogroup: {
|
radiogroup: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.$element.select('input:checked').get('value');
|
let value = this.$element.select('input:checked').get('value');
|
||||||
|
switch (this.config.serializeValueAs) {
|
||||||
|
case 'integer':
|
||||||
|
let integerValue = Math.trunc(Number.parseInt(value, 10));
|
||||||
|
return Number.isNaN(integerValue) ? 0 : integerValue;
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
set: function(value) {
|
set: function(value) {
|
||||||
if (this.get() === value.toString(10)) { return this; }
|
let currentValue = this.$element.select('input:checked').get('value');
|
||||||
|
if (typeof currentValue !== 'undefined' &&
|
||||||
|
currentValue === value.toString(10)) { return this; }
|
||||||
this.$element
|
this.$element
|
||||||
.select('input[value="' + value.replace('"', '\\"') + '"]')
|
.select('input[value="' + value.toString(10).replace('"', '\\"') + '"]')
|
||||||
.set('checked', true);
|
.set('checked', true);
|
||||||
return this.trigger('change');
|
return this.trigger('change');
|
||||||
},
|
},
|
||||||
@@ -118,24 +151,27 @@ module.exports = {
|
|||||||
checkboxgroup: {
|
checkboxgroup: {
|
||||||
get: function() {
|
get: function() {
|
||||||
var result = [];
|
var result = [];
|
||||||
this.$element.select('input:checked').each(function(item) {
|
this.$element.select('input').each(function(item) {
|
||||||
result.push(item.value);
|
result.push(!!item.checked);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
set: function(values) {
|
set: function(values) {
|
||||||
var self = this;
|
var self = this;
|
||||||
values = values || [];
|
values = Array.isArray(values) ? values : [];
|
||||||
|
|
||||||
|
while (values.length < this.get().length) {
|
||||||
|
values.push(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (_.equals(this.get(), values)) { return this; }
|
if (_.equals(this.get(), values)) { return this; }
|
||||||
|
|
||||||
self.$element.select('input').set('checked', false);
|
self.$element.select('input')
|
||||||
|
.set('checked', false)
|
||||||
|
.each(function(item, index) {
|
||||||
|
item.checked = !!values[index];
|
||||||
|
});
|
||||||
|
|
||||||
values.map(function(value) {
|
|
||||||
self.$element
|
|
||||||
.select('input[value="' + value.replace('"', '\\"') + '"]')
|
|
||||||
.set('checked', true);
|
|
||||||
});
|
|
||||||
return self.trigger('change');
|
return self.trigger('change');
|
||||||
},
|
},
|
||||||
disable: disable,
|
disable: disable,
|
||||||
@@ -145,16 +181,12 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return parseInt(this.$manipulatorTarget.get('value'), 16);
|
return parseInt(this.$manipulatorTarget.get('value'), 10) || 0;
|
||||||
},
|
},
|
||||||
set: function(value) {
|
set: function(value) {
|
||||||
switch (typeof value) {
|
value = this.roundColorToLayout(value || 0);
|
||||||
case 'number': value = value.toString(16); break;
|
|
||||||
case 'string': value = value.replace(/^#|^0x/, ''); break;
|
|
||||||
}
|
|
||||||
value = value || '000000';
|
|
||||||
|
|
||||||
if (this.get() === parseInt(value, 16)) { return this; }
|
if (this.get() === value) { return this; }
|
||||||
this.$manipulatorTarget.set('value', value);
|
this.$manipulatorTarget.set('value', value);
|
||||||
return this.trigger('change');
|
return this.trigger('change');
|
||||||
},
|
},
|
||||||
|
|||||||
+146
-31
@@ -18,38 +18,153 @@ module.exports.updateProperties = function(obj, descriptor) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
module.exports.capabilityMap = {
|
||||||
* Converts the val into a type compatible with Pebble.sendAppMessage().
|
PLATFORM_APLITE: {
|
||||||
* - Strings will be returned without modification
|
platforms: ['aplite'],
|
||||||
* - Numbers will be returned without modification
|
minFwMajor: 0,
|
||||||
* - Booleans will be converted to a 0 or 1
|
minFwMinor: 0
|
||||||
* - Arrays that contain strings will be split with a zero.
|
},
|
||||||
* eg: ['one', 'two'] becomes ['one', 0, 'two', 0]
|
PLATFORM_BASALT: {
|
||||||
* - Arrays that contain numbers will be returned without modification
|
platforms: ['basalt'],
|
||||||
* eg: [1, 2] becomes [1, 2]
|
minFwMajor: 0,
|
||||||
* - Arrays that contain booleans will be converted to a 0 or 1
|
minFwMinor: 0
|
||||||
* eg: [true, false] becomes [1, 0]
|
},
|
||||||
* - Arrays must be single dimensional
|
PLATFORM_CHALK: {
|
||||||
* @param {number|string|boolean|Array} val
|
platforms: ['chalk'],
|
||||||
* @returns {number|string|Array}
|
minFwMajor: 0,
|
||||||
*/
|
minFwMinor: 0
|
||||||
module.exports.prepareForAppMessage = function(val) {
|
},
|
||||||
var result;
|
PLATFORM_DIORITE: {
|
||||||
|
platforms: ['diorite'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
PLATFORM_EMERY: {
|
||||||
|
platforms: ['emery'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
PLATFORM_FLINT: {
|
||||||
|
platforms: ['flint'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
PLATFORM_GABBRO: {
|
||||||
|
platforms: ['gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
BW: {
|
||||||
|
platforms: ['aplite', 'diorite', 'flint'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
COLOR: {
|
||||||
|
platforms: ['basalt', 'chalk', 'emery', 'gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
COMPASS: {
|
||||||
|
platforms: ['aplite', 'basalt', 'chalk', 'emery', 'flint', 'gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
MICROPHONE: {
|
||||||
|
platforms: ['basalt', 'chalk', 'diorite', 'emery', 'flint', 'gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
RGB_BACKLIGHT: {
|
||||||
|
platforms: ['emery'],
|
||||||
|
minFwMajor: 4,
|
||||||
|
minFwMinor: 9
|
||||||
|
},
|
||||||
|
SMARTSTRAP: {
|
||||||
|
platforms: ['basalt', 'chalk', 'diorite', 'emery'],
|
||||||
|
minFwMajor: 3,
|
||||||
|
minFwMinor: 4
|
||||||
|
},
|
||||||
|
SMARTSTRAP_POWER: {
|
||||||
|
platforms: ['basalt', 'chalk', 'emery'],
|
||||||
|
minFwMajor: 3,
|
||||||
|
minFwMinor: 4
|
||||||
|
},
|
||||||
|
SPEAKER: {
|
||||||
|
platforms: ['emery', 'flint'],
|
||||||
|
minFwMajor: 4,
|
||||||
|
minFwMinor: 9
|
||||||
|
},
|
||||||
|
TOUCH: {
|
||||||
|
platforms: ['emery', 'gabbro'],
|
||||||
|
minFwMajor: 4,
|
||||||
|
minFwMinor: 9
|
||||||
|
},
|
||||||
|
HEALTH: {
|
||||||
|
platforms: ['basalt', 'chalk', 'diorite', 'emery', 'flint', 'gabbro'],
|
||||||
|
minFwMajor: 3,
|
||||||
|
minFwMinor: 10
|
||||||
|
},
|
||||||
|
RECT: {
|
||||||
|
platforms: ['aplite', 'basalt', 'diorite', 'emery', 'flint'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
ROUND: {
|
||||||
|
platforms: ['chalk', 'gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
DISPLAY_144x168: {
|
||||||
|
platforms: ['aplite', 'basalt', 'diorite', 'flint'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
DISPLAY_180x180_ROUND: {
|
||||||
|
platforms: ['chalk'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
DISPLAY_200x228: {
|
||||||
|
platforms: ['emery'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
},
|
||||||
|
DISPLAY_260x260_ROUND: {
|
||||||
|
platforms: ['gabbro'],
|
||||||
|
minFwMajor: 0,
|
||||||
|
minFwMinor: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof val === 'boolean') {
|
/**
|
||||||
result = val ? 1 : 0;
|
* Checks if all of the provided capabilities are compatible with the watch
|
||||||
} else if (Array.isArray(val)) {
|
* @param {Object} activeWatchInfo
|
||||||
result = [];
|
* @param {Array<string>} [capabilities]
|
||||||
val.forEach(function(item) {
|
* @return {boolean}
|
||||||
var itemConverted = module.exports.prepareForAppMessage(item);
|
*/
|
||||||
result.push(itemConverted);
|
module.exports.includesCapability = function(activeWatchInfo, capabilities) {
|
||||||
if (typeof itemConverted === 'string') {
|
var notRegex = /^NOT_/;
|
||||||
result.push(0);
|
var result = [];
|
||||||
}
|
|
||||||
});
|
if (!capabilities || !capabilities.length) {
|
||||||
} else {
|
return true;
|
||||||
result = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
for (var i = capabilities.length - 1; i >= 0; i--) {
|
||||||
|
var capability = capabilities[i];
|
||||||
|
var mapping = module.exports.capabilityMap[capability.replace(notRegex, '')];
|
||||||
|
|
||||||
|
if (!mapping ||
|
||||||
|
mapping.platforms.indexOf(activeWatchInfo.platform) === -1 ||
|
||||||
|
mapping.minFwMajor > activeWatchInfo.firmware.major ||
|
||||||
|
mapping.minFwMajor === activeWatchInfo.firmware.major &&
|
||||||
|
mapping.minFwMinor > activeWatchInfo.firmware.minor
|
||||||
|
) {
|
||||||
|
result.push(!!capability.match(notRegex));
|
||||||
|
} else {
|
||||||
|
result.push(!capability.match(notRegex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.indexOf(false) === -1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,6 +67,12 @@ h6 {
|
|||||||
@include font-size(0.8);
|
@include font-size(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -107,6 +113,7 @@ label {
|
|||||||
|
|
||||||
.tap-highlight {
|
.tap-highlight {
|
||||||
@include tap-highlight();
|
@include tap-highlight();
|
||||||
|
border-radius: $border-radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component {
|
.component {
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ $item-spacing-v: $base-height / 2;
|
|||||||
$item-spacing-h: 0.75rem;
|
$item-spacing-h: 0.75rem;
|
||||||
$small-component-width: $base-height * $golden;
|
$small-component-width: $base-height * $golden;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ---- Colors ------
|
// ---- Colors ------
|
||||||
$color-orange: #ff4700;
|
$color-orange: #ff4700;
|
||||||
$color-orange-dark: #993d19;
|
$color-orange-dark: #993d19;
|
||||||
@@ -37,4 +35,5 @@ $color-gray-11: #f2f2f2;
|
|||||||
$button-padding: 0.6rem;
|
$button-padding: 0.6rem;
|
||||||
$button-padding-ios: 0.5rem;
|
$button-padding-ios: 0.5rem;
|
||||||
|
|
||||||
$box-shadow-small-components: $color-gray-1 0 0.1rem 0.1rem;
|
$box-shadow-small-components: 0 0.1rem 0.1rem $color-gray-1;
|
||||||
|
$box-shadow-large-components: 0 rem(3px) rem(15px) rgba(0,0,0,0.4);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
border-radius: $base-height / 2;
|
border-radius: $base-height / 2;
|
||||||
box-shadow: $box-shadow-small-components;
|
box-shadow: $box-shadow-small-components;
|
||||||
display: block;
|
display: block;
|
||||||
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.picker-wrap {
|
.picker-wrap {
|
||||||
@@ -20,17 +21,25 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding: 1rem;
|
padding: $item-spacing-v $item-spacing-h /2;
|
||||||
background: rgba(0,0,0,0.7);
|
background: rgba(0, 0, 0, 0.65);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 70ms ease-in 175ms;
|
transition: opacity 100ms ease-in 175ms;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.picker {
|
.picker {
|
||||||
padding: 1rem;
|
padding: $item-spacing-v $item-spacing-h;
|
||||||
background: $color-gray-11;
|
background: $color-gray-4;
|
||||||
|
box-shadow: $box-shadow-large-components;
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 26rem;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.show {
|
&.show {
|
||||||
@@ -46,7 +55,6 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 0 100% 0; // overridden with inline style
|
padding: 0 0 100% 0; // overridden with inline style
|
||||||
margin: 0.6em 0 0;
|
|
||||||
|
|
||||||
.color-box-container {
|
.color-box-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -77,7 +85,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
transform: scale(1.15);
|
transform: scale(1.1);
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
box-shadow: #111 0 0 0.24rem;
|
box-shadow: #111 0 0 0.24rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
|
appearance: none;
|
||||||
|
min-height: $item-spacing-v + ($base-height + 0rem) ;
|
||||||
|
|
||||||
@include placeholder {
|
@include placeholder {
|
||||||
color: $color-gray-8;
|
color: $color-gray-8;
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: #000;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
margin:0;
|
margin:0;
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
@import "clay";
|
||||||
|
|
||||||
|
.component-slider {
|
||||||
|
|
||||||
|
.section & {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: $item-spacing-v;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 1rem;
|
||||||
|
display: block;
|
||||||
|
padding-right: $item-spacing-h;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-wrap {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value,
|
||||||
|
.value-pad {
|
||||||
|
display: block;
|
||||||
|
background: $color-gray-2;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
padding: $item-spacing-v / 2 $item-spacing-h / 2;
|
||||||
|
border: none;
|
||||||
|
vertical-align: baseline;
|
||||||
|
color: $color-white;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0;
|
||||||
|
min-width: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-pad {
|
||||||
|
visibility: hidden;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: ' ';
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
max-width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left:0;
|
||||||
|
top:0
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrap {
|
||||||
|
padding: 0 $item-spacing-h $item-spacing-v;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
$track-height: rem(3px);
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
min-width: 100%;
|
||||||
|
height: $base-height;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-left: 0;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
height: $track-height;
|
||||||
|
background: $color-gray-6;
|
||||||
|
width: 100%;
|
||||||
|
top: $base-height / 2 - $track-height / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
height: $base-height;
|
||||||
|
margin: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-slider-runnable-track {
|
||||||
|
border: none;
|
||||||
|
height: $base-height;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
height: $base-height;
|
||||||
|
width: $base-height;
|
||||||
|
background-color: $color-orange;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -1000px;
|
||||||
|
top: $base-height / 2 - $track-height / 2;
|
||||||
|
height: $track-height;
|
||||||
|
width: 1001px;
|
||||||
|
background: $color-orange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,14 +3,8 @@
|
|||||||
<div class="checkbox-group">
|
<div class="checkbox-group">
|
||||||
{{each options}}
|
{{each options}}
|
||||||
<label class="tap-highlight">
|
<label class="tap-highlight">
|
||||||
<span class="label">{{{this.label}}}</span>
|
<span class="label">{{{this}}}</span>
|
||||||
<input
|
<input type="checkbox" value="1" name="clay-{{clayId}}" />
|
||||||
type="checkbox"
|
|
||||||
value="{{this.value}}"
|
|
||||||
name="clay-{{clayId}}"
|
|
||||||
data-manipulator-target
|
|
||||||
{{each key: attributes}}{{key}}="{{this}}"{{/each}}
|
|
||||||
/>
|
|
||||||
<i></i>
|
<i></i>
|
||||||
</label>
|
</label>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
value="{{this.value}}"
|
value="{{this.value}}"
|
||||||
name="clay-{{clayId}}"
|
name="clay-{{clayId}}"
|
||||||
data-manipulator-target
|
|
||||||
{{each key: attributes}}{{key}}="{{this}}"{{/each}}
|
{{each key: attributes}}{{key}}="{{this}}"{{/each}}
|
||||||
/>
|
/>
|
||||||
<i></i>
|
<i></i>
|
||||||
|
|||||||
@@ -4,7 +4,15 @@
|
|||||||
<span class="value"></span>
|
<span class="value"></span>
|
||||||
<select data-manipulator-target {{each key: attributes}}{{key}}="{{this}}"{{/each}}>
|
<select data-manipulator-target {{each key: attributes}}{{key}}="{{this}}"{{/each}}>
|
||||||
{{each options}}
|
{{each options}}
|
||||||
<option value="{{this.value}}" class="item-select-option">{{this.label}}</option>
|
{{if Array.isArray(this.value)}}
|
||||||
|
<optgroup label="{{this.label}}">
|
||||||
|
{{each this.value}}
|
||||||
|
<option value="{{this.value}}" class="item-select-option">{{this.label}}</option>
|
||||||
|
{{/each}}
|
||||||
|
</optgroup>
|
||||||
|
{{else}}
|
||||||
|
<option value="{{this.value}}" class="item-select-option">{{this.label}}</option>
|
||||||
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<div class="component component-slider">
|
||||||
|
<label class="tap-highlight">
|
||||||
|
<span class="label-container">
|
||||||
|
<span class="label">{{{label}}}</span>
|
||||||
|
<span class="value-wrap">
|
||||||
|
<span class="value-pad"></span>
|
||||||
|
<input type="text" class="value" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="input">
|
||||||
|
<input
|
||||||
|
data-manipulator-target
|
||||||
|
class="slider"
|
||||||
|
type="range"
|
||||||
|
min="{{min}}"
|
||||||
|
max="{{max}}"
|
||||||
|
step="{{step}}"
|
||||||
|
{{each key: attributes}}{{key}}="{{this}}"{{/each}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{{if description}}
|
||||||
|
<div class="description">{{{description}}}</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
+72
-7
@@ -11,12 +11,13 @@ var componentRegistry = require('../src/scripts/lib/component-registry');
|
|||||||
var idCounter = 0;
|
var idCounter = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {Object} [extra] - add/replace keys in the meta
|
||||||
* @returns {{accountToken: string, watchToken: string, activeWatchInfo: {platform:
|
* @returns {{accountToken: string, watchToken: string, activeWatchInfo: {platform:
|
||||||
* string, model: string, language: string, firmware: {major: number, minor:
|
* string, model: string, language: string, firmware: {major: number, minor:
|
||||||
* number, patch: number, suffix: string}}}}
|
* number, patch: number, suffix: string}}, userData: {}}}
|
||||||
*/
|
*/
|
||||||
module.exports.meta = function() {
|
module.exports.meta = function(extra) {
|
||||||
return {
|
var result = {
|
||||||
accountToken: '0123456789abcdef0123456789abcdef',
|
accountToken: '0123456789abcdef0123456789abcdef',
|
||||||
watchToken: '0123456789abcdef0123456789abcdef',
|
watchToken: '0123456789abcdef0123456789abcdef',
|
||||||
activeWatchInfo: {
|
activeWatchInfo: {
|
||||||
@@ -29,8 +30,15 @@ module.exports.meta = function() {
|
|||||||
patch: 2,
|
patch: 2,
|
||||||
suffix: ''
|
suffix: ''
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
userData: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_.eachObj(extra || {}, function(key, val) {
|
||||||
|
result[key] = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +53,7 @@ module.exports.configItem = function(config, autoRegister) {
|
|||||||
|
|
||||||
var result = _.extend({}, {
|
var result = _.extend({}, {
|
||||||
label: config.type + '-label',
|
label: config.type + '-label',
|
||||||
appKey: 'appKey-' + idCounter,
|
messageKey: 'messageKey-' + idCounter,
|
||||||
id: 'id-' + idCounter
|
id: 'id-' + idCounter
|
||||||
}, config);
|
}, config);
|
||||||
|
|
||||||
@@ -87,14 +95,15 @@ module.exports.config = function(types, autoRegister) {
|
|||||||
* @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 {Object} [settings] - settings to pass to constructor
|
* @param {Object} [settings] - settings to pass to constructor
|
||||||
|
* @param {Object} [meta] - override the meta
|
||||||
* @returns {ClayConfig}
|
* @returns {ClayConfig}
|
||||||
*/
|
*/
|
||||||
module.exports.clayConfig = function(types, build, autoRegister, settings) {
|
module.exports.clayConfig = function(types, build, autoRegister, settings, meta) {
|
||||||
var clayConfig = new ClayConfig(
|
var clayConfig = new ClayConfig(
|
||||||
settings || {},
|
settings || {},
|
||||||
module.exports.config(types, autoRegister),
|
module.exports.config(types, autoRegister),
|
||||||
$(HTML('<div>')),
|
$(HTML('<div>')),
|
||||||
module.exports.meta()
|
module.exports.meta(meta)
|
||||||
);
|
);
|
||||||
return build === false ? clayConfig : clayConfig.build();
|
return build === false ? clayConfig : clayConfig.build();
|
||||||
};
|
};
|
||||||
@@ -106,6 +115,8 @@ module.exports.clayConfig = function(types, build, autoRegister, settings) {
|
|||||||
* @param {Object} [options] - Additional options to pass to Clay
|
* @param {Object} [options] - Additional options to pass to Clay
|
||||||
* @param {boolean} [options.autoHandleEvents] - If false, Clay will not
|
* @param {boolean} [options.autoHandleEvents] - If false, Clay will not
|
||||||
* automatically handle the 'showConfiguration' and 'webviewclosed' events
|
* automatically handle the 'showConfiguration' and 'webviewclosed' events
|
||||||
|
* @param {*} [options.userData={}] - Arbitrary data to pass to the config page. Will
|
||||||
|
* be available as `clayConfig.meta.userData`
|
||||||
* @param {boolean} [destroyLocalStorage=true]
|
* @param {boolean} [destroyLocalStorage=true]
|
||||||
* @return {Clay}
|
* @return {Clay}
|
||||||
*/
|
*/
|
||||||
@@ -115,3 +126,57 @@ module.exports.clay = function(config, customFn, options, destroyLocalStorage) {
|
|||||||
}
|
}
|
||||||
return new Clay(config, customFn, options);
|
return new Clay(config, customFn, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} keys
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
module.exports.messageKeys = function(keys) {
|
||||||
|
var counter = 10000;
|
||||||
|
var result = {};
|
||||||
|
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
var matches = key.match(/(.+?)(?:\[(\d*)\])?$/);
|
||||||
|
var parsedKey = matches[1];
|
||||||
|
var length = parseInt(matches[2] || 1, 10);
|
||||||
|
|
||||||
|
result[parsedKey] = counter;
|
||||||
|
|
||||||
|
counter += length;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} obj
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
module.exports.messageKeysObjToArray = function(obj) {
|
||||||
|
return Object.keys(obj).map(function(key) {
|
||||||
|
return Array.isArray(obj[key]) ?
|
||||||
|
key + '[' + obj[key].length + ']' :
|
||||||
|
key;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} expected
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
module.exports.messageKeysExpected = function(expected) {
|
||||||
|
var result = {};
|
||||||
|
var messageKeys = module.exports.messageKeysObjToArray(expected);
|
||||||
|
messageKeys = module.exports.messageKeys(messageKeys);
|
||||||
|
|
||||||
|
Object.keys(expected).forEach(function(key) {
|
||||||
|
var expectedVal = Array.isArray(expected[key]) ? expected[key] : [expected[key]];
|
||||||
|
expectedVal.forEach(function(val, index) {
|
||||||
|
if (typeof val !== 'undefined') {
|
||||||
|
result[messageKeys[key] + index] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|||||||
+13
-16
@@ -12,30 +12,22 @@ module.exports = function(config) {
|
|||||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
frameworks: ['browserify', 'source-map-support', 'mocha'],
|
frameworks: ['browserify', 'source-map-support', 'mocha'],
|
||||||
|
|
||||||
|
client: {
|
||||||
|
mocha: {
|
||||||
|
timeout: 10000 // 10 sec because Travis struggles sometimes.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
browserify: {
|
browserify: {
|
||||||
debug: true,
|
debug: true,
|
||||||
transform: [
|
transform: [
|
||||||
[
|
[
|
||||||
'stringify',
|
'stringify',
|
||||||
{
|
{
|
||||||
extensions: ['.html', '.tpl']
|
extensions: ['.html', '.tpl', '.css']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'deamdify',
|
'deamdify',
|
||||||
[
|
|
||||||
'sassify',
|
|
||||||
{
|
|
||||||
base64Encode: false,
|
|
||||||
sourceMap: false,
|
|
||||||
sourceMapEmbed: false,
|
|
||||||
sourceMapContents: false,
|
|
||||||
outputStyle: 'compact',
|
|
||||||
includePaths: [].concat(
|
|
||||||
require('bourbon').includePaths,
|
|
||||||
'src/styles'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'browserify-istanbul',
|
'browserify-istanbul',
|
||||||
{
|
{
|
||||||
@@ -47,7 +39,12 @@ module.exports = function(config) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
configure: function(bundle) {
|
||||||
|
bundle.on('prebundle', function() {
|
||||||
|
bundle.ignore('message_keys');
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// list of files / patterns to load in the browser
|
// list of files / patterns to load in the browser
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"mocha": true
|
"mocha": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"max-params": [0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,48 @@
|
|||||||
var assert = require('chai').assert;
|
var assert = require('chai').assert;
|
||||||
var fixture = require('../../fixture');
|
var fixture = require('../../fixture');
|
||||||
|
|
||||||
|
var sunlightColorMap = {
|
||||||
|
'000000': '000000', '000055': '001e41', '0000aa': '004387', '0000ff': '0068ca',
|
||||||
|
'005500': '2b4a2c', '005555': '27514f', '0055aa': '16638d', '0055ff': '007dce',
|
||||||
|
'00aa00': '5e9860', '00aa55': '5c9b72', '00aaaa': '57a5a2', '00aaff': '4cb4db',
|
||||||
|
'00ff00': '8ee391', '00ff55': '8ee69e', '00ffaa': '8aebc0', '00ffff': '84f5f1',
|
||||||
|
'550000': '4a161b', '550055': '482748', '5500aa': '40488a', '5500ff': '2f6bcc',
|
||||||
|
'555500': '564e36', '555555': '545454', '5555aa': '4f6790', '5555ff': '4180d0',
|
||||||
|
'55aa00': '759a64', '55aa55': '759d76', '55aaaa': '71a6a4', '55aaff': '69b5dd',
|
||||||
|
'55ff00': '9ee594', '55ff55': '9de7a0', '55ffaa': '9becc2', '55ffff': '95f6f2',
|
||||||
|
'aa0000': '99353f', 'aa0055': '983e5a', 'aa00aa': '955694', 'aa00ff': '8f74d2',
|
||||||
|
'aa5500': '9d5b4d', 'aa5555': '9d6064', 'aa55aa': '9a7099', 'aa55ff': '9587d5',
|
||||||
|
'aaaa00': 'afa072', 'aaaa55': 'aea382', 'aaaaaa': 'ababab', 'ffffff': 'ffffff',
|
||||||
|
'aaaaff': 'a7bae2', 'aaff00': 'c9e89d', 'aaff55': 'c9eaa7', 'aaffaa': 'c7f0c8',
|
||||||
|
'aaffff': 'c3f9f7', 'ff0000': 'e35462', 'ff0055': 'e25874', 'ff00aa': 'e16aa3',
|
||||||
|
'ff00ff': 'de83dc', 'ff5500': 'e66e6b', 'ff5555': 'e6727c', 'ff55aa': 'e37fa7',
|
||||||
|
'ff55ff': 'e194df', 'ffaa00': 'f1aa86', 'ffaa55': 'f1ad93', 'ffaaaa': 'efb5b8',
|
||||||
|
'ffaaff': 'ecc3eb', 'ffff00': 'ffeeab', 'ffff55': 'fff1b5', 'ffffaa': 'fff6d3'
|
||||||
|
};
|
||||||
|
|
||||||
|
/* eslint-disable comma-spacing, no-multi-spaces, max-len,
|
||||||
|
standard/array-bracket-even-spacing */
|
||||||
|
var standardLayouts = {
|
||||||
|
COLOR: [
|
||||||
|
[false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ],
|
||||||
|
[false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ],
|
||||||
|
['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'],
|
||||||
|
['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'],
|
||||||
|
[false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ],
|
||||||
|
['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'],
|
||||||
|
['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'],
|
||||||
|
[false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ],
|
||||||
|
[false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ]
|
||||||
|
],
|
||||||
|
GRAY: [
|
||||||
|
['000000', 'aaaaaa', 'ffffff']
|
||||||
|
],
|
||||||
|
BLACK_WHITE: [
|
||||||
|
['000000', 'ffffff']
|
||||||
|
]
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ClayItem} colorItem
|
* @param {ClayItem} colorItem
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
@@ -11,6 +53,182 @@ function openPicker(colorItem) {
|
|||||||
colorItem.$element.select('label')[0].click();
|
colorItem.$element.select('label')[0].click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} hex
|
||||||
|
* @returns {string} - eg: "rgb(1, 2, 3)"
|
||||||
|
*/
|
||||||
|
function hexToRgb(hex) {
|
||||||
|
var result = /^(?:#|0x)?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result ?
|
||||||
|
'rgb(' +
|
||||||
|
parseInt(result[1], 16) + ', ' +
|
||||||
|
parseInt(result[2], 16) + ', ' +
|
||||||
|
parseInt(result[3], 16) + ')' :
|
||||||
|
hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|string} value
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function normalizeColor(value) {
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'number': value = value.toString(16); break;
|
||||||
|
case 'string': value = value.replace(/^#|^0x/, ''); break;
|
||||||
|
}
|
||||||
|
return value || '000000';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array.<Array>} layout
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
function flattenLayout(layout) {
|
||||||
|
return layout.reduce(function(a, b) {
|
||||||
|
return a.concat(b);
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array|string} [layout=color]
|
||||||
|
* @param {Array} [expectedColors]
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function testCustomLayout(layout, expectedColors) {
|
||||||
|
|
||||||
|
describe('layout: ' + JSON.stringify(layout || 'default'), function() {
|
||||||
|
|
||||||
|
describe('Normal', function() {
|
||||||
|
testColors(false, layout, expectedColors);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Sunlight', function() {
|
||||||
|
testColors(true, layout, expectedColors);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} platform
|
||||||
|
* @param {Array} layout
|
||||||
|
* @param {boolean} allowGray
|
||||||
|
* @param {string} desc
|
||||||
|
* @param {Object} activeWatchInfo
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function testAutoLayout(platform, layout, allowGray, desc, activeWatchInfo) {
|
||||||
|
it('chooses the best layout for the ' + (desc || platform) +
|
||||||
|
' platform when allowGray is ' + allowGray,
|
||||||
|
function() {
|
||||||
|
var clayConfig = fixture.clayConfig(
|
||||||
|
[{type: 'color', allowGray: allowGray}],
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
activeWatchInfo: activeWatchInfo
|
||||||
|
}
|
||||||
|
);
|
||||||
|
var colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
assert.deepEqual(colorItem._layout, layout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|string} input
|
||||||
|
* @param {number} expected
|
||||||
|
* @param {array|string} layout
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function testClosestToLayout(input, expected, layout) {
|
||||||
|
it('rounds ' + input + ' to ' + expected.toString(16) +
|
||||||
|
' in layout: ' + JSON.stringify(layout),
|
||||||
|
function() {
|
||||||
|
var clayConfig;
|
||||||
|
var colorItem;
|
||||||
|
|
||||||
|
clayConfig = fixture.clayConfig([{
|
||||||
|
type: 'color',
|
||||||
|
sunlight: false,
|
||||||
|
layout: layout
|
||||||
|
}]);
|
||||||
|
colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
colorItem.set(input);
|
||||||
|
assert.strictEqual(colorItem.get(), expected);
|
||||||
|
|
||||||
|
clayConfig = fixture.clayConfig([{
|
||||||
|
type: 'color',
|
||||||
|
sunlight: false,
|
||||||
|
layout: layout
|
||||||
|
}]);
|
||||||
|
colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
colorItem.set(input);
|
||||||
|
assert.strictEqual(colorItem.get(), expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} sunlight
|
||||||
|
* @param {Array|string} [layout=color]
|
||||||
|
* @param {Array} [expectedColors]
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function testColors(sunlight, layout, expectedColors) {
|
||||||
|
var clayConfig;
|
||||||
|
var colorItem;
|
||||||
|
var $colorBoxes;
|
||||||
|
var colors;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
clayConfig = fixture.clayConfig([
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
layout: layout,
|
||||||
|
sunlight: sunlight
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
|
||||||
|
layout = layout || 'COLOR';
|
||||||
|
if (typeof layout === 'string') {
|
||||||
|
layout = standardLayouts[layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
colors = expectedColors || flattenLayout(layout);
|
||||||
|
$colorBoxes = colorItem.$element.select('.color-box');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Has the correct items in the layout', function() {
|
||||||
|
colors.forEach(function(color, index) {
|
||||||
|
if (color === false) {
|
||||||
|
assert.strictEqual($colorBoxes[index].dataset.value, undefined);
|
||||||
|
} else {
|
||||||
|
assert.strictEqual(
|
||||||
|
parseInt($colorBoxes[index].dataset.value, 10),
|
||||||
|
parseInt(color || 0, 16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the color correctly', function() {
|
||||||
|
colors.forEach(function(color, index) {
|
||||||
|
if (color === false) {
|
||||||
|
assert.strictEqual(
|
||||||
|
$colorBoxes[index].style.backgroundColor,
|
||||||
|
'transparent'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var normalizedColor = normalizeColor(color);
|
||||||
|
assert.strictEqual(
|
||||||
|
$colorBoxes[index].style.backgroundColor,
|
||||||
|
hexToRgb(sunlight ? sunlightColorMap[normalizedColor] : normalizedColor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
describe('component - color', function() {
|
describe('component - color', function() {
|
||||||
it('shows the sunlit colors in the value display', function() {
|
it('shows the sunlit colors in the value display', function() {
|
||||||
var clayConfig = fixture.clayConfig([
|
var clayConfig = fixture.clayConfig([
|
||||||
@@ -105,4 +323,224 @@ describe('component - color', function() {
|
|||||||
$picker[0].click();
|
$picker[0].click();
|
||||||
assert.strictEqual($picker.get('classList').contains('show'), false);
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('color rounding', function() {
|
||||||
|
var layout = 'GRAY';
|
||||||
|
testClosestToLayout('000000', 0x000000, layout);
|
||||||
|
testClosestToLayout('005500', 0x000000, layout);
|
||||||
|
testClosestToLayout('55aa55', 0xaaaaaa, layout);
|
||||||
|
testClosestToLayout('ffaaff', 0xaaaaaa, layout);
|
||||||
|
testClosestToLayout('ffffaa', 0xffffff, layout);
|
||||||
|
testClosestToLayout('ffffff', 0xffffff, layout);
|
||||||
|
|
||||||
|
layout = 'BLACK_WHITE';
|
||||||
|
testClosestToLayout('000000', 0x000000, layout);
|
||||||
|
testClosestToLayout('005500', 0x000000, layout);
|
||||||
|
testClosestToLayout('55aa55', 0xffffff, layout);
|
||||||
|
testClosestToLayout('ffaaff', 0xffffff, layout);
|
||||||
|
testClosestToLayout('ffffaa', 0xffffff, layout);
|
||||||
|
testClosestToLayout('ffffff', 0xffffff, layout);
|
||||||
|
|
||||||
|
layout = 'COLOR';
|
||||||
|
testClosestToLayout('000000', 0x000000, layout);
|
||||||
|
testClosestToLayout('005500', 0x005500, layout);
|
||||||
|
testClosestToLayout('55bb55', 0x55aa55, layout);
|
||||||
|
testClosestToLayout('ff99ff', 0xffaaff, layout);
|
||||||
|
testClosestToLayout('ffffee', 0xffffff, layout);
|
||||||
|
testClosestToLayout('ffffff', 0xffffff, layout);
|
||||||
|
|
||||||
|
layout = ['ff0000', 'ff5500', 'ff00ff', '00ff00', '555555'];
|
||||||
|
testClosestToLayout('000000', 0x555555, layout);
|
||||||
|
testClosestToLayout('ff0000', 0xff0000, layout);
|
||||||
|
testClosestToLayout('ff1111', 0xff0000, layout);
|
||||||
|
testClosestToLayout('00aa00', 0x00ff00, layout);
|
||||||
|
testClosestToLayout('ff55ff', 0xff00ff, layout);
|
||||||
|
testClosestToLayout('aaaaaa', 0x555555, layout);
|
||||||
|
testClosestToLayout('ffffff', 0x555555, layout);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('layouts', function() {
|
||||||
|
|
||||||
|
// allow gray does nothing for 2.x
|
||||||
|
testAutoLayout('aplite', standardLayouts.BLACK_WHITE, true, 'aplite (2.x)',
|
||||||
|
null
|
||||||
|
);
|
||||||
|
testAutoLayout('aplite', standardLayouts.BLACK_WHITE, true, 'aplite (2.x)', {
|
||||||
|
platform: 'aplite',
|
||||||
|
model: 'qemu_platform_aplite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 2,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (2.x)',
|
||||||
|
null
|
||||||
|
);
|
||||||
|
testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (2.x)', {
|
||||||
|
platform: 'aplite',
|
||||||
|
model: 'qemu_platform_aplite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 2,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (3.x)', {
|
||||||
|
platform: 'aplite',
|
||||||
|
model: 'qemu_platform_aplite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 3,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('aplite', standardLayouts.GRAY, true, 'aplite (3.x)', {
|
||||||
|
platform: 'aplite',
|
||||||
|
model: 'qemu_platform_aplite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 3,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('basalt', standardLayouts.COLOR, true, '', {
|
||||||
|
platform: 'basalt',
|
||||||
|
model: 'qemu_platform_basalt',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 3,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('chalk', standardLayouts.COLOR, true, '', {
|
||||||
|
platform: 'chalk',
|
||||||
|
model: 'qemu_platform_chalk',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 3,
|
||||||
|
minor: 10,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('diorite', standardLayouts.BLACK_WHITE, false, '', {
|
||||||
|
platform: 'diorite',
|
||||||
|
model: 'qemu_platform_diorite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('diorite', standardLayouts.GRAY, true, '', {
|
||||||
|
platform: 'diorite',
|
||||||
|
model: 'qemu_platform_diorite',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('emery', standardLayouts.COLOR, true, '', {
|
||||||
|
platform: 'emery',
|
||||||
|
model: 'qemu_platform_emery',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('flint', standardLayouts.BLACK_WHITE, false, '', {
|
||||||
|
platform: 'flint',
|
||||||
|
model: 'qemu_platform_flint',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('flint', standardLayouts.GRAY, true, '', {
|
||||||
|
platform: 'flint',
|
||||||
|
model: 'qemu_platform_flint',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testAutoLayout('gabbro', standardLayouts.COLOR, true, '', {
|
||||||
|
platform: 'gabbro',
|
||||||
|
model: 'qemu_platform_gabbro',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: 4,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testCustomLayout();
|
||||||
|
testCustomLayout('COLOR');
|
||||||
|
testCustomLayout('GRAY');
|
||||||
|
testCustomLayout('BLACK_WHITE');
|
||||||
|
testCustomLayout(['aaffaa', '55ff55', '00ff00']);
|
||||||
|
testCustomLayout([false, '55ff55', '00ff00']);
|
||||||
|
testCustomLayout([['aaffaa', '55ff55', '00ff00']]);
|
||||||
|
testCustomLayout(
|
||||||
|
[['AAFFAA', '#55ff55', '0x00ff00', 0xff5500, null]],
|
||||||
|
['aaffaa', '55ff55', '00ff00', 'ff5500', false]
|
||||||
|
);
|
||||||
|
testCustomLayout([
|
||||||
|
['aaffaa', '55ff55', '00ff00'],
|
||||||
|
['005555', 'ffffff', '000000']]
|
||||||
|
);
|
||||||
|
testCustomLayout([
|
||||||
|
['aaffaa', '55ff55', '00ff00'],
|
||||||
|
[false, 'ffffff', false]]
|
||||||
|
);
|
||||||
|
testCustomLayout(
|
||||||
|
[
|
||||||
|
['aaffaa', '55ff55', '00ff00'],
|
||||||
|
[false, 'ffffff']
|
||||||
|
],
|
||||||
|
['aaffaa', '55ff55', '00ff00', false, 'ffffff', false]
|
||||||
|
);
|
||||||
|
testCustomLayout(
|
||||||
|
[
|
||||||
|
['aaffaa', '55ff55', false],
|
||||||
|
[false, 'ffffff']
|
||||||
|
],
|
||||||
|
['aaffaa', '55ff55', false, false, 'ffffff', false]
|
||||||
|
);
|
||||||
|
testCustomLayout(
|
||||||
|
[
|
||||||
|
['aaffaa', '55ff55'],
|
||||||
|
[false, 'ffffff', '000000']
|
||||||
|
],
|
||||||
|
['aaffaa', '55ff55', false, false, 'ffffff', '000000']
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ var HTML = require('../../../src/scripts/vendor/minified').HTML;
|
|||||||
var components = require('../../../src/scripts/components');
|
var components = require('../../../src/scripts/components');
|
||||||
var manipulators = require('../../../src/scripts/lib/manipulators');
|
var manipulators = require('../../../src/scripts/lib/manipulators');
|
||||||
var fixture = require('../../fixture');
|
var fixture = require('../../fixture');
|
||||||
|
var sinon = require('sinon');
|
||||||
|
|
||||||
var componentSchema = Joi.object().keys({
|
var componentSchema = Joi.object().keys({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
@@ -39,6 +40,20 @@ describe('components', function() {
|
|||||||
it('is able to be passed to ClayConfig', function() {
|
it('is able to be passed to ClayConfig', function() {
|
||||||
fixture.clayConfig([component.name]);
|
fixture.clayConfig([component.name]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('only has one $manipulatorTarget', function() {
|
||||||
|
var configItem = fixture.clayConfig([component.name]).getAllItems()[0];
|
||||||
|
assert.strictEqual(configItem.$manipulatorTarget.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only dispatches change events once', function() {
|
||||||
|
var configItem = fixture.clayConfig([component.name]).getAllItems()[0];
|
||||||
|
var handler = sinon.spy();
|
||||||
|
configItem.on('change', handler);
|
||||||
|
configItem.trigger('change');
|
||||||
|
assert.strictEqual(handler.callCount, 1);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,4 +21,26 @@ describe('component - select', function() {
|
|||||||
selectItem.set('value-2');
|
selectItem.set('value-2');
|
||||||
assert.strictEqual($valueDisplay.get('innerHTML'), 'label 2');
|
assert.strictEqual($valueDisplay.get('innerHTML'), 'label 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets the value display to the correct value on change when using optgroups',
|
||||||
|
function() {
|
||||||
|
var clayConfig = fixture.clayConfig([
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
defaultValue: 'value-1',
|
||||||
|
options: [
|
||||||
|
{ label: 'label 1', value: 'value-1' },
|
||||||
|
{ label: 'group', value: [
|
||||||
|
{ label: 'label 2', value: 'value-2' },
|
||||||
|
{ label: 'label 3', value: 'value-3' }
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
var selectItem = clayConfig.getItemsByType('select')[0];
|
||||||
|
var $valueDisplay = selectItem.$element.select('.value');
|
||||||
|
assert.strictEqual($valueDisplay.get('innerHTML'), 'label 1');
|
||||||
|
selectItem.set('value-2');
|
||||||
|
assert.strictEqual($valueDisplay.get('innerHTML'), 'label 2');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('chai').assert;
|
||||||
|
var fixture = require('../../fixture');
|
||||||
|
|
||||||
|
describe('component - slider', function() {
|
||||||
|
it('sets the value display to the correct value on set', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['slider']);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
var $valueDisplay = sliderItem.$element.select('.value');
|
||||||
|
var $valueDisplayPad = sliderItem.$element.select('.value-pad');
|
||||||
|
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '50');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '50');
|
||||||
|
sliderItem.set(75);
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '75');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '75');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the value display to the correct value on slider change', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['slider']);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
var $valueDisplay = sliderItem.$element.select('.value');
|
||||||
|
var $valueDisplayPad = sliderItem.$element.select('.value-pad');
|
||||||
|
var $slider = sliderItem.$element.select('.slider');
|
||||||
|
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '50');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '50');
|
||||||
|
$slider.set('value', 75).trigger('change');
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '75');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '75');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the value-pad to the same value as what the user is typing', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['slider']);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
var $valueDisplay = sliderItem.$element.select('.value');
|
||||||
|
var $valueDisplayPad = sliderItem.$element.select('.value-pad');
|
||||||
|
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '50');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '50');
|
||||||
|
$valueDisplay.set('value', 75).trigger('input');
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '75');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '75');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the slider to the correct value on user input', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['slider']);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
var $valueDisplay = sliderItem.$element.select('.value');
|
||||||
|
var $slider = sliderItem.$element.select('.slider');
|
||||||
|
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '50');
|
||||||
|
assert.strictEqual($slider.get('value'), '50');
|
||||||
|
$valueDisplay.set('value', 75).trigger('change');
|
||||||
|
assert.strictEqual($slider.get('value'), '75');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the precision correctly', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([{
|
||||||
|
type: 'slider',
|
||||||
|
step: 0.25
|
||||||
|
}]);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
|
||||||
|
assert.strictEqual(sliderItem.precision, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('always displays decimal when precision is less than 1', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([{
|
||||||
|
type: 'slider',
|
||||||
|
step: 0.05
|
||||||
|
}]);
|
||||||
|
var sliderItem = clayConfig.getItemsByType('slider')[0];
|
||||||
|
var $valueDisplay = sliderItem.$element.select('.value');
|
||||||
|
var $valueDisplayPad = sliderItem.$element.select('.value-pad');
|
||||||
|
var $slider = sliderItem.$element.select('.slider');
|
||||||
|
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '50.00');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '50.00');
|
||||||
|
assert.strictEqual($slider.get('value'), '50');
|
||||||
|
sliderItem.set(75);
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '75.00');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '75.00');
|
||||||
|
assert.strictEqual($slider.get('value'), '75');
|
||||||
|
sliderItem.set(33.25);
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '33.25');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '33.25');
|
||||||
|
assert.strictEqual($slider.get('value'), '33.25');
|
||||||
|
sliderItem.set(17.1);
|
||||||
|
assert.strictEqual($valueDisplay.get('value'), '17.10');
|
||||||
|
assert.strictEqual($valueDisplayPad.get('innerHTML'), '17.10');
|
||||||
|
assert.strictEqual($slider.get('value'), '17.1');
|
||||||
|
});
|
||||||
|
});
|
||||||
+365
-84
@@ -7,34 +7,40 @@ var standardComponents = require('../../src/scripts/components');
|
|||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var toSource = require('tosource');
|
var toSource = require('tosource');
|
||||||
|
|
||||||
var accountToken = '0123456789abcdef0123456789abcdef';
|
|
||||||
var watchToken = '0123456789abcdef0123456789abcdef';
|
|
||||||
var activeWatchInfo = {
|
|
||||||
platform: 'chalk',
|
|
||||||
model: 'qemu_platform_chalk',
|
|
||||||
language: 'en_US',
|
|
||||||
firmware: {
|
|
||||||
major: 3,
|
|
||||||
minor: 3,
|
|
||||||
patch: 2,
|
|
||||||
suffix: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
function stubPebble() {
|
function stubPebble() {
|
||||||
|
var meta = fixture.meta();
|
||||||
|
|
||||||
global.Pebble = {
|
global.Pebble = {
|
||||||
addEventListener: sinon.stub(),
|
addEventListener: sinon.stub(),
|
||||||
openURL: sinon.stub(),
|
openURL: sinon.stub(),
|
||||||
sendAppMessage: sinon.stub(),
|
sendAppMessage: sinon.stub(),
|
||||||
getActiveWatchInfo: sinon.stub().returns(activeWatchInfo),
|
getActiveWatchInfo: sinon.stub().returns(meta.activeWatchInfo),
|
||||||
getAccountToken: sinon.stub().returns(accountToken),
|
getAccountToken: sinon.stub().returns(meta.accountToken),
|
||||||
getWatchToken: sinon.stub().returns(watchToken)
|
getWatchToken: sinon.stub().returns(meta.watchToken)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} keys
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
function stubMessageKeys(keys) {
|
||||||
|
var messageKeys = require('message_keys');
|
||||||
|
Object.keys(messageKeys).forEach(function(key) {
|
||||||
|
delete messageKeys[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
var newKeys = fixture.messageKeys(keys);
|
||||||
|
Object.keys(newKeys).forEach(function(key) {
|
||||||
|
messageKeys[key] = newKeys[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
return messageKeys;
|
||||||
|
}
|
||||||
|
|
||||||
describe('Clay', function() {
|
describe('Clay', function() {
|
||||||
describe('Clay constructor', function() {
|
describe('Clay constructor', function() {
|
||||||
it('throws if the config is not an array', function() {
|
it('throws if the config is not an array', function() {
|
||||||
@@ -43,6 +49,15 @@ describe('Clay', function() {
|
|||||||
}, /must be an Array/i);
|
}, /must be an Array/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws if the config contains appKeys', function() {
|
||||||
|
assert.throws(function() {
|
||||||
|
fixture.clay([
|
||||||
|
{type: 'input', appKey: 'foo'},
|
||||||
|
{type: 'someCustomComponent', appKey: 'bar'}
|
||||||
|
]);
|
||||||
|
}, /appKeys are no longer supported/i);
|
||||||
|
});
|
||||||
|
|
||||||
it('throws if customFn is not a function', function() {
|
it('throws if customFn is not a function', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
fixture.clay([], {});
|
fixture.clay([], {});
|
||||||
@@ -74,8 +89,6 @@ describe('Clay', function() {
|
|||||||
|
|
||||||
it('handles the "showConfiguration" event if autoHandleEvents is not false',
|
it('handles the "showConfiguration" event if autoHandleEvents is not false',
|
||||||
function() {
|
function() {
|
||||||
this.timeout(10000); // 10 seconds
|
|
||||||
|
|
||||||
stubPebble();
|
stubPebble();
|
||||||
var clay = fixture.clay([]);
|
var clay = fixture.clay([]);
|
||||||
|
|
||||||
@@ -94,12 +107,16 @@ describe('Clay', function() {
|
|||||||
stubPebble();
|
stubPebble();
|
||||||
fixture.clay([]);
|
fixture.clay([]);
|
||||||
var logStub = sinon.stub(console, 'log');
|
var logStub = sinon.stub(console, 'log');
|
||||||
|
var expected = {someSetting: 'value'};
|
||||||
|
|
||||||
|
stubMessageKeys(fixture.messageKeysObjToArray(expected));
|
||||||
Pebble.addEventListener
|
Pebble.addEventListener
|
||||||
.withArgs('webviewclosed')
|
.withArgs('webviewclosed')
|
||||||
.callArgWith(1, { response: '%7B%22appKey%22%3A%22value%22%7D' });
|
.callArgWith(1, {response: encodeURIComponent(JSON.stringify(expected))});
|
||||||
|
|
||||||
|
var expectedAppMessage = fixture.messageKeysExpected(expected);
|
||||||
assert(Pebble.addEventListener.calledWith('webviewclosed'));
|
assert(Pebble.addEventListener.calledWith('webviewclosed'));
|
||||||
assert(Pebble.sendAppMessage.calledWith({ appKey: 'value' }));
|
assert(Pebble.sendAppMessage.calledWith(expectedAppMessage));
|
||||||
|
|
||||||
Pebble.sendAppMessage.callArg(1);
|
Pebble.sendAppMessage.callArg(1);
|
||||||
assert(logStub.calledWith('Sent config data to Pebble'));
|
assert(logStub.calledWith('Sent config data to Pebble'));
|
||||||
@@ -135,6 +152,23 @@ describe('Clay', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.version', function() {
|
||||||
|
it('has the correct version', function() {
|
||||||
|
var config = fixture.config(['input', 'text', 'color']);
|
||||||
|
var clay = fixture.clay(config);
|
||||||
|
assert.strictEqual(clay.version, require('../../package.json').version);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.config', function() {
|
||||||
|
it('is a copy not a reference', function() {
|
||||||
|
var config = fixture.config(['input', 'text', 'color']);
|
||||||
|
var clay = fixture.clay(config);
|
||||||
|
assert.notStrictEqual(clay.config, config);
|
||||||
|
assert.deepEqual(clay.config, config);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('.registerComponent()', function() {
|
describe('.registerComponent()', function() {
|
||||||
it('adds the component to the this.components', function() {
|
it('adds the component to the this.components', function() {
|
||||||
var clay = fixture.clay([]);
|
var clay = fixture.clay([]);
|
||||||
@@ -156,13 +190,13 @@ describe('Clay', function() {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function decodeUrl(url) {
|
function decodeUrl(url) {
|
||||||
return atob(decodeURIComponent(url.replace(/^.*?[#,]/, '')));
|
return decodeURIComponent(url.replace(/^.*?[#,]/, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('string substitutions', function() {
|
describe('string substitutions', function() {
|
||||||
var customFn = function() { this.getAllItems(); };
|
var customFn = function() { this.getAllItems(); };
|
||||||
var config = fixture.config(['input', 'color']);
|
var config = fixture.config(['input', 'color']);
|
||||||
var settings = { appKey: 'value' };
|
var settings = { messageKey: 'value' };
|
||||||
var clay;
|
var clay;
|
||||||
var html;
|
var html;
|
||||||
|
|
||||||
@@ -235,62 +269,203 @@ describe('Clay', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.getSettings()', function() {
|
describe('.getSettings', function() {
|
||||||
it('stores the response to localStorage and returns the decoded data',
|
it('it writes to localStorage and returns the data when input is encoded',
|
||||||
function() {
|
function() {
|
||||||
var clay = fixture.clay([]);
|
var clay = fixture.clay([]);
|
||||||
var result = clay.getSettings('%7B%22appKey%22%3A%22value%22%7D');
|
var settings = encodeURIComponent(JSON.stringify({
|
||||||
assert.equal(localStorage.getItem('clay-settings'), '{"appKey":"value"}');
|
key1: 'value1',
|
||||||
assert.deepEqual(result, {appKey: 'value'});
|
key2: {value: 'value2'}
|
||||||
|
}));
|
||||||
|
var expected = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2'
|
||||||
|
};
|
||||||
|
|
||||||
|
stubMessageKeys(fixture.messageKeysObjToArray(expected));
|
||||||
|
|
||||||
|
var result = clay.getSettings(settings);
|
||||||
|
assert.equal(
|
||||||
|
localStorage.getItem('clay-settings'),
|
||||||
|
JSON.stringify(expected)
|
||||||
|
);
|
||||||
|
assert.deepEqual(result, fixture.messageKeysExpected(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
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 expected = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2%7Dbreaks'
|
||||||
|
};
|
||||||
|
|
||||||
|
stubMessageKeys(fixture.messageKeysObjToArray(expected));
|
||||||
|
|
||||||
|
var result = clay.getSettings(settings);
|
||||||
|
assert.equal(
|
||||||
|
localStorage.getItem('clay-settings'),
|
||||||
|
JSON.stringify(expected)
|
||||||
|
);
|
||||||
|
assert.deepEqual(result, fixture.messageKeysExpected(expected));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not store the response if it is invalid JSON and logs an error',
|
it('does not store the response if it is invalid JSON and logs an error',
|
||||||
function() {
|
function() {
|
||||||
var clay = fixture.clay([]);
|
var clay = fixture.clay([]);
|
||||||
localStorage.setItem('clay-settings', '{"appKey":"value"}');
|
localStorage.setItem('clay-settings', '{"messageKey":"value"}');
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
clay.getSettings('not valid JSON');
|
clay.getSettings('not valid JSON');
|
||||||
}, /Not Valid JSON/i);
|
}, /Not Valid JSON/i);
|
||||||
assert.equal(localStorage.getItem('clay-settings'), '{"appKey":"value"}');
|
assert.equal(localStorage.getItem('clay-settings'), '{"messageKey":"value"}');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
},
|
||||||
|
test9: {
|
||||||
|
precision: 1,
|
||||||
|
value: [1, 2, 3, 4]
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
var expected = {
|
||||||
|
test1: 0,
|
||||||
|
test2: 'val-2',
|
||||||
|
test3: 1,
|
||||||
|
test4: ['cb-1', 'cb-3'],
|
||||||
|
test5: 12345,
|
||||||
|
test6: [1, 2, 3, 4],
|
||||||
|
test7: [1, 0, 1],
|
||||||
|
test8: 1234,
|
||||||
|
test9: [10, 20, 30, 40]
|
||||||
|
};
|
||||||
|
|
||||||
|
stubMessageKeys(fixture.messageKeysObjToArray(expected));
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
clay.getSettings(response),
|
||||||
|
fixture.messageKeysExpected(expected)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 response = encodeURIComponent(JSON.stringify(settings));
|
||||||
|
|
||||||
|
assert.deepEqual(clay.getSettings(response, false), settings);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.setSettings', function() {
|
||||||
|
it('it writes to localStorage when passing an object',
|
||||||
|
function() {
|
||||||
|
var clay = fixture.clay([]);
|
||||||
|
var settings = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2'
|
||||||
|
};
|
||||||
|
var expected = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2'
|
||||||
|
};
|
||||||
|
|
||||||
|
clay.setSettings(settings);
|
||||||
|
assert.equal(
|
||||||
|
localStorage.getItem('clay-settings'),
|
||||||
|
JSON.stringify(expected)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it writes to localStorage when passing a key and a value',
|
||||||
|
function() {
|
||||||
|
var clay = fixture.clay([]);
|
||||||
|
var expected = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2%7Dbreaks'
|
||||||
|
};
|
||||||
|
|
||||||
|
clay.setSettings('key1', 'value1');
|
||||||
|
clay.setSettings('key2', 'value2%7Dbreaks');
|
||||||
|
assert.equal(localStorage.getItem('clay-settings'),
|
||||||
|
JSON.stringify(expected)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('doesn\'t throw and logs an error if settings in localStorage are broken',
|
||||||
|
function() {
|
||||||
|
var clay = fixture.clay([]);
|
||||||
|
var errorStub = sinon.stub(console, 'error');
|
||||||
|
localStorage.setItem('clay-settings', 'not valid JSON');
|
||||||
|
assert.doesNotThrow(function() {
|
||||||
|
clay.setSettings('key', 'value');
|
||||||
|
});
|
||||||
|
assert(errorStub.calledWithMatch(/SyntaxError/i));
|
||||||
|
errorStub.restore();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.meta', function() {
|
describe('.meta', function() {
|
||||||
var emptyMeta = {
|
var emptyMeta = {
|
||||||
activeWatchInfo: null,
|
activeWatchInfo: null,
|
||||||
accountToken: '',
|
accountToken: '',
|
||||||
watchToken: ''
|
watchToken: '',
|
||||||
|
userData: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
it('populates the meta in the showConfiguration handler', function() {
|
it('populates the meta in the showConfiguration handler', function() {
|
||||||
stubPebble();
|
stubPebble();
|
||||||
var clay = fixture.clay([]);
|
var userData = {foo: 'bar'};
|
||||||
|
var clay = fixture.clay([], null, {userData: userData});
|
||||||
|
|
||||||
// meta only gets populated after showConfiguration happens
|
// meta only gets populated after showConfiguration happens
|
||||||
assert.deepEqual(clay.meta, emptyMeta);
|
assert.deepEqual(clay.meta, emptyMeta);
|
||||||
Pebble.addEventListener.withArgs('showConfiguration').callArg(1);
|
Pebble.addEventListener.withArgs('showConfiguration').callArg(1);
|
||||||
|
assert.deepEqual(clay.meta, fixture.meta({userData: userData}));
|
||||||
assert.deepEqual(clay.meta, {
|
|
||||||
activeWatchInfo: activeWatchInfo,
|
|
||||||
accountToken: accountToken,
|
|
||||||
watchToken: watchToken
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('populates the meta in the ready handler', function() {
|
it('populates the meta in the ready handler', function() {
|
||||||
stubPebble();
|
stubPebble();
|
||||||
var clay = fixture.clay([], null, {autoHandleEvents: false});
|
var userData = {foo: 'bar'};
|
||||||
|
var clay = fixture.clay([], null, {
|
||||||
|
autoHandleEvents: false,
|
||||||
|
userData: userData
|
||||||
|
});
|
||||||
|
|
||||||
// meta only gets populated after ready happens
|
// meta only gets populated after ready happens
|
||||||
assert.deepEqual(clay.meta, emptyMeta);
|
assert.deepEqual(clay.meta, emptyMeta);
|
||||||
Pebble.addEventListener.withArgs('ready').callArg(1);
|
Pebble.addEventListener.withArgs('ready').callArg(1);
|
||||||
|
|
||||||
assert.deepEqual(clay.meta, {
|
assert.deepEqual(clay.meta, fixture.meta({userData: userData}));
|
||||||
activeWatchInfo: activeWatchInfo,
|
|
||||||
accountToken: accountToken,
|
|
||||||
watchToken: watchToken
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('populates the meta with with empty values when there is no Pebble global',
|
it('populates the meta with with empty values when there is no Pebble global',
|
||||||
@@ -303,49 +478,155 @@ describe('Clay', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Clay.encodeDataUri()', function() {
|
describe('Clay.encodeDataUri()', function() {
|
||||||
|
it('adds the correct prefix', function() {
|
||||||
/**
|
assert.equal(Clay.encodeDataUri('<test>', 'prefix:'), 'prefix:%3Ctest%3E');
|
||||||
* @return {void}
|
assert.equal(
|
||||||
*/
|
Clay.encodeDataUri('<test>'),
|
||||||
function testEncodeDataUri() {
|
'data:text/html;charset=utf-8,%3Ctest%3E'
|
||||||
it('adds the correct prefix', function() {
|
);
|
||||||
assert.equal(Clay.encodeDataUri('test', 'prefix:'), 'prefix:dGVzdA%3D%3D');
|
|
||||||
assert.equal(
|
|
||||||
Clay.encodeDataUri('test'),
|
|
||||||
'data:text/html;base64,dGVzdA%3D%3D'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('encodes the data correctly', function() {
|
|
||||||
assert.equal(Clay.encodeDataUri('test', ''), 'dGVzdA%3D%3D');
|
|
||||||
assert.equal(Clay.encodeDataUri('test{2}', ''), 'dGVzdHsyfQ%3D%3D');
|
|
||||||
assert.equal(Clay.encodeDataUri('test{10}', ''), 'dGVzdHsxMH0%3D');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws if the input is invalid', function() {
|
|
||||||
assert.throws(function() {
|
|
||||||
Clay.encodeDataUri('♥');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('native', function() {
|
|
||||||
testEncodeDataUri();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('polyfill', function() {
|
it('encodes the data correctly', function() {
|
||||||
var btoaOriginal = window.btoa;
|
assert.equal(Clay.encodeDataUri('test', ''), 'test');
|
||||||
|
assert.equal(Clay.encodeDataUri('test{2}', ''), 'test%7B2%7D');
|
||||||
before(function() {
|
assert.equal(Clay.encodeDataUri('test{10}', ''), 'test%7B10%7D');
|
||||||
window.btoa = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
testEncodeDataUri();
|
|
||||||
|
|
||||||
after(function() {
|
|
||||||
window.btoa = btoaOriginal;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not throw if unicode character is provided', function() {
|
||||||
|
assert.doesNotThrow(function() {
|
||||||
|
Clay.encodeDataUri('♥');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.prepareForAppMessage', function() {
|
||||||
|
it('converts an array correctly when array contains strings', function() {
|
||||||
|
assert.deepEqual(
|
||||||
|
Clay.prepareForAppMessage(['one', 'two', 'three']),
|
||||||
|
['one', 'two', 'three']
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
Clay.prepareForAppMessage([{value: 'one'}, 'two', 'three']),
|
||||||
|
['one', 'two', 'three']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts an array correctly when array contains numbers', function() {
|
||||||
|
assert.deepEqual(Clay.prepareForAppMessage([1, 2, 3]), [1, 2, 3]);
|
||||||
|
assert.deepEqual(Clay.prepareForAppMessage(
|
||||||
|
{value: [1.5, 2.34, 3], precision: 2}),
|
||||||
|
[150, 234, 300]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts an array correctly when array contains booleans', function() {
|
||||||
|
assert.deepEqual(Clay.prepareForAppMessage([true, false, true]), [1, 0, 1]);
|
||||||
|
assert.deepEqual(
|
||||||
|
Clay.prepareForAppMessage([{value: true}, false, true]),
|
||||||
|
[1, 0, 1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts booleans to ints', function() {
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage(false), 0);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage(true), 1);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({value: false}), 0);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({value: true}), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('leaves strings alone', function() {
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage('test'), 'test');
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({value: 'test'}), 'test');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Multiples the number by the precision', function() {
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage(123), 123);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({
|
||||||
|
value: 1.23,
|
||||||
|
precision: 3
|
||||||
|
}), 1230);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({
|
||||||
|
value: 123,
|
||||||
|
precision: 2
|
||||||
|
}), 12300);
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({
|
||||||
|
value: 1.23456,
|
||||||
|
precision: 4
|
||||||
|
}), 12345);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores precision for anything but numbers', function() {
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({
|
||||||
|
value: 'not a number',
|
||||||
|
precision: 3
|
||||||
|
}), 'not a number');
|
||||||
|
|
||||||
|
assert.deepEqual(Clay.prepareForAppMessage({
|
||||||
|
value: ['not', 'a', 'number'],
|
||||||
|
precision: 3
|
||||||
|
}), ['not', 'a', 'number']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats an undefined precision as 0', function() {
|
||||||
|
assert.strictEqual(Clay.prepareForAppMessage({
|
||||||
|
value: 12.45,
|
||||||
|
precision: undefined
|
||||||
|
}), 12);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Handles sparse arrays', function() {
|
||||||
|
var sparseArr = [];
|
||||||
|
sparseArr[1] = 'two';
|
||||||
|
sparseArr[2] = 'three';
|
||||||
|
assert.deepEqual(Clay.prepareForAppMessage(sparseArr), sparseArr);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.prepareSettingsForAppMessage', function() {
|
||||||
|
it('converts the settings correctly', function() {
|
||||||
|
var settings = {
|
||||||
|
test1: false,
|
||||||
|
'test2[0]': 'val-1',
|
||||||
|
'test2[1]': '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[1]': 'foo'
|
||||||
|
};
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
test1: 0,
|
||||||
|
test2: ['val-1', 'val-2'],
|
||||||
|
test3: 1,
|
||||||
|
test4: ['cb-1', 'cb-3'],
|
||||||
|
test5: 12345,
|
||||||
|
test6: [1, 2, 3, 4],
|
||||||
|
test7: [1, 0, 1],
|
||||||
|
test8: 1234,
|
||||||
|
test9: [undefined, 'foo']
|
||||||
|
};
|
||||||
|
|
||||||
|
stubMessageKeys(fixture.messageKeysObjToArray(expected));
|
||||||
|
|
||||||
|
var result = Clay.prepareSettingsForAppMessage(settings);
|
||||||
|
|
||||||
|
assert.deepEqual(result, fixture.messageKeysExpected(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if a 2 dimension array is present', function() {
|
||||||
|
var settings = {
|
||||||
|
'test1[1]': ['bad', 'developer!']
|
||||||
|
};
|
||||||
|
|
||||||
|
stubMessageKeys(['test1[2]']);
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
Clay.prepareSettingsForAppMessage(settings);
|
||||||
|
}, /2 dimensional array/i);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+446
-41
@@ -12,10 +12,11 @@ describe('ClayConfig', function() {
|
|||||||
it('defines read-only properties', function() {
|
it('defines read-only properties', function() {
|
||||||
var properties = [
|
var properties = [
|
||||||
'EVENTS',
|
'EVENTS',
|
||||||
'getItemByAppKey',
|
'getItemByMessageKey',
|
||||||
'getItemById',
|
'getItemById',
|
||||||
'getItemsByType',
|
'getItemsByType',
|
||||||
'getSettings',
|
'getItemsByGroup',
|
||||||
|
'serialize',
|
||||||
'registerComponent',
|
'registerComponent',
|
||||||
'build',
|
'build',
|
||||||
'on',
|
'on',
|
||||||
@@ -27,6 +28,286 @@ describe('ClayConfig', function() {
|
|||||||
checkReadOnly(clayConfig, properties);
|
checkReadOnly(clayConfig, properties);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the provided capabilities of the platform match
|
||||||
|
* @param {string} platform
|
||||||
|
* @param {number} fwMajor
|
||||||
|
* @param {number} fwMinor
|
||||||
|
* @param {Array} capabilities
|
||||||
|
* @param {number} expected
|
||||||
|
* @param {number} [notExpected] - defaults to the inverse of `expected`
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function testCapabilities(platform, fwMajor, fwMinor, capabilities, expected,
|
||||||
|
notExpected) {
|
||||||
|
it(platform + ' is' + (expected ? '' : ' not') + ' included on firmware ' +
|
||||||
|
fwMajor + '.' + fwMinor + ' for capabilities ' + JSON.stringify(capabilities),
|
||||||
|
function() {
|
||||||
|
var item = {
|
||||||
|
type: 'input',
|
||||||
|
capabilities: capabilities
|
||||||
|
};
|
||||||
|
var meta = {
|
||||||
|
activeWatchInfo: {
|
||||||
|
platform: platform,
|
||||||
|
model: 'qemu_platform_' + platform,
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: {
|
||||||
|
major: fwMajor,
|
||||||
|
minor: fwMinor,
|
||||||
|
patch: 0,
|
||||||
|
suffix: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var clayConfig = fixtures.clayConfig([item], true, true, null, meta);
|
||||||
|
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, expected);
|
||||||
|
|
||||||
|
// now we test the NOT_ prefix
|
||||||
|
item.capabilities = item.capabilities.map(function(capability) {
|
||||||
|
return 'NOT_' + capability.replace(/^NOT_/, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
notExpected = typeof notExpected !== 'undefined' ? notExpected : ~expected + 2;
|
||||||
|
clayConfig = fixtures.clayConfig([item], true, true, null, meta);
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, notExpected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('capability filtering', function() {
|
||||||
|
testCapabilities('aplite', 2, 9, ['BW'], 1);
|
||||||
|
testCapabilities('aplite', 2, 9, ['COLOR'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['COMPASS'], 1);
|
||||||
|
testCapabilities('aplite', 2, 9, ['MICROPHONE'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['TOUCH'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['RECT'], 1);
|
||||||
|
testCapabilities('aplite', 2, 9, ['ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['DISPLAY_144x168'], 1);
|
||||||
|
testCapabilities('aplite', 2, 9, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_APLITE'], 1);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('aplite', 2, 9, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('aplite', 3, 10, ['BW'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['COLOR'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['MICROPHONE'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('aplite', 3, 4, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('aplite', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['TOUCH'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['HEALTH'], 0);
|
||||||
|
testCapabilities('aplite', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['RECT'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['DISPLAY_144x168'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_APLITE'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('basalt', 3, 10, ['BW'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['COLOR'], 1);
|
||||||
|
testCapabilities('basalt', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('basalt', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('basalt', 3, 3, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('basalt', 3, 4, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('basalt', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('basalt', 3, 4, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('basalt', 3, 3, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('basalt', 3, 3, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('basalt', 3, 3, ['TOUCH'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('basalt', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['RECT'], 1);
|
||||||
|
testCapabilities('basalt', 3, 10, ['ROUND'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['DISPLAY_144x168'], 1);
|
||||||
|
testCapabilities('basalt', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_BASALT'], 1);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('chalk', 3, 10, ['BW'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['COLOR'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('chalk', 3, 3, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('chalk', 3, 4, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('chalk', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('chalk', 3, 4, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('chalk', 3, 3, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('chalk', 3, 3, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('chalk', 3, 3, ['TOUCH'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('chalk', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['RECT'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['ROUND'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['DISPLAY_144x168'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['DISPLAY_180x180_ROUND'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_CHALK'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('diorite', 3, 10, ['BW'], 1);
|
||||||
|
testCapabilities('diorite', 3, 10, ['COLOR'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['COMPASS'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('diorite', 3, 3, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('diorite', 3, 4, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('diorite', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('diorite', 3, 4, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('diorite', 3, 3, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('diorite', 3, 3, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('diorite', 3, 3, ['TOUCH'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('diorite', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['RECT'], 1);
|
||||||
|
testCapabilities('diorite', 3, 10, ['ROUND'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['DISPLAY_144x168'], 1);
|
||||||
|
testCapabilities('diorite', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_DIORITE'], 1);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('diorite', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('emery', 3, 10, ['BW'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['COLOR'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('emery', 4, 10, ['RGB_BACKLIGHT'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('emery', 3, 4, ['SMARTSTRAP'], 1);
|
||||||
|
testCapabilities('emery', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('emery', 3, 4, ['SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('emery', 3, 3, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('emery', 4, 10, ['SPEAKER'], 1);
|
||||||
|
testCapabilities('emery', 4, 10, ['TOUCH'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('emery', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['RECT'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['ROUND'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['DISPLAY_144x168'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['DISPLAY_200x228'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_EMERY'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('flint', 3, 10, ['BW'], 1);
|
||||||
|
testCapabilities('flint', 3, 10, ['COLOR'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('flint', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('flint', 3, 3, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('flint', 3, 4, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('flint', 3, 3, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('flint', 3, 4, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('flint', 3, 3, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('flint', 4, 10, ['SPEAKER'], 1);
|
||||||
|
testCapabilities('flint', 4, 10, ['TOUCH'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('flint', 3, 9, ['HEALTH'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['RECT'], 1);
|
||||||
|
testCapabilities('flint', 3, 10, ['ROUND'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['DISPLAY_144x168'], 1);
|
||||||
|
testCapabilities('flint', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['DISPLAY_260x260_ROUND'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_FLINT'], 1);
|
||||||
|
testCapabilities('flint', 3, 10, ['PLATFORM_GABBRO'], 0);
|
||||||
|
|
||||||
|
testCapabilities('gabbro', 3, 10, ['BW'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['COLOR'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['COMPASS'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['RGB_BACKLIGHT'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['SMARTSTRAP'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['SMARTSTRAP_POWER'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['SPEAKER'], 0);
|
||||||
|
testCapabilities('gabbro', 4, 10, ['TOUCH'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['HEALTH'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['RECT'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['ROUND'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['DISPLAY_144x168'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['DISPLAY_180x180_ROUND'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['DISPLAY_200x228'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['DISPLAY_260x260_ROUND'], 1);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_APLITE'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_CHALK'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_DIORITE'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_EMERY'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_FLINT'], 0);
|
||||||
|
testCapabilities('gabbro', 3, 10, ['PLATFORM_GABBRO'], 1);
|
||||||
|
|
||||||
|
testCapabilities('aplite', 3, 10, ['BW', 'HEALTH'], 0, 0);
|
||||||
|
testCapabilities('emery', 3, 10, ['COLOR', 'HEALTH'], 1);
|
||||||
|
testCapabilities('emery', 3, 10, ['MICROPHONE'], 1);
|
||||||
|
testCapabilities('chalk', 3, 10, ['PLATFORM_APLITE', 'PLATFORM_BASALT'], 0);
|
||||||
|
testCapabilities('basalt', 3, 10, ['SMARTSTRAP', 'SMARTSTRAP_POWER'], 1);
|
||||||
|
testCapabilities('aplite', 3, 10, ['COLOR', 'PLATFORM_APLITE'], 0, 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['PLATFORM_APLITE', 'COLOR'], 0, 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['BW', 'NOT_COLOR'], 1, 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['NOT_BASALT', 'RECT'], 1, 0);
|
||||||
|
testCapabilities('aplite', 3, 10, ['NOT_CHALK', 'BW', 'PLATFORM_APLITE'], 1, 0);
|
||||||
|
});
|
||||||
|
|
||||||
describe('.meta', function() {
|
describe('.meta', function() {
|
||||||
it('populates meta', function() {
|
it('populates meta', function() {
|
||||||
var clayConfig = fixtures.clayConfig(['input']);
|
var clayConfig = fixtures.clayConfig(['input']);
|
||||||
@@ -36,10 +317,11 @@ describe('ClayConfig', function() {
|
|||||||
|
|
||||||
describe('throws when trying to run methods before being built', function() {
|
describe('throws when trying to run methods before being built', function() {
|
||||||
[
|
[
|
||||||
'getItemByAppKey',
|
'getItemByMessageKey',
|
||||||
'getItemById',
|
'getItemById',
|
||||||
'getItemsByType',
|
'getItemsByType',
|
||||||
'getSettings'
|
'getItemsByGroup',
|
||||||
|
'serialize'
|
||||||
].forEach(function(method) {
|
].forEach(function(method) {
|
||||||
it('.' + method + '()', function() {
|
it('.' + method + '()', function() {
|
||||||
var clayConfig = fixtures.clayConfig(['input', 'text'], false);
|
var clayConfig = fixtures.clayConfig(['input', 'text'], false);
|
||||||
@@ -64,14 +346,17 @@ describe('ClayConfig', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.getItemByAppKey()', function() {
|
describe('.getItemByMessageKey()', function() {
|
||||||
it('it returns the correct item', function() {
|
it('it returns the correct item', function() {
|
||||||
var config = fixtures.config([
|
var config = fixtures.config([
|
||||||
{type: 'input', appKey: 'test-app-key', clayId: 0},
|
{type: 'input', messageKey: 'test-app-key', clayId: 0},
|
||||||
{type: 'input', appKey: undefined, clayId: 1}
|
{type: 'input', messageKey: undefined, clayId: 1}
|
||||||
]);
|
]);
|
||||||
var clayConfig = fixtures.clayConfig(config);
|
var clayConfig = fixtures.clayConfig(config);
|
||||||
assert.deepEqual(clayConfig.getItemByAppKey('test-app-key').config, config[0]);
|
assert.deepEqual(
|
||||||
|
clayConfig.getItemByMessageKey('test-app-key').config,
|
||||||
|
config[0]
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -99,45 +384,103 @@ describe('ClayConfig', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.getSettings()', function() {
|
describe('.getItemsByGroup()', function() {
|
||||||
it('returns the correct settings', function() {
|
it('it returns the correct items', function() {
|
||||||
var clayConfig = fixtures.clayConfig(
|
var config = fixtures.config([
|
||||||
[
|
{type: 'input', id: 'g1-0', group: 'group1'},
|
||||||
{type: 'input', appKey: 'test1', defaultValue: 'default val'},
|
{type: 'text', id: 'g2-0', group: 'group2'},
|
||||||
{type: 'select', appKey: 'test2', options: [
|
{type: 'input', id: 'g1-1', group: 'group1'}
|
||||||
{label: 'label-1', value: 'val-1'},
|
]);
|
||||||
{label: 'label-2', value: 'val-2'}
|
|
||||||
]},
|
|
||||||
{type: 'toggle', appKey: 'test3'},
|
|
||||||
{type: 'checkboxgroup', appKey: 'test4', options: [
|
|
||||||
{label: 'label-1', value: 'cb-1'},
|
|
||||||
{label: 'label-2', value: 'cb-2'},
|
|
||||||
{label: 'label-2', value: 'cb-3'}
|
|
||||||
]}
|
|
||||||
],
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
test2: 'val-2' // set one of the values via settings
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(clayConfig.getSettings(), {
|
var clayConfig = fixtures.clayConfig(config);
|
||||||
test1: 'default val',
|
assert.deepEqual(clayConfig.getItemsByGroup('group1'), [
|
||||||
test2: 'val-2',
|
clayConfig.getItemById('g1-0'),
|
||||||
test3: 0,
|
clayConfig.getItemById('g1-1')
|
||||||
test4: []
|
]);
|
||||||
|
assert.deepEqual(clayConfig.getItemsByGroup('group2'), [
|
||||||
|
clayConfig.getItemById('g2-0')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.serialize()', function() {
|
||||||
|
it('returns the correct settings', function() {
|
||||||
|
var config = [
|
||||||
|
{type: 'input', messageKey: 'test1', defaultValue: 'default val'},
|
||||||
|
{type: 'select', messageKey: 'test2', options: [
|
||||||
|
{label: 'label-1', value: 'val-1'},
|
||||||
|
{label: 'label-2', value: 'val-2'}
|
||||||
|
]},
|
||||||
|
{type: 'toggle', messageKey: 'test3'},
|
||||||
|
{type: 'checkboxgroup', messageKey: 'test4', options: [
|
||||||
|
'label-1',
|
||||||
|
'label-2',
|
||||||
|
'label-3'
|
||||||
|
]},
|
||||||
|
{type: 'slider', messageKey: 'test5', step: 0.05, defaultValue: 12.5}
|
||||||
|
];
|
||||||
|
var settings = {
|
||||||
|
test2: 'val-2'
|
||||||
|
};
|
||||||
|
|
||||||
|
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}
|
||||||
});
|
});
|
||||||
|
|
||||||
clayConfig.getItemByAppKey('test1').set('val-1');
|
clayConfig.getItemByMessageKey('test1').set('val-1');
|
||||||
clayConfig.getItemByAppKey('test3').set(true);
|
clayConfig.getItemByMessageKey('test3').set(true);
|
||||||
clayConfig.getItemByAppKey('test4').set(['cb-1', 'cb-3']);
|
clayConfig.getItemByMessageKey('test4').set([true, false, true]);
|
||||||
|
|
||||||
assert.deepEqual(clayConfig.getSettings(), {
|
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}
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure the result of serialize() can actually be fed back in to
|
||||||
|
// a new instance of ClayConfig
|
||||||
|
var clay = fixtures.clay(config);
|
||||||
|
var response = encodeURIComponent(JSON.stringify(clayConfig.serialize()));
|
||||||
|
clay.getSettings(response);
|
||||||
|
var loadedSettings = JSON.parse(localStorage.getItem('clay-settings'));
|
||||||
|
|
||||||
|
assert.deepEqual(loadedSettings, {
|
||||||
test1: 'val-1',
|
test1: 'val-1',
|
||||||
test2: 'val-2',
|
test2: 'val-2',
|
||||||
test3: 1,
|
test3: true,
|
||||||
test4: ['cb-1', 0, 'cb-3', 0]
|
test4: [true, false, true],
|
||||||
|
test5: 12.5
|
||||||
|
});
|
||||||
|
assert.doesNotThrow(function() {
|
||||||
|
fixtures.clayConfig(config, true, true, loadedSettings);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only returns the settings present in the config', function() {
|
||||||
|
var config = [
|
||||||
|
{type: 'input', messageKey: 'test1', defaultValue: 'default val'},
|
||||||
|
{type: 'select', messageKey: 'test2', options: [
|
||||||
|
{label: 'label-1', value: 'val-1'},
|
||||||
|
{label: 'label-2', value: 'val-2'}
|
||||||
|
]}
|
||||||
|
];
|
||||||
|
var settings = {
|
||||||
|
test2: 'val-2',
|
||||||
|
notInTheConfig: 'Should not exist'
|
||||||
|
};
|
||||||
|
|
||||||
|
var clayConfig = fixtures.clayConfig(config, true, true, settings);
|
||||||
|
assert.deepEqual(clayConfig.serialize(), {
|
||||||
|
test1: {value: 'default val'},
|
||||||
|
test2: {value: 'val-2'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -235,7 +578,69 @@ describe('ClayConfig', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.destroy().', function() {
|
||||||
|
it('Destroys all the items on the page and in the items array', function() {
|
||||||
|
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
||||||
|
|
||||||
|
clayConfig.build();
|
||||||
|
clayConfig.destroy();
|
||||||
|
|
||||||
|
// this should throw because the config has not been built yet
|
||||||
|
assert.throws(clayConfig.getAllItems);
|
||||||
|
|
||||||
|
// there should be no DOM inside the container
|
||||||
|
assert.strictEqual(clayConfig.$rootContainer[0].children.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches the BEFORE_DESTROY event at the right time', function(done) {
|
||||||
|
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
||||||
|
|
||||||
|
clayConfig.on(clayConfig.EVENTS.BEFORE_DESTROY, function() {
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, 3);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
clayConfig.build();
|
||||||
|
clayConfig.destroy();
|
||||||
|
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches the AFTER_DESTROY event at the right time', function(done) {
|
||||||
|
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
||||||
|
|
||||||
|
clayConfig.on(clayConfig.EVENTS.AFTER_DESTROY, function() {
|
||||||
|
|
||||||
|
// this should throw because the config has not been built yet
|
||||||
|
assert.throws(clayConfig.getAllItems);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
clayConfig.build();
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, 3);
|
||||||
|
clayConfig.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('.build()', function() {
|
describe('.build()', function() {
|
||||||
|
it('Destroys the config if called a consecutive time', function() {
|
||||||
|
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
||||||
|
var destroyHandlerSpy = sinon.spy();
|
||||||
|
|
||||||
|
clayConfig.on(clayConfig.EVENTS.AFTER_DESTROY, destroyHandlerSpy);
|
||||||
|
|
||||||
|
clayConfig.build();
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, 3);
|
||||||
|
|
||||||
|
clayConfig.config = fixtures.config(['select']);
|
||||||
|
clayConfig.build();
|
||||||
|
assert.strictEqual(clayConfig.getAllItems().length, 1);
|
||||||
|
assert(destroyHandlerSpy.calledOnce);
|
||||||
|
|
||||||
|
clayConfig.build();
|
||||||
|
assert(destroyHandlerSpy.calledTwice);
|
||||||
|
});
|
||||||
|
|
||||||
it('dispatches the BEFORE_BUILD event at the right time', function(done) {
|
it('dispatches the BEFORE_BUILD event at the right time', function(done) {
|
||||||
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], false);
|
||||||
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
|
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
|
||||||
|
|||||||
+12
-10
@@ -12,7 +12,7 @@ describe('ClayItem', function() {
|
|||||||
it('defines read-only properties', function() {
|
it('defines read-only properties', function() {
|
||||||
var properties = [
|
var properties = [
|
||||||
'id',
|
'id',
|
||||||
'appKey',
|
'messageKey',
|
||||||
'config',
|
'config',
|
||||||
'$element',
|
'$element',
|
||||||
'$manipulatorTarget',
|
'$manipulatorTarget',
|
||||||
@@ -53,24 +53,25 @@ describe('ClayItem', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.appKey', function() {
|
describe('.messageKey', function() {
|
||||||
it('sets appKey correctly', function() {
|
it('sets messageKey correctly', function() {
|
||||||
var config = fixture.configItem('input');
|
var config = fixture.configItem('input');
|
||||||
var clayItem = new ClayItem(config);
|
var clayItem = new ClayItem(config);
|
||||||
assert.strictEqual(clayItem.appKey, config.appKey);
|
assert.strictEqual(clayItem.messageKey, config.messageKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets appKey to null if there is no appKey in the config', function() {
|
it('sets messageKey to null if there is no messageKey in the config',
|
||||||
var clayItem = fixture.clayItem({type: 'input', appKey: undefined});
|
function() {
|
||||||
assert.strictEqual(clayItem.appKey, null);
|
var clayItem = fixture.clayItem({type: 'input', messageKey: undefined});
|
||||||
|
assert.strictEqual(clayItem.messageKey, null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.config', function() {
|
describe('.config', function() {
|
||||||
it('sets appKey correctly', function() {
|
it('sets messageKey correctly', function() {
|
||||||
var config = fixture.configItem('input');
|
var config = fixture.configItem('input');
|
||||||
var clayItem = new ClayItem(config);
|
var clayItem = new ClayItem(config);
|
||||||
assert.strictEqual(clayItem.appKey, config.appKey);
|
assert.strictEqual(clayItem.messageKey, config.messageKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -104,7 +105,8 @@ describe('ClayItem', function() {
|
|||||||
|
|
||||||
it('returns itself for chaining', function() {
|
it('returns itself for chaining', function() {
|
||||||
var clayItem = fixture.clayItem('select');
|
var clayItem = fixture.clayItem('select');
|
||||||
assert.strictEqual(clayItem.initialize(), clayItem);
|
var clayConfig = fixture.clayConfig([]);
|
||||||
|
assert.strictEqual(clayItem.initialize(clayConfig), clayItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does nothing if there is no initialize function', function() {
|
it('does nothing if there is no initialize function', function() {
|
||||||
|
|||||||
+171
-61
@@ -143,93 +143,203 @@ describe('manipulators', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('html', function() {
|
describe('html', function() {
|
||||||
testSetGet('text', 'test123');
|
var type = 'text';
|
||||||
testSetGet('button', '<span>some HTML</span>');
|
testSetGet(type, 'test123');
|
||||||
testShow('text');
|
testSetGet(type, '<span>some HTML</span>');
|
||||||
testHide('text');
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('button', function() {
|
describe('button', function() {
|
||||||
testSetGet('button', 'test123');
|
var type = 'button';
|
||||||
testSetGet('button', '<span>some HTML</span>');
|
testSetGet(type, 'test123');
|
||||||
testDisable('button');
|
testSetGet(type, '<span>some HTML</span>');
|
||||||
testEnable('button');
|
testDisable(type);
|
||||||
testShow('button');
|
testEnable(type);
|
||||||
testHide('button');
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('val', function() {
|
describe('val', function() {
|
||||||
testSetGet('input', 'test321');
|
let stringInputType = {
|
||||||
testSetGet('input', 1234, '1234');
|
type: 'input',
|
||||||
testDisable('input');
|
serializeValueAs: 'string'
|
||||||
testEnable('input');
|
};
|
||||||
testShow('text');
|
|
||||||
testHide('text');
|
let integerInputType = {
|
||||||
|
type: 'input',
|
||||||
|
serializeValueAs: 'integer'
|
||||||
|
};
|
||||||
|
|
||||||
|
let stringSelectType = {
|
||||||
|
type: 'select',
|
||||||
|
defaultValue: 'value-1',
|
||||||
|
options: [
|
||||||
|
{ label: 'label 1', value: '1' },
|
||||||
|
{ label: 'label 2', value: '2' }],
|
||||||
|
serializeValueAs: 'string'
|
||||||
|
};
|
||||||
|
|
||||||
|
let integerSelectType = {
|
||||||
|
type: 'select',
|
||||||
|
defaultValue: 'value-1',
|
||||||
|
options: [
|
||||||
|
{ label: 'label 1', value: '1' },
|
||||||
|
{ label: 'label 2', value: '2' }],
|
||||||
|
serializeValueAs: 'integer'
|
||||||
|
};
|
||||||
|
|
||||||
|
testSetGet(stringInputType, 'test321');
|
||||||
|
testSetGet(stringInputType, 1234, '1234');
|
||||||
|
testSetGet(integerInputType, 'test321', 0);
|
||||||
|
testSetGet(integerInputType, 1234);
|
||||||
|
|
||||||
|
testSetGet(stringSelectType, '1');
|
||||||
|
testSetGet(stringSelectType, 2, '2');
|
||||||
|
testSetGet(integerSelectType, 1);
|
||||||
|
testSetGet(integerSelectType, '2', 2);
|
||||||
|
|
||||||
|
testDisable(stringInputType);
|
||||||
|
testDisable(integerInputType);
|
||||||
|
testDisable(stringSelectType);
|
||||||
|
testDisable(integerSelectType);
|
||||||
|
|
||||||
|
testEnable(stringInputType);
|
||||||
|
testEnable(integerInputType);
|
||||||
|
testEnable(stringSelectType);
|
||||||
|
testEnable(integerSelectType);
|
||||||
|
|
||||||
|
testHide(stringInputType);
|
||||||
|
testHide(integerInputType);
|
||||||
|
testHide(stringSelectType);
|
||||||
|
testHide(integerSelectType);
|
||||||
|
|
||||||
|
testShow(stringInputType);
|
||||||
|
testShow(integerInputType);
|
||||||
|
testShow(stringSelectType);
|
||||||
|
testShow(integerSelectType);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('slider', function() {
|
||||||
|
var type = {
|
||||||
|
type: 'slider',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
testSetGet(type, '12', 12);
|
||||||
|
testSetGet(type, 12);
|
||||||
|
testSetGet(type, '12.3', 12.3);
|
||||||
|
testSetGet(type, 12.3);
|
||||||
|
testSetGet(type, 12.34, 12.3);
|
||||||
|
testSetGet(type, '12.34', 12.3);
|
||||||
|
testDisable(type);
|
||||||
|
testEnable(type);
|
||||||
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('checked', function() {
|
describe('checked', function() {
|
||||||
testSetGet({type: 'toggle', defaultValue: false}, 1, true);
|
var type = 'toggle';
|
||||||
testSetGet({type: 'toggle', defaultValue: false}, true);
|
testSetGet({type: type, defaultValue: false}, 1, true);
|
||||||
testSetGet({type: 'toggle', defaultValue: true}, 0, false);
|
testSetGet({type: type, defaultValue: false}, true);
|
||||||
testSetGet({type: 'toggle', defaultValue: true}, false);
|
testSetGet({type: type, defaultValue: true}, 0, false);
|
||||||
testDisable('toggle');
|
testSetGet({type: type, defaultValue: true}, false);
|
||||||
testEnable('toggle');
|
testDisable(type);
|
||||||
testShow('toggle');
|
testEnable(type);
|
||||||
testHide('toggle');
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('radiogroup', function() {
|
describe('radiogroup', function() {
|
||||||
var item = {
|
var stringType = {
|
||||||
type: 'radiogroup',
|
type: 'radiogroup',
|
||||||
clayId: 1,
|
clayId: 1,
|
||||||
options: [
|
options: [
|
||||||
{ label: '1', value: 'one' },
|
{ label: '1', value: 'one' },
|
||||||
{ label: '2', value: 'two' },
|
{ label: '2', value: 'two' },
|
||||||
{ label: '3', value: 'three "quote' }
|
{ label: '3', value: 'three "quote' },
|
||||||
]
|
{ label: '4', value: 4 },
|
||||||
|
{ label: '5', value: '5 with text after' },
|
||||||
|
{ label: '5', value: '6.5' }
|
||||||
|
],
|
||||||
|
serializeValueAs: 'string'
|
||||||
};
|
};
|
||||||
testSetGet(item, 'one');
|
|
||||||
testSetGet(item, 'two');
|
|
||||||
testSetGet(item, 'three "quote');
|
|
||||||
testDisable(item);
|
|
||||||
testEnable(item);
|
|
||||||
testShow(item);
|
|
||||||
testHide(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('checkboxgroup', function() {
|
var integerType = {
|
||||||
var item = {
|
type: 'radiogroup',
|
||||||
type: 'checkboxgroup',
|
|
||||||
clayId: 1,
|
clayId: 1,
|
||||||
defaultValue: ['two'],
|
|
||||||
options: [
|
options: [
|
||||||
{ label: '1', value: 'one' },
|
{ label: '1', value: 'one' },
|
||||||
{ label: '2', value: 'two' },
|
{ label: '2', value: 'two' },
|
||||||
{ label: '3', value: 'three "quote' }
|
{ label: '3', value: 'three "quote' },
|
||||||
]
|
{ label: '4', value: 4 },
|
||||||
|
{ label: '5', value: '5 with text after' },
|
||||||
|
{ label: '5', value: '6.5' }
|
||||||
|
],
|
||||||
|
serializeValueAs: 'integer'
|
||||||
};
|
};
|
||||||
testSetGet(item, ['one', 'two']);
|
|
||||||
testSetGet(item, ['three "quote']);
|
testSetGet(stringType, 'one');
|
||||||
testSetGet(item, []);
|
testSetGet(stringType, 'two');
|
||||||
testSetGet(item, false, []);
|
testSetGet(stringType, 'three "quote');
|
||||||
testDisable(item);
|
testSetGet(stringType, '4');
|
||||||
testEnable(item);
|
testSetGet(stringType, '5 with text after');
|
||||||
testShow(item);
|
testSetGet(stringType, '6.5');
|
||||||
testHide(item);
|
testSetGet(integerType, 'one', 0);
|
||||||
|
testSetGet(integerType, 'two', 0);
|
||||||
|
testSetGet(integerType, 'three "quote', 0);
|
||||||
|
testSetGet(integerType, 4, 4);
|
||||||
|
testSetGet(integerType, '5 with text after', 5);
|
||||||
|
testSetGet(integerType, '6.5', 6);
|
||||||
|
testDisable(stringType);
|
||||||
|
testDisable(integerType);
|
||||||
|
testEnable(stringType);
|
||||||
|
testEnable(integerType);
|
||||||
|
testShow(stringType);
|
||||||
|
testShow(integerType);
|
||||||
|
testHide(stringType);
|
||||||
|
testHide(integerType);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkboxgroup', function() {
|
||||||
|
var type = {
|
||||||
|
type: 'checkboxgroup',
|
||||||
|
clayId: 1,
|
||||||
|
defaultValue: [true, true, true],
|
||||||
|
options: ['First', 'Second', 'Third']
|
||||||
|
};
|
||||||
|
testSetGet(type, [false, false, true]);
|
||||||
|
testSetGet(type, [true, false], [true, false, false]);
|
||||||
|
testSetGet(type, [1, 0], [true, false, false]);
|
||||||
|
testSetGet(type, [true], [true, false, false]);
|
||||||
|
testSetGet(type, [1], [true, false, false]);
|
||||||
|
testSetGet(type, [], [false, false, false]);
|
||||||
|
|
||||||
|
// any non-array values should result in all false
|
||||||
|
testSetGet(type, false, [false, false, false]);
|
||||||
|
testSetGet(type, true, [false, false, false]);
|
||||||
|
testSetGet(type, null, [false, false, false]);
|
||||||
|
testDisable(type);
|
||||||
|
testEnable(type);
|
||||||
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('color', function() {
|
describe('color', function() {
|
||||||
testSetGet('color', 'FF0000', 0xff0000);
|
var type = 'color';
|
||||||
testSetGet('color', '#FF0000', 0xff0000);
|
testSetGet(type, 'FF0000', 0xff0000);
|
||||||
testSetGet('color', '0xFF0000', 0xff0000);
|
testSetGet(type, '#FF0000', 0xff0000);
|
||||||
testSetGet('color', '#ff0000', 0xff0000);
|
testSetGet(type, '0xFF0000', 0xff0000);
|
||||||
testSetGet('color', 0xff0000, 0xff0000);
|
testSetGet(type, '#ff0000', 0xff0000);
|
||||||
testSetGet({type: 'color', defaultValue: 0x00ff00}, '', 0x000000);
|
testSetGet(type, 0xff0000, 0xff0000);
|
||||||
testSetGet({type: 'color', defaultValue: 0x00ff00}, false, 0x000000);
|
testSetGet({type: type, defaultValue: 0x00ff00}, '', 0x000000);
|
||||||
testSetGet({type: 'color', defaultValue: 0x00ff00}, undefined, 0x000000);
|
testSetGet({type: type, defaultValue: 0x00ff00}, false, 0x000000);
|
||||||
testDisable('color');
|
testSetGet({type: type, defaultValue: 0x00ff00}, undefined, 0x000000);
|
||||||
testEnable('color');
|
testDisable(type);
|
||||||
testShow('color');
|
testEnable(type);
|
||||||
testHide('color');
|
testShow(type);
|
||||||
|
testHide(type);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-30
@@ -26,34 +26,5 @@ describe('Utils', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.prepareForAppMessage', function() {
|
|
||||||
it('converts an array correctly when array contains strings', function() {
|
|
||||||
assert.deepEqual(
|
|
||||||
utils.prepareForAppMessage(['one', 'two']),
|
|
||||||
['one', 0, 'two', 0]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts an array correctly when array contains numbers', function() {
|
|
||||||
assert.deepEqual(utils.prepareForAppMessage([1, 2, 3]), [1, 2, 3]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts an array correctly when array contains booleans', function() {
|
|
||||||
assert.deepEqual(utils.prepareForAppMessage([true, false, true]), [1, 0, 1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts booleans to ints', function() {
|
|
||||||
assert.strictEqual(utils.prepareForAppMessage(false), 0);
|
|
||||||
assert.strictEqual(utils.prepareForAppMessage(true), 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('leaves strings alone', function() {
|
|
||||||
assert.strictEqual(utils.prepareForAppMessage('test'), 'test');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('leaves numbers alone', function() {
|
|
||||||
assert.strictEqual(utils.prepareForAppMessage(123), 123);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import Clay = require('../index');
|
||||||
|
|
||||||
|
// --- Exported types are accessible via the Clay namespace ---
|
||||||
|
|
||||||
|
const configItem: Clay.ClayConfigItem = {
|
||||||
|
type: 'input',
|
||||||
|
messageKey: 'name',
|
||||||
|
defaultValue: '',
|
||||||
|
label: 'Name',
|
||||||
|
attributes: { placeholder: 'Enter name' },
|
||||||
|
capabilities: ['COLOR'],
|
||||||
|
group: 'appearance',
|
||||||
|
};
|
||||||
|
|
||||||
|
const meta: Clay.ClayMeta = {
|
||||||
|
activeWatchInfo: {
|
||||||
|
platform: 'basalt',
|
||||||
|
model: 'qemu_platform_basalt',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: { major: 4, minor: 3, patch: 0, suffix: '' },
|
||||||
|
},
|
||||||
|
accountToken: 'abc',
|
||||||
|
watchToken: 'def',
|
||||||
|
userData: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const options: Clay.ClayOptions = {
|
||||||
|
autoHandleEvents: true,
|
||||||
|
userData: { foo: 'bar' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const manipulator: Clay.ClayManipulator = {
|
||||||
|
get() { return this.$manipulatorTarget.get('value'); },
|
||||||
|
set(value) {
|
||||||
|
this.$manipulatorTarget.set('value', value);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
disable() { return this; },
|
||||||
|
enable() { return this; },
|
||||||
|
hide() { return this; },
|
||||||
|
show() { return this; },
|
||||||
|
};
|
||||||
|
|
||||||
|
const component: Clay.ClayComponent = {
|
||||||
|
name: 'my-component',
|
||||||
|
template: '<div></div>',
|
||||||
|
manipulator,
|
||||||
|
defaults: { label: 'Default' },
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Constructor ---
|
||||||
|
|
||||||
|
const clay = new Clay(
|
||||||
|
[configItem, { type: 'heading', defaultValue: 'My App' }],
|
||||||
|
function() {
|
||||||
|
// `this` is ClayConfig — verify event methods
|
||||||
|
const self: Clay.ClayConfig = this;
|
||||||
|
|
||||||
|
const handler = (..._args: unknown[]) => {};
|
||||||
|
this.on('AFTER_BUILD', handler);
|
||||||
|
this.off(handler);
|
||||||
|
this.trigger('AFTER_BUILD');
|
||||||
|
|
||||||
|
// Verify chaining returns the same type
|
||||||
|
this.on('BEFORE_BUILD', handler).off(handler);
|
||||||
|
|
||||||
|
// Verify EVENTS constants
|
||||||
|
const events: Clay.ClayConfigEvents = this.EVENTS;
|
||||||
|
const beforeBuild: 'BEFORE_BUILD' = events.BEFORE_BUILD;
|
||||||
|
const afterBuild: 'AFTER_BUILD' = events.AFTER_BUILD;
|
||||||
|
const beforeDestroy: 'BEFORE_DESTROY' = events.BEFORE_DESTROY;
|
||||||
|
const afterDestroy: 'AFTER_DESTROY' = events.AFTER_DESTROY;
|
||||||
|
|
||||||
|
// Verify build/destroy return ClayConfig for chaining
|
||||||
|
this.build().destroy().build();
|
||||||
|
|
||||||
|
// Verify item getters
|
||||||
|
const allItems: Clay.ClayItem[] = this.getAllItems();
|
||||||
|
const byKey: Clay.ClayItem = this.getItemByMessageKey('bg_color');
|
||||||
|
const byId: Clay.ClayItem = this.getItemById('my-id');
|
||||||
|
const byType: Clay.ClayItem[] = this.getItemsByType('color');
|
||||||
|
const byGroup: Clay.ClayItem[] = this.getItemsByGroup('appearance');
|
||||||
|
|
||||||
|
// Verify ClayItem properties
|
||||||
|
const item = byKey;
|
||||||
|
const itemId: string | null = item.id;
|
||||||
|
const itemMsgKey: string | null = item.messageKey;
|
||||||
|
const itemConfig: Clay.ClayConfigItem = item.config;
|
||||||
|
const $el: Clay.M = item.$element;
|
||||||
|
const $target: Clay.M = item.$manipulatorTarget;
|
||||||
|
|
||||||
|
// Verify ClayItem manipulator methods
|
||||||
|
const value: unknown = item.get();
|
||||||
|
const afterSet: Clay.ClayItem = item.set('new value');
|
||||||
|
const afterDisable: Clay.ClayItem = item.disable();
|
||||||
|
const afterEnable: Clay.ClayItem = item.enable();
|
||||||
|
const afterHide: Clay.ClayItem = item.hide();
|
||||||
|
const afterShow: Clay.ClayItem = item.show();
|
||||||
|
|
||||||
|
// Verify ClayItem event methods
|
||||||
|
item.on('change', handler).off(handler);
|
||||||
|
item.trigger('change');
|
||||||
|
|
||||||
|
// Verify ClayItem initialize
|
||||||
|
const afterInit: Clay.ClayItem = item.initialize(this);
|
||||||
|
|
||||||
|
// Verify serialize
|
||||||
|
const serialised: Record<string, { value: unknown; precision?: number }> =
|
||||||
|
this.serialize();
|
||||||
|
|
||||||
|
// Verify meta
|
||||||
|
const configMeta: Clay.ClayMeta = this.meta;
|
||||||
|
|
||||||
|
// Verify registerComponent on instance
|
||||||
|
const registered: boolean = this.registerComponent(component);
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Constructor with null customFn
|
||||||
|
const clay2 = new Clay([{ type: 'heading' }], null);
|
||||||
|
|
||||||
|
// Constructor with no options
|
||||||
|
const clay3 = new Clay([{ type: 'heading' }]);
|
||||||
|
|
||||||
|
// --- Instance properties ---
|
||||||
|
|
||||||
|
const config: Clay.ClayConfigItem[] = clay.config;
|
||||||
|
const version: string = clay.version;
|
||||||
|
const components: Record<string, Clay.ClayComponent> = clay.components;
|
||||||
|
const clayMeta: Clay.ClayMeta = clay.meta;
|
||||||
|
const customFn: (this: Clay.ClayConfig) => void = clay.customFn;
|
||||||
|
|
||||||
|
// --- Instance methods ---
|
||||||
|
|
||||||
|
clay.registerComponent(component);
|
||||||
|
|
||||||
|
// String manipulator name
|
||||||
|
clay.registerComponent({
|
||||||
|
name: 'another',
|
||||||
|
template: '<input>',
|
||||||
|
manipulator: 'val',
|
||||||
|
});
|
||||||
|
|
||||||
|
const url: string = clay.generateUrl();
|
||||||
|
const settings: Record<string, unknown> = clay.getSettings('{}');
|
||||||
|
const rawSettings: Record<string, unknown> = clay.getSettings('{}', false);
|
||||||
|
clay.setSettings('key', 'value');
|
||||||
|
clay.setSettings({ key: 'value' });
|
||||||
|
|
||||||
|
// --- Static methods ---
|
||||||
|
|
||||||
|
const uri: string = Clay.encodeDataUri('<html></html>');
|
||||||
|
const uriWithPrefix: string = Clay.encodeDataUri('<html></html>', 'http://example.com/#');
|
||||||
|
const prepared: number | string | (number | string)[] = Clay.prepareForAppMessage(42);
|
||||||
|
const appMsg: Record<number, number | string> =
|
||||||
|
Clay.prepareSettingsForAppMessage({ bg_color: { value: 255 } });
|
||||||
|
|
||||||
|
// --- M interface ---
|
||||||
|
|
||||||
|
function testM(el: Clay.M) {
|
||||||
|
const len: number = el.length;
|
||||||
|
const htmlEl: HTMLElement = el[0];
|
||||||
|
const added: Clay.M = el.add('<span>');
|
||||||
|
const afterSet: Clay.M = el.set('className', 'active');
|
||||||
|
const val: unknown = el.get('value');
|
||||||
|
const selected: Clay.M = el.select('.child');
|
||||||
|
el.on('click', () => {});
|
||||||
|
el.each((element: HTMLElement, index: number) => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PebbleActiveWatchInfo ---
|
||||||
|
|
||||||
|
const watchInfo: Clay.PebbleActiveWatchInfo = {
|
||||||
|
platform: 'chalk',
|
||||||
|
model: 'qemu_platform_chalk',
|
||||||
|
language: 'en_US',
|
||||||
|
firmware: { major: 4, minor: 3, patch: 0, suffix: '' },
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2015",
|
||||||
|
"module": "node16",
|
||||||
|
"allowJs": true,
|
||||||
|
"declaration": true,
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"rootDir": ".",
|
||||||
|
"outDir": "./dist-types",
|
||||||
|
"strict": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "node16",
|
||||||
|
"typeRoots": ["./types", "./node_modules/@types"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/scripts/lib/clay-config.js",
|
||||||
|
"src/scripts/lib/clay-events.js",
|
||||||
|
"src/scripts/lib/clay-item.js",
|
||||||
|
"src/scripts/lib/component-registry.js",
|
||||||
|
"src/scripts/lib/manipulators.js",
|
||||||
|
"src/scripts/lib/utils.js"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"test",
|
||||||
|
"dev",
|
||||||
|
"tmp",
|
||||||
|
"src/scripts/config-page.js",
|
||||||
|
"src/scripts/components",
|
||||||
|
"src/scripts/vendor",
|
||||||
|
"src/js"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2015",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node10",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"ignoreDeprecations": "6.0"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"test/type-checks.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
declare module './tmp/config-page.html' {
|
||||||
|
const html: string;
|
||||||
|
export = html;
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
declare module 'message_keys' {
|
||||||
|
const messageKeys: { [key: string]: number };
|
||||||
|
export = messageKeys;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# This file is the default set of rules to compile a Pebble project.
|
||||||
|
#
|
||||||
|
# Feel free to customize this to your needs.
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import waflib
|
||||||
|
|
||||||
|
top = '.'
|
||||||
|
out = 'build'
|
||||||
|
|
||||||
|
|
||||||
|
def distclean(ctx):
|
||||||
|
if os.path.exists('dist.zip'):
|
||||||
|
os.remove('dist.zip')
|
||||||
|
if os.path.exists('dist'):
|
||||||
|
shutil.rmtree('dist')
|
||||||
|
waflib.Scripting.distclean(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def options(ctx):
|
||||||
|
ctx.load('pebble_sdk_lib')
|
||||||
|
|
||||||
|
|
||||||
|
def configure(ctx):
|
||||||
|
ctx.load('pebble_sdk_lib')
|
||||||
|
|
||||||
|
|
||||||
|
def build(ctx):
|
||||||
|
ctx.load('pebble_sdk_lib')
|
||||||
|
|
||||||
|
cached_env = ctx.env
|
||||||
|
for platform in ctx.env.TARGET_PLATFORMS:
|
||||||
|
ctx.env = ctx.all_envs[platform]
|
||||||
|
ctx.set_group(ctx.env.PLATFORM_NAME)
|
||||||
|
lib_name = '{}/{}'.format(ctx.env.BUILD_DIR, ctx.env.PROJECT_INFO['name'])
|
||||||
|
ctx.pbl_build(source=ctx.path.ant_glob('src/c/**/*.c'), target=lib_name, bin_type='lib')
|
||||||
|
ctx.env = cached_env
|
||||||
|
|
||||||
|
ctx.set_group('bundle')
|
||||||
|
ctx.pbl_bundle(includes=ctx.path.ant_glob('include/**/*.h'),
|
||||||
|
js=ctx.path.ant_glob(['src/js/**/*.js', 'src/js/**/*.json']),
|
||||||
|
bin_type='lib')
|
||||||
|
|
||||||
|
if ctx.cmd == 'clean':
|
||||||
|
for n in ctx.path.ant_glob(['dist/**/*', 'dist.zip'], quiet=True):
|
||||||
|
n.delete()
|
||||||
Reference in New Issue
Block a user