Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions __tests__/tests/components/GithubHtmlView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { Text } from 'react-native';
import renderer from 'react-test-renderer';
import { GithubHtmlView } from 'components';
import { Icon } from 'react-native-elements';

describe('<GithubHtmlView />', () => {
it('correctly renders <details/> tag in GithubHtmlView with correct icon', () => {
const sourceHtml = `
<details>
<summary>title</summary>
<div>description</div>
</details>
`;

const inst = renderer.create(
<GithubHtmlView source={sourceHtml} onLinkPress={() => 0} />
);

expect(inst.root.findByType(Icon).props.name).toEqual('triangle-right');
});

it('if <summary/> tag contains a single text node, we shoud prettify it', () => {
const sourceHtml = `
<details>
<summary>
make some space and line break here...

</summary>
<div>description</div>
</details>
`;

const inst = renderer.create(
<GithubHtmlView source={sourceHtml} onLinkPress={() => 0} />
);

expect(
!!inst.root
.findAllByType(Text)
.find(
e => e.props.children === 'make some space and line break here...'
)
).toBe(true);
});

it('if there is no <summary/> tag, we should do fallback render which contains no icon', () => {
const sourceHtml = `
<details>
<div>no summary here!!</div>
</details>
`;

const inst = renderer.create(
<GithubHtmlView source={sourceHtml} onLinkPress={() => 0} />
);

expect(inst.root.findAllByType(Icon).length).toBe(0);
});

it('if <summary/> contain nested tags, should still be rendered without exception', () => {
const sourceHtml = `
<details>
<summary>
abcde <div>test</div> fg
</summary>
<div>no summary here!!</div>
</details>
`;

const inst = renderer.create(
<GithubHtmlView source={sourceHtml} onLinkPress={() => 0} />
);

expect(inst.root.findByType(Icon).props.name).toEqual('triangle-right');
});
});
48 changes: 48 additions & 0 deletions src/components/github-htmlview.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { TableWrapper, Table, Cell } from 'react-native-table-component';
import SyntaxHighlighter from 'react-native-syntax-highlighter';
import { github as GithubStyle } from 'react-syntax-highlighter/dist/styles';
import entities from 'entities';
import { Icon } from 'react-native-elements';

import { ImageZoom, ToggleView } from 'components';
import { colors, fonts, normalize } from 'config';
Expand Down Expand Up @@ -386,6 +387,53 @@ export class GithubHtmlView extends Component {
</Text>
);
},
details: (node, index, siblings, parent, defaultRenderer) => {
const summaryTagIdx = node.children.findIndex(
n => n.type === 'tag' && n.name === 'summary'
);
const summaryTag = node.children[summaryTagIdx];

if (!summaryTag) {
// we have a details tag without summary, rollback to default render
return <View>{defaultRenderer(node.children, node)}</View>;
}

const childrenWithoutSummary = [...node.children]; // don't touch the original data

childrenWithoutSummary.splice(summaryTagIdx, 1);

const renderSummary = tag => {
if (tag.children.length === 1 && tag.children[0].type === 'text') {
// if we only have one text child, make it prettier
// by removing line break and triming space
return (
<Text>
{tag.children[0].data.replace(/\s\s+/g, ' ').trim()}
</Text>
);
}

return defaultRenderer(tag.children, tag);
};

return (
<ToggleView
renderTouchable={collapsed => (
<View
style={{ flexDirection: 'row', alignItems: 'flex-start' }}
>
<Icon
type="octicon"
name={collapsed ? 'triangle-right' : 'triangle-down'}
/>
<View style={{ flex: 1 }}>{renderSummary(summaryTag)}</View>
</View>
)}
>
{defaultRenderer(childrenWithoutSummary, node)}
</ToggleView>
);
},
};

if (_node.type === 'text') {
Expand Down
5 changes: 4 additions & 1 deletion src/components/toggle-view.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class ToggleView extends Component {
props: {
children: any,
TouchableView: any,
renderTouchable: Function,
};

state: {
Expand All @@ -28,7 +29,9 @@ export class ToggleView extends Component {
return (
<View>
<TouchableOpacity onPress={() => this._toggle()}>
{this.props.TouchableView}
{this.props.renderTouchable
? this.props.renderTouchable(this.state.collapsed)
: this.props.TouchableView}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

</TouchableOpacity>
<Collapsible collapsed={this.state.collapsed}>
{this.props.children}
Expand Down