Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add element dependency with events #81

Merged
merged 10 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions examples/advanced_behaviors/dispatch_event/dispatch_event.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<doc xmlns="https://hyperview.org/hyperview">
<screen>
<styles>
<style id="Header"
alignItems="center"
backgroundColor="white"
borderBottomColor="#eee"
borderBottomWidth="1"
flexDirection="row"
height="72"
paddingLeft="24"
paddingRight="24"
paddingTop="24" />
<style id="Header__Back"
color="blue"
fontSize="16"
fontWeight="600"
paddingRight="16" />
<style id="Header__Title"
color="black"
fontSize="24"
fontWeight="600" />
<style id="Body"
backgroundColor="white"
flex="1" />
<style id="Description"
fontSize="16"
fontWeight="normal"
margin="24"
marginBottom="0" />
<style id="Item"
alignItems="center"
borderBottomColor="#eee"
borderBottomWidth="1"
flex="1"
flexDirection="row"
height="48"
justifyContent="space-between"
paddingLeft="24"
paddingRight="24" />
<style id="Item__Label"
fontSize="18"
fontWeight="normal" />
<style id="Item__Chevron"
fontSize="18"
fontWeight="bold" />
<style id="Button"
backgroundColor="#63CB76"
borderRadius="16"
flexDirection="row"
justifyContent="center"
margin="24"
padding="24" />
<style id="Button__Label"
color="white"
fontSize="24"
fontWeight="bold" />
<style id="Main"
flex="1" />
<style id="Containers"
flex="1"
flexDirection="row"
marginLeft="24"
marginRight="24" />
<style id="Container"
flex="1" />
<style id="Append"
marginLeft="24"
fontSize="16"
color="hotpink"
/>
</styles>
<body style="Body">
<header style="Header">
<text action="back"
href="#"
style="Header__Back">Back</text>
<text style="Header__Title">Dispatch Event</text>
</header>
<view action="append" trigger="on-event" event-name="test-event" scroll="true" href="/advanced_behaviors/dispatch_event/dispatch_event_append.xml"
style="Main">
<text style="Description">Dispatch events to load screens</text>
<view style="Button" href="/advanced_behaviors/dispatch_event/dispatch_event_source.xml">
<text style="Button__Label">Open new screen</text>
</view>
</view>
</body>
</screen>
</doc>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<text xmlns="https://hyperview.org/hyperview" style="Append">This just got added from an event!</text>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<doc xmlns="https://hyperview.org/hyperview">
<screen>
<styles>
<style id="Header"
alignItems="center"
backgroundColor="white"
borderBottomColor="#eee"
borderBottomWidth="1"
flexDirection="row"
height="72"
paddingLeft="24"
paddingRight="24"
paddingTop="24" />
<style id="Header__Back"
color="blue"
fontSize="16"
fontWeight="600"
paddingRight="16" />
<style id="Header__Title"
color="black"
fontSize="24"
fontWeight="600" />
<style id="Body"
backgroundColor="white"
flex="1" />
<style id="Description"
fontSize="16"
fontWeight="normal"
margin="24"
marginBottom="0" />
<style id="Item"
alignItems="center"
borderBottomColor="#eee"
borderBottomWidth="1"
flex="1"
flexDirection="row"
height="48"
justifyContent="space-between"
paddingLeft="24"
paddingRight="24" />
<style id="Item__Label"
fontSize="18"
fontWeight="normal" />
<style id="Item__Chevron"
fontSize="18"
fontWeight="bold" />
<style id="Button"
backgroundColor="#63CB76"
borderRadius="16"
flexDirection="row"
justifyContent="center"
margin="24"
padding="24" />
<style id="Button__Label"
color="white"
fontSize="24"
fontWeight="bold" />
<style id="Main"
flex="1" />
<style id="Containers"
flex="1"
flexDirection="row"
marginLeft="24"
marginRight="24" />
<style id="Container"
flex="1" />
</styles>
<body style="Body">
<header style="Header">
<text action="back"
href="#"
style="Header__Back">Back</text>
<text style="Header__Title">Dispatch Event Source</text>
</header>
<view scroll="true"
style="Main">
<text style="Description">Dispatch events to load previous screen</text>
<view style="Button">
<behavior trigger="press" action="dispatch-event" event-name="test-event" />
<text style="Button__Label">Reload previous</text>
</view>
</view>
</body>
</screen>
</doc>
7 changes: 7 additions & 0 deletions examples/advanced_behaviors/index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@
<text style="Item__Label">Custom: Share</text>
<text style="Item__Chevron">&gt;</text>
</item>
<item href="/advanced_behaviors/dispatch_event/dispatch_event.xml"
key="dispatch_event"
show-during-load="loadingScreen"
style="Item">
<text style="Item__Label">Dispatch Event</text>
<text style="Item__Chevron">&gt;</text>
</item>
</list>
</body>
</screen>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"test": "yarn generate test && yarn test:flow && yarn test:lint && yarn test:render && yarn test:unit"
},
"dependencies": {
"tiny-emitter": "2.1.0",
"url-parse": "1.4.3",
"xmldom": "0.1.27"
},
Expand Down
49 changes: 49 additions & 0 deletions src/core/hyper-ref/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
} from 'hyperview/src/types';
import {
NAV_ACTIONS,
ON_EVENT_DISPATCH,
PRESS_TRIGGERS,
TRIGGERS,
UPDATE_ACTIONS,
Expand All @@ -25,6 +26,9 @@ import type { PressHandlers, Props, State } from './types';
import React, { PureComponent } from 'react';
import { RefreshControl, ScrollView, TouchableOpacity } from 'react-native';
import VisibilityDetectingView from 'hyperview/src/VisibilityDetectingView';
import { XMLSerializer } from 'xmldom';
// eslint-disable-next-line import/no-internal-modules
import eventEmitter from 'tiny-emitter/instance';
import { getBehaviorElements } from 'hyperview/src/services';

/**
Expand All @@ -40,6 +44,9 @@ export default class HyperRef extends PureComponent<Props, State> {

componentDidMount() {
this.triggerLoadBehaviors();

// Register event listener for on-event triggers
eventEmitter.on(ON_EVENT_DISPATCH, this.onEventDispatch);
}

componentDidUpdate(prevProps: Props) {
Expand All @@ -49,6 +56,48 @@ export default class HyperRef extends PureComponent<Props, State> {
this.triggerLoadBehaviors();
}

componentWillUnmount() {
// Remove event listener for on-event triggers to avoid memory leaks
eventEmitter.off(ON_EVENT_DISPATCH, this.onEventDispatch);
}

onEventDispatch = (eventName: string) => {
const behaviorElements = getBehaviorElements(this.props.element);
const onEventBehaviors = behaviorElements.filter(e => {
if (e.getAttribute(ATTRIBUTES.TRIGGER) === TRIGGERS.ON_EVENT) {
const currentAttributeEventName: ?string = e.getAttribute('event-name');
const currentAttributeAction: ?string = e.getAttribute('action');
if (currentAttributeAction === 'dispatch-event') {
throw new Error(
'trigger="on-event" and action="dispatch-event" cannot be used on the same element',
);
}
if (!currentAttributeEventName) {
throw new Error('on-event trigger requires an event-name attribute');
}
return currentAttributeEventName === eventName;
}
return false;
});
onEventBehaviors.forEach(behaviorElement => {
const handler = this.createActionHandler(
this.props.element,
behaviorElement,
this.props.onUpdate,
);
handler();
if (__DEV__) {
const listenerElement: Element = behaviorElement.cloneNode(false);
const caughtEvent: string = behaviorElement.getAttribute('event-name');
const serializer = new XMLSerializer();
console.log(
`[on-event] trigger [${caughtEvent}] caught by:`,
serializer.serializeToString(listenerElement),
);
}
});
};

createActionHandler = (
element: Element,
behaviorElement: Element,
Expand Down
43 changes: 41 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import {
View,
} from 'react-native';
import { DOMParser, XMLSerializer } from 'xmldom';
import HyperRef from 'hyperview/src/core/hyper-ref';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scrollview';
import Navigation from 'hyperview/src/services/navigation';
import React from 'react';
import VisibilityDetectingView from './VisibilityDetectingView.js';
import { addHref, createProps, getBehaviorElements, getFirstTag, later } from 'hyperview/src/services';
import { version } from '../package.json';
import { ACTIONS, FORM_NAMES, NAV_ACTIONS, UPDATE_ACTIONS } from 'hyperview/src/types';
import { ACTIONS, FORM_NAMES, NAV_ACTIONS, ON_EVENT_DISPATCH, UPDATE_ACTIONS } from 'hyperview/src/types';
import urlParse from 'url-parse';
import eventEmitter from 'tiny-emitter/instance';

const AMPLITUDE_NS = Namespaces.AMPLITUDE;
const HYPERVIEW_ALERT_NS = Namespaces.HYPERVIEW_ALERT;
Expand Down Expand Up @@ -495,6 +495,45 @@ export default class HyperScreen extends React.Component {
this.onUpdateFragment(href, action, currentElement, opts);
} else if (action === ACTIONS.SWAP) {
this.onSwap(currentElement, opts.newElement);
} else if (action === ACTIONS.DISPATCH_EVENT) {
const { behaviorElement } = opts;
const eventName = behaviorElement.getAttribute('event-name');
const trigger = behaviorElement.getAttribute('trigger');
const ranOnce = behaviorElement.getAttribute('ran-once');
const once = behaviorElement.getAttribute('once');
const delay = behaviorElement.getAttribute('delay');
flochtililoch marked this conversation as resolved.
Show resolved Hide resolved

if (once === 'true' && ranOnce === 'true') {
return;
} else if (once === 'true') {
behaviorElement.setAttribute('ran-once', 'true');
}

// Check for event loop formation
if (trigger === 'on-event') {
throw new Error('trigger="on-event" and action="dispatch-event" cannot be used on the same element');
}
if (!eventName) {
throw new Error('dispatch-event requires an event-name attribute to be present');
}

const dispatchEvent = () => {
// Log the dispatched action before emitting to ensure it appears first in logs
if (__DEV__) {
const emitterElement: Element = behaviorElement.cloneNode(false);
console.log(
`[dispatch-event] action [${eventName}] emitted by:`,
this.serializer.serializeToString(emitterElement),
);
}
eventEmitter.emit(ON_EVENT_DISPATCH, eventName);
}

if (delay) {
setTimeout(dispatchEvent, parseInt(delay, 10));
} else {
dispatchEvent();
}
} else {
const { behaviorElement } = opts;
this.onCustomUpdate(behaviorElement);
Expand Down
4 changes: 4 additions & 0 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ export const TRIGGERS = Object.freeze({
DESELECT: 'deselect',
LOAD: 'load',
LONG_PRESS: 'longPress',
ON_EVENT: 'on-event',
PRESS_IN: 'pressIn',
PRESS_OUT: 'pressOut',
PRESS: 'press',
Expand All @@ -337,6 +338,7 @@ export const ACTIONS = {
BACK: 'back',
CLOSE: 'close',
DEEP_LINK: 'deep-link',
DISPATCH_EVENT: 'dispatch-event',
NAVIGATE: 'navigate',
NEW: 'new',
PREPEND: 'prepend',
Expand Down Expand Up @@ -388,3 +390,5 @@ export type NavigationProps = {|
push: (routeParams: NavigationRouteParams) => void,
replace: (routeParams: NavigationRouteParams) => void,
|};

export const ON_EVENT_DISPATCH = 'hyperview:on-event';
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8456,6 +8456,11 @@ timers-browserify@^2.0.4:
dependencies:
setimmediate "^1.0.4"

tiny-emitter@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==

tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
Expand Down