Skip to content

Commit

Permalink
Merge branch 'feature/clipboard-html' into autofeather-dash
Browse files Browse the repository at this point in the history
  • Loading branch information
Lxstr committed Oct 30, 2023
2 parents 22829f9 + 26bf6ab commit 69aa6cb
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 6 deletions.
41 changes: 36 additions & 5 deletions components/dash-core-components/src/components/Clipboard.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ export default class Clipboard extends React.Component {
};
}

componentDidUpdate(prevProps) {
// If the data hasn't changed, do nothing.
if (!this.props.content || this.props.content === prevProps.content) {
return;
}
// If the data has changed, copy to clipboard
this.copyToClipboard();
}

// stringifies object ids used in pattern matching callbacks
stringifyId(id) {
if (typeof id !== 'object') {
Expand All @@ -38,9 +47,23 @@ export default class Clipboard extends React.Component {
return '{' + parts.join(',') + '}';
}

async copySuccess(content) {
async copySuccess(content, htmlContent) {
const showCopiedIcon = 1000;
await clipboardAPI.writeText(content);
if (htmlContent) {
const blobHtml = new Blob([htmlContent], {type: 'text/html'});
const blobText = new Blob([content ?? htmlContent], {
type: 'text/plain',
});
const data = [
new ClipboardItem({
['text/plain']: blobText,
['text/html']: blobHtml,
}),
];
await navigator.clipboard.write(data);
} else {
await clipboardAPI.writeText(content);
}
this.setState({copied: true});
await wait(showCopiedIcon);
this.setState({copied: false});
Expand Down Expand Up @@ -76,15 +99,17 @@ export default class Clipboard extends React.Component {
});

let content;
let htmlContent;
if (this.props.target_id) {
content = this.getTargetText();
} else {
await wait(100); // gives time for callback to start
await this.loading();
content = this.props.content;
htmlContent = this.props.html_content;
}
if (content) {
this.copySuccess(content);
if (content || htmlContent) {
this.copySuccess(content, htmlContent);
}
}

Expand Down Expand Up @@ -119,6 +144,7 @@ export default class Clipboard extends React.Component {

Clipboard.defaultProps = {
content: null,
html_content: null,
target_id: null,
n_clicks: 0,
};
Expand All @@ -137,7 +163,7 @@ Clipboard.propTypes = {
target_id: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),

/**
* The text to be copied to the clipboard if the `target_id` is None.
* The text to be copied to the clipboard if the `target_id` is None.
*/
content: PropTypes.string,

Expand All @@ -146,6 +172,11 @@ Clipboard.propTypes = {
*/
n_clicks: PropTypes.number,

/**
* The clipboard html text be copied to the clipboard if the `target_id` is None.
*/
html_content: PropTypes.string,

/**
* The text shown as a tooltip when hovering over the copy icon.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dash import Dash, html, dcc
from dash import Dash, html, dcc, callback, Output, Input

import dash.testing.wait as wait
import time
Expand Down Expand Up @@ -54,3 +54,32 @@ def test_clp002_clipboard_text(dash_dcc_headed):
== copy_text,
timeout=3,
)

def test_clp003_clipboard_text(dash_dcc_headed):
copy_text = "Copy this text to the clipboard using a separate button"
app = Dash(__name__, prevent_initial_callbacks=True)
app.layout = html.Div(
[dcc.Clipboard(id="copy_icon", content=copy_text), dcc.Textarea(id="paste"), html.Button("Copy", id="copy_button")]
)
@callback(
Output("copy_icon", "content"),
Input("copy_button", "n_clicks"),
prevent_initial_call=True,
)
def selected(clicks):
return f"{clicks}"

dash_dcc_headed.start_server(app)

dash_dcc_headed.find_element("#copy_button").click()
time.sleep(1)
dash_dcc_headed.find_element("#paste").click()
ActionChains(dash_dcc_headed.driver).key_down(Keys.CONTROL).send_keys("v").key_up(
Keys.CONTROL
).perform()

wait.until(
lambda: dash_dcc_headed.find_element("#paste").get_attribute("value")
== copy_text,
timeout=3,
)

0 comments on commit 69aa6cb

Please # to comment.