From e7667b8729308920c3309ad374b9e03a8c555d0e Mon Sep 17 00:00:00 2001 From: Mitch Robb Date: Fri, 3 Jun 2016 00:57:40 -0700 Subject: [PATCH] first stab at merging global and instance linkifyIt customizations --- src/Linkify.jsx | 64 +++++++++++++++++--- src/__tests__/Linkify-test.js | 107 +++++++++++++++++++++++++++++++++- 2 files changed, 162 insertions(+), 9 deletions(-) diff --git a/src/Linkify.jsx b/src/Linkify.jsx index 4142e12..8eabe58 100644 --- a/src/Linkify.jsx +++ b/src/Linkify.jsx @@ -2,8 +2,42 @@ import React from 'react'; import LinkifyIt from 'linkify-it'; import tlds from 'tlds'; -export const linkify = new LinkifyIt(); -linkify.tlds(tlds); +const globalLinkify = new LinkifyIt(); +globalLinkify.tlds(tlds); + +const globalCustomizations = { + add: [], + tlds: [], + set: [] +}; + +export const config = { + add: (...args) => { + globalCustomizations.add.push(args); + globalLinkify.add(...args); + + return config; + }, + tlds: (...args) => { + globalCustomizations.tlds.push(args); + globalLinkify.tlds(...args); + + return config; + }, + set: (...args) => { + globalCustomizations.set.push(args); + globalLinkify.set(...args); + + return config; + }, + resetAll: () => { + for (let type in globalCustomizations) { + globalCustomizations[type] = []; + } + + return config; + } +}; class Linkify extends React.Component { static MATCH = 'LINKIFY_MATCH' @@ -20,14 +54,20 @@ class Linkify extends React.Component { validate: React.PropTypes.func.isRequired, normalize: React.PropTypes.func.isRequired }) - ) + ), + fuzzyLink: React.PropTypes.bool, + fuzzyIP: React.PropTypes.bool, + fuzzyEmail: React.PropTypes.bool } static defaultProps = { className: 'Linkify', component: 'a', properties: {}, - handlers: [] + handlers: [], + fuzzyLink: true, + fuzzyIP: false, + fuzzyEmail: true } componentDidMount() { @@ -41,25 +81,33 @@ class Linkify extends React.Component { } addCustomHandlers() { - const { handlers } = this.props; + const { handlers, fuzzyLink, fuzzyIP, fuzzyEmail } = this.props; - if (handlers.length) { + if (handlers.length || fuzzyLink || fuzzyIP || fuzzyEmail) { this.linkify = new LinkifyIt(); this.linkify.tlds(tlds); - handlers.forEach(handler => { + // add global customizations + for (let type in globalCustomizations) { + globalCustomizations[type].forEach(c => this.linkify[type](...c)) + } + + // add instance customizations + (handlers || []).forEach((handler) => { this.linkify.add(handler.prefix, { validate: handler.validate, normalize: handler.normalize }); }); + + this.linkify.set({ fuzzyLink, fuzzyIP, fuzzyEmail }) } } parseCounter = 0 getMatches(string) { - const linkifyInstance = this.linkify || linkify; + const linkifyInstance = this.linkify || globalLinkify; return linkifyInstance.match(string); } diff --git a/src/__tests__/Linkify-test.js b/src/__tests__/Linkify-test.js index 4f2578d..528a986 100644 --- a/src/__tests__/Linkify-test.js +++ b/src/__tests__/Linkify-test.js @@ -5,6 +5,8 @@ let TestUtils = require('react-addons-test-utils'); describe('Linkify', () => { let Linkify = require('../Linkify.jsx').default; + let linkifyCustomizations = require('../Linkify.jsx').config; + describe('#parseString', () => { let linkify = TestUtils.renderIntoDocument(); @@ -121,7 +123,7 @@ describe('Linkify', () => { }); }); - describe('#addCustomHandlers', () => { + describe('LinkifyIt config', () => { it('should match a custom handler added through the "handlers" prop', () => { const linkify = TestUtils.renderIntoDocument( { expect(output[3].props.children).toEqual(input[3]); expect(output[4]).toEqual(input[4]); }) + + it('should apply global customizations', () => { + linkifyCustomizations + .resetAll() + .tlds('linkify', true) + .add('@', { + validate() { + return 7; + }, + normalize(match) { + match.url = 'https://twitter.com/' + match.url.replace(/^@/, ''); + } + }) + const linkify = TestUtils.renderIntoDocument( + + ); + + const input = ['this is an ', '@mention', ' and ', 'test.linkify', ' TLD handler']; + const output = linkify.parseString(input.join('')); + + expect(output[0]).toEqual(input[0]); + expect(output[1].type).toEqual('a'); + expect(output[1].props.href).toEqual(`https://twitter.com/mention`); + expect(output[1].props.children).toEqual(input[1]); + + expect(output[2]).toEqual(input[2]); + expect(output[3].type).toEqual('a'); + expect(output[3].props.href).toEqual(`http://test.linkify`); + expect(output[3].props.children).toEqual(input[3]); + expect(output[4]).toEqual(input[4]); + }); + + it('should merge global and instance handlers', () => { + linkifyCustomizations + .resetAll() + .add('@', { + validate() { + return 7; + }, + normalize(match) { + match.url = 'https://twitter.com/' + match.url.replace(/^@/, ''); + } + }) + const linkify = TestUtils.renderIntoDocument( + + + ); + + const input = ['this is an ', '@mention', ' and ', '$mention', ' handler']; + const output = linkify.parseString(input.join('')); + + expect(output[0]).toEqual(input[0]); + expect(output[1].type).toEqual('a'); + expect(output[1].props.href).toEqual(`https://twitter.com/mention`); + expect(output[1].props.children).toEqual(input[1]); + + expect(output[2]).toEqual(input[2]); + expect(output[3].type).toEqual('a'); + expect(output[3].props.href).toEqual(`https://blingtwitter.com/mention`); + expect(output[3].props.children).toEqual(input[3]); + expect(output[4]).toEqual(input[4]); + }); + + it('should set fuzzy* options', () => { + const linkify = TestUtils.renderIntoDocument( + + ); + + const linkInput = 'this should not match: www.test.com'; + const linkOutput = linkify.parseString(linkInput); + expect(linkOutput).toEqual(linkInput); + }); + + it('should reset global customizations', () => { + linkifyCustomizations + .add('@', { + validate() { + return 7; + }, + normalize(match) { + match.url = 'https://twitter.com/' + match.url.replace(/^@/, ''); + } + }) + .resetAll() + + const linkify = TestUtils.renderIntoDocument( + + ); + + const input = 'this @mention should not match'; + const output = linkify.parseString(input); + + expect(output).toEqual(input); + }) }); describe('#render', () => {