Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bind service and state component (#6449)
* initial commit for bind component/service * make default value error more descriptive, only fire in dev mode * rename some methods/vars * don't strict equality check for default verification * hack support for on='tap:setState' * remove null result check for expr eval * use vsync for digest mutation, add class and attr toggle * first pass on amp-bind-state element * add class change example * add amp-img ex, fix dumb sanitize attr bug * move state to separate element per design doc * document methods in bind-impl.js * properly handle boolean attributes * add framework for reacting to attr changes, support size change, fix comments * propagate attrs in amp-img * move bind service to /extensions, skip digest for amp-bind-state * clean up action-impl * fix lint errors * handle amp-bind not installed * fix closure errors in compiled bind expr * fix type annotations * add amp-video support * add amp-bind validator proto * PR comments, more types, TODOs * fix long line * remove local assets in bind example * fix typedef * more type fixes * fix lint error * revert amp-video changes * rename bind-state to state * PR comments * add unit tests * check shallow equality during mutate, more unit tests * PR comments * nit fix * call attr changed callback for bool attrs * more PR comments * lint and style fixes * PR comments, class-ify bind-expr * move expr eval to separate file * fix lint and type errors * PR comments
- Loading branch information
William Chou
committed
Dec 14, 2016
1 parent
40c9a1a
commit d25c72e
Showing
19 changed files
with
1,408 additions
and
303 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<!doctype html> | ||
<html ⚡> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>amp-bind</title> | ||
<link rel="canonical" href="amps.html"> | ||
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> | ||
<link href="https://fonts.googleapis.com/css?family=Questrial" rel="stylesheet" type="text/css"> | ||
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript> | ||
<script async src="https://cdn.ampproject.org/v0.js"></script> | ||
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script> | ||
|
||
<style amp-custom> | ||
.redBackground { | ||
background-color: red; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<amp-state id="myState"> | ||
<script type="application/json"> | ||
{ | ||
"myStateKey1": "myStateValue1" | ||
} | ||
</script> | ||
</amp-state> | ||
|
||
<button onclick="AMP.toggleExperiment('amp-bind');window.location.href=window.location.href;">Toggle Experiment</button> | ||
|
||
<p [text]="foo">After clicking the button below, this will read 'foo'<p> | ||
<p id="foo" [text]="foo + 'bar'">And this will read 'foobar'<p> | ||
<p [text]="myState.myStateKey1">This will read 'myStateValue1'<p> | ||
<button [disabled]="isButtonDisabled">This button will be disabled</button> | ||
<p [class]="textClass">This text will have have a red background color</p> | ||
<amp-img src="https://ampbyexample.com/img/Border_Collie.jpg" [src]="imgSrc" width=100 [width]="imgSize" height=100 [height]="imgSize" alt="asdf" [alt]="imgAlt"></amp-img> | ||
<p>The image above will increase in size and change its src</p> | ||
<!-- | ||
<amp-video src="https://ampbyexample.com/video/tokyo.mp4" [src]="videoSrc" width=480 height=270 controls></amp-video> | ||
--> | ||
<hr> | ||
<button on="tap:AMP.setState(foo='foo', isButtonDisabled=true, textClass='redBackground', imgSrc='https://ampbyexample.com/img/Shetland_Sheepdog.jpg', imgSize=200, imgAlt='Sheepdog', videoSrc='https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4')">Click me</button> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* Copyright 2016 The AMP HTML Authors. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS-IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import {bindForDoc} from '../../../src/bind'; | ||
import {isJsonScriptTag} from '../../../src/dom'; | ||
import {toggle} from '../../../src/style'; | ||
import {tryParseJson} from '../../../src/json'; | ||
import {user} from '../../../src/log'; | ||
|
||
export class AmpState extends AMP.BaseElement { | ||
/** @override */ | ||
getPriority() { | ||
// Loads after other content. | ||
return 1; | ||
} | ||
|
||
/** @override */ | ||
isAlwaysFixed() { | ||
return true; | ||
} | ||
|
||
/** @override */ | ||
isLayoutSupported(unusedLayout) { | ||
return true; | ||
} | ||
|
||
/** @override */ | ||
buildCallback() { | ||
const TAG = this.getName_(); | ||
|
||
toggle(this.element, false); | ||
this.element.setAttribute('aria-hidden', 'true'); | ||
|
||
const id = user().assert(this.element.id, | ||
'%s element must have an id.', TAG); | ||
|
||
let json; | ||
const children = this.element.children; | ||
if (children.length == 1) { | ||
const child = children[0]; | ||
if (isJsonScriptTag(child)) { | ||
json = tryParseJson(children[0].textContent, e => { | ||
user().error(TAG, 'Failed to parse state. Is it valid JSON?', e); | ||
}); | ||
} else { | ||
user().error(TAG, | ||
'State should be in a <script> tag with type="application/json"'); | ||
} | ||
} else if (children.length > 1) { | ||
user().error(TAG, 'Should contain only one <script> child.'); | ||
} | ||
|
||
if (id && json) { | ||
const state = Object.create(null); | ||
state[id] = json; | ||
|
||
bindForDoc(this.getAmpDoc()).then(bind => { | ||
bind.setState(state, true); | ||
}); | ||
} | ||
} | ||
|
||
/** @override */ | ||
renderOutsideViewport() { | ||
// We want the state data to be available wherever it is in the document. | ||
return true; | ||
} | ||
|
||
/** | ||
* @return {string} Returns a string to identify this tag. May not be unique | ||
* if the element id is not unique. | ||
* @private | ||
*/ | ||
getName_() { | ||
return '<amp-state> ' + | ||
(this.element.getAttribute('id') || '<unknown id>'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** | ||
* Copyright 2016 The AMP HTML Authors. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS-IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import {BindExpression} from './bind-expression'; | ||
|
||
/** | ||
* Asynchronously evaluates a set of Bind expressions. | ||
*/ | ||
export class BindEvaluator { | ||
/** | ||
* @param {!Array<string>} expressionStrings | ||
*/ | ||
constructor(expressionStrings) { | ||
/** @const {!Array<!BindExpression>} */ | ||
this.expressions_ = []; | ||
for (let i = 0; i < expressionStrings.length; i++) { | ||
this.expressions_[i] = new BindExpression(expressionStrings[i]); | ||
} | ||
} | ||
|
||
/** | ||
* Evaluates all expressions with the given `scope` data and resolves | ||
* the returned Promise with the results. | ||
* @param {!Object} scope | ||
* @return {!Promise<!Object<string,*>>} Maps expression strings to results. | ||
*/ | ||
evaluate(scope) { | ||
return new Promise(resolve => { | ||
/** @type {!Object<string,*>} */ | ||
const cache = {}; | ||
this.expressions_.forEach(expression => { | ||
const string = expression.expressionString; | ||
if (cache[string] === undefined) { | ||
cache[string] = expression.evaluate(scope); | ||
} | ||
}); | ||
resolve(cache); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* Copyright 2016 The AMP HTML Authors. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS-IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import {parser} from './bind-expr-impl'; | ||
|
||
/** | ||
* A single Bind expression. | ||
*/ | ||
export class BindExpression { | ||
/** | ||
* @param {string} expressionString | ||
*/ | ||
constructor(expressionString) { | ||
/** @const {string} */ | ||
this.expressionString = expressionString; | ||
} | ||
|
||
/** | ||
* Evaluates the expression given a scope. | ||
* @param {!Object} scope | ||
* @return {*} | ||
*/ | ||
evaluate(scope) { | ||
// TODO(choumx): Improve performance by extracting AST construction | ||
// and generating evaluator with Function constructor. | ||
try { | ||
parser.yy = scope; | ||
return parser.parse(this.expressionString); | ||
} finally { | ||
parser.yy = null; | ||
} | ||
} | ||
} |
Oops, something went wrong.