You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2016/12/23 16:39:47 UTC
fauxton commit: updated refs/heads/master to 2e770d6
Repository: couchdb-fauxton
Updated Branches:
refs/heads/master 2a3dccaf4 -> 2e770d66b
rip and replace zeroclipboard with clipboardjs
PR: #825
PR-URL: https://github.com/apache/couchdb-fauxton/pull/825
Reviewed-By: Robert Kowalski <ro...@kowalski.gd>
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/2e770d66
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/2e770d66
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/2e770d66
Branch: refs/heads/master
Commit: 2e770d66b2b849a60468ad390dfed57da54561a9
Parents: 2a3dcca
Author: Ryan Millay <ry...@gmail.com>
Authored: Mon Dec 19 15:38:11 2016 -0500
Committer: Robert Kowalski <ro...@apache.org>
Committed: Fri Dec 23 17:39:30 2016 +0100
----------------------------------------------------------------------
.../activetasks/assets/less/activetasks.less | 45 ------
app/addons/activetasks/components.react.jsx | 62 +--------
app/addons/components/__tests__/copy.test.js | 39 ++++++
app/addons/components/components/apibar.js | 15 +-
app/addons/components/components/copy.js | 100 ++++++++++++++
.../components/react-components.react.jsx | 4 +-
.../tests/nightwatch/copyToClipboard.js | 92 +++++++++++++
.../tests/nightwatch/deletesDatabase.js | 2 +
.../nightwatch/deletesDatabaseSpecialChars.js | 3 +-
.../documents/changes/components.react.jsx | 15 +-
.../designdocinfo/components.react.jsx | 11 +-
.../index-results.components.react.jsx | 12 +-
app/addons/fauxton/assets/less/components.less | 9 +-
app/addons/fauxton/components.react.jsx | 136 +------------------
.../notifications/notifications.react.jsx | 8 +-
.../fauxton/tests/componentsSpec.react.jsx | 19 ---
assets/less/notification-center.less | 5 +-
jest-setup.js | 1 -
package.json | 5 +-
19 files changed, 282 insertions(+), 301 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/activetasks/assets/less/activetasks.less
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/assets/less/activetasks.less b/app/addons/activetasks/assets/less/activetasks.less
index cad281c..94444c9 100644
--- a/app/addons/activetasks/assets/less/activetasks.less
+++ b/app/addons/activetasks/assets/less/activetasks.less
@@ -141,51 +141,6 @@
color: @brandPrimaryDark;
}
}
-
- .view-source-sequence-btn { // "View" Button
- background-color: #999;
- display: inline;
- border-radius: 3px;
- padding: 2px;
- margin: 3px;
- color: #fff !important;
- white-space: nowrap;
- }
-
- .view-source-sequence-tray {
- padding: 16px 20px 28px;
-
- position: relative;
- min-width: 365px;
- top: 15px;
- float: right;
-
- &:before {
- right: 110px;
- }
- input.input-xxlarge {
- margin-bottom: 0px;
- width: 250px;
- .border-radius(5px 0 0 5px);
- }
-
- a.btn {
- color: white;
- background-color: @linkColor;
- margin-left: 0;
- line-height: 1.5em;
- border: 0px;
- padding: 10px 10px 9px;
- font-size: 14px;
- .border-radius(0 5px 5px 0);
-
-
- &:hover, &.copy-button.zeroclipboard-is-hover {
- background-color: #cbcbcb;
- color: white;
- }
- }
- }
}
.active-tasks__polling-wrapper {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/activetasks/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/components.react.jsx b/app/addons/activetasks/components.react.jsx
index f739823..33c6c4c 100644
--- a/app/addons/activetasks/components.react.jsx
+++ b/app/addons/activetasks/components.react.jsx
@@ -365,71 +365,12 @@ var ActiveTaskTableBodyContents = React.createClass({
<td>{startedOnMsg}</td>
<td>{updatedOnMsg}</td>
<td>{rowData.pid}</td>
- <td>{progressMsg}<ActiveTasksViewSourceSequence item={this.props.item}/></td>
+ <td>{progressMsg}</td>
</tr>
);
}
});
-var ActiveTasksViewSourceSequence = React.createClass({
- getInitialState () {
- return {
- contentVisible: false
- };
- },
-
- toggleTray (e) {
- e.preventDefault();
- this.setState({contentVisible: !this.state.contentVisible});
- },
-
- closeTray () {
- this.setState({contentVisible: false});
- },
-
- sequences (item) {
- if (_.isNumber(item) || _.isString(item)) {
- return <ComponentsReact.ClipboardWithTextField onClipBoardClick={() => {}} textToCopy={item.toString()} uniqueKey={item.toString()}/>;
- }
-
- if (_.isArray(item)) {
- return _.map(item, function (seq, i) {
- return <ComponentsReact.ClipboardWithTextField onClipBoardClick={() => {}} textToCopy={seq.toString()} uniqueKey={`${i + Math.random(100)}`} key={i}/>;
- });
- }
-
- return <ComponentsReact.ClipboardWithTextField textToCopy="???" onClipBoardClick={() => {}} uniqueKey='unknownRevision'/>;
- },
-
- render () {
- if (!_.has(this.props.item, 'source_seq')) {
- return null;
- }
-
- const sequences = this.sequences(this.props.item.source_seq);
- return (
- <div>
- Current source sequence:
- <a href="#"
- className="view-source-sequence-btn"
- onClick={this.toggleTray}
- data-bypass="true">
- View
- </a>
- <TrayContents
- ref="view_source_sequence_btn"
- contentVisible={this.state.contentVisible}
- closeTray={this.closeTray}
- container={this}
- className="view-source-sequence-tray">
- <span className="add-on">Source Sequence</span>
- {sequences}
- </TrayContents>
- </div>
- );
- }
-});
-
export const ActiveTasksPollingWidgetController = React.createClass({
getStoreState () {
@@ -542,7 +483,6 @@ export default {
TableHeader: TableHeader,
ActiveTasksTableBody: ActiveTasksTableBody,
ActiveTaskTableBodyContents: ActiveTaskTableBodyContents,
- ActiveTasksViewSourceSequence: ActiveTasksViewSourceSequence,
ActiveTasksPollingWidgetController: ActiveTasksPollingWidgetController
};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/components/__tests__/copy.test.js
----------------------------------------------------------------------
diff --git a/app/addons/components/__tests__/copy.test.js b/app/addons/components/__tests__/copy.test.js
new file mode 100644
index 0000000..64216c7
--- /dev/null
+++ b/app/addons/components/__tests__/copy.test.js
@@ -0,0 +1,39 @@
+// 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 { Copy } from "../components/copy";
+import { mount } from "enzyme";
+import React from "react";
+import ReactDOM from "react-dom";
+import uuid from 'uuid';
+
+describe('Copy', () => {
+
+ it('shows a copy icon by default', () => {
+ const wrapper = mount(<Copy uniqueKey={uuid.v4()} text="copy me"/>);
+ expect(wrapper.find('.icon-paste').length).toBe(1);
+ });
+
+ it('shows text if specified', () => {
+ const wrapper = mount(<Copy uniqueKey={uuid.v4()} text="copy me" displayType="text" />);
+ expect(wrapper.find('.icon-paste').length).toBe(0);
+ });
+
+ it('shows custom text if specified', () => {
+ const wrapper = mount(<Copy uniqueKey={uuid.v4()} displayType="text" textDisplay="booyah!" text="copy me" />);
+ expect(wrapper.html()).toMatch(/booyah!/);
+ });
+
+ it('shows an input field and button if specified', () => {
+ const wrapper = mount(<Copy uniqueKey={uuid.v4()} displayType='input' text="http://localhost:8000/_all_dbs" />);
+ expect(wrapper.find('input').length).toBe(1);
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/components/components/apibar.js
----------------------------------------------------------------------
diff --git a/app/addons/components/components/apibar.js b/app/addons/components/components/apibar.js
index 6718604..e51e418 100644
--- a/app/addons/components/components/apibar.js
+++ b/app/addons/components/components/apibar.js
@@ -14,11 +14,12 @@ import React from "react";
import ReactDOM from "react-dom";
import FauxtonAPI from "../../../core/api";
import {TrayContents, TrayWrapper, connectToStores} from './tray';
-import FauxtonComponents from "../../fauxton/components.react";
+import { Copy } from "./copy";
import Actions from "../actions";
import Stores from "../stores";
import {ToggleHeaderButton} from './toggleheaderbutton';
const { componentStore } = Stores;
+import uuid from 'uuid';
export const APIBar = React.createClass({
propTypes: {
@@ -62,12 +63,12 @@ export const APIBar = React.createClass({
{this.getDocIcon()}
</span>
- <FauxtonComponents.ClipboardWithTextField
- onClipBoardClick={this.showCopiedMessage}
- text="Copy URL"
- textToCopy={endpoint}
- showCopyIcon={false}
- uniqueKey="clipboard-apiurl" />
+ <Copy
+ textDisplay="Copy URL"
+ text={endpoint}
+ displayType="input"
+ uniqueKey={uuid.v4()}
+ onClipboardClick={this.showCopiedMessage} />
<div className="add-on">
<a
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/components/components/copy.js
----------------------------------------------------------------------
diff --git a/app/addons/components/components/copy.js b/app/addons/components/components/copy.js
new file mode 100644
index 0000000..2c00793
--- /dev/null
+++ b/app/addons/components/components/copy.js
@@ -0,0 +1,100 @@
+// 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 React from 'react';
+import ReactDOM from 'react-dom';
+import Clipboard from 'clipboard';
+
+let clipboard;
+
+// Locates the specific element on the DOM, configures the clipboard, and
+// sets the callback on 'success' (usually a Fauxton notification).
+export const initializeClipboard = (uniqueKey, cb) => {
+ clipboard = new Clipboard('#copy-' + uniqueKey);
+ clipboard.on('success', function(e) {
+ cb();
+ });
+};
+
+// Cleans up the fake elements left around by clipboard.js
+export const destroyClipboard = () => {
+ clipboard.destroy();
+};
+
+export class Copy extends React.Component {
+ componentDidMount () {
+ initializeClipboard(this.props.uniqueKey, this.props.onClipboardClick);
+ }
+
+ componentWillUnmount () {
+ destroyClipboard();
+ }
+
+ // Necessary for copy elements that are not unmounted even though they are
+ // no longer visible (ex. Notification rows in the notification center).
+ componentDidUpdate () {
+ initializeClipboard(this.props.uniqueKey, this.props.onClipboardClick);
+ }
+
+ getClipboardElement () {
+ if (this.props.displayType === 'icon') {
+ return (<i className="fontawesome icon-paste"></i>);
+ }
+ return this.props.textDisplay;
+ }
+
+ getClipboardButton () {
+ const btnClasses = this.props.displayType === 'input' ? "btn copy-button" : "copy" + " clipboard-copy-element";
+ return (
+ <button
+ className={btnClasses}
+ data-clipboard-text={this.props.text}
+ title={this.props.title}
+ id={"copy-" + this.props.uniqueKey}
+ >
+ {this.getClipboardElement()}
+ </button>
+ );
+ }
+
+ render () {
+ if (this.props.displayType === 'input') {
+ return (
+ <p>
+ <input
+ type="text"
+ className="input-xxlarge text-field-to-copy"
+ readOnly
+ value={this.props.text} />
+ {this.getClipboardButton()}
+ </p>
+ );
+ }
+ return (
+ this.getClipboardButton()
+ );
+ }
+};
+
+Copy.defaultProps = {
+ displayType: 'icon',
+ textDisplay: 'Copy',
+ title: 'Copy to clipboard',
+ onClipboardClick: function () { }
+};
+
+Copy.propTypes = {
+ text: React.PropTypes.string.isRequired,
+ displayType: React.PropTypes.oneOf(['icon', 'text', 'input']),
+ uniqueKey: React.PropTypes.string.isRequired,
+ onClipboardClick: React.PropTypes.func.isRequired
+};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx b/app/addons/components/react-components.react.jsx
index 6c8fdcd..c404871 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -29,6 +29,7 @@ import {ApiBarController} from './components/apibar';
import {DeleteDatabaseModal} from './components/deletedatabasemodal';
import {TabElement, TabElementWrapper} from './components/tabelement';
import {Polling, RefreshBtn} from './components/polling';
+import {Copy} from './components/copy';
export default {
BadgeList,
@@ -54,5 +55,6 @@ export default {
DeleteDatabaseModal,
TabElement,
TabElementWrapper,
- RefreshBtn
+ RefreshBtn,
+ Copy
};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/components/tests/nightwatch/copyToClipboard.js
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/nightwatch/copyToClipboard.js b/app/addons/components/tests/nightwatch/copyToClipboard.js
new file mode 100644
index 0000000..1b9942a
--- /dev/null
+++ b/app/addons/components/tests/nightwatch/copyToClipboard.js
@@ -0,0 +1,92 @@
+// 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.
+
+
+module.exports = {
+
+ // Since we can't directly access the clipboard to verify, we'll confirm that
+ // the text to copy is correct and the successful callback is displayed.
+
+ 'Copy API URL to Clipboard Test' : (client) => {
+
+ const waitTime = client.globals.maxWaitTime;
+ const baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .loginToGUI()
+ .url(baseUrl + '/#/_all_dbs')
+
+ .clickWhenVisible('.control-toggle-api-url', waitTime, false)
+ .waitForElementVisible('.text-field-to-copy', waitTime, false)
+ .assert.attributeEquals('.text-field-to-copy', 'value', baseUrl + '/_all_dbs')
+ .waitForElementVisible('.copy-button', waitTime, false)
+ .assert.attributeEquals('.copy-button', 'data-clipboard-text', baseUrl + '/_all_dbs')
+ .click('.copy-button')
+ .waitForElementVisible('.global-notification', waitTime, false)
+ .assert.containsText('.global-notification > span', 'The API URL has been copied to the clipboard.')
+ .end();
+ },
+
+ 'Copy MD5 Checksum to Clipboard Test' : (client) => {
+
+ const waitTime = client.globals.maxWaitTime;
+ const newDatabaseName = client.globals.testDatabaseName;
+ const baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .loginToGUI()
+ .populateDatabase(newDatabaseName)
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+
+ .clickWhenVisible('.design-doc-name > span', waitTime, false)
+ .clickWhenVisible('a[href*="_info"]', waitTime, false)
+ .clickWhenVisible('li > button.clipboard-copy-element', waitTime, false)
+ .waitForElementVisible('.global-notification', waitTime, false)
+ .assert.containsText('.global-notification > span', 'The MD5 sha has been copied to your clipboard.')
+ .end();
+ },
+
+ 'Copy Changes Feed Data to Clipboard Test' : (client) => {
+
+ const waitTime = client.globals.maxWaitTime;
+ const newDatabaseName = client.globals.testDatabaseName;
+ const baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_changes')
+
+ .clickWhenVisible('.change-wrapper:first-child .row-fluid:first-child .clipboard-copy-element', waitTime, false)
+ .waitForElementVisible('.global-notification', waitTime, false)
+ .assert.containsText('.global-notification > span', 'The document seq number has been copied to your clipboard.')
+ .clickWhenVisible('.change-wrapper:first-child .row-fluid:nth-child(2) .clipboard-copy-element', waitTime, false)
+ .waitForElementVisible('.global-notification', waitTime, false)
+ .assert.containsText('.global-notification > span', 'The document ID has been copied to your clipboard.')
+ .end();
+ },
+
+ 'Cppy Document from Table View to Clipboard Test' : (client) => {
+ const waitTime = client.globals.maxWaitTime;
+ const newDatabaseName = client.globals.testDatabaseName;
+ const baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+
+ .clickWhenVisible('.fonticon-table', waitTime, false)
+ .clickWhenVisible('.table-view-docs tr:first-child .clipboard-copy-element', waitTime, false)
+ .waitForElementVisible('.global-notification', waitTime, false)
+ .assert.containsText('.global-notification > span', 'The document content has been copied to the clipboard.')
+ .end();
+ }
+};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/databases/tests/nightwatch/deletesDatabase.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/deletesDatabase.js b/app/addons/databases/tests/nightwatch/deletesDatabase.js
index c015a6f..9e2212c 100644
--- a/app/addons/databases/tests/nightwatch/deletesDatabase.js
+++ b/app/addons/databases/tests/nightwatch/deletesDatabase.js
@@ -45,6 +45,8 @@ module.exports = {
.waitForElementPresent('a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
.assert.elementPresent('a[href="database/' + newDatabaseName + '/_all_docs"]')
.clickWhenVisible('[title="Delete ' + newDatabaseName + '"]', waitTime, false)
+ .waitForElementVisible('.delete-db-modal', waitTime, false)
+ .clickWhenVisible('.delete-db-modal input[type="text"]', waitTime, false)
.setValue('.delete-db-modal input[type="text"]', [newDatabaseName, client.Keys.ENTER])
.waitForElementNotPresent('.global-notification .fonticon-cancel', waitTime, false)
.waitForElementPresent('.fauxton-table-list', waitTime, false)
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js b/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
index a0769d6..71b253a 100644
--- a/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
+++ b/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
@@ -44,7 +44,8 @@ module.exports = {
.waitForElementPresent('a[href="database/' + encodeURIComponent(newDatabaseName) + '/_all_docs"]', waitTime, false)
.assert.elementPresent('a[href="database/' + encodeURIComponent(newDatabaseName) + '/_all_docs"]')
.clickWhenVisible('[title="Delete ' + newDatabaseName + '"]', waitTime, false)
- .waitForElementPresent('.delete-db-modal input[type="text"]', waitTime, false)
+ .waitForElementPresent('.delete-db-modal', waitTime, false)
+ .clickWhenVisible('.delete-db-modal input[type="text"]', waitTime, false)
.setValue('.delete-db-modal input[type="text"]', [newDatabaseName, client.Keys.ENTER])
.waitForElementNotPresent('.global-notification .fonticon-cancel', waitTime, false)
.waitForElementPresent('.fauxton-table-list', waitTime, false)
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/documents/changes/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/changes/components.react.jsx b/app/addons/documents/changes/components.react.jsx
index fb01a36..1b9aefd 100644
--- a/app/addons/documents/changes/components.react.jsx
+++ b/app/addons/documents/changes/components.react.jsx
@@ -20,10 +20,11 @@ import Components from "../../fauxton/components.react";
import ReactComponents from "../../components/react-components.react";
import ReactCSSTransitionGroup from "react-addons-css-transition-group";
import "../../../../assets/js/plugins/prettify";
+import uuid from 'uuid';
const store = Stores.changesStore;
const BadgeList = ReactComponents.BadgeList;
-
+const {Copy} = ReactComponents;
class ChangesController extends React.Component {
constructor (props) {
@@ -255,7 +256,7 @@ class ChangeRow extends React.Component {
};
}
- onClipboardClick (target) {
+ showCopiedMessage (target) {
let msg = 'The document ID has been copied to your clipboard.';
if (target === 'seq') {
msg = 'The document seq number has been copied to your clipboard.';
@@ -280,7 +281,10 @@ class ChangeRow extends React.Component {
<div className="span2">seq</div>
<div className="span8 change-sequence">{change.seq}</div>
<div className="span2 text-right">
- <Components.Clipboard text={change.seq} onClipboardClick={() => this.onClipboardClick('seq')} />
+ <Copy
+ uniqueKey={uuid.v4()}
+ text={change.seq.toString()}
+ onClipboardClick={() => this.showCopiedMessage('seq')} />
</div>
</div>
@@ -290,7 +294,10 @@ class ChangeRow extends React.Component {
<ChangeID id={change.id} deleted={change.deleted} databaseName={databaseName} />
</div>
<div className="span2 text-right">
- <Components.Clipboard text={change.id} onClipboardClick={() => this.onClipboardClick('id')} />
+ <Copy
+ uniqueKey={uuid.v4()}
+ text={change.id}
+ onClipboardClick={() => this.showCopiedMessage('id')} />
</div>
</div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/documents/designdocinfo/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/designdocinfo/components.react.jsx b/app/addons/documents/designdocinfo/components.react.jsx
index a6909e8..d5a7070 100644
--- a/app/addons/documents/designdocinfo/components.react.jsx
+++ b/app/addons/documents/designdocinfo/components.react.jsx
@@ -16,10 +16,10 @@ import React from "react";
import Stores from "./stores";
import Actions from "./actions";
import ReactComponents from "../../components/react-components.react";
-import GeneralComponents from "../../fauxton/components.react";
var designDocInfoStore = Stores.designDocInfoStore;
var LoadLines = ReactComponents.LoadLines;
-var Clipboard = GeneralComponents.Clipboard;
+var Copy = ReactComponents.Copy;
+import uuid from 'uuid';
var DesignDocInfo = React.createClass({
@@ -130,9 +130,10 @@ var DesignDocInfo = React.createClass({
<ul>
<li>
<span className="item-title">MD5 Signature:</span>
- <Clipboard
- onClipboardClick={this.showCopiedMessage}
- text={viewIndex.signature} />
+ <Copy
+ uniqueKey={uuid.v4()}
+ text={viewIndex.signature}
+ onClipboardClick={this.showCopiedMessage} />
</li>
</ul>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/documents/index-results/index-results.components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/index-results.components.react.jsx b/app/addons/documents/index-results/index-results.components.react.jsx
index b78ca1d..0e84ff3 100644
--- a/app/addons/documents/index-results/index-results.components.react.jsx
+++ b/app/addons/documents/index-results/index-results.components.react.jsx
@@ -17,13 +17,12 @@ import Stores from "./stores";
import Actions from "./actions";
import Components from "../../components/react-components.react";
import Documents from "../resources";
-import FauxtonComponents from "../..//fauxton/components.react";
import { SplitButton, MenuItem } from "react-bootstrap";
import ReactSelect from "react-select";
import "../../../../assets/js/plugins/prettify";
+import uuid from 'uuid';
-const {LoadLines, BulkActionComponent} = Components;
-const { Clipboard } = FauxtonComponents;
+const {LoadLines, BulkActionComponent, Copy} = Components;
const store = Stores.indexResultsStore;
var NoResultsScreen = React.createClass({
@@ -159,10 +158,11 @@ var TableRow = React.createClass({
var text = JSON.stringify(el, null, ' ');
return (
<td title={text} className="tableview-el-copy">
- <Clipboard
- onClipboardClick={this.showCopiedMessage}
+ <Copy
title={text}
- text={text} />
+ text={text}
+ uniqueKey={uuid.v4()}
+ onClipboardClick={this.showCopiedMessage} />
</td>
);
},
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/fauxton/assets/less/components.less
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/assets/less/components.less b/app/addons/fauxton/assets/less/components.less
index 8e737d1..c124c9b 100644
--- a/app/addons/fauxton/assets/less/components.less
+++ b/app/addons/fauxton/assets/less/components.less
@@ -23,10 +23,6 @@
}
}
- .zeroclipboard-is-hover {
- background-color: #cbcbcb;
- }
-
.icon-question-sign {
margin-left: 3px;
}
@@ -44,6 +40,7 @@
}
-a.clipboard-copy-element:hover {
- text-decoration: none;
+button.clipboard-copy-element {
+ background: transparent;
+ border: 0;
}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/fauxton/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/components.react.jsx b/app/addons/fauxton/components.react.jsx
index 3ca7bfd..dc85481 100644
--- a/app/addons/fauxton/components.react.jsx
+++ b/app/addons/fauxton/components.react.jsx
@@ -14,142 +14,10 @@ import app from "../../app";
import FauxtonAPI from "../../core/api";
import React from "react";
import ReactDOM from "react-dom";
-import ZeroClipboard from "zeroclipboard";
import { Modal } from "react-bootstrap";
import "velocity-animate/velocity";
import "velocity-animate/velocity.ui";
-import "zeroclipboard/dist/ZeroClipboard.swf";
-function getZeroClipboardSwfPath () {
- return './dashboard.assets/ZeroClipboard.swf';
-}
-
-// super basic right now, but can be expanded later to handle all the varieties of copy-to-clipboards
-// (target content element, custom label, classes, notifications, etc.)
-var Clipboard = React.createClass({
- propTypes: function () {
- return {
- text: React.PropTypes.string.isRequired,
- displayType: React.PropTypes.string.oneOf(['icon', 'text'])
- };
- },
-
- getDefaultProps: function () {
- return {
- displayType: 'icon',
- textDisplay: 'Copy',
- onClipboardClick: function () { },
- title: 'Copy to clipboard'
- };
- },
-
- componentWillMount: function () {
- ZeroClipboard.config({ swfPath: getZeroClipboardSwfPath() });
- },
-
- getClipboardElement: function () {
- if (this.props.displayType === 'icon') {
- return (<i className="fontawesome icon-paste"></i>);
- }
- return this.props.textDisplay;
- },
-
- componentDidMount: function () {
- var el = ReactDOM.findDOMNode(this);
- this.clipboard = new ZeroClipboard(el);
- this.clipboard.on('ready', function () {
- this.clipboard.on('copy', function () {
- this.props.onClipboardClick();
- }.bind(this));
- }.bind(this));
-
- this.clipboard.on('error', function (event) {
- console.log('ZeroClipboard error of type "' + event.name + '": ' + event.message);
- });
- },
-
- onClick: function (event) {
- event.preventDefault();
- },
-
- render: function () {
- return (
- <a href="#"
- onClick={this.onClick}
- ref="copy"
- className="copy clipboard-copy-element"
- data-clipboard-text={this.props.text}
- data-bypass="true"
- title={this.props.title}
- >
- {this.getClipboardElement()}
- </a>
- );
- }
-});
-
-// use like this:
-// <ComponentsReact.ClipboardWithTextField textToCopy={yourText} uniqueKey={someUniqueValue}>
-// </ComponentsReact.ClipboardWithTextField>
-// pass in the text and a unique key, the key has to be unique or you'll get a warning
-var ClipboardWithTextField = React.createClass({
- propTypes: {
- onClipBoardClick: React.PropTypes.func.isRequired,
- textToCopy: React.PropTypes.string.isRequired,
- uniqueKey: React.PropTypes.string.isRequired,
- showCopyIcon: React.PropTypes.bool
- },
-
- getDefaultProps: function () {
- return {
- showCopyIcon: true,
- text: 'Copy'
- };
- },
-
- componentWillMount: function () {
- ZeroClipboard.config({ swfPath: getZeroClipboardSwfPath() });
- },
-
- componentDidMount: function () {
- var el = ReactDOM.findDOMNode(this.refs["copy-text-" + this.props.uniqueKey]);
- this.clipboard = new ZeroClipboard(el);
- this.clipboard.on('ready', function () {
- this.clipboard.on('copy', function () {
- this.props.onClipBoardClick();
- }.bind(this));
- }.bind(this));
- },
-
- getCopyIcon: function () {
- if (!this.props.showCopyIcon) {
- return null;
- }
- return (<i className="fontawesome icon-paste"></i>);
- },
-
- render: function () {
- return (
- <p key={this.props.uniqueKey}>
- <input
- type="text"
- className="input-xxlarge text-field-to-copy"
- readOnly
- value={this.props.textToCopy} />
- <a
- id={"copy-text-" + this.props.uniqueKey}
- className="btn copy-button clipboard-copy-element"
- data-clipboard-text={this.props.textToCopy}
- data-bypass="true"
- ref={"copy-text-" + this.props.uniqueKey}
- title="Copy to clipboard"
- >
- {this.getCopyIcon()} {this.props.text}
- </a>
- </p>
- );
- }
-});
// formats a block of code and pretty-prints it in the page. Currently uses the prettyPrint plugin
var CodeFormat = React.createClass({
@@ -181,7 +49,7 @@ var CodeFormat = React.createClass({
},
render: function () {
- var code = JSON.stringify(this.props.code, null, " ");
+ const code = JSON.stringify(this.props.code, null, " ");
return (
<div><pre className={this.getClasses()}>{code}</pre></div>
);
@@ -332,8 +200,6 @@ var ConfirmationModal = React.createClass({
export default {
- Clipboard: Clipboard,
- ClipboardWithTextField: ClipboardWithTextField,
CodeFormat: CodeFormat,
Pagination: Pagination,
ConfirmationModal: ConfirmationModal
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/fauxton/notifications/notifications.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/notifications/notifications.react.jsx b/app/addons/fauxton/notifications/notifications.react.jsx
index a7ab3ae..37f5848 100644
--- a/app/addons/fauxton/notifications/notifications.react.jsx
+++ b/app/addons/fauxton/notifications/notifications.react.jsx
@@ -16,15 +16,15 @@ import React from "react";
import ReactDOM from "react-dom";
import Actions from "./actions";
import Stores from "./stores";
-import Components from "../components.react";
+import Components from "../../components/react-components.react";
import VelocityReact from "velocity-react";
import "velocity-animate/velocity";
import "velocity-animate/velocity.ui";
+import uuid from 'uuid';
var store = Stores.notificationStore;
-var Clipboard = Components.Clipboard;
var VelocityComponent = VelocityReact.VelocityComponent;
-
+const {Copy} = Components;
// The one-stop-shop for Fauxton notifications. This controller handler the header notifications and the rightmost
// notification center panel
@@ -427,7 +427,7 @@ var NotificationPanelRow = React.createClass({
<div className="notification-actions">
<span className="time-elapsed">{timeElapsed}</span>
<span className="divider">|</span>
- <Clipboard text={this.props.item.cleanMsg} displayType="text" />
+ <Copy uniqueKey={uuid.v4()} text={this.props.item.cleanMsg} displayType="text" />
</div>
</div>
<button type="button" onClick={this.clearNotification}>�</button>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/app/addons/fauxton/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/tests/componentsSpec.react.jsx b/app/addons/fauxton/tests/componentsSpec.react.jsx
index 3c1e16b..c33555d 100644
--- a/app/addons/fauxton/tests/componentsSpec.react.jsx
+++ b/app/addons/fauxton/tests/componentsSpec.react.jsx
@@ -149,22 +149,3 @@ describe('Pagination', function () {
});
});
-
-
-describe('Clipboard', function () {
-
- it('shows a clipboard icon by default', function () {
- const clipboard = mount(<Views.Clipboard text="copy me" />);
- assert.equal(clipboard.find('.icon-paste').length, 1);
- });
-
- it('shows text if specified', function () {
- const clipboard = mount(<Views.Clipboard text="copy me" displayType="text" />);
- assert.equal(clipboard.find('.icon-paste').length, 0);
- });
-
- it('shows custom text if specified ', function () {
- var clipboard = mount(<Views.Clipboard displayType="text" textDisplay='booyah!' text="copy me" />);
- assert.ok(/booyah!/.test(clipboard.html()));
- });
-});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/assets/less/notification-center.less
----------------------------------------------------------------------
diff --git a/assets/less/notification-center.less b/assets/less/notification-center.less
index af9939a..657c2bd 100644
--- a/assets/less/notification-center.less
+++ b/assets/less/notification-center.less
@@ -138,6 +138,7 @@ body #dashboard #notification-center-btn {
height: 20px;
margin-top: -4px;
margin-left: 6px;
+ font-size: 100%;
&:hover {
color: @hoverRed;
}
@@ -171,10 +172,6 @@ body #dashboard #notification-center-btn {
color: @blue;
text-decoration: none;
}
- .copy.zeroclipboard-is-hover {
- color: @hoverRed;
- text-decoration: underline;
- }
}
footer {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/jest-setup.js
----------------------------------------------------------------------
diff --git a/jest-setup.js b/jest-setup.js
index 35502e6..0eca991 100644
--- a/jest-setup.js
+++ b/jest-setup.js
@@ -13,6 +13,5 @@
const jest = require('jest');
window.$ = window.jQuery = require('jquery');
-jest.mock('zeroclipboard', () => {});
global.fetch = require('jest-fetch-mock');
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2e770d66/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 8656fc7..4be5550 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"brace": "^0.7.0",
"chai": "^3.5.0",
"clean-css": "^3.4.9",
+ "clipboard": "^1.5.16",
"couchapp": "~0.11.0",
"css-loader": "^0.26.0",
"d3": "^3.4.11",
@@ -98,13 +99,13 @@
"url": "~0.7.9",
"url-loader": "^0.5.7",
"urls": "~0.0.3",
+ "uuid": "^3.0.1",
"velocity-animate": "^1.2.3",
"velocity-react": "1.1.11",
"visualizeRevTree": "git+https://github.com/neojski/visualizeRevTree.git#gh-pages",
"webpack": "^1.12.12",
"webpack-dev-server": "^1.14.1",
- "whatwg-fetch": "^2.0.1",
- "zeroclipboard": "^2.2.0"
+ "whatwg-fetch": "^2.0.1"
},
"scripts": {
"stylecheck": "eslint --ext=js,jsx .",