Skip to content

Instantly share code, notes, and snippets.

@bigopon
Forked from jdanyow/app.html
Created January 5, 2017 12:44
Show Gist options
  • Save bigopon/3de3547be0993f155eb831e4af4aadc7 to your computer and use it in GitHub Desktop.
Save bigopon/3de3547be0993f155eb831e4af4aadc7 to your computer and use it in GitHub Desktop.
Aurelia capture binding command
<template>
<style>
.active {
border-color: blue;
}
</style>
<form blur.capture="currentFieldSet = null"
focus.capture="currentFieldSet = $event.target.closest('fieldset')">
<h1>Order Pizza:</h1>
<fieldset ref="sizeFieldSet"
class="${currentFieldSet === sizeFieldSet ? 'active' : '' }">
<legend>Choose Size:</legend>
<label repeat.for="size of sizes" for.bind="size">
<input type="radio" id.bind="size" name="size" value.bind="size"> ${size}
</label>
</fieldset>
<fieldset ref="toppingsFieldSet"
class="${currentFieldSet === toppingsFieldSet ? 'active' : '' }">
<legend>Choose Toppings:</legend>
<label repeat.for="topping of toppings" for.bind="topping">
<input type="checkbox" id.bind="topping" name="topping" value.bind="topping"> ${topping}
</label>
</fieldset>
</form>
</template>
export class App {
sizes = ['Small', 'Medium', 'Large'];
toppings = ['Pepperoni', 'Sausage', 'Anchovies', 'Peppers', 'Onions', 'Mushrooms'];
blurred() {
console.log('blurred!');
}
}
import {DOM} from 'aurelia-pal';
import {EventManager, ListenerExpression} from 'aurelia-binding';
import {SyntaxInterpreter} from 'aurelia-templating-binding';
//Note: path and deepPath are designed to handle v0 and v1 shadow dom specs respectively
function findOriginalEventTarget(event) {
return (event.path && event.path[0]) || (event.deepPath && event.deepPath[0]) || event.target;
}
function interceptStopPropagation(event) {
event.standardStopPropagation = event.stopPropagation;
event.stopPropagation = function() {
this.propagationStopped = true;
this.standardStopPropagation();
};
}
function handleCapturedEvent(event) {
let interceptInstalled = false;
event.propagationStopped = false;
let target = findOriginalEventTarget(event);
while (target && !event.propagationStopped) {
if (target.capturedCallbacks) {
let callback = target.capturedCallbacks[event.type];
if (callback) {
if (!interceptInstalled) {
interceptStopPropagation(event);
interceptInstalled = true;
}
callback(event);
}
}
target = target.parentNode;
}
}
const eventInit = { capture: true };
class CapturedHandlerEntry {
constructor(eventName) {
this.eventName = eventName;
this.count = 0;
}
increment() {
this.count++;
if (this.count === 1) {
document.body.addEventListener(this.eventName, handleCapturedEvent, eventInit);
}
}
decrement() {
this.count--;
if (this.count === 0) {
document.body.removeEventListener(this.eventName, handleCapturedEvent);
}
}
}
// this would actually be integrated into binding's DefaultEventStrategy.subscribe...
// it's currently not exported so we have to override EventManager.addEventListener instead...
class DefaultEventStrategy2 {
capturedHandlers = {};
subscribe(target, targetEvent, callback, delegate) {
const capturedHandlers = this.capturedHandlers;
const handlerEntry = capturedHandlers[targetEvent] || (capturedHandlers[targetEvent] = new CapturedHandlerEntry(targetEvent));
const capturedCallbacks = target.capturedCallbacks || (target.capturedCallbacks = {});
handlerEntry.increment();
capturedCallbacks[targetEvent] = callback;
return function() {
handlerEntry.decrement();
capturedCallbacks[targetEvent] = null;
};
}
}
const strategy2 = new DefaultEventStrategy2();
// quick and dirty defaultEventStrategy override... not how we'd really do this...
EventManager.prototype.addEventListener = function(target, targetEvent, callback, delegate) {
return (this.eventStrategyLookup[targetEvent] || (delegate === 'capture' ? strategy2 : this.defaultEventStrategy))
.subscribe(target, targetEvent, callback, delegate);
}
// add the "capture" binding command:
SyntaxInterpreter.prototype.capture = function(resources, element, info) {
return new ListenerExpression(
this.eventManager,
info.attrName,
this.parser.parse(info.attrValue),
'capture', // hack: passing "capture" into the "delegate" parameter (which expects a boolean)
true,
resources.lookupFunctions
);
};
<!doctype html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body aurelia-app="main">
<h1>Loading...</h1>
<script src="https://jdanyow.github.io/rjs-bundle/node_modules/requirejs/require.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/config.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/babel.js"></script>
<script>
require(['aurelia-bootstrapper']);
</script>
</body>
</html>
import './capture';
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start().then(() => aurelia.setRoot());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment