Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove replaceSymbols method, add transform prop #10

Merged
merged 2 commits into from
Aug 20, 2015
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Markdown viewer and editor for the Zooniverse",
"main": "src/index.js",
"scripts": {
"start": "gulp watch",
"test": "gulp test",
"test-sauce": "zuul -- test/**/*.js"
},
Expand Down
4 changes: 2 additions & 2 deletions src/components/markdown-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class MarkdownEditor extends React.Component {
<div className="editor-area">
<textarea ref="textarea" className="markdown-editor-input" name={this.props.name} placeholder={this.props.placeholder} value={this.props.value} rows={this.props.rows} cols={this.props.cols} onChange={this.onInputChange.bind(this)} />

<Markdown className="markdown-editor-preview">{this.props.value}</Markdown>
<Markdown className="markdown-editor-preview" transform={this.props.transform}>{this.props.value}</Markdown>
</div>
</div>
);
Expand Down Expand Up @@ -186,6 +186,7 @@ MarkdownEditor.defaultProps = {
value: '',
placeholder: '',
rows: 5,
transform: arg => arg,
onChange: NOOP,
previewing: null,
onHelp: NOOP
Expand All @@ -194,4 +195,3 @@ MarkdownEditor.defaultProps = {
MarkdownEditor.initialState = {
previewing: false
};

46 changes: 2 additions & 44 deletions src/components/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import React from "react";
import MarkdownIt from "markdown-it";
import MarkdownItContainer from "markdown-it-container";
import twemoji from 'twemoji';
import {State} from 'react-router';
import reactMixin from 'react-mixin';

const markdownIt = new MarkdownIt({linkify: true, breaks: true})
.use(require('markdown-it-emoji'))
Expand All @@ -18,45 +16,6 @@ export default class Markdown extends React.Component {
return 'Markdown';
}

replaceSymbols(input) {
// Catch getParams in case we're in a non-routed context like an alert
var owner, name;
try {
({owner, name} = this.getParams());
} catch (_) {
owner = null;
name = null;
}

return input
// hashtags #tagname
.replace(/(?!\B[\w+-\/]+\b)\B#(\b[\w+-\/]+\b)/g, function(fullTag, tagName) {
if (owner && name) {
return `<a href='#/projects/${owner}/${name}/talk/search?query=${tagName}'>${fullTag}</a>`;
}
else {
return `<a href='#/talk/search?query=${tagName}'>${fullTag}</a>`;
}
})

// subjects in a specific project : @owner-slug/project-slug^subject_id
// \b[\w-]+\b is hyphen boundary for slugs
.replace(/@(\b[\w-]+\b)\/(\b[\w-]+\b)\^([0-9]+)/g, "<a href='#/projects/$1/$2/talk/subjects/$3'>$1/$2 - Subject $3</a>")

.replace(/\^([0-9]+)/g, function(_, subjectID) {
if (owner && name) {
return `<a href='#/projects/${owner}/${name}/talk/subjects/${subjectID}'>${owner}/${name} - Subject ${subjectID}</a>`;
}
else {
return subjectID;
}
})

// user mentions : @username
.replace(/\B@(\b[\w-]+\b)/g, "<a href='#/users/$1'>@$1</a>")

}

emojify(input) {
return twemoji.parse(input);
}
Expand All @@ -72,7 +31,7 @@ export default class Markdown extends React.Component {

getHtml() {
try {
return this.replaceSymbols(this.emojify(this.markdownify(this.props.children || this.props.content)));
return this.props.transform(this.emojify(this.markdownify(this.props.children || this.props.content)));
} catch (e) {
return this.props.children || this.props.content;
}
Expand All @@ -92,7 +51,6 @@ Markdown.defaultProps = {
tag: 'div',
content: '',
inline: false,
transform: arg => arg,
className: ''
}

reactMixin.onClass(Markdown, State);
55 changes: 12 additions & 43 deletions test/components/markdown-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,11 @@ describe('Markdown', () => {
tag: 'div',
content: '',
inline: false,
transform: Markdown.defaultProps.transform,
className: ''
});
});

describe('#replaceSymbols', () => {
it('replaces #hashtags with hashtag links', () => {
var tagLink = markdown.replaceSymbols('#test');
expect(tagLink).to.equal("<a href='#/talk/search?query=test'>#test</a>");
});

it('replaces #hashtags inside of html without conflicting with urls', () => {
let htmlTagLink = markdown.replaceSymbols(`<p>#good \n https://www.zooniverse.org/#/talk/17/1403?page=1&comment=3063</p>`);

expect(htmlTagLink).to.equal(`<p><a href=\'#/talk/search?query=good\'>#good</a> \n https://www.zooniverse.org/#/talk/17/1403?page=1&comment=3063</p>`)
})

it('replaces ^subject mentions with subject links', () =>{
markdown.getParams = () => {
return {
owner: 'test',
name: 'project'
};
};

var subjectLink = markdown.replaceSymbols('^123456');
expect(subjectLink).to.equal("<a href='#/projects/test/project/talk/subjects/123456'>test/project - Subject 123456</a>");
});

it('does not format subject Ids when not in a routed context', () =>{
markdown.getParams = Function.prototype;

var subjectLink = markdown.replaceSymbols('^123456');
expect(subjectLink).to.equal("123456");
});

it('replaces @ownerslug/project-slug^subject_id mentions with links', () => {
var projectSubjectLink = markdown.replaceSymbols('@owner/project-d^123456');

expect(projectSubjectLink).to.equal("<a href='#/projects/owner/project-d/talk/subjects/123456'>owner/project-d - Subject 123456</a>");
});
});

describe('#markdownify', () => {
it('renders markdown', () => {
var md = markdown.markdownify('# test header');
Expand All @@ -83,7 +46,7 @@ describe('Markdown', () => {
})

it('renders bare child content on error', () => {
md.replaceSymbols = () => {
md.props.transform = () => {
throw new Error("fail")
}
let html = md.getHtml()
Expand All @@ -94,19 +57,25 @@ describe('Markdown', () => {
describe('#render', () => {
var editor, md
before(() => {
editor = React.createElement(Markdown, { className: 'MyComponent', tag: 'div'}, 'Test children')
editor = React.createElement(Markdown, {
className: 'MyComponent',
tag: 'div',
transform: (html) => {
return html.replace('foo', 'bar');
}
}, 'Test children foo');
md = TestUtils.renderIntoDocument(editor);
})

it('renders', () => {
var markdownDiv = TestUtils.findRenderedDOMComponentWithTag(md, 'div');
expect(markdownDiv.props.dangerouslySetInnerHTML.__html).to.equal('<p>Test children</p>\n');
expect(markdownDiv.props.dangerouslySetInnerHTML.__html).to.equal('<p>Test children bar</p>\n');
});

it('calls getHtml in render', () => {
let replaceSymbolsSpy = spy.on(md, 'getHtml')
let getHtmlSpy = spy.on(md, 'getHtml')
md.render()
expect(replaceSymbolsSpy).to.have.been.called()
expect(getHtmlSpy).to.have.been.called()
});

it('returns a react component, with customizable tag', () =>{
Expand Down