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

Improved Link component #215

Merged
merged 10 commits into from Jul 12, 2018
@@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.23.1]
### fixed
- Link component now is a proper <a> tag so you can right click on it, and will scroll back to top. [#99](https://github.com/plotly/dash-core-components/issues/99)

This comment has been minimized.

Copy link
@chriddyp

chriddyp Jul 10, 2018

Member

Maybe say "Fixes #99, implemented in #215"

Link component now is a proper tag. This allows you to right-click on dcc.Link and see the standard html link context menu. Also, clicking on a dcc.Link will now scroll the next page to the top, rather than keeping the scroll position at the position of the previous page.


## [0.23.0]
### Added
- Upgraded Plotly.js, the underlying library behind the
@@ -32,7 +32,7 @@
'external_url': (
'https://unpkg.com/dash-core-components@{}'
'/dash_core_components/bundle.js'
).format(__version__),
).format('0.23.1-rc1'),
'namespace': 'dash_core_components'
}
]

Large diffs are not rendered by default.

@@ -139,73 +139,6 @@
}
}
},
"src/components/Confirm.react.js": {
"description": "Confirm wraps window.confirm",
"displayName": "Confirm",
"methods": [],
"props": {
"id": {
"type": {
"name": "string"
},
"required": false,
"description": ""
},
"message": {
"type": {
"name": "string"
},
"required": false,
"description": ""
},
"init": {
"type": {
"name": "shape",
"value": {
"value": {
"name": "any",
"required": false
},
"ask": {
"name": "bool",
"required": false
}
}
},
"required": false,
"description": ""
},
"result": {
"type": {
"name": "shape",
"value": {
"timestamp": {
"name": "custom",
"raw": "PropTypes.integer",
"required": false
},
"value": {
"name": "any",
"required": false
}
}
},
"required": false,
"description": "",
"defaultValue": {
"value": "{\n timestamp: -1\n}",
"computed": false
}
},
"setProps": {
"type": {
"name": "func"
},
"required": false,
"description": "Dash-assigned callback that gets fired when the value changes."
}
}
},
"src/components/DatePickerRange.react.js": {
"description": "DatePickerRange is a tailor made component designed for selecting\ntimespan across multiple days off of a calendar.\n\nThe DatePicker integrates well with the Python datetime module with the\nstartDate and endDate being returned in a string format suitable for\ncreating datetime objects.\n\nThis component is based off of Airbnb's react-dates react component\nwhich can be found here: https://github.com/airbnb/react-dates",
"displayName": "DatePickerRange",
@@ -1724,7 +1657,12 @@
"name": "updateLocation",
"docblock": null,
"modifiers": [],
"params": [],
"params": [
{
"name": "e",
"type": null
}
],
"returns": null
}
],
@@ -1 +1 @@
__version__ = '0.23.0'
__version__ = '0.23.1rc1'
@@ -1,6 +1,6 @@
{
"name": "dash-core-components",
"version": "0.23.0",
"version": "0.23.1-rc1",
"description": "Core component suite for Dash",
"repository": {
"type": "git",
@@ -8,15 +8,14 @@ import React, {Component} from 'react';
* event polyfill for IE
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
*/
function CustomEvent (event, params) {
function CustomEvent(event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(
event, params.bubbles, params.cancelable, params.detail);
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
@@ -27,28 +26,32 @@ export default class Link extends Component {
this.updateLocation = this.updateLocation.bind(this);
}

updateLocation() {
const {href, refresh} = this.props;
updateLocation(e) {
e.preventDefault(); // prevent anchor from updating location
const { href, refresh } = this.props;
if (refresh) {
window.location.pathname = href;
} else {
window.history.pushState({}, '', href);
window.dispatchEvent(new CustomEvent('onpushstate'));
}
window.scrollTo(0, 0); // scroll back to top

This comment has been minimized.

Copy link
@chriddyp

chriddyp Jul 10, 2018

Member

Very sweet. For some reason I thought we would need to do this after the content was updated, but after playing around with it seems like this totally works 👏

}

render() {
const {className, style, id} = this.props;
const { className, style, id, href } = this.props;
/*
* ideally, we would use cloneElement however
* that doesn't work with dash's recursive
* renderTree implementation for some reason
*/
* ideally, we would use cloneElement however
* that doesn't work with dash's recursive
* renderTree implementation for some reason
*/
return (
<a id={id}
className={className}
style={style}
onClick={this.updateLocation}
<a
id={id}
className={className}
style={style}
href={href}
onClick={e => this.updateLocation(e)}
>
{this.props.children}
</a>
@@ -494,6 +494,43 @@ def update_pathname(n_clicks, current_pathname):
self.wait_for_text_to_equal('#test-hash', '')
self.snapshot('link -- /test/pathname/a?queryA=valueA')

def test_link_scroll(self):
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Location(id='test-url', refresh=False),

html.Div(id='push-to-bottom', children=[], style={
'display': 'block',
'height': '200vh'
}),
html.Div(id='page-content'),
dcc.Link('Test link', href='/test-link', id='test-link')
])

@app.callback(Output('page-content', 'children'),
[Input('test-url', 'pathname')])
def display_page(pathname):
return 'You are on page {}'.format(pathname)

This comment has been minimized.

Copy link
@chriddyp

chriddyp Jul 10, 2018

Member

Let's increment a multiprocessing.Value in here so that we can ensure that the callback is only fired a single time.
Here's an example of incrementing Value in a callback:
https://github.com/plotly/dash-renderer/blob/70bb93e8f0151ddc7d0810f3df271036a069360a/tests/test_render.py#L458-L463

and further down, the assertion:
https://github.com/plotly/dash-renderer/blob/70bb93e8f0151ddc7d0810f3df271036a069360a/tests/test_render.py#L478-L484


self.startServer(app=app)

# test if link correctly scrolls back to top of page
test_link = self.wait_for_element_by_css_selector('#test-link')
test_link.send_keys(Keys.NULL)
self.snapshot('link on bottom of page - initial')
test_link.click()
time.sleep(2)
self.snapshot('link on bottom of page - after clicking (should be scrolled back to top)')

# test link still fires update on Location
page_content = self.wait_for_element_by_css_selector('#page-content')
self.assertNotEquals(page_content.text, 'You are on page /')
self.assertEquals(page_content.text, 'You are on page /test-link')

#test if rendered Link's <a> tag has a href attribute
link_href = test_link.get_attribute("href")
self.assertEqual(link_href, 'http://localhost:8050/test-link')

def test_candlestick(self):
app = dash.Dash(__name__)
app.layout = html.Div([
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.