Browse Source

now can draw 闭社树

pull/4/head
欧醚 4 years ago
parent
commit
a8e4c3f5a2
3 changed files with 82 additions and 12 deletions
  1. +48
    -10
      app/javascript/mastodon/features/status/index.js
  2. +2
    -1
      package.json
  3. +32
    -1
      yarn.lock

+ 48
- 10
app/javascript/mastodon/features/status/index.js View File

@ -10,6 +10,7 @@ import MissingIndicator from '../../components/missing_indicator';
import DetailedStatus from './components/detailed_status';
import ActionBar from './components/action_bar';
import Column from '../ui/components/column';
import Tree from 'react-tree-graph';
import {
favourite,
unfavourite,
@ -46,6 +47,8 @@ import { boostModal, deleteModal } from '../../initial_state';
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import Icon from 'mastodon/components/icon';
//import { htmlToText } from 'html-to-text';
//const htmlToText = require('html-to-text');
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -115,6 +118,26 @@ const makeMapStateToProps = () => {
return Immutable.List(descendantsIds);
});
const getTreeData = createSelector([
(_, { id }) => id,
state => state.getIn(['contexts', 'replies']),
state => state.get('statuses'),
], (statusId, contextReplies, statuses) => {
const getMore = (id) => {
const replies = contextReplies.get(id);
const cur_status = statuses.get(id);
return {
name: cur_status.get('search_index') + (cur_status.get('media_attachments').size > 0 ? " [图片]" : " "), //htmlToText.fromString(statuses.getIn([id, 'content']), {ignoreHref: true}),
children: replies ? Array.from(replies.map( i => getMore(i) )) : null
}
}
let treeData = getMore(statusId)
return treeData;
});
const mapStateToProps = (state, props) => {
const status = getStatus(state, { id: props.params.statusId });
@ -122,18 +145,15 @@ const makeMapStateToProps = () => {
let descendantsIds = Immutable.List();
let rootAcct;
let deep;
let tree_data;
if (status) {
ancestorsIds = getAncestorsIds(state, { id: status.get('in_reply_to_id') });
//console.log(ancestorsIds.get(0));
const root_status = ancestorsIds.size? getStatus(state, {id: ancestorsIds.get(0)}) : status; //error is directly visit url of non-root detailedStatus, feature!
//console.log('statuese', state.get('statuses').size);
//console.log('root_status', root_status);
//console.log(root_status.get('account'));
rootAcct = root_status.getIn(['account', 'acct']);
//console.log('rootAcct', rootAcct);
rootAcct = root_status? root_status.getIn(['account', 'acct']) : -1;
descendantsIds = rootAcct == '0' ? state.getIn(['contexts', 'replies', status.get('id')]) : getDescendantsIds(state, { id: status.get('id') });
deep = rootAcct == '0' ? ancestorsIds.size : null;
deep = rootAcct == '0' ? ancestorsIds.size : null;
tree_data = rootAcct == '0' ? getTreeData(state, {id: status.get('id')}) : null;
}
return {
@ -141,6 +161,7 @@ const makeMapStateToProps = () => {
deep,
ancestorsIds,
descendantsIds,
tree_data,
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
domain: state.getIn(['meta', 'domain']),
};
@ -173,6 +194,7 @@ class Status extends ImmutablePureComponent {
fullscreen: false,
showMedia: defaultMediaVisibility(this.props.status),
loadedStatusId: undefined,
showTree: false
};
componentWillMount () {
@ -304,6 +326,10 @@ class Status extends ImmutablePureComponent {
}
}
handleShowTree = () => {
this.setState({ showTree: !this.state.showTree });
}
handleBlockClick = (status) => {
const { dispatch } = this.props;
const account = status.get('account');
@ -450,8 +476,8 @@ class Status extends ImmutablePureComponent {
render () {
let ancestors, descendants;
const { shouldUpdateScroll, status, deep, ancestorsIds, descendantsIds, intl, domain, multiColumn } = this.props;
const { fullscreen } = this.state;
const { shouldUpdateScroll, status, deep, ancestorsIds, descendantsIds, tree_data, intl, domain, multiColumn } = this.props;
const { fullscreen, showTree } = this.state;
if (status === null) {
return (
@ -488,7 +514,7 @@ class Status extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={status.get('hidden') ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
<button className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={deep ==null ? this.handleToggleAll : this.handleShowTree} aria-pressed={status.get('hidden') ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
)}
/>
@ -498,6 +524,17 @@ class Status extends ImmutablePureComponent {
<HotKeys handlers={handlers}>
<div className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}>
{showTree ?
<Tree
data={tree_data}
height={300}
width={500}
animated
svgProps={{
className: 'tree-svg'
}}/>
:
<DetailedStatus
status={status}
deep={deep}
@ -508,6 +545,7 @@ class Status extends ImmutablePureComponent {
showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility}
/>
}
<ActionBar
status={status}

+ 2
- 1
package.json View File

@ -167,7 +167,8 @@
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.7",
"webpack-merge": "^4.2.1",
"websocket.js": "^0.1.12"
"websocket.js": "^0.1.12",
"react-tree-graph":"^4.0.1"
},
"devDependencies": {
"babel-eslint": "^10.0.3",

+ 32
- 1
yarn.lock View File

@ -2521,6 +2521,11 @@ clone-deep@^2.0.1:
kind-of "^6.0.0"
shallow-clone "^1.0.0"
clone@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@ -2775,6 +2780,11 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042"
integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==
core-js@^2.5.0:
version "2.6.10"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f"
integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -3126,6 +3136,16 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
d3-ease@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb"
integrity sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ==
d3-hierarchy@^1.1.5:
version "1.1.8"
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#7a6317bd3ed24e324641b6f1e76e978836b008cc"
integrity sha512-L+GHMSZNwTpiq4rt9GEsNcpLa4M96lXMR8M/nMG9p5hBE0jy6C+3hWtyZMenPQdwla249iJy7Nx0uKt3n+u9+w==
d@1, d@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
@ -8302,7 +8322,7 @@ prop-types-extra@^1.0.1:
react-is "^16.3.2"
warning "^3.0.0"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -8753,6 +8773,17 @@ react-transition-group@^2.2.0, react-transition-group@^2.2.1:
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
react-tree-graph@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/react-tree-graph/-/react-tree-graph-4.0.1.tgz#03e9b30836cf27ba8faebe9c78257f9cc41fe66f"
integrity sha512-kKwyR5NqPCuxxa8FcGHjkqRxVxRobf7cQP3WaVjb66bO3LicD/vpH5Fu19wTS+HHReqcrSchP42n/axz6m1sXw==
dependencies:
clone "^2.1.1"
core-js "^2.5.0"
d3-ease "^1.0.3"
d3-hierarchy "^1.1.5"
prop-types "^15.5.7"
react@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"

Loading…
Cancel
Save