Autolinker.js icon indicating copy to clipboard operation
Autolinker.js copied to clipboard

Having trouble creating custom matcher

Open payamazadi opened this issue 9 years ago • 15 comments

Hello, I don't know if this is the right approach, but I'm trying to create a new matcher implementation. Just like HashTag and email already exist, I want to create a custom one.

What I'm tryign to accomplish is look for something that matches regex y, and generates a specific link. Soon, the regex will be a whole set of related regexes, which is why I'd like to use a matcher.

if there is an easier way to do this, let me know.

what I have now, I'm just including the minified Autolinker.js file. Then I have code that tries to do:

Autolinker.matcher.DmReference = Autolinker.Util.extend( Autolinker.matcher.Matcher, { parseMatches: function (text){ ... }

But I'm getting console errors of Autolinker.matcher is undefined. Do I need to set this somewhere? Is this some sort of namespacing issue? Am I approaching this correctly? I'm basically just copying the code from HashTag and Email and repurposing it.

Thanks for any help!

payamazadi avatar Jul 06 '16 20:07 payamazadi

Hey @payamazadi. So Autolinker wasn't really intended to be extended by custom matchers (there's currently no way to add them to the Autolinker constructor). The code in Autolinker.getMatchers() would need to be modified to add your custom one at the moment.

But if Autolinker.matcher is undefined, then the Autolinker library must not be loaded in the browser yet. Do you have a <script> tag for it?

gregjacobs avatar Jul 07 '16 00:07 gregjacobs

Hi! Yes, the script is loaded, it's already doing some URL replacements correctly. Autolinker.match(Es?) is defined and many other items attached to Autolinker. Just not this one. Weird! Good to know about .getMatchers(). I might play with that and submit a PR. Thanks for your quick follow up.

On Jul 6, 2016, at 20:34, Gregory Jacobs <[email protected]mailto:[email protected]> wrote:

Hey @payamazadihttps://github.com/payamazadi. So Autolinker wasn't really intended to be extended by custom matchers (there's currently no way to add them to the Autolinker constructor). The code in Autolinker.getMatchers() would need to be modified to add your custom one at the moment.

But if Autolinker.matcher is undefined, then the Autolinker library must not be loaded in the browser yet. Do you have a

You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/gregjacobs/Autolinker.js/issues/168#issuecomment-230947597, or mute the threadhttps://github.com/notifications/unsubscribe/AABQaFQUF21vDwnpLhHYUCh_drTXtXB2ks5qTEmHgaJpZM4JGekU.

payamazadi avatar Jul 07 '16 00:07 payamazadi

Hmm, ok, so you're using Autolinker on the page. Are you by any chance trying to attach this new matcher before Autolinker's <script> tag?

If you get a chance, can you attach your code and the error message from the console?

gregjacobs avatar Jul 07 '16 00:07 gregjacobs

Will do -

On Jul 6, 2016, at 20:40, Gregory Jacobs <[email protected]mailto:[email protected]> wrote:

Hmm, ok, so you're using Autolinker on the page. Are you by any chance trying to attach this new matcher before Autolinker's

If you get a chance, can you attach your code and the error message from the console?

You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/gregjacobs/Autolinker.js/issues/168#issuecomment-230948459, or mute the threadhttps://github.com/notifications/unsubscribe/AABQaJGfKtjyOIhUb6isaPHveu0Jcg1Qks5qTEsJgaJpZM4JGekU.

payamazadi avatar Jul 07 '16 00:07 payamazadi

So @gregjacobs here are some excerpts. The code base is actually rather large and I don't have time to strip all of it out right now.

Here is my HTML file, it uses handlebars.

Near top of file, after including JQuery and several custom libraries, <script src="./js/thirdparty/autolinker/Autolinker.min.js"></script>

Then later, my code was just:


entryContent = Autolinker.link(entry.content,{
                                                replaceFn : function( autolinker, match ) {
                                                    var tag = autolinker.getTagBuilder().build( match );  // returns an Autolinker.HtmlTag instance

                                                    tag.setInnerHtml(match.matchedText); // preserve original text content

                                                    return tag;
                                                }
                                            } );

And that is working fine.

In firebug debugger,here's what I get attached to Autolinker.: Util htmlParser match matchParser AnchorTagBuilder HtmlTag MatchValidator link prototype

Here's all the code I'm trying to add:

Autolinker.matcher.DmReference = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
                                                matcherRegex : (function() {
                                                    var dm1 = new RegExp('DM([0-9]{7}$)');
                                                    return new RegExp(dm1.source, 'gi');
                                                })(),

                                                parseMatches : function ( text ) {
                                                    var matcherRegex = this.matcherRegex,
                                                        tagbuilder = this.tagBuilder,
                                                        matches = [],
                                                        match;

                                                    while ( ( match = matcherRegex.exec( text ) ) !== null ) {
                                                        var matchedText = match [ 0 ];
                                                        matches.push( new Autolnker.match.DmReference( {
                                                            tagBuilder  : tagBuilder,
                                                            matchedText : matchedText,
                                                            offset      : match.index,
                                                            dmnumber    : matchedText 
                                                        } ) );
                                                    }

                                                    return matches; 
                                                }
                                            });

                                            Autolinker.match.DmReference = Autolnker.Util.extend ( Autolinker.match.Match, {
                                                getType: function() {
                                                    return 'dmreference';
                                                },

                                                getDmNumber: function() {
                                                    return this.dmnumber;
                                                },

                                                getAnchorHref : function() {
                                                    return 'http://dm.gao.gov/dm.aspx?id=' + this.dmnumber;
                                                },

                                                getAnchorText: function() {
                                                    return 'DM' + this.dmnumber;
                                                }
                                            });

