diff --git a/package.json b/package.json index 96c37a61c8..15080456fe 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", + "qrcode-react": "^0.1.16", "querystring": "^0.2.0", "react": "^15.6.0", "react-addons-css-transition-group": "15.3.2", diff --git a/res/img/icons-share.svg b/res/img/icons-share.svg new file mode 100644 index 0000000000..b27616d5d5 --- /dev/null +++ b/res/img/icons-share.svg @@ -0,0 +1,6 @@ + + diff --git a/res/img/matrix-m.svg b/res/img/matrix-m.svg new file mode 100644 index 0000000000..ccb1df0fc5 --- /dev/null +++ b/res/img/matrix-m.svg @@ -0,0 +1,15 @@ + + + diff --git a/res/img/social/email-1.png b/res/img/social/email-1.png new file mode 100644 index 0000000000..193cb659da Binary files /dev/null and b/res/img/social/email-1.png differ diff --git a/res/img/social/facebook.png b/res/img/social/facebook.png new file mode 100644 index 0000000000..6a29e3820a Binary files /dev/null and b/res/img/social/facebook.png differ diff --git a/res/img/social/linkedin.png b/res/img/social/linkedin.png new file mode 100644 index 0000000000..2b868a585b Binary files /dev/null and b/res/img/social/linkedin.png differ diff --git a/res/img/social/reddit.png b/res/img/social/reddit.png new file mode 100644 index 0000000000..bd6131186f Binary files /dev/null and b/res/img/social/reddit.png differ diff --git a/res/img/social/twitter-2.png b/res/img/social/twitter-2.png new file mode 100644 index 0000000000..84f8033a30 Binary files /dev/null and b/res/img/social/twitter-2.png differ diff --git a/src/components/views/dialogs/ShareDialog.js b/src/components/views/dialogs/ShareDialog.js new file mode 100644 index 0000000000..8bfa0ad931 --- /dev/null +++ b/src/components/views/dialogs/ShareDialog.js @@ -0,0 +1,211 @@ +/* +Copyright 2018 Vector Creations Ltd + +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 PropTypes from 'prop-types'; +import {Room, User, Group, RoomMember} from 'matrix-js-sdk'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; +import QRCode from 'qrcode-react'; +import {makeEventPermalink, makeGroupPermalink, makeRoomPermalink, makeUserPermalink} from "../../../matrix-to"; +import * as ContextualMenu from "../../structures/ContextualMenu"; + +const socials = [ + { + name: 'Facebook', + img: 'img/social/facebook.png', + url: (url) => `https://www.facebook.com/sharer/sharer.php?u=${url}`, + }, { + name: 'Twitter', + img: 'img/social/twitter-2.png', + url: (url) => `https://twitter.com/home?status=${url}`, + }, /* // icon missing + name: 'Google Plus', + img: 'img/social/', + url: (url) => `https://plus.google.com/share?url=${url}`, + },*/ { + name: 'Linked In', + img: 'img/social/linkedin.png', + url: (url) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`, + }, { + name: 'Reddit', + img: 'img/social/reddit.png', + url: (url) => `http://www.reddit.com/submit?url=${url}`, + }, { + name: 'email', + img: 'img/social/email-1.png', + url: (url) => `mailto:?body=${url}`, + }, +]; + +export default class ShareDialog extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + target: PropTypes.oneOfType([ + PropTypes.instanceOf(Room), + PropTypes.instanceOf(User), + PropTypes.instanceOf(Group), + PropTypes.instanceOf(RoomMember), + // PropTypes.instanceOf(MatrixEvent), + ]).isRequired, + }; + + constructor(props) { + super(props); + + this.onCopyClick = this.onCopyClick.bind(this); + this.onCheckboxClick = this.onCheckboxClick.bind(this); + + this.state = { + ticked: false, + }; + } + + static _selectText(target) { + const range = document.createRange(); + range.selectNodeContents(target); + + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + } + + static onLinkClick(e) { + e.preventDefault(); + const {target} = e; + ShareDialog._selectText(target); + } + + onCopyClick(e) { + e.preventDefault(); + + ShareDialog._selectText(this.refs.link); + + let successful; + try { + successful = document.execCommand('copy'); + } catch (err) { + console.error('Failed to copy: ', err); + } + + const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu'); + const buttonRect = e.target.getBoundingClientRect(); + + // The window X and Y offsets are to adjust position when zoomed in to page + const x = buttonRect.right + window.pageXOffset; + const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19; + const {close} = ContextualMenu.createMenu(GenericTextContextMenu, { + chevronOffset: 10, + left: x, + top: y, + message: successful ? _t('Copied!') : _t('Failed to copy'), + }, false); + e.target.onmouseleave = close; + } + + onCheckboxClick() { + this.setState({ + ticked: !this.state.ticked, + }); + } + + render() { + let title; + let matrixToUrl; + + let checkbox; + + if (this.props.target instanceof Room) { + title = _t('Share Room'); + + const events = this.props.target.getLiveTimeline().getEvents(); + if (events.length > 0) { + checkbox =