[Pkg-javascript-commits] [rainloop] 01/01: Unbundled node-autolinker, node-classnames, node-normalize.css, node-pikaday, node-ifvisible.js, and node-simplestatemanager.
Daniel Ring
techwolf-guest at moszumanska.debian.org
Sat Dec 30 11:50:42 UTC 2017
This is an automated email from the git hooks/post-receive script.
techwolf-guest pushed a commit to branch master
in repository rainloop.
commit 73529fa3ce5060899353a3a5f4c0610fb3c28e14
Author: Daniel Ring <dring at wolfishly.me>
Date: Sun Dec 17 00:43:02 2017 -0800
Unbundled node-autolinker, node-classnames, node-normalize.css,
node-pikaday, node-ifvisible.js, and node-simplestatemanager.
---
debian/Makefile | 10 +-
debian/control | 7 +-
debian/copyright | 24 -
debian/lib/autolinker/Autolinker.js | 4187 --------------------------------
debian/lib/classnames/index.js | 48 -
debian/lib/ifvisible/ifvisible.js | 315 ---
debian/lib/normalize/normalize.css | 447 ----
debian/lib/pikaday/pikaday.css | 222 --
debian/lib/pikaday/pikaday.js | 1193 ---------
debian/lib/simplestatemanager/ssm.js | 408 ----
debian/patches/build.patch | 41 +-
debian/patches/bundled-libraries.patch | 4 +-
12 files changed, 22 insertions(+), 6884 deletions(-)
diff --git a/debian/Makefile b/debian/Makefile
index 99cf1eb..79bb5d4 100644
--- a/debian/Makefile
+++ b/debian/Makefile
@@ -42,7 +42,7 @@ assets:
#CSS
cssMainCSS = \
- debian/lib/normalize/normalize.css \
+ /usr/lib/nodejs/normalize.css/normalize.css \
vendors/jquery-ui/css/smoothness/jquery-ui-1.10.3.custom.css \
vendors/fontastic/styles.css \
vendors/jquery-nanoscroller/nanoscroller.css \
@@ -50,7 +50,7 @@ cssMainCSS = \
vendors/inputosaurus/inputosaurus.css \
vendors/flags/flags-fixed.css \
debian/lib/opentip/opentip.css \
- debian/lib/pikaday/pikaday.css \
+ /usr/lib/nodejs/pikaday/pikaday.css \
debian/lib/lightgallery/lightgallery.css \
debian/lib/lightgallery/lg-transitions.css \
debian/lib/progressjs/progressjs.css \
@@ -118,8 +118,8 @@ jsLibs = \
debian/lib/knockout/knockout-latest.js \
debian/lib/knockout-projections/knockout-projections.js \
debian/lib/knockout-sortable/knockout-sortable.js \
- debian/lib/simplestatemanager/ssm.js \
- debian/lib/autolinker/Autolinker.js \
+ /usr/lib/nodejs/simplestatemanager/ssm.min.js \
+ /usr/lib/nodejs/autolinker/Autolinker.min.js \
debian/lib/opentip/opentip.js \
debian/lib/opentip/adapter-jquery.js \
debian/lib/lightgallery/lightgallery.js \
@@ -127,7 +127,7 @@ jsLibs = \
debian/lib/lightgallery/lg-thumbnail.js \
debian/lib/lightgallery/lg-zoom.js \
debian/lib/lightgallery/lg-autoplay.js \
- debian/lib/ifvisible/ifvisible.js
+ /usr/lib/nodejs/ifvisible/ifvisible.js
.PHONY: jsLibs
jsLibs: $(jsLibs)
diff --git a/debian/control b/debian/control
index f0d06f9..728516e 100644
--- a/debian/control
+++ b/debian/control
@@ -18,11 +18,16 @@ Build-Depends:
, node-json-loader
, node-raw-loader
, node-style-loader
+ , node-autolinker
+ , node-classnames
+ , node-normalize.css
+ , node-pikaday
+ , node-simplestatemanager
, libjs-jquery-mousewheel
, libjs-jquery-lazyload
, libjs-moment
, libjs-underscore
-Standards-Version: 4.1.0
+Standards-Version: 4.1.2
Homepage: https://rainloop.net/
Vcs-Git: https://github.com/techwolfy/rainloop-webmail.git
Vcs-Browser: https://github.com/techwolfy/rainloop-webmail
diff --git a/debian/copyright b/debian/copyright
index ed9a3e9..c1e97a5 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -90,18 +90,6 @@ Copyright: 2012 Miller Medeiros
License: MIT
-Files: debian/lib/autolinker/*
-Copyright: 2017 Gregory Jacobs <greg at greg-jacobs.com>
-License: MIT
-
-Files: debian/lib/classnames/*
-Copyright: 2016 Jed Watson
-License: MIT
-
-Files: debian/lib/ifvisible/*
-Copyright: 2013 Serkan Yersen
-License: MIT
-
Files: debian/lib/jquery-backstretch/*
Copyright: 2013 Scott Robbin
License: MIT
@@ -130,10 +118,6 @@ Files: debian/lib/lightgallery/*
Copyright: 2016 Sachin N.
License: Apache-2.0
-Files: debian/lib/normalize/*
-Copyright: 2017 Nicolas Gallagher
-License: MIT
-
Files: debian/lib/openpgp/*
Copyright: 2017 Bart Butler, Tankred Hase, and Thomas Oberndorfer
License: LGPL-3
@@ -142,18 +126,10 @@ Files: debian/lib/opentip/*
Copyright: 2012 Matias Meno
License: MIT
-Files: debian/lib/pikaday/*
-Copyright: 2014 David Bushell
-License: MIT
-
Files: debian/lib/progressjs/*
Copyright: 2013 Afshin Mehrabani
License: MIT
-Files: debian/lib/simplestatemanager/*
-Copyright: 2016 Jonathan Fielding
-License: MIT
-
License: AGPL-3
GNU AFFERO GENERAL PUBLIC LICENSE
diff --git a/debian/lib/autolinker/Autolinker.js b/debian/lib/autolinker/Autolinker.js
deleted file mode 100644
index d463c33..0000000
--- a/debian/lib/autolinker/Autolinker.js
+++ /dev/null
@@ -1,4187 +0,0 @@
-/*!
- * Autolinker.js
- * 1.4.3
- *
- * Copyright(c) 2017 Gregory Jacobs <greg at greg-jacobs.com>
- * MIT License
- *
- * https://github.com/gregjacobs/Autolinker.js
- */
-;(function(root, factory) {
- if (typeof define === 'function' && define.amd) {
- define([], factory);
- } else if (typeof exports === 'object') {
- module.exports = factory();
- } else {
- root.Autolinker = factory();
- }
-}(this, function() {
-/**
- * @class Autolinker
- * @extends Object
- *
- * Utility class used to process a given string of text, and wrap the matches in
- * the appropriate anchor (<a>) tags to turn them into links.
- *
- * Any of the configuration options may be provided in an Object (map) provided
- * to the Autolinker constructor, which will configure how the {@link #link link()}
- * method will process the links.
- *
- * For example:
- *
- * var autolinker = new Autolinker( {
- * newWindow : false,
- * truncate : 30
- * } );
- *
- * var html = autolinker.link( "Joe went to www.yahoo.com" );
- * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
- *
- *
- * The {@link #static-link static link()} method may also be used to inline
- * options into a single call, which may be more convenient for one-off uses.
- * For example:
- *
- * var html = Autolinker.link( "Joe went to www.yahoo.com", {
- * newWindow : false,
- * truncate : 30
- * } );
- * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
- *
- *
- * ## Custom Replacements of Links
- *
- * If the configuration options do not provide enough flexibility, a {@link #replaceFn}
- * may be provided to fully customize the output of Autolinker. This function is
- * called once for each URL/Email/Phone#/Hashtag/Mention (Twitter, Instagram)
- * match that is encountered.
- *
- * For example:
- *
- * var input = "..."; // string with URLs, Email Addresses, Phone #s, Hashtags, and Mentions (Twitter, Instagram)
- *
- * var linkedText = Autolinker.link( input, {
- * replaceFn : function( match ) {
- * console.log( "href = ", match.getAnchorHref() );
- * console.log( "text = ", match.getAnchorText() );
- *
- * switch( match.getType() ) {
- * case 'url' :
- * console.log( "url: ", match.getUrl() );
- *
- * if( match.getUrl().indexOf( 'mysite.com' ) === -1 ) {
- * var tag = match.buildTag(); // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes
- * tag.setAttr( 'rel', 'nofollow' );
- * tag.addClass( 'external-link' );
- *
- * return tag;
- *
- * } else {
- * return true; // let Autolinker perform its normal anchor tag replacement
- * }
- *
- * case 'email' :
- * var email = match.getEmail();
- * console.log( "email: ", email );
- *
- * if( email === "my at own.address" ) {
- * return false; // don't auto-link this particular email address; leave as-is
- * } else {
- * return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`)
- * }
- *
- * case 'phone' :
- * var phoneNumber = match.getPhoneNumber();
- * console.log( phoneNumber );
- *
- * return '<a href="http://newplace.to.link.phone.numbers.to/">' + phoneNumber + '</a>';
- *
- * case 'hashtag' :
- * var hashtag = match.getHashtag();
- * console.log( hashtag );
- *
- * return '<a href="http://newplace.to.link.hashtag.handles.to/">' + hashtag + '</a>';
- *
- * case 'mention' :
- * var mention = match.getMention();
- * console.log( mention );
- *
- * return '<a href="http://newplace.to.link.mention.to/">' + mention + '</a>';
- * }
- * }
- * } );
- *
- *
- * The function may return the following values:
- *
- * - `true` (Boolean): Allow Autolinker to replace the match as it normally
- * would.
- * - `false` (Boolean): Do not replace the current match at all - leave as-is.
- * - Any String: If a string is returned from the function, the string will be
- * used directly as the replacement HTML for the match.
- * - An {@link Autolinker.HtmlTag} instance, which can be used to build/modify
- * an HTML tag before writing out its HTML text.
- *
- * @constructor
- * @param {Object} [cfg] The configuration options for the Autolinker instance,
- * specified in an Object (map).
- */
-var Autolinker = function( cfg ) {
- cfg = cfg || {};
-
- this.version = Autolinker.version;
-
- this.urls = this.normalizeUrlsCfg( cfg.urls );
- this.email = typeof cfg.email === 'boolean' ? cfg.email : true;
- this.phone = typeof cfg.phone === 'boolean' ? cfg.phone : true;
- this.hashtag = cfg.hashtag || false;
- this.mention = cfg.mention || false;
- this.newWindow = typeof cfg.newWindow === 'boolean' ? cfg.newWindow : true;
- this.stripPrefix = this.normalizeStripPrefixCfg( cfg.stripPrefix );
- this.stripTrailingSlash = typeof cfg.stripTrailingSlash === 'boolean' ? cfg.stripTrailingSlash : true;
-
- // Validate the value of the `mention` cfg
- var mention = this.mention;
- if( mention !== false && mention !== 'twitter' && mention !== 'instagram' ) {
- throw new Error( "invalid `mention` cfg - see docs" );
- }
-
- // Validate the value of the `hashtag` cfg
- var hashtag = this.hashtag;
- if( hashtag !== false && hashtag !== 'twitter' && hashtag !== 'facebook' && hashtag !== 'instagram' ) {
- throw new Error( "invalid `hashtag` cfg - see docs" );
- }
-
- this.truncate = this.normalizeTruncateCfg( cfg.truncate );
- this.className = cfg.className || '';
- this.replaceFn = cfg.replaceFn || null;
- this.context = cfg.context || this;
-
- this.htmlParser = null;
- this.matchers = null;
- this.tagBuilder = null;
-};
-
-
-
-/**
- * Automatically links URLs, Email addresses, Phone Numbers, Twitter handles,
- * Hashtags, and Mentions found in the given chunk of HTML. Does not link URLs
- * found within HTML tags.
- *
- * For instance, if given the text: `You should go to http://www.yahoo.com`,
- * then the result will be `You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a>`
- *
- * Example:
- *
- * var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } );
- * // Produces: "Go to <a href="http://google.com">google.com</a>"
- *
- * @static
- * @param {String} textOrHtml The HTML or text to find matches within (depending
- * on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #mention},
- * {@link #hashtag}, and {@link #mention} options are enabled).
- * @param {Object} [options] Any of the configuration options for the Autolinker
- * class, specified in an Object (map). See the class description for an
- * example call.
- * @return {String} The HTML text, with matches automatically linked.
- */
-Autolinker.link = function( textOrHtml, options ) {
- var autolinker = new Autolinker( options );
- return autolinker.link( textOrHtml );
-};
-
-
-
-/**
- * Parses the input `textOrHtml` looking for URLs, email addresses, phone
- * numbers, username handles, and hashtags (depending on the configuration
- * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match}
- * objects describing those matches (without making any replacements).
- *
- * Note that if parsing multiple pieces of text, it is slightly more efficient
- * to create an Autolinker instance, and use the instance-level {@link #parse}
- * method.
- *
- * Example:
- *
- * var matches = Autolinker.parse( "Hello google.com, I am asdf at asdf.com", {
- * urls: true,
- * email: true
- * } );
- *
- * console.log( matches.length ); // 2
- * console.log( matches[ 0 ].getType() ); // 'url'
- * console.log( matches[ 0 ].getUrl() ); // 'google.com'
- * console.log( matches[ 1 ].getType() ); // 'email'
- * console.log( matches[ 1 ].getEmail() ); // 'asdf at asdf.com'
- *
- * @static
- * @param {String} textOrHtml The HTML or text to find matches within
- * (depending on if the {@link #urls}, {@link #email}, {@link #phone},
- * {@link #hashtag}, and {@link #mention} options are enabled).
- * @param {Object} [options] Any of the configuration options for the Autolinker
- * class, specified in an Object (map). See the class description for an
- * example call.
- * @return {Autolinker.match.Match[]} The array of Matches found in the
- * given input `textOrHtml`.
- */
-Autolinker.parse = function( textOrHtml, options ) {
- var autolinker = new Autolinker( options );
- return autolinker.parse( textOrHtml );
-};
-
-
-/**
- * @static
- * @property {String} version (readonly)
- *
- * The Autolinker version number in the form major.minor.patch
- *
- * Ex: 0.25.1
- */
-Autolinker.version = '1.4.3';
-
-
-Autolinker.prototype = {
- constructor : Autolinker, // fix constructor property
-
- /**
- * @cfg {Boolean/Object} [urls]
- *
- * `true` if URLs should be automatically linked, `false` if they should not
- * be. Defaults to `true`.
- *
- * Examples:
- *
- * urls: true
- *
- * // or
- *
- * urls: {
- * schemeMatches : true,
- * wwwMatches : true,
- * tldMatches : true
- * }
- *
- * As shown above, this option also accepts an Object form with 3 properties
- * to allow for more customization of what exactly gets linked. All default
- * to `true`:
- *
- * @cfg {Boolean} [urls.schemeMatches] `true` to match URLs found prefixed
- * with a scheme, i.e. `http://google.com`, or `other+scheme://google.com`,
- * `false` to prevent these types of matches.
- * @cfg {Boolean} [urls.wwwMatches] `true` to match urls found prefixed with
- * `'www.'`, i.e. `www.google.com`. `false` to prevent these types of
- * matches. Note that if the URL had a prefixed scheme, and
- * `schemeMatches` is true, it will still be linked.
- * @cfg {Boolean} [urls.tldMatches] `true` to match URLs with known top
- * level domains (.com, .net, etc.) that are not prefixed with a scheme or
- * `'www.'`. This option attempts to match anything that looks like a URL
- * in the given text. Ex: `google.com`, `asdf.org/?page=1`, etc. `false`
- * to prevent these types of matches.
- */
-
- /**
- * @cfg {Boolean} [email=true]
- *
- * `true` if email addresses should be automatically linked, `false` if they
- * should not be.
- */
-
- /**
- * @cfg {Boolean} [phone=true]
- *
- * `true` if Phone numbers ("(555)555-5555") should be automatically linked,
- * `false` if they should not be.
- */
-
- /**
- * @cfg {Boolean/String} [hashtag=false]
- *
- * A string for the service name to have hashtags (ex: "#myHashtag")
- * auto-linked to. The currently-supported values are:
- *
- * - 'twitter'
- * - 'facebook'
- * - 'instagram'
- *
- * Pass `false` to skip auto-linking of hashtags.
- */
-
- /**
- * @cfg {String/Boolean} [mention=false]
- *
- * A string for the service name to have mentions (ex: "@myuser")
- * auto-linked to. The currently supported values are:
- *
- * - 'twitter'
- * - 'instagram'
- *
- * Defaults to `false` to skip auto-linking of mentions.
- */
-
- /**
- * @cfg {Boolean} [newWindow=true]
- *
- * `true` if the links should open in a new window, `false` otherwise.
- */
-
- /**
- * @cfg {Boolean/Object} [stripPrefix]
- *
- * `true` if 'http://' (or 'https://') and/or the 'www.' should be stripped
- * from the beginning of URL links' text, `false` otherwise. Defaults to
- * `true`.
- *
- * Examples:
- *
- * stripPrefix: true
- *
- * // or
- *
- * stripPrefix: {
- * scheme : true,
- * www : true
- * }
- *
- * As shown above, this option also accepts an Object form with 2 properties
- * to allow for more customization of what exactly is prevented from being
- * displayed. Both default to `true`:
- *
- * @cfg {Boolean} [stripPrefix.scheme] `true` to prevent the scheme part of
- * a URL match from being displayed to the user. Example:
- * `'http://google.com'` will be displayed as `'google.com'`. `false` to
- * not strip the scheme. NOTE: Only an `'http://'` or `'https://'` scheme
- * will be removed, so as not to remove a potentially dangerous scheme
- * (such as `'file://'` or `'javascript:'`)
- * @cfg {Boolean} [stripPrefix.www] www (Boolean): `true` to prevent the
- * `'www.'` part of a URL match from being displayed to the user. Ex:
- * `'www.google.com'` will be displayed as `'google.com'`. `false` to not
- * strip the `'www'`.
- */
-
- /**
- * @cfg {Boolean} [stripTrailingSlash=true]
- *
- * `true` to remove the trailing slash from URL matches, `false` to keep
- * the trailing slash.
- *
- * Example when `true`: `http://google.com/` will be displayed as
- * `http://google.com`.
- */
-
- /**
- * @cfg {Number/Object} [truncate=0]
- *
- * ## Number Form
- *
- * A number for how many characters matched text should be truncated to
- * inside the text of a link. If the matched text is over this number of
- * characters, it will be truncated to this length by adding a two period
- * ellipsis ('..') to the end of the string.
- *
- * For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file'
- * truncated to 25 characters might look something like this:
- * 'yahoo.com/some/long/pat..'
- *
- * Example Usage:
- *
- * truncate: 25
- *
- *
- * Defaults to `0` for "no truncation."
- *
- *
- * ## Object Form
- *
- * An Object may also be provided with two properties: `length` (Number) and
- * `location` (String). `location` may be one of the following: 'end'
- * (default), 'middle', or 'smart'.
- *
- * Example Usage:
- *
- * truncate: { length: 25, location: 'middle' }
- *
- * @cfg {Number} [truncate.length=0] How many characters to allow before
- * truncation will occur. Defaults to `0` for "no truncation."
- * @cfg {"end"/"middle"/"smart"} [truncate.location="end"]
- *
- * - 'end' (default): will truncate up to the number of characters, and then
- * add an ellipsis at the end. Ex: 'yahoo.com/some/long/pat..'
- * - 'middle': will truncate and add the ellipsis in the middle. Ex:
- * 'yahoo.com/s..th/to/a/file'
- * - 'smart': for URLs where the algorithm attempts to strip out unnecessary
- * parts first (such as the 'www.', then URL scheme, hash, etc.),
- * attempting to make the URL human-readable before looking for a good
- * point to insert the ellipsis if it is still too long. Ex:
- * 'yahoo.com/some..to/a/file'. For more details, see
- * {@link Autolinker.truncate.TruncateSmart}.
- */
-
- /**
- * @cfg {String} className
- *
- * A CSS class name to add to the generated links. This class will be added
- * to all links, as well as this class plus match suffixes for styling
- * url/email/phone/hashtag/mention links differently.
- *
- * For example, if this config is provided as "myLink", then:
- *
- * - URL links will have the CSS classes: "myLink myLink-url"
- * - Email links will have the CSS classes: "myLink myLink-email", and
- * - Phone links will have the CSS classes: "myLink myLink-phone"
- * - Hashtag links will have the CSS classes: "myLink myLink-hashtag"
- * - Mention links will have the CSS classes: "myLink myLink-mention myLink-[type]"
- * where [type] is either "instagram" or "twitter"
- */
-
- /**
- * @cfg {Function} replaceFn
- *
- * A function to individually process each match found in the input string.
- *
- * See the class's description for usage.
- *
- * The `replaceFn` can be called with a different context object (`this`
- * reference) using the {@link #context} cfg.
- *
- * This function is called with the following parameter:
- *
- * @cfg {Autolinker.match.Match} replaceFn.match The Match instance which
- * can be used to retrieve information about the match that the `replaceFn`
- * is currently processing. See {@link Autolinker.match.Match} subclasses
- * for details.
- */
-
- /**
- * @cfg {Object} context
- *
- * The context object (`this` reference) to call the `replaceFn` with.
- *
- * Defaults to this Autolinker instance.
- */
-
-
- /**
- * @property {String} version (readonly)
- *
- * The Autolinker version number in the form major.minor.patch
- *
- * Ex: 0.25.1
- */
-
- /**
- * @private
- * @property {Autolinker.htmlParser.HtmlParser} htmlParser
- *
- * The HtmlParser instance used to skip over HTML tags, while finding text
- * nodes to process. This is lazily instantiated in the {@link #getHtmlParser}
- * method.
- */
-
- /**
- * @private
- * @property {Autolinker.matcher.Matcher[]} matchers
- *
- * The {@link Autolinker.matcher.Matcher} instances for this Autolinker
- * instance.
- *
- * This is lazily created in {@link #getMatchers}.
- */
-
- /**
- * @private
- * @property {Autolinker.AnchorTagBuilder} tagBuilder
- *
- * The AnchorTagBuilder instance used to build match replacement anchor tags.
- * Note: this is lazily instantiated in the {@link #getTagBuilder} method.
- */
-
-
- /**
- * Normalizes the {@link #urls} config into an Object with 3 properties:
- * `schemeMatches`, `wwwMatches`, and `tldMatches`, all Booleans.
- *
- * See {@link #urls} config for details.
- *
- * @private
- * @param {Boolean/Object} urls
- * @return {Object}
- */
- normalizeUrlsCfg : function( urls ) {
- if( urls == null ) urls = true; // default to `true`
-
- if( typeof urls === 'boolean' ) {
- return { schemeMatches: urls, wwwMatches: urls, tldMatches: urls };
-
- } else { // object form
- return {
- schemeMatches : typeof urls.schemeMatches === 'boolean' ? urls.schemeMatches : true,
- wwwMatches : typeof urls.wwwMatches === 'boolean' ? urls.wwwMatches : true,
- tldMatches : typeof urls.tldMatches === 'boolean' ? urls.tldMatches : true
- };
- }
- },
-
-
- /**
- * Normalizes the {@link #stripPrefix} config into an Object with 2
- * properties: `scheme`, and `www` - both Booleans.
- *
- * See {@link #stripPrefix} config for details.
- *
- * @private
- * @param {Boolean/Object} stripPrefix
- * @return {Object}
- */
- normalizeStripPrefixCfg : function( stripPrefix ) {
- if( stripPrefix == null ) stripPrefix = true; // default to `true`
-
- if( typeof stripPrefix === 'boolean' ) {
- return { scheme: stripPrefix, www: stripPrefix };
-
- } else { // object form
- return {
- scheme : typeof stripPrefix.scheme === 'boolean' ? stripPrefix.scheme : true,
- www : typeof stripPrefix.www === 'boolean' ? stripPrefix.www : true
- };
- }
- },
-
-
- /**
- * Normalizes the {@link #truncate} config into an Object with 2 properties:
- * `length` (Number), and `location` (String).
- *
- * See {@link #truncate} config for details.
- *
- * @private
- * @param {Number/Object} truncate
- * @return {Object}
- */
- normalizeTruncateCfg : function( truncate ) {
- if( typeof truncate === 'number' ) {
- return { length: truncate, location: 'end' };
-
- } else { // object, or undefined/null
- return Autolinker.Util.defaults( truncate || {}, {
- length : Number.POSITIVE_INFINITY,
- location : 'end'
- } );
- }
- },
-
-
- /**
- * Parses the input `textOrHtml` looking for URLs, email addresses, phone
- * numbers, username handles, and hashtags (depending on the configuration
- * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match}
- * objects describing those matches (without making any replacements).
- *
- * This method is used by the {@link #link} method, but can also be used to
- * simply do parsing of the input in order to discover what kinds of links
- * there are and how many.
- *
- * Example usage:
- *
- * var autolinker = new Autolinker( {
- * urls: true,
- * email: true
- * } );
- *
- * var matches = autolinker.parse( "Hello google.com, I am asdf at asdf.com" );
- *
- * console.log( matches.length ); // 2
- * console.log( matches[ 0 ].getType() ); // 'url'
- * console.log( matches[ 0 ].getUrl() ); // 'google.com'
- * console.log( matches[ 1 ].getType() ); // 'email'
- * console.log( matches[ 1 ].getEmail() ); // 'asdf at asdf.com'
- *
- * @param {String} textOrHtml The HTML or text to find matches within
- * (depending on if the {@link #urls}, {@link #email}, {@link #phone},
- * {@link #hashtag}, and {@link #mention} options are enabled).
- * @return {Autolinker.match.Match[]} The array of Matches found in the
- * given input `textOrHtml`.
- */
- parse : function( textOrHtml ) {
- var htmlParser = this.getHtmlParser(),
- htmlNodes = htmlParser.parse( textOrHtml ),
- anchorTagStackCount = 0, // used to only process text around anchor tags, and any inner text/html they may have;
- matches = [];
-
- // Find all matches within the `textOrHtml` (but not matches that are
- // already nested within <a> tags)
- for( var i = 0, len = htmlNodes.length; i < len; i++ ) {
- var node = htmlNodes[ i ],
- nodeType = node.getType();
-
- if( nodeType === 'element' && node.getTagName() === 'a' ) { // Process HTML anchor element nodes in the input `textOrHtml` to find out when we're within an <a> tag
- if( !node.isClosing() ) { // it's the start <a> tag
- anchorTagStackCount++;
- } else { // it's the end </a> tag
- anchorTagStackCount = Math.max( anchorTagStackCount - 1, 0 ); // attempt to handle extraneous </a> tags by making sure the stack count never goes below 0
- }
-
- } else if( nodeType === 'text' && anchorTagStackCount === 0 ) { // Process text nodes that are not within an <a> tag
- var textNodeMatches = this.parseText( node.getText(), node.getOffset() );
-
- matches.push.apply( matches, textNodeMatches );
- }
- }
-
-
- // After we have found all matches, remove subsequent matches that
- // overlap with a previous match. This can happen for instance with URLs,
- // where the url 'google.com/#link' would match '#link' as a hashtag.
- matches = this.compactMatches( matches );
-
- // And finally, remove matches for match types that have been turned
- // off. We needed to have all match types turned on initially so that
- // things like hashtags could be filtered out if they were really just
- // part of a URL match (for instance, as a named anchor).
- matches = this.removeUnwantedMatches( matches );
-
- return matches;
- },
-
-
- /**
- * After we have found all matches, we need to remove subsequent matches
- * that overlap with a previous match. This can happen for instance with
- * URLs, where the url 'google.com/#link' would match '#link' as a hashtag.
- *
- * @private
- * @param {Autolinker.match.Match[]} matches
- * @return {Autolinker.match.Match[]}
- */
- compactMatches : function( matches ) {
- // First, the matches need to be sorted in order of offset
- matches.sort( function( a, b ) { return a.getOffset() - b.getOffset(); } );
-
- for( var i = 0; i < matches.length - 1; i++ ) {
- var match = matches[ i ],
- offset = match.getOffset(),
- matchedTextLength = match.getMatchedText().length,
- endIdx = offset + matchedTextLength;
-
- if( i + 1 < matches.length ) {
- // Remove subsequent matches that equal offset with current match
- if( matches[ i + 1 ].getOffset() === offset ) {
- var removeIdx = matches[ i + 1 ].getMatchedText().length > matchedTextLength ? i : i + 1;
- matches.splice( removeIdx, 1 );
- continue;
- }
-
- // Remove subsequent matches that overlap with the current match
- if( matches[ i + 1 ].getOffset() <= endIdx ) {
- matches.splice( i + 1, 1 );
- }
- }
- }
-
- return matches;
- },
-
-
- /**
- * Removes matches for matchers that were turned off in the options. For
- * example, if {@link #hashtag hashtags} were not to be matched, we'll
- * remove them from the `matches` array here.
- *
- * @private
- * @param {Autolinker.match.Match[]} matches The array of matches to remove
- * the unwanted matches from. Note: this array is mutated for the
- * removals.
- * @return {Autolinker.match.Match[]} The mutated input `matches` array.
- */
- removeUnwantedMatches : function( matches ) {
- var remove = Autolinker.Util.remove;
-
- if( !this.hashtag ) remove( matches, function( match ) { return match.getType() === 'hashtag'; } );
- if( !this.email ) remove( matches, function( match ) { return match.getType() === 'email'; } );
- if( !this.phone ) remove( matches, function( match ) { return match.getType() === 'phone'; } );
- if( !this.mention ) remove( matches, function( match ) { return match.getType() === 'mention'; } );
- if( !this.urls.schemeMatches ) {
- remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'scheme'; } );
- }
- if( !this.urls.wwwMatches ) {
- remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'www'; } );
- }
- if( !this.urls.tldMatches ) {
- remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'tld'; } );
- }
-
- return matches;
- },
-
-
- /**
- * Parses the input `text` looking for URLs, email addresses, phone
- * numbers, username handles, and hashtags (depending on the configuration
- * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match}
- * objects describing those matches.
- *
- * This method processes a **non-HTML string**, and is used to parse and
- * match within the text nodes of an HTML string. This method is used
- * internally by {@link #parse}.
- *
- * @private
- * @param {String} text The text to find matches within (depending on if the
- * {@link #urls}, {@link #email}, {@link #phone},
- * {@link #hashtag}, and {@link #mention} options are enabled). This must be a non-HTML string.
- * @param {Number} [offset=0] The offset of the text node within the
- * original string. This is used when parsing with the {@link #parse}
- * method to generate correct offsets within the {@link Autolinker.match.Match}
- * instances, but may be omitted if calling this method publicly.
- * @return {Autolinker.match.Match[]} The array of Matches found in the
- * given input `text`.
- */
- parseText : function( text, offset ) {
- offset = offset || 0;
- var matchers = this.getMatchers(),
- matches = [];
-
- for( var i = 0, numMatchers = matchers.length; i < numMatchers; i++ ) {
- var textMatches = matchers[ i ].parseMatches( text );
-
- // Correct the offset of each of the matches. They are originally
- // the offset of the match within the provided text node, but we
- // need to correct them to be relative to the original HTML input
- // string (i.e. the one provided to #parse).
- for( var j = 0, numTextMatches = textMatches.length; j < numTextMatches; j++ ) {
- textMatches[ j ].setOffset( offset + textMatches[ j ].getOffset() );
- }
-
- matches.push.apply( matches, textMatches );
- }
- return matches;
- },
-
-
- /**
- * Automatically links URLs, Email addresses, Phone numbers, Hashtags,
- * and Mentions (Twitter, Instagram) found in the given chunk of HTML. Does not link
- * URLs found within HTML tags.
- *
- * For instance, if given the text: `You should go to http://www.yahoo.com`,
- * then the result will be `You should go to
- * <a href="http://www.yahoo.com">http://www.yahoo.com</a>`
- *
- * This method finds the text around any HTML elements in the input
- * `textOrHtml`, which will be the text that is processed. Any original HTML
- * elements will be left as-is, as well as the text that is already wrapped
- * in anchor (<a>) tags.
- *
- * @param {String} textOrHtml The HTML or text to autolink matches within
- * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #hashtag}, and {@link #mention} options are enabled).
- * @return {String} The HTML, with matches automatically linked.
- */
- link : function( textOrHtml ) {
- if( !textOrHtml ) { return ""; } // handle `null` and `undefined`
-
- var matches = this.parse( textOrHtml ),
- newHtml = [],
- lastIndex = 0;
-
- for( var i = 0, len = matches.length; i < len; i++ ) {
- var match = matches[ i ];
-
- newHtml.push( textOrHtml.substring( lastIndex, match.getOffset() ) );
- newHtml.push( this.createMatchReturnVal( match ) );
-
- lastIndex = match.getOffset() + match.getMatchedText().length;
- }
- newHtml.push( textOrHtml.substring( lastIndex ) ); // handle the text after the last match
-
- return newHtml.join( '' );
- },
-
-
- /**
- * Creates the return string value for a given match in the input string.
- *
- * This method handles the {@link #replaceFn}, if one was provided.
- *
- * @private
- * @param {Autolinker.match.Match} match The Match object that represents
- * the match.
- * @return {String} The string that the `match` should be replaced with.
- * This is usually the anchor tag string, but may be the `matchStr` itself
- * if the match is not to be replaced.
- */
- createMatchReturnVal : function( match ) {
- // Handle a custom `replaceFn` being provided
- var replaceFnResult;
- if( this.replaceFn ) {
- replaceFnResult = this.replaceFn.call( this.context, match ); // Autolinker instance is the context
- }
-
- if( typeof replaceFnResult === 'string' ) {
- return replaceFnResult; // `replaceFn` returned a string, use that
-
- } else if( replaceFnResult === false ) {
- return match.getMatchedText(); // no replacement for the match
-
- } else if( replaceFnResult instanceof Autolinker.HtmlTag ) {
- return replaceFnResult.toAnchorString();
-
- } else { // replaceFnResult === true, or no/unknown return value from function
- // Perform Autolinker's default anchor tag generation
- var anchorTag = match.buildTag(); // returns an Autolinker.HtmlTag instance
-
- return anchorTag.toAnchorString();
- }
- },
-
-
- /**
- * Lazily instantiates and returns the {@link #htmlParser} instance for this
- * Autolinker instance.
- *
- * @protected
- * @return {Autolinker.htmlParser.HtmlParser}
- */
- getHtmlParser : function() {
- var htmlParser = this.htmlParser;
-
- if( !htmlParser ) {
- htmlParser = this.htmlParser = new Autolinker.htmlParser.HtmlParser();
- }
-
- return htmlParser;
- },
-
-
- /**
- * Lazily instantiates and returns the {@link Autolinker.matcher.Matcher}
- * instances for this Autolinker instance.
- *
- * @protected
- * @return {Autolinker.matcher.Matcher[]}
- */
- getMatchers : function() {
- if( !this.matchers ) {
- var matchersNs = Autolinker.matcher,
- tagBuilder = this.getTagBuilder();
-
- var matchers = [
- new matchersNs.Hashtag( { tagBuilder: tagBuilder, serviceName: this.hashtag } ),
- new matchersNs.Email( { tagBuilder: tagBuilder } ),
- new matchersNs.Phone( { tagBuilder: tagBuilder } ),
- new matchersNs.Mention( { tagBuilder: tagBuilder, serviceName: this.mention } ),
- new matchersNs.Url( { tagBuilder: tagBuilder, stripPrefix: this.stripPrefix, stripTrailingSlash: this.stripTrailingSlash } )
- ];
-
- return ( this.matchers = matchers );
-
- } else {
- return this.matchers;
- }
- },
-
-
- /**
- * Returns the {@link #tagBuilder} instance for this Autolinker instance, lazily instantiating it
- * if it does not yet exist.
- *
- * This method may be used in a {@link #replaceFn} to generate the {@link Autolinker.HtmlTag HtmlTag} instance that
- * Autolinker would normally generate, and then allow for modifications before returning it. For example:
- *
- * var html = Autolinker.link( "Test google.com", {
- * replaceFn : function( match ) {
- * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance
- * tag.setAttr( 'rel', 'nofollow' );
- *
- * return tag;
- * }
- * } );
- *
- * // generated html:
- * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
- *
- * @return {Autolinker.AnchorTagBuilder}
- */
- getTagBuilder : function() {
- var tagBuilder = this.tagBuilder;
-
- if( !tagBuilder ) {
- tagBuilder = this.tagBuilder = new Autolinker.AnchorTagBuilder( {
- newWindow : this.newWindow,
- truncate : this.truncate,
- className : this.className
- } );
- }
-
- return tagBuilder;
- }
-
-};
-
-
-// Autolinker Namespaces
-
-Autolinker.match = {};
-Autolinker.matcher = {};
-Autolinker.htmlParser = {};
-Autolinker.truncate = {};
-
-/*global Autolinker */
-/*jshint eqnull:true, boss:true */
-/**
- * @class Autolinker.Util
- * @singleton
- *
- * A few utility methods for Autolinker.
- */
-Autolinker.Util = {
-
- /**
- * @property {Function} abstractMethod
- *
- * A function object which represents an abstract method.
- */
- abstractMethod : function() { throw "abstract"; },
-
-
- /**
- * @private
- * @property {RegExp} trimRegex
- *
- * The regular expression used to trim the leading and trailing whitespace
- * from a string.
- */
- trimRegex : /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
-
- /**
- * Assigns (shallow copies) the properties of `src` onto `dest`.
- *
- * @param {Object} dest The destination object.
- * @param {Object} src The source object.
- * @return {Object} The destination object (`dest`)
- */
- assign : function( dest, src ) {
- for( var prop in src ) {
- if( src.hasOwnProperty( prop ) ) {
- dest[ prop ] = src[ prop ];
- }
- }
-
- return dest;
- },
-
-
- /**
- * Assigns (shallow copies) the properties of `src` onto `dest`, if the
- * corresponding property on `dest` === `undefined`.
- *
- * @param {Object} dest The destination object.
- * @param {Object} src The source object.
- * @return {Object} The destination object (`dest`)
- */
- defaults : function( dest, src ) {
- for( var prop in src ) {
- if( src.hasOwnProperty( prop ) && dest[ prop ] === undefined ) {
- dest[ prop ] = src[ prop ];
- }
- }
-
- return dest;
- },
-
-
- /**
- * Extends `superclass` to create a new subclass, adding the `protoProps` to the new subclass's prototype.
- *
- * @param {Function} superclass The constructor function for the superclass.
- * @param {Object} protoProps The methods/properties to add to the subclass's prototype. This may contain the
- * special property `constructor`, which will be used as the new subclass's constructor function.
- * @return {Function} The new subclass function.
- */
- extend : function( superclass, protoProps ) {
- var superclassProto = superclass.prototype;
-
- var F = function() {};
- F.prototype = superclassProto;
-
- var subclass;
- if( protoProps.hasOwnProperty( 'constructor' ) ) {
- subclass = protoProps.constructor;
- } else {
- subclass = function() { superclassProto.constructor.apply( this, arguments ); };
- }
-
- var subclassProto = subclass.prototype = new F(); // set up prototype chain
- subclassProto.constructor = subclass; // fix constructor property
- subclassProto.superclass = superclassProto;
-
- delete protoProps.constructor; // don't re-assign constructor property to the prototype, since a new function may have been created (`subclass`), which is now already there
- Autolinker.Util.assign( subclassProto, protoProps );
-
- return subclass;
- },
-
-
- /**
- * Truncates the `str` at `len - ellipsisChars.length`, and adds the `ellipsisChars` to the
- * end of the string (by default, two periods: '..'). If the `str` length does not exceed
- * `len`, the string will be returned unchanged.
- *
- * @param {String} str The string to truncate and add an ellipsis to.
- * @param {Number} truncateLen The length to truncate the string at.
- * @param {String} [ellipsisChars=...] The ellipsis character(s) to add to the end of `str`
- * when truncated. Defaults to '...'
- */
- ellipsis : function( str, truncateLen, ellipsisChars ) {
- var ellipsisLength;
-
- if( str.length > truncateLen ) {
- if(ellipsisChars == null) {
- ellipsisChars = '…';
- ellipsisLength = 3;
- } else {
- ellipsisLength = ellipsisChars.length;
- }
-
- str = str.substring( 0, truncateLen - ellipsisLength ) + ellipsisChars;
- }
- return str;
- },
-
-
- /**
- * Supports `Array.prototype.indexOf()` functionality for old IE (IE8 and below).
- *
- * @param {Array} arr The array to find an element of.
- * @param {*} element The element to find in the array, and return the index of.
- * @return {Number} The index of the `element`, or -1 if it was not found.
- */
- indexOf : function( arr, element ) {
- if( Array.prototype.indexOf ) {
- return arr.indexOf( element );
-
- } else {
- for( var i = 0, len = arr.length; i < len; i++ ) {
- if( arr[ i ] === element ) return i;
- }
- return -1;
- }
- },
-
-
- /**
- * Removes array elements based on a filtering function. Mutates the input
- * array.
- *
- * Using this instead of the ES5 Array.prototype.filter() function, to allow
- * Autolinker compatibility with IE8, and also to prevent creating many new
- * arrays in memory for filtering.
- *
- * @param {Array} arr The array to remove elements from. This array is
- * mutated.
- * @param {Function} fn A function which should return `true` to
- * remove an element.
- * @return {Array} The mutated input `arr`.
- */
- remove : function( arr, fn ) {
- for( var i = arr.length - 1; i >= 0; i-- ) {
- if( fn( arr[ i ] ) === true ) {
- arr.splice( i, 1 );
- }
- }
- },
-
-
- /**
- * Performs the functionality of what modern browsers do when `String.prototype.split()` is called
- * with a regular expression that contains capturing parenthesis.
- *
- * For example:
- *
- * // Modern browsers:
- * "a,b,c".split( /(,)/ ); // --> [ 'a', ',', 'b', ',', 'c' ]
- *
- * // Old IE (including IE8):
- * "a,b,c".split( /(,)/ ); // --> [ 'a', 'b', 'c' ]
- *
- * This method emulates the functionality of modern browsers for the old IE case.
- *
- * @param {String} str The string to split.
- * @param {RegExp} splitRegex The regular expression to split the input `str` on. The splitting
- * character(s) will be spliced into the array, as in the "modern browsers" example in the
- * description of this method.
- * Note #1: the supplied regular expression **must** have the 'g' flag specified.
- * Note #2: for simplicity's sake, the regular expression does not need
- * to contain capturing parenthesis - it will be assumed that any match has them.
- * @return {String[]} The split array of strings, with the splitting character(s) included.
- */
- splitAndCapture : function( str, splitRegex ) {
- if( !splitRegex.global ) throw new Error( "`splitRegex` must have the 'g' flag set" );
-
- var result = [],
- lastIdx = 0,
- match;
-
- while( match = splitRegex.exec( str ) ) {
- result.push( str.substring( lastIdx, match.index ) );
- result.push( match[ 0 ] ); // push the splitting char(s)
-
- lastIdx = match.index + match[ 0 ].length;
- }
- result.push( str.substring( lastIdx ) );
-
- return result;
- },
-
-
- /**
- * Trims the leading and trailing whitespace from a string.
- *
- * @param {String} str The string to trim.
- * @return {String}
- */
- trim : function( str ) {
- return str.replace( this.trimRegex, '' );
- }
-
-};
-
-/*global Autolinker */
-/*jshint boss:true */
-/**
- * @class Autolinker.HtmlTag
- * @extends Object
- *
- * Represents an HTML tag, which can be used to easily build/modify HTML tags programmatically.
- *
- * Autolinker uses this abstraction to create HTML tags, and then write them out as strings. You may also use
- * this class in your code, especially within a {@link Autolinker#replaceFn replaceFn}.
- *
- * ## Examples
- *
- * Example instantiation:
- *
- * var tag = new Autolinker.HtmlTag( {
- * tagName : 'a',
- * attrs : { 'href': 'http://google.com', 'class': 'external-link' },
- * innerHtml : 'Google'
- * } );
- *
- * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a>
- *
- * // Individual accessor methods
- * tag.getTagName(); // 'a'
- * tag.getAttr( 'href' ); // 'http://google.com'
- * tag.hasClass( 'external-link' ); // true
- *
- *
- * Using mutator methods (which may be used in combination with instantiation config properties):
- *
- * var tag = new Autolinker.HtmlTag();
- * tag.setTagName( 'a' );
- * tag.setAttr( 'href', 'http://google.com' );
- * tag.addClass( 'external-link' );
- * tag.setInnerHtml( 'Google' );
- *
- * tag.getTagName(); // 'a'
- * tag.getAttr( 'href' ); // 'http://google.com'
- * tag.hasClass( 'external-link' ); // true
- *
- * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a>
- *
- *
- * ## Example use within a {@link Autolinker#replaceFn replaceFn}
- *
- * var html = Autolinker.link( "Test google.com", {
- * replaceFn : function( match ) {
- * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text
- * tag.setAttr( 'rel', 'nofollow' );
- *
- * return tag;
- * }
- * } );
- *
- * // generated html:
- * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
- *
- *
- * ## Example use with a new tag for the replacement
- *
- * var html = Autolinker.link( "Test google.com", {
- * replaceFn : function( match ) {
- * var tag = new Autolinker.HtmlTag( {
- * tagName : 'button',
- * attrs : { 'title': 'Load URL: ' + match.getAnchorHref() },
- * innerHtml : 'Load URL: ' + match.getAnchorText()
- * } );
- *
- * return tag;
- * }
- * } );
- *
- * // generated html:
- * // Test <button title="Load URL: http://google.com">Load URL: google.com</button>
- */
-Autolinker.HtmlTag = Autolinker.Util.extend( Object, {
-
- /**
- * @cfg {String} tagName
- *
- * The tag name. Ex: 'a', 'button', etc.
- *
- * Not required at instantiation time, but should be set using {@link #setTagName} before {@link #toAnchorString}
- * is executed.
- */
-
- /**
- * @cfg {Object.<String, String>} attrs
- *
- * An key/value Object (map) of attributes to create the tag with. The keys are the attribute names, and the
- * values are the attribute values.
- */
-
- /**
- * @cfg {String} innerHtml
- *
- * The inner HTML for the tag.
- *
- * Note the camel case name on `innerHtml`. Acronyms are camelCased in this utility (such as not to run into the acronym
- * naming inconsistency that the DOM developers created with `XMLHttpRequest`). You may alternatively use {@link #innerHTML}
- * if you prefer, but this one is recommended.
- */
-
- /**
- * @cfg {String} innerHTML
- *
- * Alias of {@link #innerHtml}, accepted for consistency with the browser DOM api, but prefer the camelCased version
- * for acronym names.
- */
-
-
- /**
- * @protected
- * @property {RegExp} whitespaceRegex
- *
- * Regular expression used to match whitespace in a string of CSS classes.
- */
- whitespaceRegex : /\s+/,
-
-
- /**
- * @constructor
- * @param {Object} [cfg] The configuration properties for this class, in an Object (map)
- */
- constructor : function( cfg ) {
- Autolinker.Util.assign( this, cfg );
-
- this.innerHtml = this.innerHtml || this.innerHTML; // accept either the camelCased form or the fully capitalized acronym
- },
-
-
- /**
- * Sets the tag name that will be used to generate the tag with.
- *
- * @param {String} tagName
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- setTagName : function( tagName ) {
- this.tagName = tagName;
- return this;
- },
-
-
- /**
- * Retrieves the tag name.
- *
- * @return {String}
- */
- getTagName : function() {
- return this.tagName || "";
- },
-
-
- /**
- * Sets an attribute on the HtmlTag.
- *
- * @param {String} attrName The attribute name to set.
- * @param {String} attrValue The attribute value to set.
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- setAttr : function( attrName, attrValue ) {
- var tagAttrs = this.getAttrs();
- tagAttrs[ attrName ] = attrValue;
-
- return this;
- },
-
-
- /**
- * Retrieves an attribute from the HtmlTag. If the attribute does not exist, returns `undefined`.
- *
- * @param {String} attrName The attribute name to retrieve.
- * @return {String} The attribute's value, or `undefined` if it does not exist on the HtmlTag.
- */
- getAttr : function( attrName ) {
- return this.getAttrs()[ attrName ];
- },
-
-
- /**
- * Sets one or more attributes on the HtmlTag.
- *
- * @param {Object.<String, String>} attrs A key/value Object (map) of the attributes to set.
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- setAttrs : function( attrs ) {
- var tagAttrs = this.getAttrs();
- Autolinker.Util.assign( tagAttrs, attrs );
-
- return this;
- },
-
-
- /**
- * Retrieves the attributes Object (map) for the HtmlTag.
- *
- * @return {Object.<String, String>} A key/value object of the attributes for the HtmlTag.
- */
- getAttrs : function() {
- return this.attrs || ( this.attrs = {} );
- },
-
-
- /**
- * Sets the provided `cssClass`, overwriting any current CSS classes on the HtmlTag.
- *
- * @param {String} cssClass One or more space-separated CSS classes to set (overwrite).
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- setClass : function( cssClass ) {
- return this.setAttr( 'class', cssClass );
- },
-
-
- /**
- * Convenience method to add one or more CSS classes to the HtmlTag. Will not add duplicate CSS classes.
- *
- * @param {String} cssClass One or more space-separated CSS classes to add.
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- addClass : function( cssClass ) {
- var classAttr = this.getClass(),
- whitespaceRegex = this.whitespaceRegex,
- indexOf = Autolinker.Util.indexOf, // to support IE8 and below
- classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
- newClasses = cssClass.split( whitespaceRegex ),
- newClass;
-
- while( newClass = newClasses.shift() ) {
- if( indexOf( classes, newClass ) === -1 ) {
- classes.push( newClass );
- }
- }
-
- this.getAttrs()[ 'class' ] = classes.join( " " );
- return this;
- },
-
-
- /**
- * Convenience method to remove one or more CSS classes from the HtmlTag.
- *
- * @param {String} cssClass One or more space-separated CSS classes to remove.
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- removeClass : function( cssClass ) {
- var classAttr = this.getClass(),
- whitespaceRegex = this.whitespaceRegex,
- indexOf = Autolinker.Util.indexOf, // to support IE8 and below
- classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
- removeClasses = cssClass.split( whitespaceRegex ),
- removeClass;
-
- while( classes.length && ( removeClass = removeClasses.shift() ) ) {
- var idx = indexOf( classes, removeClass );
- if( idx !== -1 ) {
- classes.splice( idx, 1 );
- }
- }
-
- this.getAttrs()[ 'class' ] = classes.join( " " );
- return this;
- },
-
-
- /**
- * Convenience method to retrieve the CSS class(es) for the HtmlTag, which will each be separated by spaces when
- * there are multiple.
- *
- * @return {String}
- */
- getClass : function() {
- return this.getAttrs()[ 'class' ] || "";
- },
-
-
- /**
- * Convenience method to check if the tag has a CSS class or not.
- *
- * @param {String} cssClass The CSS class to check for.
- * @return {Boolean} `true` if the HtmlTag has the CSS class, `false` otherwise.
- */
- hasClass : function( cssClass ) {
- return ( ' ' + this.getClass() + ' ' ).indexOf( ' ' + cssClass + ' ' ) !== -1;
- },
-
-
- /**
- * Sets the inner HTML for the tag.
- *
- * @param {String} html The inner HTML to set.
- * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
- */
- setInnerHtml : function( html ) {
- this.innerHtml = html;
-
- return this;
- },
-
-
- /**
- * Retrieves the inner HTML for the tag.
- *
- * @return {String}
- */
- getInnerHtml : function() {
- return this.innerHtml || "";
- },
-
-
- /**
- * Override of superclass method used to generate the HTML string for the tag.
- *
- * @return {String}
- */
- toAnchorString : function() {
- var tagName = this.getTagName(),
- attrsStr = this.buildAttrsStr();
-
- attrsStr = ( attrsStr ) ? ' ' + attrsStr : ''; // prepend a space if there are actually attributes
-
- return [ '<', tagName, attrsStr, '>', this.getInnerHtml(), '</', tagName, '>' ].join( "" );
- },
-
-
- /**
- * Support method for {@link #toAnchorString}, returns the string space-separated key="value" pairs, used to populate
- * the stringified HtmlTag.
- *
- * @protected
- * @return {String} Example return: `attr1="value1" attr2="value2"`
- */
- buildAttrsStr : function() {
- if( !this.attrs ) return ""; // no `attrs` Object (map) has been set, return empty string
-
- var attrs = this.getAttrs(),
- attrsArr = [];
-
- for( var prop in attrs ) {
- if( attrs.hasOwnProperty( prop ) ) {
- attrsArr.push( prop + '="' + attrs[ prop ] + '"' );
- }
- }
- return attrsArr.join( " " );
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.RegexLib
- * @singleton
- *
- * Builds and stores a library of the common regular expressions used by the
- * Autolinker utility.
- *
- * Other regular expressions may exist ad-hoc, but these are generally the
- * regular expressions that are shared between source files.
- */
-Autolinker.RegexLib = (function() {
-
- /**
- * The string form of a regular expression that would match all of the
- * alphabetic ("letter") chars in the unicode character set when placed in a
- * RegExp character class (`[]`). This includes all international alphabetic
- * characters.
- *
- * These would be the characters matched by unicode regex engines `\p{L}`
- * escape ("all letters").
- *
- * Taken from the XRegExp library: http://xregexp.com/
- * Specifically: http://xregexp.com/v/3.0.0/unicode-categories.js
- *
- * @private
- * @type {String}
- */
- var alphaCharsStr = 'A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u08 [...]
-
- /**
- * The string form of a regular expression that would match all of the
- * decimal number chars in the unicode character set when placed in a RegExp
- * character class (`[]`).
- *
- * These would be the characters matched by unicode regex engines `\p{Nd}`
- * escape ("all decimal numbers")
- *
- * Taken from the XRegExp library: http://xregexp.com/
- * Specifically: http://xregexp.com/v/3.0.0/unicode-categories.js
- *
- * @private
- * @type {String}
- */
- var decimalNumbersStr = '0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19';
-
-
- // See documentation below
- var alphaNumericCharsStr = alphaCharsStr + decimalNumbersStr;
-
-
- // See documentation below
- var domainNameRegex = new RegExp( '[' + alphaNumericCharsStr + '.\\-]*[' + alphaNumericCharsStr + '\\-]' );
-
- return {
-
- /**
- * The string form of a regular expression that would match all of the
- * letters and decimal number chars in the unicode character set when placed
- * in a RegExp character class (`[]`).
- *
- * These would be the characters matched by unicode regex engines `[\p{L}\p{Nd}]`
- * escape ("all letters and decimal numbers")
- *
- * @property {String} alphaNumericCharsStr
- */
- alphaNumericCharsStr : alphaNumericCharsStr,
-
- /**
- * The string form of a regular expression that would match all of the
- * letters and in the unicode character set when placed
- * in a RegExp character class (`[]`).
- *
- * These would be the characters matched by unicode regex engines `[\p{L}]`
- * escape ("all letters")
- *
- * @property {String} alphaCharsStr
- */
- alphaCharsStr : alphaCharsStr,
-
- /**
- * A regular expression to match domain names of a URL or email address.
- * Ex: 'google', 'yahoo', 'some-other-company', etc.
- *
- * @property {RegExp} domainNameRegex
- */
- domainNameRegex : domainNameRegex,
-
- };
-
-
-}() );
-
-/*global Autolinker */
-/*jshint sub:true */
-/**
- * @protected
- * @class Autolinker.AnchorTagBuilder
- * @extends Object
- *
- * Builds anchor (<a>) tags for the Autolinker utility when a match is
- * found.
- *
- * Normally this class is instantiated, configured, and used internally by an
- * {@link Autolinker} instance, but may actually be used indirectly in a
- * {@link Autolinker#replaceFn replaceFn} to create {@link Autolinker.HtmlTag HtmlTag}
- * instances which may be modified before returning from the
- * {@link Autolinker#replaceFn replaceFn}. For example:
- *
- * var html = Autolinker.link( "Test google.com", {
- * replaceFn : function( match ) {
- * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance
- * tag.setAttr( 'rel', 'nofollow' );
- *
- * return tag;
- * }
- * } );
- *
- * // generated html:
- * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
- */
-Autolinker.AnchorTagBuilder = Autolinker.Util.extend( Object, {
-
- /**
- * @cfg {Boolean} newWindow
- * @inheritdoc Autolinker#newWindow
- */
-
- /**
- * @cfg {Object} truncate
- * @inheritdoc Autolinker#truncate
- */
-
- /**
- * @cfg {String} className
- * @inheritdoc Autolinker#className
- */
-
-
- /**
- * @constructor
- * @param {Object} [cfg] The configuration options for the AnchorTagBuilder instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- cfg = cfg || {};
-
- this.newWindow = cfg.newWindow;
- this.truncate = cfg.truncate;
- this.className = cfg.className;
- },
-
-
- /**
- * Generates the actual anchor (<a>) tag to use in place of the
- * matched text, via its `match` object.
- *
- * @param {Autolinker.match.Match} match The Match instance to generate an
- * anchor tag from.
- * @return {Autolinker.HtmlTag} The HtmlTag instance for the anchor tag.
- */
- build : function( match ) {
- return new Autolinker.HtmlTag( {
- tagName : 'a',
- attrs : this.createAttrs( match ),
- innerHtml : this.processAnchorText( match.getAnchorText() )
- } );
- },
-
-
- /**
- * Creates the Object (map) of the HTML attributes for the anchor (<a>)
- * tag being generated.
- *
- * @protected
- * @param {Autolinker.match.Match} match The Match instance to generate an
- * anchor tag from.
- * @return {Object} A key/value Object (map) of the anchor tag's attributes.
- */
- createAttrs : function( match ) {
- var attrs = {
- 'href' : match.getAnchorHref() // we'll always have the `href` attribute
- };
-
- var cssClass = this.createCssClass( match );
- if( cssClass ) {
- attrs[ 'class' ] = cssClass;
- }
- if( this.newWindow ) {
- attrs[ 'target' ] = "_blank";
- attrs[ 'rel' ] = "noopener noreferrer";
- }
-
- if( this.truncate ) {
- if( this.truncate.length && this.truncate.length < match.getAnchorText().length ) {
- attrs[ 'title' ] = match.getAnchorHref();
- }
- }
-
- return attrs;
- },
-
-
- /**
- * Creates the CSS class that will be used for a given anchor tag, based on
- * the `matchType` and the {@link #className} config.
- *
- * Example returns:
- *
- * - "" // no {@link #className}
- * - "myLink myLink-url" // url match
- * - "myLink myLink-email" // email match
- * - "myLink myLink-phone" // phone match
- * - "myLink myLink-hashtag" // hashtag match
- * - "myLink myLink-mention myLink-twitter" // mention match with Twitter service
- *
- * @private
- * @param {Autolinker.match.Match} match The Match instance to generate an
- * anchor tag from.
- * @return {String} The CSS class string for the link. Example return:
- * "myLink myLink-url". If no {@link #className} was configured, returns
- * an empty string.
- */
- createCssClass : function( match ) {
- var className = this.className;
-
- if( !className ) {
- return "";
-
- } else {
- var returnClasses = [ className ],
- cssClassSuffixes = match.getCssClassSuffixes();
-
- for( var i = 0, len = cssClassSuffixes.length; i < len; i++ ) {
- returnClasses.push( className + '-' + cssClassSuffixes[ i ] );
- }
- return returnClasses.join( ' ' );
- }
- },
-
-
- /**
- * Processes the `anchorText` by truncating the text according to the
- * {@link #truncate} config.
- *
- * @private
- * @param {String} anchorText The anchor tag's text (i.e. what will be
- * displayed).
- * @return {String} The processed `anchorText`.
- */
- processAnchorText : function( anchorText ) {
- anchorText = this.doTruncate( anchorText );
-
- return anchorText;
- },
-
-
- /**
- * Performs the truncation of the `anchorText` based on the {@link #truncate}
- * option. If the `anchorText` is longer than the length specified by the
- * {@link #truncate} option, the truncation is performed based on the
- * `location` property. See {@link #truncate} for details.
- *
- * @private
- * @param {String} anchorText The anchor tag's text (i.e. what will be
- * displayed).
- * @return {String} The truncated anchor text.
- */
- doTruncate : function( anchorText ) {
- var truncate = this.truncate;
- if( !truncate || !truncate.length ) return anchorText;
-
- var truncateLength = truncate.length,
- truncateLocation = truncate.location;
-
- if( truncateLocation === 'smart' ) {
- return Autolinker.truncate.TruncateSmart( anchorText, truncateLength );
-
- } else if( truncateLocation === 'middle' ) {
- return Autolinker.truncate.TruncateMiddle( anchorText, truncateLength );
-
- } else {
- return Autolinker.truncate.TruncateEnd( anchorText, truncateLength );
- }
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.htmlParser.HtmlParser
- * @extends Object
- *
- * An HTML parser implementation which simply walks an HTML string and returns an array of
- * {@link Autolinker.htmlParser.HtmlNode HtmlNodes} that represent the basic HTML structure of the input string.
- *
- * Autolinker uses this to only link URLs/emails/mentions within text nodes, effectively ignoring / "walking
- * around" HTML tags.
- */
-Autolinker.htmlParser.HtmlParser = Autolinker.Util.extend( Object, {
-
- /**
- * @private
- * @property {RegExp} htmlRegex
- *
- * The regular expression used to pull out HTML tags from a string. Handles namespaced HTML tags and
- * attribute names, as specified by http://www.w3.org/TR/html-markup/syntax.html.
- *
- * Capturing groups:
- *
- * 1. The "!DOCTYPE" tag name, if a tag is a <!DOCTYPE> tag.
- * 2. If it is an end tag, this group will have the '/'.
- * 3. If it is a comment tag, this group will hold the comment text (i.e.
- * the text inside the `<!--` and `-->`.
- * 4. The tag name for a tag without attributes (other than the <!DOCTYPE> tag)
- * 5. The tag name for a tag with attributes (other than the <!DOCTYPE> tag)
- */
- htmlRegex : (function() {
- var commentTagRegex = /!--([\s\S]+?)--/,
- tagNameRegex = /[0-9a-zA-Z][0-9a-zA-Z:]*/,
- attrNameRegex = /[^\s"'>\/=\x00-\x1F\x7F]+/, // the unicode range accounts for excluding control chars, and the delete char
- attrValueRegex = /(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/, // double quoted, single quoted, or unquoted attribute values
- nameEqualsValueRegex = attrNameRegex.source + '(?:\\s*=\\s*' + attrValueRegex.source + ')?'; // optional '=[value]'
-
- return new RegExp( [
- // for <!DOCTYPE> tag. Ex: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
- '(?:',
- '<(!DOCTYPE)', // *** Capturing Group 1 - If it's a doctype tag
-
- // Zero or more attributes following the tag name
- '(?:',
- '\\s+', // one or more whitespace chars before an attribute
-
- // Either:
- // A. attr="value", or
- // B. "value" alone (To cover example doctype tag: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
- '(?:', nameEqualsValueRegex, '|', attrValueRegex.source + ')',
- ')*',
- '>',
- ')',
-
- '|',
-
- // All other HTML tags (i.e. tags that are not <!DOCTYPE>)
- '(?:',
- '<(/)?', // Beginning of a tag or comment. Either '<' for a start tag, or '</' for an end tag.
- // *** Capturing Group 2: The slash or an empty string. Slash ('/') for end tag, empty string for start or self-closing tag.
-
- '(?:',
- commentTagRegex.source, // *** Capturing Group 3 - A Comment Tag's Text
-
- '|',
-
- // Handle tag without attributes.
- // Doing this separately from a tag that has attributes
- // to fix a regex time complexity issue seen with the
- // example in https://github.com/gregjacobs/Autolinker.js/issues/172
- '(?:',
- // *** Capturing Group 4 - The tag name for a tag without attributes
- '(' + tagNameRegex.source + ')',
-
- '\\s*/?', // any trailing spaces and optional '/' before the closing '>'
- ')',
-
- '|',
-
- // Handle tag with attributes
- // Doing this separately from a tag with no attributes
- // to fix a regex time complexity issue seen with the
- // example in https://github.com/gregjacobs/Autolinker.js/issues/172
- '(?:',
- // *** Capturing Group 5 - The tag name for a tag with attributes
- '(' + tagNameRegex.source + ')',
-
- '\\s+', // must have at least one space after the tag name to prevent ReDoS issue (issue #172)
-
- // Zero or more attributes following the tag name
- '(?:',
- '(?:\\s+|\\b)', // any number of whitespace chars before an attribute. NOTE: Using \s* here throws Chrome into an infinite loop for some reason, so using \s+|\b instead
- nameEqualsValueRegex, // attr="value" (with optional ="value" part)
- ')*',
-
- '\\s*/?', // any trailing spaces and optional '/' before the closing '>'
- ')',
- ')',
- '>',
- ')'
- ].join( "" ), 'gi' );
- } )(),
-
- /**
- * @private
- * @property {RegExp} htmlCharacterEntitiesRegex
- *
- * The regular expression that matches common HTML character entities.
- *
- * Ignoring & as it could be part of a query string -- handling it separately.
- */
- htmlCharacterEntitiesRegex: /( | |<|<|>|>|"|"|')/gi,
-
-
- /**
- * Parses an HTML string and returns a simple array of {@link Autolinker.htmlParser.HtmlNode HtmlNodes}
- * to represent the HTML structure of the input string.
- *
- * @param {String} html The HTML to parse.
- * @return {Autolinker.htmlParser.HtmlNode[]}
- */
- parse : function( html ) {
- var htmlRegex = this.htmlRegex,
- currentResult,
- lastIndex = 0,
- textAndEntityNodes,
- nodes = []; // will be the result of the method
-
- while( ( currentResult = htmlRegex.exec( html ) ) !== null ) {
- var tagText = currentResult[ 0 ],
- commentText = currentResult[ 3 ], // if we've matched a comment
- tagName = currentResult[ 1 ] || currentResult[ 4 ] || currentResult[ 5 ], // The <!DOCTYPE> tag (ex: "!DOCTYPE"), or another tag (ex: "a" or "img")
- isClosingTag = !!currentResult[ 2 ],
- offset = currentResult.index,
- inBetweenTagsText = html.substring( lastIndex, offset );
-
- // Push TextNodes and EntityNodes for any text found between tags
- if( inBetweenTagsText ) {
- textAndEntityNodes = this.parseTextAndEntityNodes( lastIndex, inBetweenTagsText );
- nodes.push.apply( nodes, textAndEntityNodes );
- }
-
- // Push the CommentNode or ElementNode
- if( commentText ) {
- nodes.push( this.createCommentNode( offset, tagText, commentText ) );
- } else {
- nodes.push( this.createElementNode( offset, tagText, tagName, isClosingTag ) );
- }
-
- lastIndex = offset + tagText.length;
- }
-
- // Process any remaining text after the last HTML element. Will process all of the text if there were no HTML elements.
- if( lastIndex < html.length ) {
- var text = html.substring( lastIndex );
-
- // Push TextNodes and EntityNodes for any text found between tags
- if( text ) {
- textAndEntityNodes = this.parseTextAndEntityNodes( lastIndex, text );
-
- // Note: the following 3 lines were previously:
- // nodes.push.apply( nodes, textAndEntityNodes );
- // but this was causing a "Maximum Call Stack Size Exceeded"
- // error on inputs with a large number of html entities.
- textAndEntityNodes.forEach( function( node ) {
- nodes.push( node );
- } );
- }
- }
-
- return nodes;
- },
-
-
- /**
- * Parses text and HTML entity nodes from a given string. The input string
- * should not have any HTML tags (elements) within it.
- *
- * @private
- * @param {Number} offset The offset of the text node match within the
- * original HTML string.
- * @param {String} text The string of text to parse. This is from an HTML
- * text node.
- * @return {Autolinker.htmlParser.HtmlNode[]} An array of HtmlNodes to
- * represent the {@link Autolinker.htmlParser.TextNode TextNodes} and
- * {@link Autolinker.htmlParser.EntityNode EntityNodes} found.
- */
- parseTextAndEntityNodes : function( offset, text ) {
- var nodes = [],
- textAndEntityTokens = Autolinker.Util.splitAndCapture( text, this.htmlCharacterEntitiesRegex ); // split at HTML entities, but include the HTML entities in the results array
-
- // Every even numbered token is a TextNode, and every odd numbered token is an EntityNode
- // For example: an input `text` of "Test "this" today" would turn into the
- // `textAndEntityTokens`: [ 'Test ', '"', 'this', '"', ' today' ]
- for( var i = 0, len = textAndEntityTokens.length; i < len; i += 2 ) {
- var textToken = textAndEntityTokens[ i ],
- entityToken = textAndEntityTokens[ i + 1 ];
-
- if( textToken ) {
- nodes.push( this.createTextNode( offset, textToken ) );
- offset += textToken.length;
- }
- if( entityToken ) {
- nodes.push( this.createEntityNode( offset, entityToken ) );
- offset += entityToken.length;
- }
- }
- return nodes;
- },
-
-
- /**
- * Factory method to create an {@link Autolinker.htmlParser.CommentNode CommentNode}.
- *
- * @private
- * @param {Number} offset The offset of the match within the original HTML
- * string.
- * @param {String} tagText The full text of the tag (comment) that was
- * matched, including its <!-- and -->.
- * @param {String} commentText The full text of the comment that was matched.
- */
- createCommentNode : function( offset, tagText, commentText ) {
- return new Autolinker.htmlParser.CommentNode( {
- offset : offset,
- text : tagText,
- comment: Autolinker.Util.trim( commentText )
- } );
- },
-
-
- /**
- * Factory method to create an {@link Autolinker.htmlParser.ElementNode ElementNode}.
- *
- * @private
- * @param {Number} offset The offset of the match within the original HTML
- * string.
- * @param {String} tagText The full text of the tag (element) that was
- * matched, including its attributes.
- * @param {String} tagName The name of the tag. Ex: An <img> tag would
- * be passed to this method as "img".
- * @param {Boolean} isClosingTag `true` if it's a closing tag, false
- * otherwise.
- * @return {Autolinker.htmlParser.ElementNode}
- */
- createElementNode : function( offset, tagText, tagName, isClosingTag ) {
- return new Autolinker.htmlParser.ElementNode( {
- offset : offset,
- text : tagText,
- tagName : tagName.toLowerCase(),
- closing : isClosingTag
- } );
- },
-
-
- /**
- * Factory method to create a {@link Autolinker.htmlParser.EntityNode EntityNode}.
- *
- * @private
- * @param {Number} offset The offset of the match within the original HTML
- * string.
- * @param {String} text The text that was matched for the HTML entity (such
- * as ' ').
- * @return {Autolinker.htmlParser.EntityNode}
- */
- createEntityNode : function( offset, text ) {
- return new Autolinker.htmlParser.EntityNode( { offset: offset, text: text } );
- },
-
-
- /**
- * Factory method to create a {@link Autolinker.htmlParser.TextNode TextNode}.
- *
- * @private
- * @param {Number} offset The offset of the match within the original HTML
- * string.
- * @param {String} text The text that was matched.
- * @return {Autolinker.htmlParser.TextNode}
- */
- createTextNode : function( offset, text ) {
- return new Autolinker.htmlParser.TextNode( { offset: offset, text: text } );
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @abstract
- * @class Autolinker.htmlParser.HtmlNode
- *
- * Represents an HTML node found in an input string. An HTML node is one of the
- * following:
- *
- * 1. An {@link Autolinker.htmlParser.ElementNode ElementNode}, which represents
- * HTML tags.
- * 2. A {@link Autolinker.htmlParser.CommentNode CommentNode}, which represents
- * HTML comments.
- * 3. A {@link Autolinker.htmlParser.TextNode TextNode}, which represents text
- * outside or within HTML tags.
- * 4. A {@link Autolinker.htmlParser.EntityNode EntityNode}, which represents
- * one of the known HTML entities that Autolinker looks for. This includes
- * common ones such as " and
- */
-Autolinker.htmlParser.HtmlNode = Autolinker.Util.extend( Object, {
-
- /**
- * @cfg {Number} offset (required)
- *
- * The offset of the HTML node in the original text that was parsed.
- */
- offset : undefined,
-
- /**
- * @cfg {String} text (required)
- *
- * The text that was matched for the HtmlNode.
- *
- * - In the case of an {@link Autolinker.htmlParser.ElementNode ElementNode},
- * this will be the tag's text.
- * - In the case of an {@link Autolinker.htmlParser.CommentNode CommentNode},
- * this will be the comment's text.
- * - In the case of a {@link Autolinker.htmlParser.TextNode TextNode}, this
- * will be the text itself.
- * - In the case of a {@link Autolinker.htmlParser.EntityNode EntityNode},
- * this will be the text of the HTML entity.
- */
- text : undefined,
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match instance,
- * specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.Util.assign( this, cfg );
-
- if( this.offset == null ) throw new Error( '`offset` cfg required' );
- if( this.text == null ) throw new Error( '`text` cfg required' );
- },
-
-
- /**
- * Returns a string name for the type of node that this class represents.
- *
- * @abstract
- * @return {String}
- */
- getType : Autolinker.Util.abstractMethod,
-
-
- /**
- * Retrieves the {@link #offset} of the HtmlNode. This is the offset of the
- * HTML node in the original string that was parsed.
- *
- * @return {Number}
- */
- getOffset : function() {
- return this.offset;
- },
-
-
- /**
- * Retrieves the {@link #text} for the HtmlNode.
- *
- * @return {String}
- */
- getText : function() {
- return this.text;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.htmlParser.CommentNode
- * @extends Autolinker.htmlParser.HtmlNode
- *
- * Represents an HTML comment node that has been parsed by the
- * {@link Autolinker.htmlParser.HtmlParser}.
- *
- * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more
- * details.
- */
-Autolinker.htmlParser.CommentNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
-
- /**
- * @cfg {String} comment (required)
- *
- * The text inside the comment tag. This text is stripped of any leading or
- * trailing whitespace.
- */
- comment : '',
-
-
- /**
- * Returns a string name for the type of node that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'comment';
- },
-
-
- /**
- * Returns the comment inside the comment tag.
- *
- * @return {String}
- */
- getComment : function() {
- return this.comment;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.htmlParser.ElementNode
- * @extends Autolinker.htmlParser.HtmlNode
- *
- * Represents an HTML element node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
- *
- * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more
- * details.
- */
-Autolinker.htmlParser.ElementNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
-
- /**
- * @cfg {String} tagName (required)
- *
- * The name of the tag that was matched.
- */
- tagName : '',
-
- /**
- * @cfg {Boolean} closing (required)
- *
- * `true` if the element (tag) is a closing tag, `false` if its an opening
- * tag.
- */
- closing : false,
-
-
- /**
- * Returns a string name for the type of node that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'element';
- },
-
-
- /**
- * Returns the HTML element's (tag's) name. Ex: for an <img> tag,
- * returns "img".
- *
- * @return {String}
- */
- getTagName : function() {
- return this.tagName;
- },
-
-
- /**
- * Determines if the HTML element (tag) is a closing tag. Ex: <div>
- * returns `false`, while </div> returns `true`.
- *
- * @return {Boolean}
- */
- isClosing : function() {
- return this.closing;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.htmlParser.EntityNode
- * @extends Autolinker.htmlParser.HtmlNode
- *
- * Represents a known HTML entity node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
- * Ex: ' ', or '&#160;' (which will be retrievable from the {@link #getText}
- * method.
- *
- * Note that this class will only be returned from the HtmlParser for the set of
- * checked HTML entity nodes defined by the {@link Autolinker.htmlParser.HtmlParser#htmlCharacterEntitiesRegex}.
- *
- * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more
- * details.
- */
-Autolinker.htmlParser.EntityNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
-
- /**
- * Returns a string name for the type of node that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'entity';
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.htmlParser.TextNode
- * @extends Autolinker.htmlParser.HtmlNode
- *
- * Represents a text node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}.
- *
- * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more
- * details.
- */
-Autolinker.htmlParser.TextNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, {
-
- /**
- * Returns a string name for the type of node that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'text';
- }
-
-} );
-/*global Autolinker */
-/**
- * @abstract
- * @class Autolinker.match.Match
- *
- * Represents a match found in an input string which should be Autolinked. A Match object is what is provided in a
- * {@link Autolinker#replaceFn replaceFn}, and may be used to query for details about the match.
- *
- * For example:
- *
- * var input = "..."; // string with URLs, Email Addresses, and Mentions (Twitter, Instagram)
- *
- * var linkedText = Autolinker.link( input, {
- * replaceFn : function( match ) {
- * console.log( "href = ", match.getAnchorHref() );
- * console.log( "text = ", match.getAnchorText() );
- *
- * switch( match.getType() ) {
- * case 'url' :
- * console.log( "url: ", match.getUrl() );
- *
- * case 'email' :
- * console.log( "email: ", match.getEmail() );
- *
- * case 'mention' :
- * console.log( "mention: ", match.getMention() );
- * }
- * }
- * } );
- *
- * See the {@link Autolinker} class for more details on using the {@link Autolinker#replaceFn replaceFn}.
- */
-Autolinker.match.Match = Autolinker.Util.extend( Object, {
-
- /**
- * @cfg {Autolinker.AnchorTagBuilder} tagBuilder (required)
- *
- * Reference to the AnchorTagBuilder instance to use to generate an anchor
- * tag for the Match.
- */
-
- /**
- * @cfg {String} matchedText (required)
- *
- * The original text that was matched by the {@link Autolinker.matcher.Matcher}.
- */
-
- /**
- * @cfg {Number} offset (required)
- *
- * The offset of where the match was made in the input string.
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- if( cfg.tagBuilder == null ) throw new Error( '`tagBuilder` cfg required' );
- if( cfg.matchedText == null ) throw new Error( '`matchedText` cfg required' );
- if( cfg.offset == null ) throw new Error( '`offset` cfg required' );
-
- this.tagBuilder = cfg.tagBuilder;
- this.matchedText = cfg.matchedText;
- this.offset = cfg.offset;
- },
-
-
- /**
- * Returns a string name for the type of match that this class represents.
- *
- * @abstract
- * @return {String}
- */
- getType : Autolinker.Util.abstractMethod,
-
-
- /**
- * Returns the original text that was matched.
- *
- * @return {String}
- */
- getMatchedText : function() {
- return this.matchedText;
- },
-
-
- /**
- * Sets the {@link #offset} of where the match was made in the input string.
- *
- * A {@link Autolinker.matcher.Matcher} will be fed only HTML text nodes,
- * and will therefore set an original offset that is relative to the HTML
- * text node itself. However, we want this offset to be relative to the full
- * HTML input string, and thus if using {@link Autolinker#parse} (rather
- * than calling a {@link Autolinker.matcher.Matcher} directly), then this
- * offset is corrected after the Matcher itself has done its job.
- *
- * @param {Number} offset
- */
- setOffset : function( offset ) {
- this.offset = offset;
- },
-
-
- /**
- * Returns the offset of where the match was made in the input string. This
- * is the 0-based index of the match.
- *
- * @return {Number}
- */
- getOffset : function() {
- return this.offset;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @abstract
- * @return {String}
- */
- getAnchorHref : Autolinker.Util.abstractMethod,
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @abstract
- * @return {String}
- */
- getAnchorText : Autolinker.Util.abstractMethod,
-
-
- /**
- * Returns the CSS class suffix(es) for this match.
- *
- * A CSS class suffix is appended to the {@link Autolinker#className} in
- * the {@link Autolinker.AnchorTagBuilder} when a match is translated into
- * an anchor tag.
- *
- * For example, if {@link Autolinker#className} was configured as 'myLink',
- * and this method returns `[ 'url' ]`, the final class name of the element
- * will become: 'myLink myLink-url'.
- *
- * The match may provide multiple CSS class suffixes to be appended to the
- * {@link Autolinker#className} in order to facilitate better styling
- * options for different match criteria. See {@link Autolinker.match.Mention}
- * for an example.
- *
- * By default, this method returns a single array with the match's
- * {@link #getType type} name, but may be overridden by subclasses.
- *
- * @return {String[]}
- */
- getCssClassSuffixes : function() {
- return [ this.getType() ];
- },
-
-
- /**
- * Builds and returns an {@link Autolinker.HtmlTag} instance based on the
- * Match.
- *
- * This can be used to easily generate anchor tags from matches, and either
- * return their HTML string, or modify them before doing so.
- *
- * Example Usage:
- *
- * var tag = match.buildTag();
- * tag.addClass( 'cordova-link' );
- * tag.setAttr( 'target', '_system' );
- *
- * tag.toAnchorString(); // <a href="http://google.com" class="cordova-link" target="_system">Google</a>
- */
- buildTag : function() {
- return this.tagBuilder.build( this );
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.match.Email
- * @extends Autolinker.match.Match
- *
- * Represents a Email match found in an input string which should be Autolinked.
- *
- * See this class's superclass ({@link Autolinker.match.Match}) for more details.
- */
-Autolinker.match.Email = Autolinker.Util.extend( Autolinker.match.Match, {
-
- /**
- * @cfg {String} email (required)
- *
- * The email address that was matched.
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.match.Match.prototype.constructor.call( this, cfg );
-
- if( !cfg.email ) throw new Error( '`email` cfg required' );
-
- this.email = cfg.email;
- },
-
-
- /**
- * Returns a string name for the type of match that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'email';
- },
-
-
- /**
- * Returns the email address that was matched.
- *
- * @return {String}
- */
- getEmail : function() {
- return this.email;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorHref : function() {
- return 'mailto:' + this.email;
- },
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorText : function() {
- return this.email;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.match.Hashtag
- * @extends Autolinker.match.Match
- *
- * Represents a Hashtag match found in an input string which should be
- * Autolinked.
- *
- * See this class's superclass ({@link Autolinker.match.Match}) for more
- * details.
- */
-Autolinker.match.Hashtag = Autolinker.Util.extend( Autolinker.match.Match, {
-
- /**
- * @cfg {String} serviceName
- *
- * The service to point hashtag matches to. See {@link Autolinker#hashtag}
- * for available values.
- */
-
- /**
- * @cfg {String} hashtag (required)
- *
- * The Hashtag that was matched, without the '#'.
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.match.Match.prototype.constructor.call( this, cfg );
-
- // TODO: if( !serviceName ) throw new Error( '`serviceName` cfg required' );
- if( !cfg.hashtag ) throw new Error( '`hashtag` cfg required' );
-
- this.serviceName = cfg.serviceName;
- this.hashtag = cfg.hashtag;
- },
-
-
- /**
- * Returns the type of match that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'hashtag';
- },
-
-
- /**
- * Returns the configured {@link #serviceName} to point the Hashtag to.
- * Ex: 'facebook', 'twitter'.
- *
- * @return {String}
- */
- getServiceName : function() {
- return this.serviceName;
- },
-
-
- /**
- * Returns the matched hashtag, without the '#' character.
- *
- * @return {String}
- */
- getHashtag : function() {
- return this.hashtag;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorHref : function() {
- var serviceName = this.serviceName,
- hashtag = this.hashtag;
-
- switch( serviceName ) {
- case 'twitter' :
- return 'https://twitter.com/hashtag/' + hashtag;
- case 'facebook' :
- return 'https://www.facebook.com/hashtag/' + hashtag;
- case 'instagram' :
- return 'https://instagram.com/explore/tags/' + hashtag;
-
- default : // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.
- throw new Error( 'Unknown service name to point hashtag to: ', serviceName );
- }
- },
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorText : function() {
- return '#' + this.hashtag;
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.match.Phone
- * @extends Autolinker.match.Match
- *
- * Represents a Phone number match found in an input string which should be
- * Autolinked.
- *
- * See this class's superclass ({@link Autolinker.match.Match}) for more
- * details.
- */
-Autolinker.match.Phone = Autolinker.Util.extend( Autolinker.match.Match, {
-
- /**
- * @protected
- * @property {String} number (required)
- *
- * The phone number that was matched, without any delimiter characters.
- *
- * Note: This is a string to allow for prefixed 0's.
- */
-
- /**
- * @protected
- * @property {Boolean} plusSign (required)
- *
- * `true` if the matched phone number started with a '+' sign. We'll include
- * it in the `tel:` URL if so, as this is needed for international numbers.
- *
- * Ex: '+1 (123) 456 7879'
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.match.Match.prototype.constructor.call( this, cfg );
-
- if( !cfg.number ) throw new Error( '`number` cfg required' );
- if( cfg.plusSign == null ) throw new Error( '`plusSign` cfg required' );
-
- this.number = cfg.number;
- this.plusSign = cfg.plusSign;
- },
-
-
- /**
- * Returns a string name for the type of match that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'phone';
- },
-
-
- /**
- * Returns the phone number that was matched as a string, without any
- * delimiter characters.
- *
- * Note: This is a string to allow for prefixed 0's.
- *
- * @return {String}
- */
- getNumber: function() {
- return this.number;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorHref : function() {
- return 'tel:' + ( this.plusSign ? '+' : '' ) + this.number;
- },
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorText : function() {
- return this.matchedText;
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.match.Mention
- * @extends Autolinker.match.Match
- *
- * Represents a Mention match found in an input string which should be Autolinked.
- *
- * See this class's superclass ({@link Autolinker.match.Match}) for more details.
- */
-Autolinker.match.Mention = Autolinker.Util.extend( Autolinker.match.Match, {
-
- /**
- * @cfg {String} serviceName
- *
- * The service to point mention matches to. See {@link Autolinker#mention}
- * for available values.
- */
-
- /**
- * @cfg {String} mention (required)
- *
- * The Mention that was matched, without the '@' character.
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.match.Match.prototype.constructor.call( this, cfg );
-
- if( !cfg.serviceName ) throw new Error( '`serviceName` cfg required' );
- if( !cfg.mention ) throw new Error( '`mention` cfg required' );
-
- this.mention = cfg.mention;
- this.serviceName = cfg.serviceName;
- },
-
-
- /**
- * Returns the type of match that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'mention';
- },
-
-
- /**
- * Returns the mention, without the '@' character.
- *
- * @return {String}
- */
- getMention : function() {
- return this.mention;
- },
-
-
- /**
- * Returns the configured {@link #serviceName} to point the mention to.
- * Ex: 'instagram', 'twitter'.
- *
- * @return {String}
- */
- getServiceName : function() {
- return this.serviceName;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorHref : function() {
- switch( this.serviceName ) {
- case 'twitter' :
- return 'https://twitter.com/' + this.mention;
- case 'instagram' :
- return 'https://instagram.com/' + this.mention;
-
- default : // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.
- throw new Error( 'Unknown service name to point mention to: ', this.serviceName );
- }
- },
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorText : function() {
- return '@' + this.mention;
- },
-
-
- /**
- * Returns the CSS class suffixes that should be used on a tag built with
- * the match. See {@link Autolinker.match.Match#getCssClassSuffixes} for
- * details.
- *
- * @return {String[]}
- */
- getCssClassSuffixes : function() {
- var cssClassSuffixes = Autolinker.match.Match.prototype.getCssClassSuffixes.call( this ),
- serviceName = this.getServiceName();
-
- if( serviceName ) {
- cssClassSuffixes.push( serviceName );
- }
- return cssClassSuffixes;
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.match.Url
- * @extends Autolinker.match.Match
- *
- * Represents a Url match found in an input string which should be Autolinked.
- *
- * See this class's superclass ({@link Autolinker.match.Match}) for more details.
- */
-Autolinker.match.Url = Autolinker.Util.extend( Autolinker.match.Match, {
-
- /**
- * @cfg {String} url (required)
- *
- * The url that was matched.
- */
-
- /**
- * @cfg {"scheme"/"www"/"tld"} urlMatchType (required)
- *
- * The type of URL match that this class represents. This helps to determine
- * if the match was made in the original text with a prefixed scheme (ex:
- * 'http://www.google.com'), a prefixed 'www' (ex: 'www.google.com'), or
- * was matched by a known top-level domain (ex: 'google.com').
- */
-
- /**
- * @cfg {Boolean} protocolUrlMatch (required)
- *
- * `true` if the URL is a match which already has a protocol (i.e.
- * 'http://'), `false` if the match was from a 'www' or known TLD match.
- */
-
- /**
- * @cfg {Boolean} protocolRelativeMatch (required)
- *
- * `true` if the URL is a protocol-relative match. A protocol-relative match
- * is a URL that starts with '//', and will be either http:// or https://
- * based on the protocol that the site is loaded under.
- */
-
- /**
- * @cfg {Object} stripPrefix (required)
- *
- * The Object form of {@link Autolinker#cfg-stripPrefix}.
- */
-
- /**
- * @cfg {Boolean} stripTrailingSlash (required)
- * @inheritdoc Autolinker#cfg-stripTrailingSlash
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.match.Match.prototype.constructor.call( this, cfg );
-
- if( cfg.urlMatchType !== 'scheme' && cfg.urlMatchType !== 'www' && cfg.urlMatchType !== 'tld' ) throw new Error( '`urlMatchType` cfg must be one of: "scheme", "www", or "tld"' );
- if( !cfg.url ) throw new Error( '`url` cfg required' );
- if( cfg.protocolUrlMatch == null ) throw new Error( '`protocolUrlMatch` cfg required' );
- if( cfg.protocolRelativeMatch == null ) throw new Error( '`protocolRelativeMatch` cfg required' );
- if( cfg.stripPrefix == null ) throw new Error( '`stripPrefix` cfg required' );
- if( cfg.stripTrailingSlash == null ) throw new Error( '`stripTrailingSlash` cfg required' );
-
- this.urlMatchType = cfg.urlMatchType;
- this.url = cfg.url;
- this.protocolUrlMatch = cfg.protocolUrlMatch;
- this.protocolRelativeMatch = cfg.protocolRelativeMatch;
- this.stripPrefix = cfg.stripPrefix;
- this.stripTrailingSlash = cfg.stripTrailingSlash;
- },
-
-
- /**
- * @private
- * @property {RegExp} schemePrefixRegex
- *
- * A regular expression used to remove the 'http://' or 'https://' from
- * URLs.
- */
- schemePrefixRegex: /^(https?:\/\/)?/i,
-
- /**
- * @private
- * @property {RegExp} wwwPrefixRegex
- *
- * A regular expression used to remove the 'www.' from URLs.
- */
- wwwPrefixRegex: /^(https?:\/\/)?(www\.)?/i,
-
- /**
- * @private
- * @property {RegExp} protocolRelativeRegex
- *
- * The regular expression used to remove the protocol-relative '//' from the {@link #url} string, for purposes
- * of {@link #getAnchorText}. A protocol-relative URL is, for example, "//yahoo.com"
- */
- protocolRelativeRegex : /^\/\//,
-
- /**
- * @private
- * @property {Boolean} protocolPrepended
- *
- * Will be set to `true` if the 'http://' protocol has been prepended to the {@link #url} (because the
- * {@link #url} did not have a protocol)
- */
- protocolPrepended : false,
-
-
- /**
- * Returns a string name for the type of match that this class represents.
- *
- * @return {String}
- */
- getType : function() {
- return 'url';
- },
-
-
- /**
- * Returns a string name for the type of URL match that this class
- * represents.
- *
- * This helps to determine if the match was made in the original text with a
- * prefixed scheme (ex: 'http://www.google.com'), a prefixed 'www' (ex:
- * 'www.google.com'), or was matched by a known top-level domain (ex:
- * 'google.com').
- *
- * @return {"scheme"/"www"/"tld"}
- */
- getUrlMatchType : function() {
- return this.urlMatchType;
- },
-
-
- /**
- * Returns the url that was matched, assuming the protocol to be 'http://' if the original
- * match was missing a protocol.
- *
- * @return {String}
- */
- getUrl : function() {
- var url = this.url;
-
- // if the url string doesn't begin with a protocol, assume 'http://'
- if( !this.protocolRelativeMatch && !this.protocolUrlMatch && !this.protocolPrepended ) {
- url = this.url = 'http://' + url;
-
- this.protocolPrepended = true;
- }
-
- return url;
- },
-
-
- /**
- * Returns the anchor href that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorHref : function() {
- var url = this.getUrl();
-
- return url.replace( /&/g, '&' ); // any &'s in the URL should be converted back to '&' if they were displayed as & in the source html
- },
-
-
- /**
- * Returns the anchor text that should be generated for the match.
- *
- * @return {String}
- */
- getAnchorText : function() {
- var anchorText = this.getMatchedText();
-
- if( this.protocolRelativeMatch ) {
- // Strip off any protocol-relative '//' from the anchor text
- anchorText = this.stripProtocolRelativePrefix( anchorText );
- }
- if( this.stripPrefix.scheme ) {
- anchorText = this.stripSchemePrefix( anchorText );
- }
- if( this.stripPrefix.www ) {
- anchorText = this.stripWwwPrefix( anchorText );
- }
- if( this.stripTrailingSlash ) {
- anchorText = this.removeTrailingSlash( anchorText ); // remove trailing slash, if there is one
- }
-
- return anchorText;
- },
-
-
- // ---------------------------------------
-
- // Utility Functionality
-
- /**
- * Strips the scheme prefix (such as "http://" or "https://") from the given
- * `url`.
- *
- * @private
- * @param {String} url The text of the anchor that is being generated, for
- * which to strip off the url scheme.
- * @return {String} The `url`, with the scheme stripped.
- */
- stripSchemePrefix : function( url ) {
- return url.replace( this.schemePrefixRegex, '' );
- },
-
-
- /**
- * Strips the 'www' prefix from the given `url`.
- *
- * @private
- * @param {String} url The text of the anchor that is being generated, for
- * which to strip off the 'www' if it exists.
- * @return {String} The `url`, with the 'www' stripped.
- */
- stripWwwPrefix : function( url ) {
- return url.replace( this.wwwPrefixRegex, '$1' ); // leave any scheme ($1), it one exists
- },
-
-
- /**
- * Strips any protocol-relative '//' from the anchor text.
- *
- * @private
- * @param {String} text The text of the anchor that is being generated, for which to strip off the
- * protocol-relative prefix (such as stripping off "//")
- * @return {String} The `anchorText`, with the protocol-relative prefix stripped.
- */
- stripProtocolRelativePrefix : function( text ) {
- return text.replace( this.protocolRelativeRegex, '' );
- },
-
-
- /**
- * Removes any trailing slash from the given `anchorText`, in preparation for the text to be displayed.
- *
- * @private
- * @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing
- * slash ('/') that may exist.
- * @return {String} The `anchorText`, with the trailing slash removed.
- */
- removeTrailingSlash : function( anchorText ) {
- if( anchorText.charAt( anchorText.length - 1 ) === '/' ) {
- anchorText = anchorText.slice( 0, -1 );
- }
- return anchorText;
- }
-
-} );
-// NOTE: THIS IS A GENERATED FILE
-// To update with the latest TLD list, run `gulp update-tld-list`
-
-/*global Autolinker */
-Autolinker.tldRegex = /(?:xn--vermgensberatung-pwb|xn--vermgensberater-ctb|xn--clchc0ea0b2g2a9gcd|xn--w4r85el8fhu5dnra|northwesternmutual|travelersinsurance|vermögensberatung|xn--3oq18vl8pn36a|xn--5su34j936bgsg|xn--bck1b9a5dre4c|xn--mgbai9azgqp6j|xn--mgberp4a5d4ar|xn--xkc2dl3a5ee0h|vermögensberater|xn--fzys8d69uvgm|xn--mgba7c0bbn0a|xn--xkc2al3hye2a|americanexpress|kerryproperties|sandvikcoromant|xn--i1b6b1a6a2e|xn--kcrx77d1x4a|xn--lgbbat1ad8j|xn--mgba3a4f16a|xn--mgbc0a9azcg|xn--nqv7fs00e [...]
-
-/*global Autolinker */
-/**
- * @abstract
- * @class Autolinker.matcher.Matcher
- *
- * An abstract class and interface for individual matchers to find matches in
- * an input string with linkified versions of them.
- *
- * Note that Matchers do not take HTML into account - they must be fed the text
- * nodes of any HTML string, which is handled by {@link Autolinker#parse}.
- */
-Autolinker.matcher.Matcher = Autolinker.Util.extend( Object, {
-
- /**
- * @cfg {Autolinker.AnchorTagBuilder} tagBuilder (required)
- *
- * Reference to the AnchorTagBuilder instance to use to generate HTML tags
- * for {@link Autolinker.match.Match Matches}.
- */
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Matcher
- * instance, specified in an Object (map).
- */
- constructor : function( cfg ) {
- if( !cfg.tagBuilder ) throw new Error( '`tagBuilder` cfg required' );
-
- this.tagBuilder = cfg.tagBuilder;
- },
-
-
- /**
- * Parses the input `text` and returns the array of {@link Autolinker.match.Match Matches}
- * for the matcher.
- *
- * @abstract
- * @param {String} text The text to scan and replace matches in.
- * @return {Autolinker.match.Match[]}
- */
- parseMatches : Autolinker.Util.abstractMethod
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.matcher.Email
- * @extends Autolinker.matcher.Matcher
- *
- * Matcher to find email matches in an input string.
- *
- * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more details.
- */
-Autolinker.matcher.Email = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
-
- /**
- * The regular expression to match email addresses. Example match:
- *
- * person at place.com
- *
- * @private
- * @property {RegExp} matcherRegex
- */
- matcherRegex : (function() {
- var alphaNumericChars = Autolinker.RegexLib.alphaNumericCharsStr,
- emailRegex = new RegExp( '[' + alphaNumericChars + '\\-_\';:&=+$.,]+@' ), // something@ for email addresses (a.k.a. local-part)
- domainNameRegex = Autolinker.RegexLib.domainNameRegex,
- tldRegex = Autolinker.tldRegex; // match our known top level domains (TLDs)
-
- return new RegExp( [
- emailRegex.source,
- domainNameRegex.source,
- '\\.', tldRegex.source // '.com', '.net', etc
- ].join( "" ), 'gi' );
- } )(),
-
-
- /**
- * @inheritdoc
- */
- 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 Autolinker.match.Email( {
- tagBuilder : tagBuilder,
- matchedText : matchedText,
- offset : match.index,
- email : matchedText
- } ) );
- }
-
- return matches;
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.matcher.Hashtag
- * @extends Autolinker.matcher.Matcher
- *
- * Matcher to find Hashtag matches in an input string.
- */
-Autolinker.matcher.Hashtag = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
-
- /**
- * @cfg {String} serviceName
- *
- * The service to point hashtag matches to. See {@link Autolinker#hashtag}
- * for available values.
- */
-
-
- /**
- * The regular expression to match Hashtags. Example match:
- *
- * #asdf
- *
- * @private
- * @property {RegExp} matcherRegex
- */
- matcherRegex : new RegExp( '#[_' + Autolinker.RegexLib.alphaNumericCharsStr + ']{1,139}', 'g' ),
-
- /**
- * The regular expression to use to check the character before a username match to
- * make sure we didn't accidentally match an email address.
- *
- * For example, the string "asdf at asdf.com" should not match "@asdf" as a username.
- *
- * @private
- * @property {RegExp} nonWordCharRegex
- */
- nonWordCharRegex : new RegExp( '[^' + Autolinker.RegexLib.alphaNumericCharsStr + ']' ),
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match instance,
- * specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.matcher.Matcher.prototype.constructor.call( this, cfg );
-
- this.serviceName = cfg.serviceName;
- },
-
-
- /**
- * @inheritdoc
- */
- parseMatches : function( text ) {
- var matcherRegex = this.matcherRegex,
- nonWordCharRegex = this.nonWordCharRegex,
- serviceName = this.serviceName,
- tagBuilder = this.tagBuilder,
- matches = [],
- match;
-
- while( ( match = matcherRegex.exec( text ) ) !== null ) {
- var offset = match.index,
- prevChar = text.charAt( offset - 1 );
-
- // If we found the match at the beginning of the string, or we found the match
- // and there is a whitespace char in front of it (meaning it is not a '#' char
- // in the middle of a word), then it is a hashtag match.
- if( offset === 0 || nonWordCharRegex.test( prevChar ) ) {
- var matchedText = match[ 0 ],
- hashtag = match[ 0 ].slice( 1 ); // strip off the '#' character at the beginning
-
- matches.push( new Autolinker.match.Hashtag( {
- tagBuilder : tagBuilder,
- matchedText : matchedText,
- offset : offset,
- serviceName : serviceName,
- hashtag : hashtag
- } ) );
- }
- }
-
- return matches;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.matcher.Phone
- * @extends Autolinker.matcher.Matcher
- *
- * Matcher to find Phone number matches in an input string.
- *
- * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more
- * details.
- */
-Autolinker.matcher.Phone = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
-
- /**
- * The regular expression to match Phone numbers. Example match:
- *
- * (123) 456-7890
- *
- * This regular expression has the following capturing groups:
- *
- * 1. The prefixed '+' sign, if there is one.
- *
- * @private
- * @property {RegExp} matcherRegex
- */
- matcherRegex : /(?:(\+)?\d{1,3}[-\040.]?)?\(?\d{3}\)?[-\040.]?\d{3}[-\040.]?\d{4}([,;]*[0-9]+#?)*/g,
-
- // ex: (123) 456-7890, 123 456 7890, 123-456-7890, +18004441234,,;,10226420346#,
- // +1 (800) 444 1234, 10226420346#, 1-800-444-1234,1022,64,20346#
-
- /**
- * @inheritdoc
- */
- parseMatches: function(text) {
- var matcherRegex = this.matcherRegex,
- tagBuilder = this.tagBuilder,
- matches = [],
- match;
-
- while ((match = matcherRegex.exec(text)) !== null) {
- // Remove non-numeric values from phone number string
- var matchedText = match[0],
- cleanNumber = matchedText.replace(/[^0-9,;#]/g, ''), // strip out non-digit characters exclude comma semicolon and #
- plusSign = !!match[1]; // match[ 1 ] is the prefixed plus sign, if there is one
- if (/\D/.test(match[2]) && /\D/.test(matchedText)) {
- matches.push(new Autolinker.match.Phone({
- tagBuilder: tagBuilder,
- matchedText: matchedText,
- offset: match.index,
- number: cleanNumber,
- plusSign: plusSign
- }));
- }
- }
-
- return matches;
- }
-
-} );
-/*global Autolinker */
-/**
- * @class Autolinker.matcher.Mention
- * @extends Autolinker.matcher.Matcher
- *
- * Matcher to find/replace username matches in an input string.
- */
-Autolinker.matcher.Mention = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
-
- /**
- * Hash of regular expression to match username handles. Example match:
- *
- * @asdf
- *
- * @private
- * @property {Object} matcherRegexes
- */
- matcherRegexes : {
- "twitter": new RegExp( '@[_' + Autolinker.RegexLib.alphaNumericCharsStr + ']{1,20}', 'g' ),
- "instagram": new RegExp( '@[_.' + Autolinker.RegexLib.alphaNumericCharsStr + ']{1,50}', 'g' )
- },
-
- /**
- * The regular expression to use to check the character before a username match to
- * make sure we didn't accidentally match an email address.
- *
- * For example, the string "asdf at asdf.com" should not match "@asdf" as a username.
- *
- * @private
- * @property {RegExp} nonWordCharRegex
- */
- nonWordCharRegex : new RegExp( '[^' + Autolinker.RegexLib.alphaNumericCharsStr + ']' ),
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match instance,
- * specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.matcher.Matcher.prototype.constructor.call( this, cfg );
-
- this.serviceName = cfg.serviceName;
- },
-
-
- /**
- * @inheritdoc
- */
- parseMatches : function( text ) {
- var matcherRegex = this.matcherRegexes[this.serviceName],
- nonWordCharRegex = this.nonWordCharRegex,
- serviceName = this.serviceName,
- tagBuilder = this.tagBuilder,
- matches = [],
- match;
-
- if (!matcherRegex) {
- return matches;
- }
-
- while( ( match = matcherRegex.exec( text ) ) !== null ) {
- var offset = match.index,
- prevChar = text.charAt( offset - 1 );
-
- // If we found the match at the beginning of the string, or we found the match
- // and there is a whitespace char in front of it (meaning it is not an email
- // address), then it is a username match.
- if( offset === 0 || nonWordCharRegex.test( prevChar ) ) {
- var matchedText = match[ 0 ].replace(/\.+$/g, ''), // strip off trailing .
- mention = matchedText.slice( 1 ); // strip off the '@' character at the beginning
-
- matches.push( new Autolinker.match.Mention( {
- tagBuilder : tagBuilder,
- matchedText : matchedText,
- offset : offset,
- serviceName : serviceName,
- mention : mention
- } ) );
- }
- }
-
- return matches;
- }
-
-} );
-
-/*global Autolinker */
-/**
- * @class Autolinker.matcher.Url
- * @extends Autolinker.matcher.Matcher
- *
- * Matcher to find URL matches in an input string.
- *
- * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more details.
- */
-Autolinker.matcher.Url = Autolinker.Util.extend( Autolinker.matcher.Matcher, {
-
- /**
- * @cfg {Object} stripPrefix (required)
- *
- * The Object form of {@link Autolinker#cfg-stripPrefix}.
- */
-
- /**
- * @cfg {Boolean} stripTrailingSlash (required)
- * @inheritdoc Autolinker#stripTrailingSlash
- */
-
-
- /**
- * @private
- * @property {RegExp} matcherRegex
- *
- * The regular expression to match URLs with an optional scheme, port
- * number, path, query string, and hash anchor.
- *
- * Example matches:
- *
- * http://google.com
- * www.google.com
- * google.com/path/to/file?q1=1&q2=2#myAnchor
- *
- *
- * This regular expression will have the following capturing groups:
- *
- * 1. Group that matches a scheme-prefixed URL (i.e. 'http://google.com').
- * This is used to match scheme URLs with just a single word, such as
- * 'http://localhost', where we won't double check that the domain name
- * has at least one dot ('.') in it.
- * 2. Group that matches a 'www.' prefixed URL. This is only matched if the
- * 'www.' text was not prefixed by a scheme (i.e.: not prefixed by
- * 'http://', 'ftp:', etc.)
- * 3. A protocol-relative ('//') match for the case of a 'www.' prefixed
- * URL. Will be an empty string if it is not a protocol-relative match.
- * We need to know the character before the '//' in order to determine
- * if it is a valid match or the // was in a string we don't want to
- * auto-link.
- * 4. Group that matches a known TLD (top level domain), when a scheme
- * or 'www.'-prefixed domain is not matched.
- * 5. A protocol-relative ('//') match for the case of a known TLD prefixed
- * URL. Will be an empty string if it is not a protocol-relative match.
- * See #3 for more info.
- */
- matcherRegex : (function() {
- var schemeRegex = /(?:[A-Za-z][-.+A-Za-z0-9]*:(?![A-Za-z][-.+A-Za-z0-9]*:\/\/)(?!\d+\/?)(?:\/\/)?)/, // match protocol, allow in format "http://" or "mailto:". However, do not match the first part of something like 'link:http://www.google.com' (i.e. don't match "link:"). Also, make sure we don't interpret 'google.com:8000' as if 'google.com' was a protocol here (i.e. ignore a trailing port number in this regex)
- wwwRegex = /(?:www\.)/, // starting with 'www.'
- domainNameRegex = Autolinker.RegexLib.domainNameRegex,
- tldRegex = Autolinker.tldRegex, // match our known top level domains (TLDs)
- alphaNumericCharsStr = Autolinker.RegexLib.alphaNumericCharsStr,
-
- // Allow optional path, query string, and hash anchor, not ending in the following characters: "?!:,.;"
- // http://blog.codinghorror.com/the-problem-with-urls/
- urlSuffixRegex = new RegExp( '[/?#](?:[' + alphaNumericCharsStr + '\\-+&@#/%=~_()|\'$*\\[\\]?!:,.;\u2713]*[' + alphaNumericCharsStr + '\\-+&@#/%=~_()|\'$*\\[\\]\u2713])?' );
-
- return new RegExp( [
- '(?:', // parens to cover match for scheme (optional), and domain
- '(', // *** Capturing group $1, for a scheme-prefixed url (ex: http://google.com)
- schemeRegex.source,
- domainNameRegex.source,
- ')',
-
- '|',
-
- '(', // *** Capturing group $2, for a 'www.' prefixed url (ex: www.google.com)
- '(//)?', // *** Capturing group $3 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character (handled later)
- wwwRegex.source,
- domainNameRegex.source,
- ')',
-
- '|',
-
- '(', // *** Capturing group $4, for known a TLD url (ex: google.com)
- '(//)?', // *** Capturing group $5 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character (handled later)
- domainNameRegex.source + '\\.',
- tldRegex.source,
- '(?![-' + alphaNumericCharsStr + '])', // TLD not followed by a letter, behaves like unicode-aware \b
- ')',
- ')',
-
- '(?::[0-9]+)?', // port
-
- '(?:' + urlSuffixRegex.source + ')?' // match for path, query string, and/or hash anchor - optional
- ].join( "" ), 'gi' );
- } )(),
-
-
- /**
- * A regular expression to use to check the character before a protocol-relative
- * URL match. We don't want to match a protocol-relative URL if it is part
- * of another word.
- *
- * For example, we want to match something like "Go to: //google.com",
- * but we don't want to match something like "abc//google.com"
- *
- * This regular expression is used to test the character before the '//'.
- *
- * @private
- * @type {RegExp} wordCharRegExp
- */
- wordCharRegExp : new RegExp( '[' + Autolinker.RegexLib.alphaNumericCharsStr + ']' ),
-
-
- /**
- * The regular expression to match opening parenthesis in a URL match.
- *
- * This is to determine if we have unbalanced parenthesis in the URL, and to
- * drop the final parenthesis that was matched if so.
- *
- * Ex: The text "(check out: wikipedia.com/something_(disambiguation))"
- * should only autolink the inner "wikipedia.com/something_(disambiguation)"
- * part, so if we find that we have unbalanced parenthesis, we will drop the
- * last one for the match.
- *
- * @private
- * @property {RegExp}
- */
- openParensRe : /\(/g,
-
- /**
- * The regular expression to match closing parenthesis in a URL match. See
- * {@link #openParensRe} for more information.
- *
- * @private
- * @property {RegExp}
- */
- closeParensRe : /\)/g,
-
-
- /**
- * @constructor
- * @param {Object} cfg The configuration properties for the Match instance,
- * specified in an Object (map).
- */
- constructor : function( cfg ) {
- Autolinker.matcher.Matcher.prototype.constructor.call( this, cfg );
-
- if( cfg.stripPrefix == null ) throw new Error( '`stripPrefix` cfg required' );
- if( cfg.stripTrailingSlash == null ) throw new Error( '`stripTrailingSlash` cfg required' );
-
- this.stripPrefix = cfg.stripPrefix;
- this.stripTrailingSlash = cfg.stripTrailingSlash;
- },
-
-
- /**
- * @inheritdoc
- */
- parseMatches : function( text ) {
- var matcherRegex = this.matcherRegex,
- stripPrefix = this.stripPrefix,
- stripTrailingSlash = this.stripTrailingSlash,
- tagBuilder = this.tagBuilder,
- matches = [],
- match;
-
- while( ( match = matcherRegex.exec( text ) ) !== null ) {
- var matchStr = match[ 0 ],
- schemeUrlMatch = match[ 1 ],
- wwwUrlMatch = match[ 2 ],
- wwwProtocolRelativeMatch = match[ 3 ],
- //tldUrlMatch = match[ 4 ], -- not needed at the moment
- tldProtocolRelativeMatch = match[ 5 ],
- offset = match.index,
- protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch,
- prevChar = text.charAt( offset - 1 );
-
- if( !Autolinker.matcher.UrlMatchValidator.isValid( matchStr, schemeUrlMatch ) ) {
- continue;
- }
-
- // If the match is preceded by an '@' character, then it is either
- // an email address or a username. Skip these types of matches.
- if( offset > 0 && prevChar === '@' ) {
- continue;
- }
-
- // If it's a protocol-relative '//' match, but the character before the '//'
- // was a word character (i.e. a letter/number), then we found the '//' in the
- // middle of another word (such as "asdf//asdf.com"). In this case, skip the
- // match.
- if( offset > 0 && protocolRelativeMatch && this.wordCharRegExp.test( prevChar ) ) {
- continue;
- }
-
- if( /\?$/.test(matchStr) ) {
- matchStr = matchStr.substr(0, matchStr.length-1);
- }
-
- // Handle a closing parenthesis at the end of the match, and exclude
- // it if there is not a matching open parenthesis in the match
- // itself.
- if( this.matchHasUnbalancedClosingParen( matchStr ) ) {
- matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")"
- } else {
- // Handle an invalid character after the TLD
- var pos = this.matchHasInvalidCharAfterTld( matchStr, schemeUrlMatch );
- if( pos > -1 ) {
- matchStr = matchStr.substr( 0, pos ); // remove the trailing invalid chars
- }
- }
-
- var urlMatchType = schemeUrlMatch ? 'scheme' : ( wwwUrlMatch ? 'www' : 'tld' ),
- protocolUrlMatch = !!schemeUrlMatch;
-
- matches.push( new Autolinker.match.Url( {
- tagBuilder : tagBuilder,
- matchedText : matchStr,
- offset : offset,
- urlMatchType : urlMatchType,
- url : matchStr,
- protocolUrlMatch : protocolUrlMatch,
- protocolRelativeMatch : !!protocolRelativeMatch,
- stripPrefix : stripPrefix,
- stripTrailingSlash : stripTrailingSlash
- } ) );
- }
-
- return matches;
- },
-
-
- /**
- * Determines if a match found has an unmatched closing parenthesis. If so,
- * this parenthesis will be removed from the match itself, and appended
- * after the generated anchor tag.
- *
- * A match may have an extra closing parenthesis at the end of the match
- * because the regular expression must include parenthesis for URLs such as
- * "wikipedia.com/something_(disambiguation)", which should be auto-linked.
- *
- * However, an extra parenthesis *will* be included when the URL itself is
- * wrapped in parenthesis, such as in the case of "(wikipedia.com/something_(disambiguation))".
- * In this case, the last closing parenthesis should *not* be part of the
- * URL itself, and this method will return `true`.
- *
- * @private
- * @param {String} matchStr The full match string from the {@link #matcherRegex}.
- * @return {Boolean} `true` if there is an unbalanced closing parenthesis at
- * the end of the `matchStr`, `false` otherwise.
- */
- matchHasUnbalancedClosingParen : function( matchStr ) {
- var lastChar = matchStr.charAt( matchStr.length - 1 );
-
- if( lastChar === ')' ) {
- var openParensMatch = matchStr.match( this.openParensRe ),
- closeParensMatch = matchStr.match( this.closeParensRe ),
- numOpenParens = ( openParensMatch && openParensMatch.length ) || 0,
- numCloseParens = ( closeParensMatch && closeParensMatch.length ) || 0;
-
- if( numOpenParens < numCloseParens ) {
- return true;
- }
- }
-
- return false;
- },
-
-
- /**
- * Determine if there's an invalid character after the TLD in a URL. Valid
- * characters after TLD are ':/?#'. Exclude scheme matched URLs from this
- * check.
- *
- * @private
- * @param {String} urlMatch The matched URL, if there was one. Will be an
- * empty string if the match is not a URL match.
- * @param {String} schemeUrlMatch The match URL string for a scheme
- * match. Ex: 'http://yahoo.com'. This is used to match something like
- * 'http://localhost', where we won't double check that the domain name
- * has at least one '.' in it.
- * @return {Number} the position where the invalid character was found. If
- * no such character was found, returns -1
- */
- matchHasInvalidCharAfterTld : function( urlMatch, schemeUrlMatch ) {
- if( !urlMatch ) {
- return -1;
- }
-
- var offset = 0;
- if ( schemeUrlMatch ) {
- offset = urlMatch.indexOf(':');
- urlMatch = urlMatch.slice(offset);
- }
-
- var alphaNumeric = Autolinker.RegexLib.alphaNumericCharsStr;
-
- var re = new RegExp("^((.?\/\/)?[-." + alphaNumeric + "]*[-" + alphaNumeric + "]\\.[-" + alphaNumeric + "]+)");
- var res = re.exec( urlMatch );
- if ( res === null ) {
- return -1;
- }
-
- offset += res[1].length;
- urlMatch = urlMatch.slice(res[1].length);
- if (/^[^-.A-Za-z0-9:\/?#]/.test(urlMatch)) {
- return offset;
- }
-
- return -1;
- }
-
-} );
-
-/*global Autolinker */
-/*jshint scripturl:true */
-/**
- * @private
- * @class Autolinker.matcher.UrlMatchValidator
- * @singleton
- *
- * Used by Autolinker to filter out false URL positives from the
- * {@link Autolinker.matcher.Url UrlMatcher}.
- *
- * Due to the limitations of regular expressions (including the missing feature
- * of look-behinds in JS regular expressions), we cannot always determine the
- * validity of a given match. This class applies a bit of additional logic to
- * filter out any false positives that have been matched by the
- * {@link Autolinker.matcher.Url UrlMatcher}.
- */
-Autolinker.matcher.UrlMatchValidator = {
-
- /**
- * Regex to test for a full protocol, with the two trailing slashes. Ex: 'http://'
- *
- * @private
- * @property {RegExp} hasFullProtocolRegex
- */
- hasFullProtocolRegex : /^[A-Za-z][-.+A-Za-z0-9]*:\/\//,
-
- /**
- * Regex to find the URI scheme, such as 'mailto:'.
- *
- * This is used to filter out 'javascript:' and 'vbscript:' schemes.
- *
- * @private
- * @property {RegExp} uriSchemeRegex
- */
- uriSchemeRegex : /^[A-Za-z][-.+A-Za-z0-9]*:/,
-
- /**
- * Regex to determine if at least one word char exists after the protocol (i.e. after the ':')
- *
- * @private
- * @property {RegExp} hasWordCharAfterProtocolRegex
- */
- hasWordCharAfterProtocolRegex : new RegExp(":[^\\s]*?[" + Autolinker.RegexLib.alphaCharsStr + "]"),
-
- /**
- * Regex to determine if the string is a valid IP address
- *
- * @private
- * @property {RegExp} ipRegex
- */
- ipRegex: /[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?(:[0-9]*)?\/?$/,
-
- /**
- * Determines if a given URL match found by the {@link Autolinker.matcher.Url UrlMatcher}
- * is valid. Will return `false` for:
- *
- * 1) URL matches which do not have at least have one period ('.') in the
- * domain name (effectively skipping over matches like "abc:def").
- * However, URL matches with a protocol will be allowed (ex: 'http://localhost')
- * 2) URL matches which do not have at least one word character in the
- * domain name (effectively skipping over matches like "git:1.0").
- * 3) A protocol-relative url match (a URL beginning with '//') whose
- * previous character is a word character (effectively skipping over
- * strings like "abc//google.com")
- *
- * Otherwise, returns `true`.
- *
- * @param {String} urlMatch The matched URL, if there was one. Will be an
- * empty string if the match is not a URL match.
- * @param {String} protocolUrlMatch The match URL string for a protocol
- * match. Ex: 'http://yahoo.com'. This is used to match something like
- * 'http://localhost', where we won't double check that the domain name
- * has at least one '.' in it.
- * @return {Boolean} `true` if the match given is valid and should be
- * processed, or `false` if the match is invalid and/or should just not be
- * processed.
- */
- isValid : function( urlMatch, protocolUrlMatch ) {
- if(
- ( protocolUrlMatch && !this.isValidUriScheme( protocolUrlMatch ) ) ||
- this.urlMatchDoesNotHaveProtocolOrDot( urlMatch, protocolUrlMatch ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL, *unless* it was a full protocol match (like 'http://localhost')
- (this.urlMatchDoesNotHaveAtLeastOneWordChar( urlMatch, protocolUrlMatch ) && // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
- !this.isValidIpAddress( urlMatch )) || // Except if it's an IP address
- this.containsMultipleDots( urlMatch )
- ) {
- return false;
- }
-
- return true;
- },
-
-
- isValidIpAddress : function ( uriSchemeMatch ) {
- var newRegex = new RegExp(this.hasFullProtocolRegex.source + this.ipRegex.source);
- var uriScheme = uriSchemeMatch.match( newRegex );
-
- return uriScheme !== null;
- },
-
- containsMultipleDots : function ( urlMatch ) {
- return urlMatch.indexOf("..") > -1;
- },
-
- /**
- * Determines if the URI scheme is a valid scheme to be autolinked. Returns
- * `false` if the scheme is 'javascript:' or 'vbscript:'
- *
- * @private
- * @param {String} uriSchemeMatch The match URL string for a full URI scheme
- * match. Ex: 'http://yahoo.com' or 'mailto:a at a.com'.
- * @return {Boolean} `true` if the scheme is a valid one, `false` otherwise.
- */
- isValidUriScheme : function( uriSchemeMatch ) {
- var uriScheme = uriSchemeMatch.match( this.uriSchemeRegex )[ 0 ].toLowerCase();
-
- return ( uriScheme !== 'javascript:' && uriScheme !== 'vbscript:' );
- },
-
-
- /**
- * Determines if a URL match does not have either:
- *
- * a) a full protocol (i.e. 'http://'), or
- * b) at least one dot ('.') in the domain name (for a non-full-protocol
- * match).
- *
- * Either situation is considered an invalid URL (ex: 'git:d' does not have
- * either the '://' part, or at least one dot in the domain name. If the
- * match was 'git:abc.com', we would consider this valid.)
- *
- * @private
- * @param {String} urlMatch The matched URL, if there was one. Will be an
- * empty string if the match is not a URL match.
- * @param {String} protocolUrlMatch The match URL string for a protocol
- * match. Ex: 'http://yahoo.com'. This is used to match something like
- * 'http://localhost', where we won't double check that the domain name
- * has at least one '.' in it.
- * @return {Boolean} `true` if the URL match does not have a full protocol,
- * or at least one dot ('.') in a non-full-protocol match.
- */
- urlMatchDoesNotHaveProtocolOrDot : function( urlMatch, protocolUrlMatch ) {
- return ( !!urlMatch && ( !protocolUrlMatch || !this.hasFullProtocolRegex.test( protocolUrlMatch ) ) && urlMatch.indexOf( '.' ) === -1 );
- },
-
-
- /**
- * Determines if a URL match does not have at least one word character after
- * the protocol (i.e. in the domain name).
- *
- * At least one letter character must exist in the domain name after a
- * protocol match. Ex: skip over something like "git:1.0"
- *
- * @private
- * @param {String} urlMatch The matched URL, if there was one. Will be an
- * empty string if the match is not a URL match.
- * @param {String} protocolUrlMatch The match URL string for a protocol
- * match. Ex: 'http://yahoo.com'. This is used to know whether or not we
- * have a protocol in the URL string, in order to check for a word
- * character after the protocol separator (':').
- * @return {Boolean} `true` if the URL match does not have at least one word
- * character in it after the protocol, `false` otherwise.
- */
- urlMatchDoesNotHaveAtLeastOneWordChar : function( urlMatch, protocolUrlMatch ) {
- if( urlMatch && protocolUrlMatch ) {
- return !this.hasWordCharAfterProtocolRegex.test( urlMatch );
- } else {
- return false;
- }
- }
-
-};
-
-/*global Autolinker */
-/**
- * A truncation feature where the ellipsis will be placed at the end of the URL.
- *
- * @param {String} anchorText
- * @param {Number} truncateLen The maximum length of the truncated output URL string.
- * @param {String} ellipsisChars The characters to place within the url, e.g. "..".
- * @return {String} The truncated URL.
- */
-Autolinker.truncate.TruncateEnd = function(anchorText, truncateLen, ellipsisChars){
- return Autolinker.Util.ellipsis( anchorText, truncateLen, ellipsisChars );
-};
-
-/*global Autolinker */
-/**
- * Date: 2015-10-05
- * Author: Kasper Søfren <soefritz at gmail.com> (https://github.com/kafoso)
- *
- * A truncation feature, where the ellipsis will be placed in the dead-center of the URL.
- *
- * @param {String} url A URL.
- * @param {Number} truncateLen The maximum length of the truncated output URL string.
- * @param {String} ellipsisChars The characters to place within the url, e.g. "..".
- * @return {String} The truncated URL.
- */
-Autolinker.truncate.TruncateMiddle = function(url, truncateLen, ellipsisChars){
- if (url.length <= truncateLen) {
- return url;
- }
-
- var ellipsisLengthBeforeParsing;
- var ellipsisLength;
-
- if(ellipsisChars == null) {
- ellipsisChars = '…';
- ellipsisLengthBeforeParsing = 8;
- ellipsisLength = 3;
- } else {
- ellipsisLengthBeforeParsing = ellipsisChars.length;
- ellipsisLength = ellipsisChars.length;
- }
-
- var availableLength = truncateLen - ellipsisLength;
- var end = "";
- if (availableLength > 0) {
- end = url.substr((-1)*Math.floor(availableLength/2));
- }
- return (url.substr(0, Math.ceil(availableLength/2)) + ellipsisChars + end).substr(0, availableLength + ellipsisLengthBeforeParsing);
-};
-
-/*global Autolinker */
-/**
- * Date: 2015-10-05
- * Author: Kasper Søfren <soefritz at gmail.com> (https://github.com/kafoso)
- *
- * A truncation feature, where the ellipsis will be placed at a section within
- * the URL making it still somewhat human readable.
- *
- * @param {String} url A URL.
- * @param {Number} truncateLen The maximum length of the truncated output URL string.
- * @param {String} ellipsisChars The characters to place within the url, e.g. "...".
- * @return {String} The truncated URL.
- */
-Autolinker.truncate.TruncateSmart = function(url, truncateLen, ellipsisChars){
-
- var ellipsisLengthBeforeParsing;
- var ellipsisLength;
-
- if(ellipsisChars == null) {
- ellipsisChars = '…';
- ellipsisLength = 3;
- ellipsisLengthBeforeParsing = 8;
- } else {
- ellipsisLength = ellipsisChars.length;
- ellipsisLengthBeforeParsing = ellipsisChars.length;
- }
-
- var parse_url = function(url){ // Functionality inspired by PHP function of same name
- var urlObj = {};
- var urlSub = url;
- var match = urlSub.match(/^([a-z]+):\/\//i);
- if (match) {
- urlObj.scheme = match[1];
- urlSub = urlSub.substr(match[0].length);
- }
- match = urlSub.match(/^(.*?)(?=(\?|#|\/|$))/i);
- if (match) {
- urlObj.host = match[1];
- urlSub = urlSub.substr(match[0].length);
- }
- match = urlSub.match(/^\/(.*?)(?=(\?|#|$))/i);
- if (match) {
- urlObj.path = match[1];
- urlSub = urlSub.substr(match[0].length);
- }
- match = urlSub.match(/^\?(.*?)(?=(#|$))/i);
- if (match) {
- urlObj.query = match[1];
- urlSub = urlSub.substr(match[0].length);
- }
- match = urlSub.match(/^#(.*?)$/i);
- if (match) {
- urlObj.fragment = match[1];
- //urlSub = urlSub.substr(match[0].length); -- not used. Uncomment if adding another block.
- }
- return urlObj;
- };
-
- var buildUrl = function(urlObj){
- var url = "";
- if (urlObj.scheme && urlObj.host) {
- url += urlObj.scheme + "://";
- }
- if (urlObj.host) {
- url += urlObj.host;
- }
- if (urlObj.path) {
- url += "/" + urlObj.path;
- }
- if (urlObj.query) {
- url += "?" + urlObj.query;
- }
- if (urlObj.fragment) {
- url += "#" + urlObj.fragment;
- }
- return url;
- };
-
- var buildSegment = function(segment, remainingAvailableLength){
- var remainingAvailableLengthHalf = remainingAvailableLength/ 2,
- startOffset = Math.ceil(remainingAvailableLengthHalf),
- endOffset = (-1)*Math.floor(remainingAvailableLengthHalf),
- end = "";
- if (endOffset < 0) {
- end = segment.substr(endOffset);
- }
- return segment.substr(0, startOffset) + ellipsisChars + end;
- };
- if (url.length <= truncateLen) {
- return url;
- }
- var availableLength = truncateLen - ellipsisLength;
- var urlObj = parse_url(url);
- // Clean up the URL
- if (urlObj.query) {
- var matchQuery = urlObj.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i);
- if (matchQuery) {
- // Malformed URL; two or more "?". Removed any content behind the 2nd.
- urlObj.query = urlObj.query.substr(0, matchQuery[1].length);
- url = buildUrl(urlObj);
- }
- }
- if (url.length <= truncateLen) {
- return url;
- }
- if (urlObj.host) {
- urlObj.host = urlObj.host.replace(/^www\./, "");
- url = buildUrl(urlObj);
- }
- if (url.length <= truncateLen) {
- return url;
- }
- // Process and build the URL
- var str = "";
- if (urlObj.host) {
- str += urlObj.host;
- }
- if (str.length >= availableLength) {
- if (urlObj.host.length == truncateLen) {
- return (urlObj.host.substr(0, (truncateLen - ellipsisLength)) + ellipsisChars).substr(0, availableLength + ellipsisLengthBeforeParsing);
- }
- return buildSegment(str, availableLength).substr(0, availableLength + ellipsisLengthBeforeParsing);
- }
- var pathAndQuery = "";
- if (urlObj.path) {
- pathAndQuery += "/" + urlObj.path;
- }
- if (urlObj.query) {
- pathAndQuery += "?" + urlObj.query;
- }
- if (pathAndQuery) {
- if ((str+pathAndQuery).length >= availableLength) {
- if ((str+pathAndQuery).length == truncateLen) {
- return (str + pathAndQuery).substr(0, truncateLen);
- }
- var remainingAvailableLength = availableLength - str.length;
- return (str + buildSegment(pathAndQuery, remainingAvailableLength)).substr(0, availableLength + ellipsisLengthBeforeParsing);
- } else {
- str += pathAndQuery;
- }
- }
- if (urlObj.fragment) {
- var fragment = "#"+urlObj.fragment;
- if ((str+fragment).length >= availableLength) {
- if ((str+fragment).length == truncateLen) {
- return (str + fragment).substr(0, truncateLen);
- }
- var remainingAvailableLength2 = availableLength - str.length;
- return (str + buildSegment(fragment, remainingAvailableLength2)).substr(0, availableLength + ellipsisLengthBeforeParsing);
- } else {
- str += fragment;
- }
- }
- if (urlObj.scheme && urlObj.host) {
- var scheme = urlObj.scheme + "://";
- if ((str+scheme).length < availableLength) {
- return (scheme + str).substr(0, truncateLen);
- }
- }
- if (str.length <= truncateLen) {
- return str;
- }
- var end = "";
- if (availableLength > 0) {
- end = str.substr((-1)*Math.floor(availableLength/2));
- }
- return (str.substr(0, Math.ceil(availableLength/2)) + ellipsisChars + end).substr(0, availableLength + ellipsisLengthBeforeParsing);
-};
-
-return Autolinker;
-}));
diff --git a/debian/lib/classnames/index.js b/debian/lib/classnames/index.js
deleted file mode 100644
index 169de84..0000000
--- a/debian/lib/classnames/index.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/classnames
-*/
-/* global define */
-
-(function () {
- 'use strict';
-
- var hasOwn = {}.hasOwnProperty;
-
- function classNames () {
- var classes = [];
-
- for (var i = 0; i < arguments.length; i++) {
- var arg = arguments[i];
- if (!arg) continue;
-
- var argType = typeof arg;
-
- if (argType === 'string' || argType === 'number') {
- classes.push(arg);
- } else if (Array.isArray(arg)) {
- classes.push(classNames.apply(null, arg));
- } else if (argType === 'object') {
- for (var key in arg) {
- if (hasOwn.call(arg, key) && arg[key]) {
- classes.push(key);
- }
- }
- }
- }
-
- return classes.join(' ');
- }
-
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = classNames;
- } else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
- // register as 'classnames', consistent with npm package name
- define('classnames', [], function () {
- return classNames;
- });
- } else {
- window.classNames = classNames;
- }
-}());
diff --git a/debian/lib/ifvisible/ifvisible.js b/debian/lib/ifvisible/ifvisible.js
deleted file mode 100644
index aa03adb..0000000
--- a/debian/lib/ifvisible/ifvisible.js
+++ /dev/null
@@ -1,315 +0,0 @@
-(function() {
- (function(root, factory) {
- if (typeof define === 'function' && define.amd) {
- return define(function() {
- return factory();
- });
- } else if (typeof exports === 'object') {
- return module.exports = factory();
- } else {
- return root.ifvisible = factory();
- }
- })(this, function() {
- var addEvent, customEvent, doc, fireEvent, hidden, idleStartedTime, idleTime, ie, ifvisible, init, initialized, status, trackIdleStatus, visibilityChange;
- ifvisible = {};
- doc = document;
- initialized = false;
- status = "active";
- idleTime = 60000;
- idleStartedTime = false;
- customEvent = (function() {
- var S4, addCustomEvent, cgid, fireCustomEvent, guid, listeners, removeCustomEvent;
- S4 = function() {
- return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
- };
- guid = function() {
- return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4();
- };
- listeners = {};
- cgid = '__ceGUID';
- addCustomEvent = function(obj, event, callback) {
- obj[cgid] = undefined;
- if (!obj[cgid]) {
- obj[cgid] = "ifvisible.object.event.identifier";
- }
- if (!listeners[obj[cgid]]) {
- listeners[obj[cgid]] = {};
- }
- if (!listeners[obj[cgid]][event]) {
- listeners[obj[cgid]][event] = [];
- }
- return listeners[obj[cgid]][event].push(callback);
- };
- fireCustomEvent = function(obj, event, memo) {
- var ev, j, len, ref, results;
- if (obj[cgid] && listeners[obj[cgid]] && listeners[obj[cgid]][event]) {
- ref = listeners[obj[cgid]][event];
- results = [];
- for (j = 0, len = ref.length; j < len; j++) {
- ev = ref[j];
- results.push(ev(memo || {}));
- }
- return results;
- }
- };
- removeCustomEvent = function(obj, event, callback) {
- var cl, i, j, len, ref;
- if (callback) {
- if (obj[cgid] && listeners[obj[cgid]] && listeners[obj[cgid]][event]) {
- ref = listeners[obj[cgid]][event];
- for (i = j = 0, len = ref.length; j < len; i = ++j) {
- cl = ref[i];
- if (cl === callback) {
- listeners[obj[cgid]][event].splice(i, 1);
- return cl;
- }
- }
- }
- } else {
- if (obj[cgid] && listeners[obj[cgid]] && listeners[obj[cgid]][event]) {
- return delete listeners[obj[cgid]][event];
- }
- }
- };
- return {
- add: addCustomEvent,
- remove: removeCustomEvent,
- fire: fireCustomEvent
- };
- })();
- addEvent = (function() {
- var setListener;
- setListener = false;
- return function(el, ev, fn) {
- if (!setListener) {
- if (el.addEventListener) {
- setListener = function(el, ev, fn) {
- return el.addEventListener(ev, fn, false);
- };
- } else if (el.attachEvent) {
- setListener = function(el, ev, fn) {
- return el.attachEvent('on' + ev, fn, false);
- };
- } else {
- setListener = function(el, ev, fn) {
- return el['on' + ev] = fn;
- };
- }
- }
- return setListener(el, ev, fn);
- };
- })();
- fireEvent = function(element, event) {
- var evt;
- if (doc.createEventObject) {
- return element.fireEvent('on' + event, evt);
- } else {
- evt = doc.createEvent('HTMLEvents');
- evt.initEvent(event, true, true);
- return !element.dispatchEvent(evt);
- }
- };
- ie = (function() {
- var all, check, div, undef, v;
- undef = void 0;
- v = 3;
- div = doc.createElement("div");
- all = div.getElementsByTagName("i");
- check = function() {
- return (div.innerHTML = "<!--[if gt IE " + (++v) + "]><i></i><![endif]-->", all[0]);
- };
- while (check()) {
- continue;
- }
- if (v > 4) {
- return v;
- } else {
- return undef;
- }
- })();
- hidden = false;
- visibilityChange = void 0;
- if (typeof doc.hidden !== "undefined") {
- hidden = "hidden";
- visibilityChange = "visibilitychange";
- } else if (typeof doc.mozHidden !== "undefined") {
- hidden = "mozHidden";
- visibilityChange = "mozvisibilitychange";
- } else if (typeof doc.msHidden !== "undefined") {
- hidden = "msHidden";
- visibilityChange = "msvisibilitychange";
- } else if (typeof doc.webkitHidden !== "undefined") {
- hidden = "webkitHidden";
- visibilityChange = "webkitvisibilitychange";
- }
- trackIdleStatus = function() {
- var timer, wakeUp;
- timer = false;
- wakeUp = function() {
- clearTimeout(timer);
- if (status !== "active") {
- ifvisible.wakeup();
- }
- idleStartedTime = +(new Date());
- return timer = setTimeout(function() {
- if (status === "active") {
- return ifvisible.idle();
- }
- }, idleTime);
- };
- wakeUp();
- addEvent(doc, "mousemove", wakeUp);
- addEvent(doc, "keyup", wakeUp);
- addEvent(doc, "touchstart", wakeUp);
- addEvent(window, "scroll", wakeUp);
- ifvisible.focus(wakeUp);
- return ifvisible.wakeup(wakeUp);
- };
- init = function() {
- var blur;
- if (initialized) {
- return true;
- }
- if (hidden === false) {
- blur = "blur";
- if (ie < 9) {
- blur = "focusout";
- }
- addEvent(window, blur, function() {
- return ifvisible.blur();
- });
- addEvent(window, "focus", function() {
- return ifvisible.focus();
- });
- } else {
- addEvent(doc, visibilityChange, function() {
- if (doc[hidden]) {
- return ifvisible.blur();
- } else {
- return ifvisible.focus();
- }
- }, false);
- }
- initialized = true;
- return trackIdleStatus();
- };
- ifvisible = {
- setIdleDuration: function(seconds) {
- return idleTime = seconds * 1000;
- },
- getIdleDuration: function() {
- return idleTime;
- },
- getIdleInfo: function() {
- var now, res;
- now = +(new Date());
- res = {};
- if (status === "idle") {
- res.isIdle = true;
- res.idleFor = now - idleStartedTime;
- res.timeLeft = 0;
- res.timeLeftPer = 100;
- } else {
- res.isIdle = false;
- res.idleFor = now - idleStartedTime;
- res.timeLeft = (idleStartedTime + idleTime) - now;
- res.timeLeftPer = (100 - (res.timeLeft * 100 / idleTime)).toFixed(2);
- }
- return res;
- },
- focus: function(callback) {
- if (typeof callback === "function") {
- this.on("focus", callback);
- } else {
- status = "active";
- customEvent.fire(this, "focus");
- customEvent.fire(this, "wakeup");
- customEvent.fire(this, "statusChanged", {
- status: status
- });
- }
- return this;
- },
- blur: function(callback) {
- if (typeof callback === "function") {
- this.on("blur", callback);
- } else {
- status = "hidden";
- customEvent.fire(this, "blur");
- customEvent.fire(this, "idle");
- customEvent.fire(this, "statusChanged", {
- status: status
- });
- }
- return this;
- },
- idle: function(callback) {
- if (typeof callback === "function") {
- this.on("idle", callback);
- } else {
- status = "idle";
- customEvent.fire(this, "idle");
- customEvent.fire(this, "statusChanged", {
- status: status
- });
- }
- return this;
- },
- wakeup: function(callback) {
- if (typeof callback === "function") {
- this.on("wakeup", callback);
- } else {
- status = "active";
- customEvent.fire(this, "wakeup");
- customEvent.fire(this, "statusChanged", {
- status: status
- });
- }
- return this;
- },
- on: function(name, callback) {
- init();
- customEvent.add(this, name, callback);
- return this;
- },
- off: function(name, callback) {
- init();
- customEvent.remove(this, name, callback);
- return this;
- },
- onEvery: function(seconds, callback) {
- var paused, t;
- init();
- paused = false;
- if (callback) {
- t = setInterval(function() {
- if (status === "active" && paused === false) {
- return callback();
- }
- }, seconds * 1000);
- }
- return {
- stop: function() {
- return clearInterval(t);
- },
- pause: function() {
- return paused = true;
- },
- resume: function() {
- return paused = false;
- },
- code: t,
- callback: callback
- };
- },
- now: function(check) {
- init();
- return status === (check || "active");
- }
- };
- return ifvisible;
- });
-
-}).call(this);
-
-//# sourceMappingURL=ifvisible.js.map
diff --git a/debian/lib/normalize/normalize.css b/debian/lib/normalize/normalize.css
deleted file mode 100644
index fa4e73d..0000000
--- a/debian/lib/normalize/normalize.css
+++ /dev/null
@@ -1,447 +0,0 @@
-/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
-
-/* Document
- ========================================================================== */
-
-/**
- * 1. Correct the line height in all browsers.
- * 2. Prevent adjustments of font size after orientation changes in
- * IE on Windows Phone and in iOS.
- */
-
-html {
- line-height: 1.15; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/* Sections
- ========================================================================== */
-
-/**
- * Remove the margin in all browsers (opinionated).
- */
-
-body {
- margin: 0;
-}
-
-/**
- * Add the correct display in IE 9-.
- */
-
-article,
-aside,
-footer,
-header,
-nav,
-section {
- display: block;
-}
-
-/**
- * Correct the font size and margin on `h1` elements within `section` and
- * `article` contexts in Chrome, Firefox, and Safari.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/* Grouping content
- ========================================================================== */
-
-/**
- * Add the correct display in IE 9-.
- * 1. Add the correct display in IE.
- */
-
-figcaption,
-figure,
-main { /* 1 */
- display: block;
-}
-
-/**
- * Add the correct margin in IE 8.
- */
-
-figure {
- margin: 1em 40px;
-}
-
-/**
- * 1. Add the correct box sizing in Firefox.
- * 2. Show the overflow in Edge and IE.
- */
-
-hr {
- box-sizing: content-box; /* 1 */
- height: 0; /* 1 */
- overflow: visible; /* 2 */
-}
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-
-pre {
- font-family: monospace, monospace; /* 1 */
- font-size: 1em; /* 2 */
-}
-
-/* Text-level semantics
- ========================================================================== */
-
-/**
- * 1. Remove the gray background on active links in IE 10.
- * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
- */
-
-a {
- background-color: transparent; /* 1 */
- -webkit-text-decoration-skip: objects; /* 2 */
-}
-
-/**
- * 1. Remove the bottom border in Chrome 57- and Firefox 39-.
- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
- */
-
-abbr[title] {
- border-bottom: none; /* 1 */
- text-decoration: underline; /* 2 */
- text-decoration: underline dotted; /* 2 */
-}
-
-/**
- * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
- */
-
-b,
-strong {
- font-weight: inherit;
-}
-
-/**
- * Add the correct font weight in Chrome, Edge, and Safari.
- */
-
-b,
-strong {
- font-weight: bolder;
-}
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-
-code,
-kbd,
-samp {
- font-family: monospace, monospace; /* 1 */
- font-size: 1em; /* 2 */
-}
-
-/**
- * Add the correct font style in Android 4.3-.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Add the correct background and color in IE 9-.
- */
-
-mark {
- background-color: #ff0;
- color: #000;
-}
-
-/**
- * Add the correct font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` elements from affecting the line height in
- * all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-/* Embedded content
- ========================================================================== */
-
-/**
- * Add the correct display in IE 9-.
- */
-
-audio,
-video {
- display: inline-block;
-}
-
-/**
- * Add the correct display in iOS 4-7.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Remove the border on images inside links in IE 10-.
- */
-
-img {
- border-style: none;
-}
-
-/**
- * Hide the overflow in IE.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* Forms
- ========================================================================== */
-
-/**
- * 1. Change the font styles in all browsers (opinionated).
- * 2. Remove the margin in Firefox and Safari.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: sans-serif; /* 1 */
- font-size: 100%; /* 1 */
- line-height: 1.15; /* 1 */
- margin: 0; /* 2 */
-}
-
-/**
- * Show the overflow in IE.
- * 1. Show the overflow in Edge.
- */
-
-button,
-input { /* 1 */
- overflow: visible;
-}
-
-/**
- * Remove the inheritance of text transform in Edge, Firefox, and IE.
- * 1. Remove the inheritance of text transform in Firefox.
- */
-
-button,
-select { /* 1 */
- text-transform: none;
-}
-
-/**
- * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
- * controls in Android 4.
- * 2. Correct the inability to style clickable types in iOS and Safari.
- */
-
-button,
-html [type="button"], /* 1 */
-[type="reset"],
-[type="submit"] {
- -webkit-appearance: button; /* 2 */
-}
-
-/**
- * Remove the inner border and padding in Firefox.
- */
-
-button::-moz-focus-inner,
-[type="button"]::-moz-focus-inner,
-[type="reset"]::-moz-focus-inner,
-[type="submit"]::-moz-focus-inner {
- border-style: none;
- padding: 0;
-}
-
-/**
- * Restore the focus styles unset by the previous rule.
- */
-
-button:-moz-focusring,
-[type="button"]:-moz-focusring,
-[type="reset"]:-moz-focusring,
-[type="submit"]:-moz-focusring {
- outline: 1px dotted ButtonText;
-}
-
-/**
- * Correct the padding in Firefox.
- */
-
-fieldset {
- padding: 0.35em 0.75em 0.625em;
-}
-
-/**
- * 1. Correct the text wrapping in Edge and IE.
- * 2. Correct the color inheritance from `fieldset` elements in IE.
- * 3. Remove the padding so developers are not caught out when they zero out
- * `fieldset` elements in all browsers.
- */
-
-legend {
- box-sizing: border-box; /* 1 */
- color: inherit; /* 2 */
- display: table; /* 1 */
- max-width: 100%; /* 1 */
- padding: 0; /* 3 */
- white-space: normal; /* 1 */
-}
-
-/**
- * 1. Add the correct display in IE 9-.
- * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
- */
-
-progress {
- display: inline-block; /* 1 */
- vertical-align: baseline; /* 2 */
-}
-
-/**
- * Remove the default vertical scrollbar in IE.
- */
-
-textarea {
- overflow: auto;
-}
-
-/**
- * 1. Add the correct box sizing in IE 10-.
- * 2. Remove the padding in IE 10-.
- */
-
-[type="checkbox"],
-[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Correct the cursor style of increment and decrement buttons in Chrome.
- */
-
-[type="number"]::-webkit-inner-spin-button,
-[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-/**
- * 1. Correct the odd appearance in Chrome and Safari.
- * 2. Correct the outline style in Safari.
- */
-
-[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- outline-offset: -2px; /* 2 */
-}
-
-/**
- * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
- */
-
-[type="search"]::-webkit-search-cancel-button,
-[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * 1. Correct the inability to style clickable types in iOS and Safari.
- * 2. Change font properties to `inherit` in Safari.
- */
-
-::-webkit-file-upload-button {
- -webkit-appearance: button; /* 1 */
- font: inherit; /* 2 */
-}
-
-/* Interactive
- ========================================================================== */
-
-/*
- * Add the correct display in IE 9-.
- * 1. Add the correct display in Edge, IE, and Firefox.
- */
-
-details, /* 1 */
-menu {
- display: block;
-}
-
-/*
- * Add the correct display in all browsers.
- */
-
-summary {
- display: list-item;
-}
-
-/* Scripting
- ========================================================================== */
-
-/**
- * Add the correct display in IE 9-.
- */
-
-canvas {
- display: inline-block;
-}
-
-/**
- * Add the correct display in IE.
- */
-
-template {
- display: none;
-}
-
-/* Hidden
- ========================================================================== */
-
-/**
- * Add the correct display in IE 10-.
- */
-
-[hidden] {
- display: none;
-}
diff --git a/debian/lib/pikaday/pikaday.css b/debian/lib/pikaday/pikaday.css
deleted file mode 100644
index 16bfb7b..0000000
--- a/debian/lib/pikaday/pikaday.css
+++ /dev/null
@@ -1,222 +0,0 @@
- at charset "UTF-8";
-
-/*!
- * Pikaday
- * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/
- */
-
-.pika-single {
- z-index: 9999;
- display: block;
- position: relative;
- color: #333;
- background: #fff;
- border: 1px solid #ccc;
- border-bottom-color: #bbb;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-}
-
-/*
-clear child float (pika-lendar), using the famous micro clearfix hack
-http://nicolasgallagher.com/micro-clearfix-hack/
-*/
-.pika-single:before,
-.pika-single:after {
- content: " ";
- display: table;
-}
-.pika-single:after { clear: both }
-.pika-single { *zoom: 1 }
-
-.pika-single.is-hidden {
- display: none;
-}
-
-.pika-single.is-bound {
- position: absolute;
- box-shadow: 0 5px 15px -5px rgba(0,0,0,.5);
-}
-
-.pika-lendar {
- float: left;
- width: 240px;
- margin: 8px;
-}
-
-.pika-title {
- position: relative;
- text-align: center;
-}
-
-.pika-label {
- display: inline-block;
- *display: inline;
- position: relative;
- z-index: 9999;
- overflow: hidden;
- margin: 0;
- padding: 5px 3px;
- font-size: 14px;
- line-height: 20px;
- font-weight: bold;
- background-color: #fff;
-}
-.pika-title select {
- cursor: pointer;
- position: absolute;
- z-index: 9998;
- margin: 0;
- left: 0;
- top: 5px;
- filter: alpha(opacity=0);
- opacity: 0;
-}
-
-.pika-prev,
-.pika-next {
- display: block;
- cursor: pointer;
- position: relative;
- outline: none;
- border: 0;
- padding: 0;
- width: 20px;
- height: 30px;
- /* hide text using text-indent trick, using width value (it's enough) */
- text-indent: 20px;
- white-space: nowrap;
- overflow: hidden;
- background-color: transparent;
- background-position: center center;
- background-repeat: no-repeat;
- background-size: 75% 75%;
- opacity: .5;
- *position: absolute;
- *top: 0;
-}
-
-.pika-prev:hover,
-.pika-next:hover {
- opacity: 1;
-}
-
-.pika-prev,
-.is-rtl .pika-next {
- float: left;
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==');
- *left: 0;
-}
-
-.pika-next,
-.is-rtl .pika-prev {
- float: right;
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=');
- *right: 0;
-}
-
-.pika-prev.is-disabled,
-.pika-next.is-disabled {
- cursor: default;
- opacity: .2;
-}
-
-.pika-select {
- display: inline-block;
- *display: inline;
-}
-
-.pika-table {
- width: 100%;
- border-collapse: collapse;
- border-spacing: 0;
- border: 0;
-}
-
-.pika-table th,
-.pika-table td {
- width: 14.285714285714286%;
- padding: 0;
-}
-
-.pika-table th {
- color: #999;
- font-size: 12px;
- line-height: 25px;
- font-weight: bold;
- text-align: center;
-}
-
-.pika-button {
- cursor: pointer;
- display: block;
- box-sizing: border-box;
- -moz-box-sizing: border-box;
- outline: none;
- border: 0;
- margin: 0;
- width: 100%;
- padding: 5px;
- color: #666;
- font-size: 12px;
- line-height: 15px;
- text-align: right;
- background: #f5f5f5;
-}
-
-.pika-week {
- font-size: 11px;
- color: #999;
-}
-
-.is-today .pika-button {
- color: #33aaff;
- font-weight: bold;
-}
-
-.is-selected .pika-button {
- color: #fff;
- font-weight: bold;
- background: #33aaff;
- box-shadow: inset 0 1px 3px #178fe5;
- border-radius: 3px;
-}
-
-.is-inrange .pika-button {
- background: #D5E9F7;
-}
-
-.is-startrange .pika-button {
- color: #fff;
- background: #6CB31D;
- box-shadow: none;
- border-radius: 3px;
-}
-
-.is-endrange .pika-button {
- color: #fff;
- background: #33aaff;
- box-shadow: none;
- border-radius: 3px;
-}
-
-.is-disabled .pika-button,
-.is-outside-current-month .pika-button {
- pointer-events: none;
- cursor: default;
- color: #999;
- opacity: .3;
-}
-
-.pika-button:hover {
- color: #fff;
- background: #ff8000;
- box-shadow: none;
- border-radius: 3px;
-}
-
-/* styling for abbr */
-.pika-table abbr {
- border-bottom: none;
- cursor: help;
-}
-
diff --git a/debian/lib/pikaday/pikaday.js b/debian/lib/pikaday/pikaday.js
deleted file mode 100644
index 72fb602..0000000
--- a/debian/lib/pikaday/pikaday.js
+++ /dev/null
@@ -1,1193 +0,0 @@
-/*!
- * Pikaday
- *
- * Copyright © 2014 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday
- */
-
-(function (root, factory)
-{
- 'use strict';
-
- var moment;
- if (typeof exports === 'object') {
- // CommonJS module
- // Load moment.js as an optional dependency
- try { moment = require('moment'); } catch (e) {}
- module.exports = factory(moment);
- } else if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(function (req)
- {
- // Load moment.js as an optional dependency
- var id = 'moment';
- try { moment = req(id); } catch (e) {}
- return factory(moment);
- });
- } else {
- root.Pikaday = factory(root.moment);
- }
-}(this, function (moment)
-{
- 'use strict';
-
- /**
- * feature detection and helper functions
- */
- var hasMoment = typeof moment === 'function',
-
- hasEventListeners = !!window.addEventListener,
-
- document = window.document,
-
- sto = window.setTimeout,
-
- addEvent = function(el, e, callback, capture)
- {
- if (hasEventListeners) {
- el.addEventListener(e, callback, !!capture);
- } else {
- el.attachEvent('on' + e, callback);
- }
- },
-
- removeEvent = function(el, e, callback, capture)
- {
- if (hasEventListeners) {
- el.removeEventListener(e, callback, !!capture);
- } else {
- el.detachEvent('on' + e, callback);
- }
- },
-
- fireEvent = function(el, eventName, data)
- {
- var ev;
-
- if (document.createEvent) {
- ev = document.createEvent('HTMLEvents');
- ev.initEvent(eventName, true, false);
- ev = extend(ev, data);
- el.dispatchEvent(ev);
- } else if (document.createEventObject) {
- ev = document.createEventObject();
- ev = extend(ev, data);
- el.fireEvent('on' + eventName, ev);
- }
- },
-
- trim = function(str)
- {
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
- },
-
- hasClass = function(el, cn)
- {
- return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
- },
-
- addClass = function(el, cn)
- {
- if (!hasClass(el, cn)) {
- el.className = (el.className === '') ? cn : el.className + ' ' + cn;
- }
- },
-
- removeClass = function(el, cn)
- {
- el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
- },
-
- isArray = function(obj)
- {
- return (/Array/).test(Object.prototype.toString.call(obj));
- },
-
- isDate = function(obj)
- {
- return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
- },
-
- isWeekend = function(date)
- {
- var day = date.getDay();
- return day === 0 || day === 6;
- },
-
- isLeapYear = function(year)
- {
- // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
- return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
- },
-
- getDaysInMonth = function(year, month)
- {
- return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
- },
-
- setToStartOfDay = function(date)
- {
- if (isDate(date)) date.setHours(0,0,0,0);
- },
-
- compareDates = function(a,b)
- {
- // weak date comparison (use setToStartOfDay(date) to ensure correct result)
- return a.getTime() === b.getTime();
- },
-
- extend = function(to, from, overwrite)
- {
- var prop, hasProp;
- for (prop in from) {
- hasProp = to[prop] !== undefined;
- if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) {
- if (isDate(from[prop])) {
- if (overwrite) {
- to[prop] = new Date(from[prop].getTime());
- }
- }
- else if (isArray(from[prop])) {
- if (overwrite) {
- to[prop] = from[prop].slice(0);
- }
- } else {
- to[prop] = extend({}, from[prop], overwrite);
- }
- } else if (overwrite || !hasProp) {
- to[prop] = from[prop];
- }
- }
- return to;
- },
-
- adjustCalendar = function(calendar) {
- if (calendar.month < 0) {
- calendar.year -= Math.ceil(Math.abs(calendar.month)/12);
- calendar.month += 12;
- }
- if (calendar.month > 11) {
- calendar.year += Math.floor(Math.abs(calendar.month)/12);
- calendar.month -= 12;
- }
- return calendar;
- },
-
- /**
- * defaults and localisation
- */
- defaults = {
-
- // bind the picker to a form field
- field: null,
-
- // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
- bound: undefined,
-
- // position of the datepicker, relative to the field (default to bottom & left)
- // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
- position: 'bottom left',
-
- // automatically fit in the viewport even if it means repositioning from the position option
- reposition: true,
-
- // the default output format for `.toString()` and `field` value
- format: 'YYYY-MM-DD',
-
- // the initial date to view when first opened
- defaultDate: null,
-
- // make the `defaultDate` the initial selected value
- setDefaultDate: false,
-
- // first day of week (0: Sunday, 1: Monday etc)
- firstDay: 0,
-
- // the default flag for moment's strict date parsing
- formatStrict: false,
-
- // the minimum/earliest date that can be selected
- minDate: null,
- // the maximum/latest date that can be selected
- maxDate: null,
-
- // number of years either side, or array of upper/lower range
- yearRange: 10,
-
- // show week numbers at head of row
- showWeekNumber: false,
-
- // used internally (don't config outside)
- minYear: 0,
- maxYear: 9999,
- minMonth: undefined,
- maxMonth: undefined,
-
- startRange: null,
- endRange: null,
-
- isRTL: false,
-
- // Additional text to append to the year in the calendar title
- yearSuffix: '',
-
- // Render the month after year in the calendar title
- showMonthAfterYear: false,
-
- // Render days of the calendar grid that fall in the next or previous month
- showDaysInNextAndPreviousMonths: false,
-
- // how many months are visible
- numberOfMonths: 1,
-
- // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
- // only used for the first display or when a selected date is not visible
- mainCalendar: 'left',
-
- // Specify a DOM element to render the calendar in
- container: undefined,
-
- // internationalization
- i18n: {
- previousMonth : 'Previous Month',
- nextMonth : 'Next Month',
- months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
- weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
- weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
- },
-
- // Theme Classname
- theme: null,
-
- // callback function
- onSelect: null,
- onOpen: null,
- onClose: null,
- onDraw: null
- },
-
-
- /**
- * templating functions to abstract HTML rendering
- */
- renderDayName = function(opts, day, abbr)
- {
- day += opts.firstDay;
- while (day >= 7) {
- day -= 7;
- }
- return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
- },
-
- renderDay = function(opts)
- {
- var arr = [];
- var ariaSelected = 'false';
- if (opts.isEmpty) {
- if (opts.showDaysInNextAndPreviousMonths) {
- arr.push('is-outside-current-month');
- } else {
- return '<td class="is-empty"></td>';
- }
- }
- if (opts.isDisabled) {
- arr.push('is-disabled');
- }
- if (opts.isToday) {
- arr.push('is-today');
- }
- if (opts.isSelected) {
- arr.push('is-selected');
- ariaSelected = 'true';
- }
- if (opts.isInRange) {
- arr.push('is-inrange');
- }
- if (opts.isStartRange) {
- arr.push('is-startrange');
- }
- if (opts.isEndRange) {
- arr.push('is-endrange');
- }
- return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
- '<button class="pika-button pika-day" type="button" ' +
- 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
- opts.day +
- '</button>' +
- '</td>';
- },
-
- renderWeek = function (d, m, y) {
- // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
- var onejan = new Date(y, 0, 1),
- weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay()+1)/7);
- return '<td class="pika-week">' + weekNum + '</td>';
- },
-
- renderRow = function(days, isRTL)
- {
- return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>';
- },
-
- renderBody = function(rows)
- {
- return '<tbody>' + rows.join('') + '</tbody>';
- },
-
- renderHead = function(opts)
- {
- var i, arr = [];
- if (opts.showWeekNumber) {
- arr.push('<th></th>');
- }
- for (i = 0; i < 7; i++) {
- arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
- }
- return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
- },
-
- renderTitle = function(instance, c, year, month, refYear, randId)
- {
- var i, j, arr,
- opts = instance._o,
- isMinYear = year === opts.minYear,
- isMaxYear = year === opts.maxYear,
- html = '<div id="' + randId + '" class="pika-title" role="heading" aria-live="assertive">',
- monthHtml,
- yearHtml,
- prev = true,
- next = true;
-
- for (arr = [], i = 0; i < 12; i++) {
- arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
- (i === month ? ' selected="selected"': '') +
- ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
- opts.i18n.months[i] + '</option>');
- }
-
- monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>';
-
- if (isArray(opts.yearRange)) {
- i = opts.yearRange[0];
- j = opts.yearRange[1] + 1;
- } else {
- i = year - opts.yearRange;
- j = 1 + year + opts.yearRange;
- }
-
- for (arr = []; i < j && i <= opts.maxYear; i++) {
- if (i >= opts.minYear) {
- arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"': '') + '>' + (i) + '</option>');
- }
- }
- yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select class="pika-select pika-select-year" tabindex="-1">' + arr.join('') + '</select></div>';
-
- if (opts.showMonthAfterYear) {
- html += yearHtml + monthHtml;
- } else {
- html += monthHtml + yearHtml;
- }
-
- if (isMinYear && (month === 0 || opts.minMonth >= month)) {
- prev = false;
- }
-
- if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
- next = false;
- }
-
- if (c === 0) {
- html += '<button class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
- }
- if (c === (instance._o.numberOfMonths - 1) ) {
- html += '<button class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
- }
-
- return html += '</div>';
- },
-
- renderTable = function(opts, data, randId)
- {
- return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
- },
-
-
- /**
- * Pikaday constructor
- */
- Pikaday = function(options)
- {
- var self = this,
- opts = self.config(options);
-
- self._onMouseDown = function(e)
- {
- if (!self._v) {
- return;
- }
- e = e || window.event;
- var target = e.target || e.srcElement;
- if (!target) {
- return;
- }
-
- if (!hasClass(target, 'is-disabled')) {
- if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
- self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
- if (opts.bound) {
- sto(function() {
- self.hide();
- if (opts.field) {
- opts.field.blur();
- }
- }, 100);
- }
- }
- else if (hasClass(target, 'pika-prev')) {
- self.prevMonth();
- }
- else if (hasClass(target, 'pika-next')) {
- self.nextMonth();
- }
- }
- if (!hasClass(target, 'pika-select')) {
- // if this is touch event prevent mouse events emulation
- if (e.preventDefault) {
- e.preventDefault();
- } else {
- e.returnValue = false;
- return false;
- }
- } else {
- self._c = true;
- }
- };
-
- self._onChange = function(e)
- {
- e = e || window.event;
- var target = e.target || e.srcElement;
- if (!target) {
- return;
- }
- if (hasClass(target, 'pika-select-month')) {
- self.gotoMonth(target.value);
- }
- else if (hasClass(target, 'pika-select-year')) {
- self.gotoYear(target.value);
- }
- };
-
- self._onKeyChange = function(e)
- {
- e = e || window.event;
-
- if (self.isVisible()) {
-
- switch(e.keyCode){
- case 13:
- case 27:
- opts.field.blur();
- break;
- case 37:
- e.preventDefault();
- self.adjustDate('subtract', 1);
- break;
- case 38:
- self.adjustDate('subtract', 7);
- break;
- case 39:
- self.adjustDate('add', 1);
- break;
- case 40:
- self.adjustDate('add', 7);
- break;
- }
- }
- };
-
- self._onInputChange = function(e)
- {
- var date;
-
- if (e.firedBy === self) {
- return;
- }
- if (hasMoment) {
- date = moment(opts.field.value, opts.format, opts.formatStrict);
- date = (date && date.isValid()) ? date.toDate() : null;
- }
- else {
- date = new Date(Date.parse(opts.field.value));
- }
- if (isDate(date)) {
- self.setDate(date);
- }
- if (!self._v) {
- self.show();
- }
- };
-
- self._onInputFocus = function()
- {
- self.show();
- };
-
- self._onInputClick = function()
- {
- self.show();
- };
-
- self._onInputBlur = function()
- {
- // IE allows pika div to gain focus; catch blur the input field
- var pEl = document.activeElement;
- do {
- if (hasClass(pEl, 'pika-single')) {
- return;
- }
- }
- while ((pEl = pEl.parentNode));
-
- if (!self._c) {
- self._b = sto(function() {
- self.hide();
- }, 50);
- }
- self._c = false;
- };
-
- self._onClick = function(e)
- {
- e = e || window.event;
- var target = e.target || e.srcElement,
- pEl = target;
- if (!target) {
- return;
- }
- if (!hasEventListeners && hasClass(target, 'pika-select')) {
- if (!target.onchange) {
- target.setAttribute('onchange', 'return;');
- addEvent(target, 'change', self._onChange);
- }
- }
- do {
- if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) {
- return;
- }
- }
- while ((pEl = pEl.parentNode));
- if (self._v && target !== opts.trigger && pEl !== opts.trigger) {
- self.hide();
- }
- };
-
- self.el = document.createElement('div');
- self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : '');
-
- addEvent(self.el, 'mousedown', self._onMouseDown, true);
- addEvent(self.el, 'touchend', self._onMouseDown, true);
- addEvent(self.el, 'change', self._onChange);
- addEvent(document, 'keydown', self._onKeyChange);
-
- if (opts.field) {
- if (opts.container) {
- opts.container.appendChild(self.el);
- } else if (opts.bound) {
- document.body.appendChild(self.el);
- } else {
- opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
- }
- addEvent(opts.field, 'change', self._onInputChange);
-
- if (!opts.defaultDate) {
- if (hasMoment && opts.field.value) {
- opts.defaultDate = moment(opts.field.value, opts.format).toDate();
- } else {
- opts.defaultDate = new Date(Date.parse(opts.field.value));
- }
- opts.setDefaultDate = true;
- }
- }
-
- var defDate = opts.defaultDate;
-
- if (isDate(defDate)) {
- if (opts.setDefaultDate) {
- self.setDate(defDate, true);
- } else {
- self.gotoDate(defDate);
- }
- } else {
- self.gotoDate(new Date());
- }
-
- if (opts.bound) {
- this.hide();
- self.el.className += ' is-bound';
- addEvent(opts.trigger, 'click', self._onInputClick);
- addEvent(opts.trigger, 'focus', self._onInputFocus);
- addEvent(opts.trigger, 'blur', self._onInputBlur);
- } else {
- this.show();
- }
- };
-
-
- /**
- * public Pikaday API
- */
- Pikaday.prototype = {
-
-
- /**
- * configure functionality
- */
- config: function(options)
- {
- if (!this._o) {
- this._o = extend({}, defaults, true);
- }
-
- var opts = extend(this._o, options, true);
-
- opts.isRTL = !!opts.isRTL;
-
- opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
-
- opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null;
-
- opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
-
- opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
-
- opts.disableWeekends = !!opts.disableWeekends;
-
- opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null;
-
- var nom = parseInt(opts.numberOfMonths, 10) || 1;
- opts.numberOfMonths = nom > 4 ? 4 : nom;
-
- if (!isDate(opts.minDate)) {
- opts.minDate = false;
- }
- if (!isDate(opts.maxDate)) {
- opts.maxDate = false;
- }
- if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
- opts.maxDate = opts.minDate = false;
- }
- if (opts.minDate) {
- this.setMinDate(opts.minDate);
- }
- if (opts.maxDate) {
- this.setMaxDate(opts.maxDate);
- }
-
- if (isArray(opts.yearRange)) {
- var fallback = new Date().getFullYear() - 10;
- opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
- opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
- } else {
- opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
- if (opts.yearRange > 100) {
- opts.yearRange = 100;
- }
- }
-
- return opts;
- },
-
- /**
- * return a formatted string of the current selection (using Moment.js if available)
- */
- toString: function(format)
- {
- return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString();
- },
-
- /**
- * return a Moment.js object of the current selection (if available)
- */
- getMoment: function()
- {
- return hasMoment ? moment(this._d) : null;
- },
-
- /**
- * set the current selection from a Moment.js object (if available)
- */
- setMoment: function(date, preventOnSelect)
- {
- if (hasMoment && moment.isMoment(date)) {
- this.setDate(date.toDate(), preventOnSelect);
- }
- },
-
- /**
- * return a Date object of the current selection with fallback for the current date
- */
- getDate: function()
- {
- return isDate(this._d) ? new Date(this._d.getTime()) : new Date();
- },
-
- /**
- * set the current selection
- */
- setDate: function(date, preventOnSelect)
- {
- if (!date) {
- this._d = null;
-
- if (this._o.field) {
- this._o.field.value = '';
- fireEvent(this._o.field, 'change', { firedBy: this });
- }
-
- return this.draw();
- }
- if (typeof date === 'string') {
- date = new Date(Date.parse(date));
- }
- if (!isDate(date)) {
- return;
- }
-
- var min = this._o.minDate,
- max = this._o.maxDate;
-
- if (isDate(min) && date < min) {
- date = min;
- } else if (isDate(max) && date > max) {
- date = max;
- }
-
- this._d = new Date(date.getTime());
- setToStartOfDay(this._d);
- this.gotoDate(this._d);
-
- if (this._o.field) {
- this._o.field.value = this.toString();
- fireEvent(this._o.field, 'change', { firedBy: this });
- }
- if (!preventOnSelect && typeof this._o.onSelect === 'function') {
- this._o.onSelect.call(this, this.getDate());
- }
- },
-
- /**
- * change view to a specific date
- */
- gotoDate: function(date)
- {
- var newCalendar = true;
-
- if (!isDate(date)) {
- return;
- }
-
- if (this.calendars) {
- var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
- lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1),
- visibleDate = date.getTime();
- // get the end of the month
- lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1);
- lastVisibleDate.setDate(lastVisibleDate.getDate()-1);
- newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
- }
-
- if (newCalendar) {
- this.calendars = [{
- month: date.getMonth(),
- year: date.getFullYear()
- }];
- if (this._o.mainCalendar === 'right') {
- this.calendars[0].month += 1 - this._o.numberOfMonths;
- }
- }
-
- this.adjustCalendars();
- },
-
- adjustDate: function(sign, days) {
-
- var day = this.getDate();
- var difference = parseInt(days)*24*60*60*1000;
-
- var newDay;
-
- if (sign === 'add') {
- newDay = new Date(day.valueOf() + difference);
- } else if (sign === 'subtract') {
- newDay = new Date(day.valueOf() - difference);
- }
-
- if (hasMoment) {
- if (sign === 'add') {
- newDay = moment(day).add(days, "days").toDate();
- } else if (sign === 'subtract') {
- newDay = moment(day).subtract(days, "days").toDate();
- }
- }
-
- this.setDate(newDay);
- },
-
- adjustCalendars: function() {
- this.calendars[0] = adjustCalendar(this.calendars[0]);
- for (var c = 1; c < this._o.numberOfMonths; c++) {
- this.calendars[c] = adjustCalendar({
- month: this.calendars[0].month + c,
- year: this.calendars[0].year
- });
- }
- this.draw();
- },
-
- gotoToday: function()
- {
- this.gotoDate(new Date());
- },
-
- /**
- * change view to a specific month (zero-index, e.g. 0: January)
- */
- gotoMonth: function(month)
- {
- if (!isNaN(month)) {
- this.calendars[0].month = parseInt(month, 10);
- this.adjustCalendars();
- }
- },
-
- nextMonth: function()
- {
- this.calendars[0].month++;
- this.adjustCalendars();
- },
-
- prevMonth: function()
- {
- this.calendars[0].month--;
- this.adjustCalendars();
- },
-
- /**
- * change view to a specific full year (e.g. "2012")
- */
- gotoYear: function(year)
- {
- if (!isNaN(year)) {
- this.calendars[0].year = parseInt(year, 10);
- this.adjustCalendars();
- }
- },
-
- /**
- * change the minDate
- */
- setMinDate: function(value)
- {
- if(value instanceof Date) {
- setToStartOfDay(value);
- this._o.minDate = value;
- this._o.minYear = value.getFullYear();
- this._o.minMonth = value.getMonth();
- } else {
- this._o.minDate = defaults.minDate;
- this._o.minYear = defaults.minYear;
- this._o.minMonth = defaults.minMonth;
- this._o.startRange = defaults.startRange;
- }
-
- this.draw();
- },
-
- /**
- * change the maxDate
- */
- setMaxDate: function(value)
- {
- if(value instanceof Date) {
- setToStartOfDay(value);
- this._o.maxDate = value;
- this._o.maxYear = value.getFullYear();
- this._o.maxMonth = value.getMonth();
- } else {
- this._o.maxDate = defaults.maxDate;
- this._o.maxYear = defaults.maxYear;
- this._o.maxMonth = defaults.maxMonth;
- this._o.endRange = defaults.endRange;
- }
-
- this.draw();
- },
-
- setStartRange: function(value)
- {
- this._o.startRange = value;
- },
-
- setEndRange: function(value)
- {
- this._o.endRange = value;
- },
-
- /**
- * refresh the HTML
- */
- draw: function(force)
- {
- if (!this._v && !force) {
- return;
- }
- var opts = this._o,
- minYear = opts.minYear,
- maxYear = opts.maxYear,
- minMonth = opts.minMonth,
- maxMonth = opts.maxMonth,
- html = '',
- randId;
-
- if (this._y <= minYear) {
- this._y = minYear;
- if (!isNaN(minMonth) && this._m < minMonth) {
- this._m = minMonth;
- }
- }
- if (this._y >= maxYear) {
- this._y = maxYear;
- if (!isNaN(maxMonth) && this._m > maxMonth) {
- this._m = maxMonth;
- }
- }
-
- randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
-
- for (var c = 0; c < opts.numberOfMonths; c++) {
- html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId) + '</div>';
- }
-
- this.el.innerHTML = html;
-
- if (opts.bound) {
- if(opts.field.type !== 'hidden') {
- sto(function() {
- opts.trigger.focus();
- }, 1);
- }
- }
-
- if (typeof this._o.onDraw === 'function') {
- this._o.onDraw(this);
- }
-
- if (opts.bound) {
- // let the screen reader user know to use arrow keys
- opts.field.setAttribute('aria-label', 'Use the arrow keys to pick a date');
- }
- },
-
- adjustPosition: function()
- {
- var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect;
-
- if (this._o.container) return;
-
- this.el.style.position = 'absolute';
-
- field = this._o.trigger;
- pEl = field;
- width = this.el.offsetWidth;
- height = this.el.offsetHeight;
- viewportWidth = window.innerWidth || document.documentElement.clientWidth;
- viewportHeight = window.innerHeight || document.documentElement.clientHeight;
- scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
-
- if (typeof field.getBoundingClientRect === 'function') {
- clientRect = field.getBoundingClientRect();
- left = clientRect.left + window.pageXOffset;
- top = clientRect.bottom + window.pageYOffset;
- } else {
- left = pEl.offsetLeft;
- top = pEl.offsetTop + pEl.offsetHeight;
- while((pEl = pEl.offsetParent)) {
- left += pEl.offsetLeft;
- top += pEl.offsetTop;
- }
- }
-
- // default position is bottom & left
- if ((this._o.reposition && left + width > viewportWidth) ||
- (
- this._o.position.indexOf('right') > -1 &&
- left - width + field.offsetWidth > 0
- )
- ) {
- left = left - width + field.offsetWidth;
- }
- if ((this._o.reposition && top + height > viewportHeight + scrollTop) ||
- (
- this._o.position.indexOf('top') > -1 &&
- top - height - field.offsetHeight > 0
- )
- ) {
- top = top - height - field.offsetHeight;
- }
-
- this.el.style.left = left + 'px';
- this.el.style.top = top + 'px';
- },
-
- /**
- * render HTML for a particular month
- */
- render: function(year, month, randId)
- {
- var opts = this._o,
- now = new Date(),
- days = getDaysInMonth(year, month),
- before = new Date(year, month, 1).getDay(),
- data = [],
- row = [];
- setToStartOfDay(now);
- if (opts.firstDay > 0) {
- before -= opts.firstDay;
- if (before < 0) {
- before += 7;
- }
- }
- var previousMonth = month === 0 ? 11 : month - 1,
- nextMonth = month === 11 ? 0 : month + 1,
- yearOfPreviousMonth = month === 0 ? year - 1 : year,
- yearOfNextMonth = month === 11 ? year + 1 : year,
- daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth);
- var cells = days + before,
- after = cells;
- while(after > 7) {
- after -= 7;
- }
- cells += 7 - after;
- for (var i = 0, r = 0; i < cells; i++)
- {
- var day = new Date(year, month, 1 + (i - before)),
- isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
- isToday = compareDates(day, now),
- isEmpty = i < before || i >= (days + before),
- dayNumber = 1 + (i - before),
- monthNumber = month,
- yearNumber = year,
- isStartRange = opts.startRange && compareDates(opts.startRange, day),
- isEndRange = opts.endRange && compareDates(opts.endRange, day),
- isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange,
- isDisabled = (opts.minDate && day < opts.minDate) ||
- (opts.maxDate && day > opts.maxDate) ||
- (opts.disableWeekends && isWeekend(day)) ||
- (opts.disableDayFn && opts.disableDayFn(day));
-
- if (isEmpty) {
- if (i < before) {
- dayNumber = daysInPreviousMonth + dayNumber;
- monthNumber = previousMonth;
- yearNumber = yearOfPreviousMonth;
- } else {
- dayNumber = dayNumber - days;
- monthNumber = nextMonth;
- yearNumber = yearOfNextMonth;
- }
- }
-
- var dayConfig = {
- day: dayNumber,
- month: monthNumber,
- year: yearNumber,
- isSelected: isSelected,
- isToday: isToday,
- isDisabled: isDisabled,
- isEmpty: isEmpty,
- isStartRange: isStartRange,
- isEndRange: isEndRange,
- isInRange: isInRange,
- showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths
- };
-
- row.push(renderDay(dayConfig));
-
- if (++r === 7) {
- if (opts.showWeekNumber) {
- row.unshift(renderWeek(i - before, month, year));
- }
- data.push(renderRow(row, opts.isRTL));
- row = [];
- r = 0;
- }
- }
- return renderTable(opts, data, randId);
- },
-
- isVisible: function()
- {
- return this._v;
- },
-
- show: function()
- {
- if (!this.isVisible()) {
- removeClass(this.el, 'is-hidden');
- this._v = true;
- this.draw();
- if (this._o.bound) {
- addEvent(document, 'click', this._onClick);
- this.adjustPosition();
- }
- if (typeof this._o.onOpen === 'function') {
- this._o.onOpen.call(this);
- }
- }
- },
-
- hide: function()
- {
- var v = this._v;
- if (v !== false) {
- if (this._o.bound) {
- removeEvent(document, 'click', this._onClick);
- }
- this.el.style.position = 'static'; // reset
- this.el.style.left = 'auto';
- this.el.style.top = 'auto';
- addClass(this.el, 'is-hidden');
- this._v = false;
- if (v !== undefined && typeof this._o.onClose === 'function') {
- this._o.onClose.call(this);
- }
- }
- },
-
- /**
- * GAME OVER
- */
- destroy: function()
- {
- this.hide();
- removeEvent(this.el, 'mousedown', this._onMouseDown, true);
- removeEvent(this.el, 'touchend', this._onMouseDown, true);
- removeEvent(this.el, 'change', this._onChange);
- if (this._o.field) {
- removeEvent(this._o.field, 'change', this._onInputChange);
- if (this._o.bound) {
- removeEvent(this._o.trigger, 'click', this._onInputClick);
- removeEvent(this._o.trigger, 'focus', this._onInputFocus);
- removeEvent(this._o.trigger, 'blur', this._onInputBlur);
- }
- }
- if (this.el.parentNode) {
- this.el.parentNode.removeChild(this.el);
- }
- }
-
- };
-
- return Pikaday;
-
-}));
diff --git a/debian/lib/simplestatemanager/ssm.js b/debian/lib/simplestatemanager/ssm.js
deleted file mode 100644
index 24a055d..0000000
--- a/debian/lib/simplestatemanager/ssm.js
+++ /dev/null
@@ -1,408 +0,0 @@
-/*global window document clearTimeout setTimeout */
-
-(function (window, document, undefined, factory) {
- if (typeof define === 'function' && define.amd) {
- define(function() {
- return factory(window, document, undefined);
- });
- }
- else if (typeof exports === 'object') {
- module.exports = factory;
- }
- else {
- window.ssm = factory(window, document, undefined);
- }
-})(window, document, undefined, function (window, document, undefined) {
- 'use strict';
-
- var resizeTimeout = 25;
- var stateChangeMethod = function(){};
-
- function Error(message) {
- this.message = message;
- this.name = "Error";
- }
-
- //
- // State Constructor
- // When the user uses addState state manager will create instances of a State
- //
-
- function State(options) {
- this.id = options.id || makeID();
- this.query = options.query || 'all';
- // These are exposed as part of the state, not options so delete before
- // we merge these into default options.
- delete options.id;
- delete options.query;
-
- var defaultOptions = {
- onEnter: [],
- onLeave: [],
- onResize: [],
- onFirstRun: []
- };
-
- //Merge options with defaults to make the state
- this.options = mergeOptions(defaultOptions, options);
-
- //Migrate methods into an array, this is to enable future functionality of adding extra methods to an existing state
- if(typeof this.options.onEnter === "function"){
- this.options.onEnter = [this.options.onEnter];
- }
-
- if(typeof this.options.onLeave === "function"){
- this.options.onLeave = [this.options.onLeave];
- }
-
- if(typeof this.options.onResize === "function"){
- this.options.onResize = [this.options.onResize];
- }
-
- if(typeof this.options.onFirstRun === "function"){
- this.options.onFirstRun = [this.options.onFirstRun];
- }
-
- //Test the one time tests first, if the test is invalid we wont create the config option
- if (this.testConfigOptions('once') === false) {
- this.valid = false;
- return false;
- }
-
- this.valid = true;
- this.active = false;
- this.init();
- }
-
- State.prototype = {
- init: function() {
- this.test = window.matchMedia(this.query);
-
- if (this.test.matches && this.testConfigOptions('match')) {
- this.enterState();
- }
-
- this.listener = function(test){
- var changed = false;
-
- if (test.matches) {
- if (this.testConfigOptions('match')) {
- this.enterState();
- changed = true;
- }
- }
- else {
- this.leaveState();
- changed = true;
- }
-
- if (changed) {
- stateChangeMethod();
- }
- }.bind(this);
-
- this.test.addListener(this.listener);
- },
-
- //Handle entering a state
- enterState: function() {
- fireAllMethodsInArray(this.options.onFirstRun);
- fireAllMethodsInArray(this.options.onEnter);
- this.options.onFirstRun = [];
- this.active = true;
- },
-
- //Handle leaving a state
- leaveState: function() {
- fireAllMethodsInArray(this.options.onLeave);
- this.active = false;
- },
-
- //Handle the user resizing the browser
- resizeState: function() {
- if (this.testConfigOptions('resize')) {
- fireAllMethodsInArray(this.options.onResize);
- }
- },
-
- //When the StateManager removes a state we want to remove the event listener
- destroy: function() {
- this.test.removeListener(this.listener);
- },
-
- attachCallback: function(type, callback, runIfActive) {
- switch(type) {
- case 'enter':
- this.options.onEnter.push(callback);
- break;
- case 'leave':
- this.options.onLeave.push(callback);
- break;
- case 'resize':
- this.options.onResize.push(callback);
- break;
- }
-
- if (type === 'enter' && runIfActive && this.active) {
- callback();
- }
- },
-
- testConfigOptions: function(when) {
- var totalConfigOptions = this.configOptions.length;
-
- for (var j = 0; j < totalConfigOptions; j++) {
- var configOption = this.configOptions[j];
-
- if (typeof this.options[configOption.name] !== "undefined") {
- if (configOption.when === when && configOption.test.bind(this)() === false) {
- return false;
- }
- }
- }
-
- return true;
- },
-
- //An array of avaliable config options, this can be pushed to by the State Manager
- configOptions: []
- };
-
- //State Manager Constructor
-
- function StateManager(options) {
- this.states = [];
- this.resizeTimer = null;
- this.configOptions = [];
-
- window.addEventListener("resize", debounce(this.resizeBrowser.bind(this), resizeTimeout), true);
- }
-
- StateManager.prototype = {
- addState: function(options) {
- var newState = new State(options);
-
- if (newState.valid) {
- this.states.push(newState);
- }
-
- return newState;
- },
-
- addStates: function (statesArray) {
- for (var i = statesArray.length - 1; i >= 0; i--) {
- this.addState(statesArray[i]);
- }
-
- return this;
- },
-
- getState: function(id) {
- for (var i = this.states.length - 1; i >= 0; i--) {
- var state = this.states[i];
-
- if(state.id === id){
- return state;
- }
- }
- },
-
- isActive: function(id) {
- var selectedState = this.getState(id) || {};
-
- return selectedState.active || false;
- },
-
- getStates: function(idArr) {
- var idCount = null, returnArr = [];
-
- if (typeof(idArr) === "undefined") {
- return this.states;
- }
- else {
- idCount = idArr.length;
-
- for (var i = 0; i < idCount; i++) {
- returnArr.push(this.getState(idArr[i]));
- }
-
- return returnArr;
- }
- },
-
- removeState: function (id) {
- for (var i = this.states.length - 1; i >= 0; i--) {
- var state = this.states[i];
-
- if (state.id === id) {
- state.destroy();
- this.states.splice(i, 1);
- }
- }
-
- return this;
- },
-
- removeStates: function (idArray) {
- for (var i = idArray.length - 1; i >= 0; i--) {
- this.removeState(idArray[i]);
- }
-
- return this;
- },
-
- removeAllStates: function() {
- for (var i = this.states.length - 1; i >= 0; i--) {
- var state = this.states[i];
- state.destroy();
- }
-
- this.states = [];
- },
-
-
- addConfigOption: function(options){
- var defaultOptions = {
- name: '', // name, this is used to apply to a state
- test: null, //function which will perform the test
- when: 'resize' // resize or match (match will mean that resize will never fire either), or once (which will test once, then delete state if test doesnt pass)
- };
-
- //Merge options with defaults
- options = mergeOptions(defaultOptions, options);
-
- if(options.name !== '' && options.test !== null){
- State.prototype.configOptions.push(options);
- }
- },
-
- removeConfigOption: function(name){
- var configOptions = State.prototype.configOptions;
-
- for (var i = configOptions.length - 1; i >= 0; i--) {
- if (configOptions[i].name === name) {
- configOptions.splice(i, 1);
- }
- }
-
- State.prototype.configOptions = configOptions;
- },
-
- getConfigOption: function(name){
- var configOptions = State.prototype.configOptions;
-
- if(typeof name === "string"){
- for (var i = configOptions.length - 1; i >= 0; i--) {
- if(configOptions[i].name === name){
- return configOptions[i];
- }
- }
- }
- else{
- return configOptions;
- }
- },
-
- getConfigOptions: function(){
- return State.prototype.configOptions;
- },
-
- resizeBrowser: function() {
- var activeStates = filterStates(this.states, 'active', true);
- var len = activeStates.length;
-
- for (var i = 0; i < len; i++) {
- activeStates[i].resizeState();
- }
- },
-
- stateChange: function(func) {
- if (typeof func === "function") {
- stateChangeMethod = func;
- }
- else {
- throw new Error('Not a function');
- }
- }
- };
-
- //Utility functions
-
- function filterStates(states, key, value) {
- var len = states.length;
- var returnStates = [];
-
- for (var i = 0; i < len; i++) {
- var state = states[i];
-
- if (state[key] && state[key] === value) {
- returnStates.push(state);
- }
- }
-
- return returnStates;
- }
-
- function mergeOptions(obj1, obj2) {
- var obj3 = {};
-
- for (var attrname in obj1) {
- obj3[attrname] = obj1[attrname];
- }
-
- for (var attrname2 in obj2) {
- obj3[attrname2] = obj2[attrname2];
- }
-
- return obj3;
- }
-
- function makeID() {
- var text = "";
- var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-
- for (var i = 0; i < 10; i++) {
- text += possible.charAt(Math.floor(Math.random() * possible.length));
- }
- return text;
- }
-
- function fireAllMethodsInArray(arr) {
- var arrLength = arr.length;
-
- for (var i = 0; i < arrLength; i++) {
- arr[i]();
- }
- }
-
- function funcToArray(func) {
- if (typeof func === 'function') {
- return [func];
- }
- else {
- return func;
- }
- }
-
- //
- // David Walsh's Debounce - http://davidwalsh.name/javascript-debounce-function
- //
-
- function debounce(func, wait, immediate) {
- var timeout;
-
- return function() {
- var context = this, args = arguments;
- var later = function() {
- timeout = null;
- if (!immediate) func.apply(context, args);
- };
- var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) func.apply(context, args);
- };
- }
-
- return new StateManager();
-});
diff --git a/debian/patches/build.patch b/debian/patches/build.patch
index c5d1920..c9e4399 100644
--- a/debian/patches/build.patch
+++ b/debian/patches/build.patch
@@ -10,35 +10,12 @@ Simplified build process to reduce dependencies.
loose = true;
process.noDeprecation = true;
-@@ -28,15 +26,10 @@
- 'process.env': {
- NODE_ENV: '"production"'
- }
-- }),
-- new WebpackNotifierPlugin(),
-- new CopyWebpackPlugin([
-- {from: 'debian/lib/openpgp/dist/openpgp.min.js', to: 'js/min/openpgp.min.js'},
-- {from: 'debian/lib/openpgp/dist/openpgp.worker.min.js', to: 'js/min/openpgp.worker.min.js'}
-- ])
-+ })
- ],
- resolve: {
-- modules: [devPath, 'node_modules'],
-+ modules: [devPath, 'node_modules', '/usr/lib/nodejs'],
- extensions: ['.js'],
- alias: {
- 'pikaday$': __dirname + '/debian/lib/pikaday/pikaday.js',
-@@ -46,6 +39,13 @@
- 'ko$': __dirname + '/dev/External/ko.js'
- }
- },
-+ resolveLoader: {
-+ alias: {
-+ 'raw-loader': '/usr/lib/nodejs/raw-loader',
-+ 'style-loader': '/usr/lib/nodejs/style-loader',
-+ 'babel-loader': '/usr/lib/nodejs/babel-loader'
-+ },
-+ },
- module: {
- rules: [
- {
+@@ -54,7 +52,7 @@
+ include: [devPath],
+ options: {
+ cacheDirectory: true,
+- presets: [['env', {
++ presets: [[{
+ loose: loose,
+ modules: false,
+ targets: {
diff --git a/debian/patches/bundled-libraries.patch b/debian/patches/bundled-libraries.patch
index 13a90b7..7d71d81 100644
--- a/debian/patches/bundled-libraries.patch
+++ b/debian/patches/bundled-libraries.patch
@@ -37,9 +37,9 @@ Bundled libraries missing from Debian.
modules: [devPath, 'node_modules'],
extensions: ['.js'],
alias: {
-+ 'pikaday$': __dirname + '/debian/lib/pikaday/pikaday.js',
++ 'pikaday$': __dirname + '/usr/lib/nodejs/pikaday/pikaday.js',
+ 'js-cookie$': __dirname + '/debian/lib/js-cookie/js.cookie.js',
-+ 'classnames$': __dirname + '/debian/lib/classnames/index.js',
++ 'classnames$': __dirname + '/usr/lib/nodejs/classnames/index.js',
'Opentip$': __dirname + '/dev/External/Opentip.js',
'ko$': __dirname + '/dev/External/ko.js'
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/rainloop.git
More information about the Pkg-javascript-commits
mailing list