utils.js

From disqus.com, 1 Month ago, written in JavaScript, viewed 3 times. This paste is a reply to withClickLinkTracking.js from disqus.com - go back
URL https://pastebin.freepbx.org/view/28bdf1fb/diff Embed
Viewing differences between withClickLinkTracking.js and utils.js
define('home/mixins/withClickLinkTracking',[
define('core/utils',[
    'jquery',
    'underscore',
    'core/bus',
'underscore',

    'core/config',
    'core/utils/browser',
    'core/utils/isMobileUserAgent',
], function (
    $,
    _,
    bus
_,

    config,
    browser,
    isMobileUserAgent
) {
    'use strict';

    var doc = window.document;
    
// Debounce triggerClick so that an element that has multiple click
    // handlers on it that call trackClickLink with different event
    // objects will end up being debounced by this 
From https://github.com/ryanseddon/H5F/blob/039588f4b1d8513b09a49f903d70ff269435d4b3/src/H5F.js#L20
    var emailPatt = /^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
    var validateEmail = 
function and only
    // tracked once.
    var triggerClick = _.debounce(function (evt, params) 
(email) {
        bus.trigger('uiAction:clickLink', evt, params);
    }, 500, true);

    
return emailPatt.test(email);
    };

    /*
     * This uses the same url RegExp as Bleach version 1.0.3 and returns
     * the links it finds. This is not a direct match to Bleach, as there is no
     * true HTML parsing, but it is sufficient for finding urls.
     */
    // TODO: config.TLDS is included to support an Embed override. Embed gets
    // an up-to-date list every build via manifest.yaml and the interpolator;
    // an equivalent system should be incorporated in next-core
    var TLDS = config.TLDS ||
        'zw|zuerich|zone|zm|zip|za|yt|youtube|yokohama|yoga|yodobashi|ye|' +
        'yandex|yachts|xyz|xxx|xin|xerox|wtf|wtc|ws|world|works|work|wme|win|' +
        'williamhill|wiki|wien|whoswho|wf|weir|wedding|wed|website|webcam|' +
        'watch|wang|wales|vu|voyage|voto|voting|vote|vodka|vn|vlaanderen|' +
        'vision|villas|video|viajes|vi|vg|vet|versicherung|ventures|vegas|ve|' +
        'vc|vacations|va|uz|uy|us|uol|uno|university|uk|ug|ua|tz|tw|tv|tui|' +
        'tt|trust|travel|training|trading|trade|tr|toys|town|tours|toshiba|' +
        'toray|top|tools|tokyo|today|to|tn|tm|tl|tk|tj|tirol|tires|tips|' +
        'tienda|tickets|theater|th|tg|tf|tennis|temasek|tel|technology|tech|' +
        'team|td|tc|taxi|tax|tattoo|tatar|taipei|sz|systems|sydney|sy|sx|' +
        'swiss|sv|suzuki|surgery|surf|support|supply|supplies|sucks|su|style|' +
        'study|st|sr|spreadbetting|spiegel|space|soy|sony|solutions|solar|' +
        'sohu|software|social|so|sn|sm|sl|sky|sk|sj|site|singles|si|shriram|' +
        'show|shoes|shiksha|sh|sg|sexy|sex|sew|services|sener|seat|se|sd|' +
        'scot|science|schwarz|schule|school|scholarships|schmidt|scb|sca|sc|' +
        'sb|saxo|sarl|sap|samsung|sale|saarland|sa|ryukyu|rw|run|ruhr|ru|' +
        'rsvp|rs|rodeo|rocks|ro|rip|rio|rich|reviews|review|restaurant|rest|' +
        'republican|report|repair|rentals|rent|ren|reit|reisen|reise|rehab|' +
        'redstone|red|recipes|realtor|re|racing|quebec|qpon|qa|py|pw|pub|pt|' +
        'ps|property|properties|prof|productions|prod|pro|press|praxi|pr|' +
        'post|porn|poker|pohl|pn|pm|plus|plumbing|place|pl|pk|pizza|pink|' +
        'pictures|pictet|pics|piaget|physio|photos|photography|photo|philips|' +
        'pharmacy|ph|pg|pf|pe|party|parts|partners|paris|panerai|page|pa|ovh|' +
        'otsuka|osaka|organic|org|oracle|ooo|online|onl|ong|one|om|okinawa|' +
        'nz|nyc|nu|ntt|nrw|nra|nr|np|no|nl|nissan|ninja|nico|ni|nhk|ngo|ng|' +
        'nf|nexus|news|new|neustar|network|net|nec|ne|nc|navy|name|nagoya|' +
        'nadex|na|mz|my|mx|mw|mv|museum|mu|mtpc|mtn|mt|ms|mr|mq|mp|movie|mov|' +
        'motorcycles|moscow|mortgage|mormon|money|monash|moe|moda|mobi|mo|mn|' +
        'mma|mm|ml|mk|mini|mil|miami|mh|mg|menu|memorial|meme|melbourne|meet|' +
        'media|me|md|mc|marriott|markets|marketing|market|mango|management|' +
        'maison|maif|madrid|ma|ly|lv|luxury|luxe|lu|ltda|lt|ls|lr|love|lotto|' +
        'lotte|london|lol|loans|loan|lk|link|limo|limited|lighting|life|lidl|' +
        'liaison|li|lgbt|legal|leclerc|lease|lds|lc|lb|lawyer|latrobe|lat|' +
        'land|lacaixa|la|kz|kyoto|ky|kw|kred|krd|kr|kp|komatsu|koeln|kn|km|' +
        'kiwi|kitchen|kim|ki|kh|kg|ke|kddi|kaufen|juegos|jp|joburg|jobs|jo|' +
        'jm|jewelry|jetzt|je|jcb|java|iwc|it|is|irish|ir|iq|io|investments|' +
        'international|int|insure|institute|ink|ing|info|infiniti|industries|' +
        'in|immobilien|immo|im|il|ifm|ie|id|icu|ibm|hu|ht|hr|how|house|' +
        'hosting|host|horse|honda|homes|holiday|holdings|hockey|hn|hm|hk|hiv|' +
        'hitachi|hiphop|hermes|here|help|healthcare|haus|hangout|hamburg|gy|' +
        'gw|guru|guitars|guide|guge|gu|gt|gs|gripe|green|gratis|graphics|gr|' +
        'gq|gp|gov|gop|google|goog|goo|golf|goldpoint|gold|gn|gmx|gmo|gmail|' +
        'gm|globo|global|gle|glass|gl|gives|gifts|gift|gi|gh|ggee|gg|gf|gent|' +
        'ge|gdn|gd|gbiz|gb|garden|gallery|gal|ga|futbol|furniture|fund|' +
        'frogans|frl|fr|foundation|forsale|forex|football|foo|fo|fm|fly|' +
        'flsmidth|flowers|florist|flights|fk|fj|fitness|fit|fishing|fish|' +
        'firmdale|financial|finance|film|fi|feedback|fashion|farm|fans|fan|' +
        'faith|fail|express|exposed|expert|exchange|everbank|events|eus|' +
        'eurovision|eu|et|estate|esq|es|erni|er|equipment|epson|enterprises|' +
        'engineering|engineer|energy|emerck|email|eg|ee|education|edu|ec|eat|' +
        'dz|dvag|durban|download|doosan|domains|doha|dog|docs|do|dnp|dm|dk|' +
        'dj|discount|directory|direct|digital|diet|diamonds|dev|design|desi|' +
        'dentist|dental|democrat|delivery|degree|deals|de|dclk|day|datsun|' +
        'dating|date|dance|dad|dabur|cz|cyou|cymru|cy|cx|cw|cv|cuisinella|cu|' +
        'cruises|crs|cricket|creditcard|credit|cr|courses|country|coop|cool|' +
        'cooking|contractors|consulting|construction|condos|computer|company|' +
        'community|com|cologne|college|coffee|codes|coach|co|cn|cm|club|' +
        'clothing|clinic|click|cleaning|claims|cl|ck|city|citic|ci|church|' +
        'chrome|christmas|chloe|cheap|chat|channel|ch|cg|cfd|cfa|cf|cern|ceo|' +
        'center|cd|cc|cbn|catering|cat|casino|cash|casa|cartier|cars|careers|' +
        'career|care|cards|caravan|capital|capetown|canon|cancerresearch|' +
        'camp|camera|cal|cafe|cab|ca|bzh|bz|by|bw|bv|buzz|business|builders|' +
        'build|budapest|bt|bs|brussels|brother|broker|bridgestone|br|' +
        'boutique|boo|bond|boats|bo|bnpparibas|bn|bmw|bm|blue|bloomberg|' +
        'blackfriday|black|bj|biz|bio|bingo|bike|bid|bi|bh|bg|bf|best|berlin|' +
        'beer|be|bd|bbc|bb|bayern|bauhaus|bargains|barclays|barclaycard|bar|' +
        'bank|band|ba|az|axa|ax|aw|autos|auto|audio|auction|au|attorney|at|' +
        'associates|asia|as|arpa|army|archi|ar|aquarelle|aq|apartments|ao|' +
        'android|an|amsterdam|am|alsace|allfinanz|al|airforce|aig|ai|agency|' +
        'ag|afl|af|aero|ae|adult|ads|ad|actor|active|accountants|accountant|' +
        'accenture|academy|ac|abogado|abbott|abb';

    // Url RegExp
    var URL_RE = new RegExp(
        // http://
        // Note: First group must be removed from match when
        // processing, in python it was a look-behind.
        '([^@.]|^)\\b(?:\\w[\\w-]*:/{0,3}(?:(?:\\w+:)?\\w+@)?)?' +
        // xx.yy.tld
        '([\\w-]+\\.)+(?:' + TLDS + ')(?!\\.\\w)\\b' +
        // optional port
        '(?::\\d+)?' +
        // /path/zz (excluding "unsafe" chars from RFC 1738,
        // except for # and ~, which happen in practice)
        '(?:[/?][^\\s\\{\\}\\|\\\\\\^\\[\\]`<>"\\x80-\\xFF\\x00-\\x1F\\x7F]*)?',
        // Flags.
        // Note: ignore case is NOT set because Bleach version 1.0.3 does not
        // set it. This is a bug, resulting in urls being ignored if the TLD
        // is capitalized. However, it is repeated here for consistency with
        // the server; if we update Bleach we should update this method as well.
        'g'
    );

    var isUrl = 
function (area) (urlStr) {
        this.trackClickLink return Boolean(urlStr.match(URL_RE));
    };

    // Protocol RegExp
    var PROTO_RE = /^[\w-]+:\/{0,3}/;
    // Punctuation RegExp.
    // This is global so that lastIndex is set.
    var PUNCT_RE = /([.,]+)$/g;

    var bleachFindUrls 
= function (evt) {
            // Ignore if the link is taking the user to edit their post.
            // Prevents us from tracking one click as two separate events.
            if (evt.currentTarget.dataset.action === 'edit')
                return;
            
(message) {
        
var $target urlRecord $(evt.currentTarget);
            
[];
        
var params match, matchedStr, punctMatch, href, group1;

        if (!message)
            return urlRecord;

        while (match 
{
                adjective: $target.attr('data-link-name'),
            };

            
URL_RE.exec(message)) {  // Use the area as given when this mixin was applied, eslint-disable-line no-cond-assign
            matchedStr = match[0];
            group1 = match[1];

            // Remove first group of match (see comment in URL_RE)
            matchedStr = matchedStr.slice(group1.length);

            // Remove trailing punctuation
            PUNCT_RE.lastIndex = 0;
            punctMatch = PUNCT_RE.exec(matchedStr);
            
if any.
            
(punctMatch)
                matchedStr = matchedStr.slice(0, matchedStr.length - punctMatch[0].length);

            
// Otherwise use an area defined in the dom, Normalize protocol
            
if any.
            if (area)
                params.area 
(PROTO_RE.test(matchedStr))
                href 
area;
matchedStr;
            else
                params.area href $target.closest('[data-jester-area]').attr('data-jester-area');

            triggerClick(evt, params);
'http://' + matchedStr;

            // Store match
            var index = match.index + group1.length;
            urlRecord.push({
                text: matchedStr,
                url: href,
                index: index,
                endIndex: index + matchedStr.length,
            });
        }

        return urlRecord;
    };

    // Regex to match sequence of 1 or more punctuation
    // characters at the end of a string
    // See: www.unicode.org/charts/
    var terminatingPuncRe = new RegExp('[' +
            // Basic Latin (ASCII punctuation blocks)
            '\\u0021-\\u002F' +
            '\\u003A-\\u0040' +
            '\\u005B-\\u0060' +
            '\\u007B-\\u007E' +
            // Latin-1 Supplement (Latin-1 punctuation)
            '\\u00A1-\\u00BF' +
            // General Punctuation
            '\\u2010-\\u2027' +
            '\\u2030-\\u205E' +
            // Miscellaneous technical
            '\\u2300-\\u23FF' +
            // Supplemental punctuation
            '\\u2E00-\\u2E7F' +
            // CJK Symbols and Punctuation
            '\\u3001-\\u303F' +
            // Vertical forms
            '\\uFE10-\\uFE19' +
            // CJK Compatibility Forms
            '\\uFE30-\\uFE4F' +
            // Small form variants
            '\\uFE50-\\uFE6B' +
            // Fullwidth ASCII Forms
            '\\uFF01-\\uFF0F' +
            '\\uFF1A-\\uFF20' +
            '\\uFF3B-\\uFF40' +
            '\\uFF5B-\\uFF60' +
            // Halfwidth CJK Punctuation
            '\\uFF5F-\\uFF64' +
        ']+$');

    var MAX_TRUNCATION_RATIO = 0.5;
    // Given a character limit (upperLimit) return the whole text
    // if it fits within the limit, otherwise try to truncate
    // within that limit without chopping off a word halfway or
    // returning text with dangling punctuation but also without
    // truncating the text more than halfway.
    var niceTruncate = function (text, upperLimit) {
        if (text.length <= upperLimit)
            return text;

        text = text.slice(0, upperLimit - 1);  // account the ellipsis char
        var max = text;

        // There's no way to know if the last sequence of chars is
        // a whole word or not, so scan the sliced text backwards
        // for the first whitespace character and truncate there

        // Greedily match everything up to the last chunk of whitespace
        var matches = /(^.*\S)\s/.exec(text);

        if (matches)
            text = matches[1];

        var endPunctuation = terminatingPuncRe.exec(text);

        // Remove any trailing punctuation
        if (endPunctuation)
            text = text.slice(0, text.length - endPunctuation[0].length);

        // If the further truncation above caused the text we're returning
        // to be less than 1/2 what it was before further truncation, we undo
        if (text.length < MAX_TRUNCATION_RATIO * max.length)
            text = max;

        return text + '\u2026';  // Ellipsis
    };

    var _hasStyleProperty = (function () {
        var el = doc.createElement('fakeelement');

        return function (_cssName, jsName) {
            return el.style[jsName] !== undefined;
        };
    }());

    // http://stackoverflow.com/questions/5023514/how-do-i-normalize-css3-transition-functions-across-browsers
    var transitionEndEvent = (function () {
        var transitions = {
            transition: 'transitionend',
            OTransition: 'otransitionend',
            MozTransition: 'transitionend',
            WebkitTransition: 'webkitTransitionEnd',
        };

        return _.find(transitions, _hasStyleProperty) || null;
    })();

    // https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations/Detecting_CSS_animation_support
    var animationEndEvent = (function () {
        var animations = {
            animation: 'animationend',
            OAnimation: 'oAnimationEnd',
            MozAnimation: 'animationend',
            WebkitAnimation: 'webkitAnimationEnd',
        };

        return _.find(animations, _hasStyleProperty) || null;
    })();

    /**
     * Utility helper for DOM event handlers that automatically calls preventDefault for you
     *
     * @param {function} handler The event handler to be wrapped/modified
     * @returns {function} The new, augmented event handler that prevents the default action for the event
     */
    function preventDefaultHandler(handler) {
        return function (evt) {
            if (evt && evt.preventDefault)
                evt.preventDefault();
            return handler.apply(this, arguments);
        };
    }

    /**
     * Utility helper for DOM event handlers that automatically calls stopPropagation for you
     *
     * @param {function} handler The event handler to be wrapped/modified
     * @returns {function} The new, augmented event handler that stops the propagation of the event
     */
    function stopPropagationHandler(handler) {
        return function (evt) {
            if (evt && evt.stopPropagation)
                evt.stopPropagation();
            return handler.apply(this, arguments);
        };
    }

    function stopEventHandler(handler) {
        return preventDefaultHandler(stopPropagationHandler(handler));
    }

    function getDomain(url) {
        // Extracts hostname from url, without the www prefix.

        if (!url)
            return '';

        // Force the protocol to http.
        // This resolves an issue where some browsers do not extract
        // the hostname if the url does not use a typical protocol.
        // Forcing a protocol is also required since if missing the
        // url will be resolved as a relative url on our domain.
        url = 'http://' + url.replace(/^([a-z+.-]+:)?\/+/i, '');

        var link = doc.createElement('a');
        link.href = url;

        // Remove www prefix and any trailing numbers.
        // Since getDomain is used only for display purposes this is a
        // safe operation.
        var domain = link.hostname.replace(/^www\d*\./i, '');

        // Normalize capitalization since browsers are inconsistent
        // about this.
        domain = domain.toLowerCase();

        return domain;
    }

    function serializeArgs(params) {
        var pcs = [];
        _.each(params, function (val, key) {
            if (val !== undefined)
                pcs.push(key + (val === null ? '' : '=' + encodeURIComponent(val)));
        });
        return pcs.join('&');
    }

    function serialize(url, params, nocache) {
        if (params) {
            if (url.indexOf('?') === -1)
                url += '?';
            else if (url.charAt(url.length - 1) !== '&')
                url += '&';

            url += this.serializeArgs(params);
        }

        if (nocache) {
            var ncp = {};
            ncp[(new Date()).getTime()] = null;
            return this.serialize(url, ncp);
        }

        var len = url.length;
        return url.charAt(len - 1) === '&' ? url.slice(0, len - 1) : url;
    }

    /**
     * window.open wrapper
     *
     * IMPORTANT: must obey same contract as window.open
     * i.e., same function signature, same return value
     *
     * We wrap it because it is not possible to stub `window.open`
     * reliably across browsers for testing, which causes issues from time to time.
     *
     * @param {string} url The URL for the new popup window
     * @param {string} [title] The title of the new popup window
     * @param {Object} [options] Options for the new window such as height and width. The following are overridden:
     *                           location, status, resizable, scrollbars for UX and cross-browser consistency.
     * @returns {window|null} The reference to the newly created popup window, or `null` if popup is blocked.
     */
    function openWindow(url, title, options) {
        // Don't add any defaults if options object is not provided. Not using
        // options is the only way to default to opening a new tab instead of a
        // window when using `window.open`
        if (options) {
            _.extend(options, {
                'location': 1,
                'status': 1,
                'resizable': 1,
                'scrollbars': 1,
            });
        } else {
            options = {};
        }

        if (options.width && options.height) {
            // By default, position window in the middle of the browser screen
            _.defaults(options, {
                left: window.screen.width / 2 - options.width / 2,
                top: window.screen.height / 2 - options.height / 2,
            });
        }

        var optionsStr = _.map(options, function (val, key) {
            return key + '=' + val;
        }).join(',');

        return window.open(url, title, optionsStr);
    }

    /**
     * Safely insert a string into another string at specified index.
     * Spaces will be guaranteed to surround the inserted string, except
     * at the beginning of the new string.
     *
     * @param {string} string The string to be inserted into
     * @param {number} index The position to insert into
     * @param {string} stringToInsert The string to be inserted
     *
     * @returns {string} The newly crafted string
     */
    function insertWithWhitespace(string, index, stringToInsert) {
        if (index < 0)
            index = 0;

        var before = string.substring(0, index);
        var after = string.substring(index);

        // Place a space before the new string if necessary
        if (before.length && !/\s$/.test(before))
            before += ' ';

        // Place a space after the new string if necessary
        // Will also place a space if at the end of the text
        if (!/^\s/.test(after))
            after = ' ' + after;

        return before + stringToInsert + after;
    }

    /**
     * Check if a clicked link will open a new window or tab.
     *
     * We don't have to delay link clicks if they will open a new tab via
     * command / shift / control key modifiers or if the 'target' attribute is '_blank'.
     *
     * @param  {$.Event}    evt The event object from the original click event.
     * @param  {jQuery}   $link jQuery wrapped link object.
     * @returns {boolean}
     */
    var willOpenNewWindow = function (evt, $link) {
        if (!$link)
            $link = $(evt.currentTarget);

        return $link.attr('target') === '_blank' ||
            evt.ctrlKey ||  // For Windows and Linux
            evt.metaKey || // For OS X
            evt.shiftKey || // For new window
            evt.altKey;  // God knows what
    };

    var LINK_CLICK_RECENCY_TIMEOUT = 500;  /* ms */
    /**
     * Determine if a click event should be logged to our analytics servers.
     *
     * We currently log clicks only if the link's href is intended to cause
     * the parent page to change locations (disregarding modifier keys, etc.).
     *
     * @param  {$.Event}  evt The jQuery event object.
     * @param  {jQuery}   $link jQuery wrapped link object.
     * @returns {boolean}
     */
    var clickShouldBeLogged = (function () {
        var logged = {};
        var urlFragmentReg = /#.*$/;

        var getLinkTrackingId = function ($link) {
            // Because a link's href may be modified during the course
            // of a click event, we need to attach our own IDs.
            var id = $link.attr('data-tid');
            if (!id) {
                id = _.uniqueId();
                $link.attr('data-tid', id);
            }
            return id;
        };

        return function (evt, $link) {
            // We don't do anything if we're already handling this event elsewhere.
            if (evt.isDefaultPrevented())
                return false;

            // We don't bother if the clicked element is not a link.
            if (!$link.is('a'))
                return false;

            // We don't bother if the clicked link doesn't have an href attribute,
            // or if the clicked link's href attribute is just a hash.
            var href = ($link.attr('href') || '').replace(urlFragmentReg, '');
            if (!href)
                return false;

            // Because we re-trigger clicks, it is very possible that we're being
            // asked to log the same click twice. We keep an internal hash of
            // links clicks we've logged within the last .5s so that we don't
            // enter an infinite click loop.
            var linkId = getLinkTrackingId($link);
            var timestamp = new Date().getTime();

            // If we recently delayed this click, then bail out now.
            if (logged[linkId] && timestamp - logged[linkId] < LINK_CLICK_RECENCY_TIMEOUT)
                return false;

            logged[linkId] = timestamp;
            return true;
        };
    })();

    return {
        validateEmail: validateEmail,
        isUrl: isUrl,
        bleachFindUrls: bleachFindUrls,
        niceTruncate: niceTruncate,
        transitionEndEvent: transitionEndEvent,
        animationEndEvent: animationEndEvent,
        isMobileUserAgent: isMobileUserAgent,
        preventDefaultHandler: preventDefaultHandler,
        stopPropagationHandler: stopPropagationHandler,
        stopEventHandler: stopEventHandler,
        getDomain: getDomain,
        serializeArgs: serializeArgs,
        serialize: serialize,
        openWindow: openWindow,
        insertWithWhitespace: insertWithWhitespace,
        willOpenNewWindow: willOpenNewWindow,
        clickShouldBeLogged: clickShouldBeLogged,
        browser: browser,
    };
});


  
});

// https://c.disquscdn.com/next/home/js/mixins/withClickLinkTracking.com/next/next-core/core/utils.js

Reply to "utils.js"

Here you can reply to the paste above