The Util.extend for match.Match seems to work, but not with .matcher.Matcher

payamazadi avatar Jul 07 '16 16:07 payamazadi

Hey @payamazadi. Question: which version of Autolinker are you currently using? Autolinker.matcher.Matcher was added fairly recently (v0.23.0), and I wonder if you have an older version there.

gregjacobs avatar Jul 08 '16 22:07 gregjacobs

You're right, I'm on 0.19. I will update and do regression and try again and post back results. Does the approach with the code above pass your smell test?..

payamazadi avatar Jul 11 '16 17:07 payamazadi

It would be okay, except that you do still need to modify the Autolinker.getMatchers() method to add it for the moment.

I will think about a way to allow for custom matchers.

gregjacobs avatar Jul 11 '16 23:07 gregjacobs

Hi @gregjacobs would love to help out with refactoring the codebase to add the ability for custom matchers. We use this library extensively and want to be able to customise some regexes but unfortunately we can't. Let me know if you have something planned on how to go ahead with this or you want me to come up with something :)

karanjthakkar avatar Nov 29 '16 05:11 karanjthakkar

All ideas are welcome @karanjthakkar !

olafleur avatar Nov 29 '16 12:11 olafleur

Hey @karanjthakkar. Yes, would def appreciate any contributions on this. Could you come up with a proposal for an API for this? I think we need to handle a couple of scenarios:

  1. Users should be able to add their own matcher instances (obviously :))
  2. Users should be able to decide the order of matchers. Matchers found earlier in the array would take precedence over matchers found at the end of the array in the case of two matchers matching the same or overlapping piece of text.
  3. We need to somehow let the user handle the ordering of the standard matchers interlaced with the user's custom matchers. It's possible that the user wants their custom matcher to take precedence over one or more of the standard matchers.

gregjacobs avatar Nov 29 '16 22:11 gregjacobs

Hi @gregjacobs. Sorry for the delay in getting back. So I was thinking that each of these three points could be split into different PR's starting with getting in support for the easiest task:

  1. Replace any of the existing matchers for email/phone/etc. with a custom one.
  2. Allow reordering of existing matchers based on user preference
  3. Allow adding of any custom matchers

I haven't found the time to think about 2 and 3 but for 1 I think we can go ahead with each of the top level options urls, email, phone, mention, hashtag allowing an Object as a value. So this is what I propose:

AutoLinker.link({
  // accepts Boolean/Object but will also support a new option in Object now
  'urls': {
    'schemeMatches': true,
    'customRegex': new RegExp('Blah', 'i') // optional
  },
  // only supported Boolean but will also support Object now
  'email': {
    'customRegex': new RegExp('Blah', 'i') // optional
  },
  // only supported Boolean but will also support Object now
  'phone': {
    'customRegex': new RegExp('Blah', 'i') // optional
  },
  // only supported Boolean/String but will also support Object now
  'mention': {
    'serviceName': 'Twitter', // option to support the old String format
    'customRegex': new RegExp('Blah', 'i') // optional
  },
  // only supported Boolean/String but will also support Object now
  'hashtag': {
    'serviceName': 'Twitter', // option to support the old String format
    'customRegex': new RegExp('Blah', 'i') // optional
  }
})

Advantages:

  1. Instead of having these options on the top level: truncate, className, replaceFn, these can be moved inside each type object. This would then override any global option that would be set on the AutoLinker instance.
  2. This also makes it easy to move the options stripPrefix, stripTrailingSlash into the urls option in the future. Currently, they seem to be weirdly placed at the top level while they are only used for operating on urls.

What do you think?

PS: Also, I'm unsure if we should be making the user create new matcher instances when all that most users want is a custom regex for standard matchers. Hence the option customRegex.

karanjthakkar avatar Dec 07 '16 16:12 karanjthakkar

@gregjacobs @olafleur Bump :)

karanjthakkar avatar Dec 19 '16 05:12 karanjthakkar

Looks like a good plan to me !

Point 1 would be in and of itself a nice addition. Don't forget to make sure that when a value is not specified, the default is used.

olafleur avatar Dec 19 '16 21:12 olafleur

@karanjthakkar I think that's a very good idea. But I found there is nothing implementation in Autolinker.jsso far... why @olafleur ?

tangkunyin avatar May 17 '17 07:05 tangkunyin