Re: Re: ads.js

From disqus.com, 2 Months ago, written in JavaScript, viewed 3 times. This paste is a reply to Re: Re: require.js from disqus.com - view diff
URL https://pastebin.freepbx.org/view/839984f2 Embed
Download Paste or View Raw
  1. define('core/ads/ads',['require','core/shared/urls','core/apps/WindowedApp','core/host/json','stance/main','stance/utils','core/common/kernel/WindowBase','core/utils/OnceTimer','core/utils/html/toHexColorString','core/utils/object/extend','core/utils/sandbox','core/utils/url/parseQueryString','core/utils/url/serialize','core/utils/urls','core/utils/urls','core/analytics/reporting','core/ads/Geom'],function (require) {
  2.     'use strict';
  3.  
  4.     var urls = require('core/shared/urls');
  5.  
  6.     var WindowedApp = require('core/apps/WindowedApp');
  7.     var JSON = require('core/host/json'); // eslint-disable-line no-shadow
  8.  
  9.     var stance = require('stance/main');
  10.     var stanceUtils = require('stance/utils');
  11.  
  12.     var WindowBase = require('core/common/kernel/WindowBase');
  13.     var OnceTimer = require('core/utils/OnceTimer');
  14.     var toHexColorString = require('core/utils/html/toHexColorString');
  15.     var extend = require('core/utils/object/extend');
  16.     var sandbox = require('core/utils/sandbox');
  17.     var parseQueryString = require('core/utils/url/parseQueryString');
  18.     var serialize = require('core/utils/url/serialize');
  19.     var getOrigin = require('core/utils/urls').getOrigin;
  20.     var getQuery = require('core/utils/urls').getQuery;
  21.     var reporting = require('core/analytics/reporting');
  22.  
  23.     var Geom = require('core/ads/Geom');
  24.  
  25.     var AdsApp = WindowedApp.extend({
  26.         name: 'ads',
  27.  
  28.         origin: undefined,  // origin is defined by the adUrl passed during construction
  29.  
  30.         onceEvents: {
  31.             'view:enter': function () {
  32.                 this._reportLegacy({ verb: 'view', adverb: '0ms-no50perc' });
  33.             },
  34.  
  35.             'view:iab': function () {
  36.                 this._reportLegacy({ verb: 'view', adverb: 'iab-scroll' });
  37.             },
  38.         },
  39.  
  40.         events: {
  41.             'frame:ready': function (options) {
  42.                 this.forumId = options.forumId;
  43.  
  44.                 this._reportLegacy({
  45.                     verb: 'load',
  46.                     extra_data: options.extraData,
  47.                     advertisement_id: options.advertisement_id,
  48.                     provider: options.provider,
  49.                 });
  50.  
  51.                 // Start sending view events, now that the ad frame has initialized
  52.                 // TODO: Ideally this should occur after the ads are rendered, but
  53.                 // for now the ready event occurs as soon as our ads code loads
  54.                 this.bindViewEvents();
  55.                 this.triggerGeomUpdate();
  56.             },
  57.             'frame:resize': function (options) {
  58.                 this.frame.setInlineStyle('height', options.height + 'px');
  59.                 if (options.height === 0) { // No ad presented
  60.                     this.trigger('ad-placement-empty');
  61.                 } else {
  62.                     this.trigger('ad-placement-filled');
  63.                 }
  64.                 this.triggerGeomUpdate();
  65.             },
  66.             'frame:click': function () {
  67.                 this._reportOnce({ verb: 'click' }, 'click');
  68.             },
  69.             'frame:hover': function () {
  70.                 this._reportOnce({ verb: 'hover' }, 'hover');
  71.             },
  72.             'frame:error-provider-not-ready': function (options) {
  73.                 this._reportLegacy({
  74.                     verb: 'fail',
  75.                     object_type: 'provider',
  76.                     object_id: options.provider || this.getProvider(),
  77.                     adverb: 'provider_not_ready',
  78.                 });
  79.             },
  80.             'frame:error-no-height': function (options) {
  81.                 this._reportLegacy({
  82.                     verb: 'fail',
  83.                     object_type: 'provider',
  84.                     object_id: options.provider || this.getProvider(),
  85.                     adverb: 'no_height',
  86.                 });
  87.             },
  88.             'frame:clearSandbox': function () {
  89.                 if (this.frame.elem.hasAttribute('sandbox')) {
  90.                     this.frame.elem.removeAttribute('sandbox');
  91.                 }
  92.             },
  93.             'frame:redirect': function (newUrl) {
  94.                 if (this.settings.isOnHostPage) {
  95.                     this.frame.elem.src = newUrl;
  96.                 }
  97.             },
  98.             // TODO: Maybe remove this since it's no longer being fired.
  99.             'frame:logAd': function (adData) {
  100.                 this._report(adData, { usePOST: true });
  101.             },
  102.             'frame:$sf-init': function () {
  103.                 if (this.settings.isOnHostPage) {
  104.                     this.isSafeframe = true;
  105.                 }
  106.             },
  107.             'frame:error': function (error) {
  108.                 if (this.settings.isOnHostPage) {
  109.                     this.postMessageDirect({
  110.                         event: 'error',
  111.                         data: {
  112.                             error: error,
  113.                         },
  114.                     });
  115.                 }
  116.             },
  117.         },
  118.  
  119.         constructor: function () {
  120.             WindowedApp.apply(this, arguments);
  121.             this.origin = getOrigin(this.settings.adUrl);
  122.  
  123.             // Record of events which should only be reported once
  124.             this._reportOnceHistory = {};
  125.  
  126.             if (this.settings.isOnHostPage) {
  127.                 this.detectLazyload = this.detectLazyload.bind(this);
  128.                 window.addEventListener('scroll', this.detectLazyload);
  129.             }
  130.         },
  131.  
  132.         init: function () {
  133.             this.settings.forum = parseQueryString(getQuery(this.settings.adUrl)).shortname;
  134.             if (!this.settings.forum) {
  135.                 return;
  136.             }
  137.  
  138.             // Ad preferences that the publisher has set on this
  139.             // page via inline script
  140.             var disableAds = this.settings.disableAds;
  141.  
  142.             // Bail out if publisher has turned off ads for
  143.             // this page and are allowed to turn them off.
  144.             // I.e., don't show ads on a page where they
  145.             // have been explicitly disabled.
  146.             //
  147.             // We only use window.location.href if we're on
  148.             // the host page because it's disqus.com from
  149.             // within the disqus iframe, which will be
  150.             // considered to be in home.
  151.             var isInHome = this.settings.isInHome ||
  152.                 (this.settings.isOnHostPage && window.location.href.indexOf(urls.apps.home) === 0);
  153.             if (!isInHome && disableAds && this.settings.canDisableAds) {
  154.                 return void this.trigger('prevented-ad-load');
  155.             }
  156.  
  157.             this._reportOnce({
  158.                 verb: 'call',
  159.                 object_type: 'provider',
  160.                 object_id: this.getProvider(),
  161.                 adjective: 1,
  162.             }, 'call');
  163.  
  164.             // Ads iframes should include sandbox attributes to prevent malicious or annoying ads
  165.             // from annoying the user.
  166.             if (this.settings.sandboxAds) {
  167.                 this.sandbox = sandbox.getAttribute({
  168.                     'allow-scripts': true,
  169.                     'allow-same-origin': true,
  170.                     'allow-forms': true,
  171.                     'allow-popups': true,
  172.                 });
  173.             }
  174.  
  175.             WindowedApp.prototype.init.call(this);
  176.         },
  177.  
  178.         detectLazyload: function () {
  179.             // TODO: Figure out why this.frame is sometimes undefined.
  180.             if (!this.frame || !this.settings.isOnHostPage) {
  181.                 return;
  182.             }
  183.  
  184.             const distanceFromViewportTop = this.frame.elem.getBoundingClientRect().top;
  185.             const distanceFromViewportBottom = distanceFromViewportTop - window.innerHeight;
  186.             // Here we calculate the n-viewports threshold to use for lazyloading ads.
  187.             const threshold = window.innerHeight * this.settings.lazyloadViewports;
  188.             if (distanceFromViewportBottom < threshold) {
  189.                 this.postMessageDirect({
  190.                     event: 'lazyload',
  191.                 });
  192.                 window.removeEventListener('scroll', this.detectLazyload);
  193.             }
  194.         },
  195.  
  196.         getProvider: function () {
  197.             if (this._provider) {
  198.                 return this._provider;
  199.             }
  200.  
  201.             // TODO - have the server add this as a key-value pair to the server-side config?
  202.             // Matching a string seems brittle.
  203.             // try to get provider from URL, memoize if we find it.
  204.             var provider = this.settings.adUrl.match(/provider=(\w+)/);
  205.             if (provider) {
  206.                 this._provider = provider[1];
  207.             }
  208.  
  209.             return this._provider;
  210.         },
  211.  
  212.         getUrl: function () {
  213.             var settings = this.settings;
  214.  
  215.             var sourceUrl;
  216.             if (settings.experiment.experiment === 'inthreaddisqusadstxt' &&
  217.                 settings.experiment.variant === 'active' &&
  218.                 settings.placement === 'inthread') {
  219.                 sourceUrl = window.document.location.href;
  220.             } else if (settings.isOnHostPage) {
  221.                 sourceUrl = settings.url || window.document.location.href;
  222.             } else {
  223.                 sourceUrl = settings.url || settings.referrer;
  224.             }
  225.  
  226.             return serialize(settings.adUrl, {
  227.                 // send as hex color string because of API with Gravity
  228.                 // https://docs.google.com/document/d/16OhDwst-AXCLFoVWu-KOHOpyzqhrkH02gG5vE0Qi9i0/
  229.                 anchorColor: toHexColorString(settings.anchorColor),
  230.                 colorScheme: settings.colorScheme,
  231.                 sourceUrl: sourceUrl,
  232.                 typeface: settings.typeface,
  233.                 canonicalUrl: settings.canonicalUrl,
  234.                 disqus_version: settings.version,
  235.             });
  236.         },
  237.  
  238.         triggerGeomUpdate: function () {
  239.             if (!this.frame.elem || !this.isSafeframe || !this.settings.isOnHostPage) {
  240.                 return;
  241.             }
  242.  
  243.             var geom = Geom.get(this.frame.elem);
  244.  
  245.             this.postMessageDirect({
  246.                 event: 'geom-update',
  247.                 data: {
  248.                     geom: geom,
  249.                 },
  250.             });
  251.         },
  252.  
  253.         // Sets up view event triggers for this frame
  254.         // See discovery/views/BaseUnit for more details
  255.         bindViewEvents: function () {
  256.             if (this._viewEventsBound) {
  257.                 return;
  258.             }
  259.  
  260.             this._viewEventsBound = true;
  261.  
  262.             // Make sure stance is listening for window scroll and resize events
  263.             // (this will no-op after first call)
  264.             stance.bindWindowEvents(true);
  265.  
  266.             var self = this;
  267.             var trigger = function (name, percentViewable) {
  268.                 self.postMessageDirect({
  269.                     event: name,
  270.  
  271.                     // Note: JSON.stringify removes undefined
  272.                     percentViewable: percentViewable,
  273.                 });
  274.             };
  275.  
  276.             var IAB_VIEW_DURATION = 1000;
  277.             var iabTimer = new OnceTimer(function () {
  278.                 self.trigger('view:iab');
  279.                 trigger('view:iab');
  280.             }, IAB_VIEW_DURATION);
  281.  
  282.             var fiftyVisible = false;
  283.  
  284.             this.listenTo(stance({
  285.                 el: this.frame.elem,
  286.             }), {
  287.                 enter: function () {
  288.                     self.trigger('view:enter');
  289.                     trigger('view:enter');
  290.                     self.triggerGeomUpdate();
  291.                 },
  292.                 exit: function () {
  293.                     trigger('view:exit');
  294.                     if (fiftyVisible) {
  295.                         fiftyVisible = false;
  296.                         trigger('view:50out');
  297.                         iabTimer.clear();
  298.                     }
  299.                     self.triggerGeomUpdate();
  300.                 },
  301.                 visible: function (wrapper, pos) {
  302.                     var percent = stanceUtils.visiblePercent(pos, wrapper.offset());
  303.                     var half = 50;
  304.                     if (percent >= half && !fiftyVisible) {
  305.                         fiftyVisible = true;
  306.                         trigger('view:50in');
  307.                         iabTimer.start();
  308.                     } else if (percent < half && fiftyVisible) {
  309.                         fiftyVisible = false;
  310.                         trigger('view:50out');
  311.                         iabTimer.clear();
  312.                     }
  313.                     trigger('view', percent);
  314.                     self.triggerGeomUpdate();
  315.                 },
  316.             });
  317.         },
  318.  
  319.         /**
  320.          * Communicate an event to the app iframe directly, avoiding `bus`.
  321.          *
  322.          * Before sending:
  323.          *  - Stringifies the message in order to support IE8 and IE9.
  324.          *  - Namespaces the message with {space: 'disqus'} in order to
  325.          *    avoid collisions with other third-party code on the host page
  326.          *
  327.          * Normally the host code and the iframe code communicate via an intermediate
  328.          * 'bus' using `Channel.prototype.sendMessage()`
  329.          *
  330.          * However, the ads app needs to send messages directly to third-party code
  331.          * running in its iframe -- e.g., postMessage view events manifest
  332.          *
  333.          * @param  {Object} message Data that will be communicated to iframe
  334.          *                          via postMessage.
  335.          * @returns {void}
  336.          */
  337.         postMessageDirect: function (message) {
  338.  
  339.             this.frame.requiresWindow(function (msg) {
  340.                 var formattedMessage = JSON.stringify(extend({}, msg, { space: 'disqus' }));
  341.                 WindowBase.postMessage(this.window, formattedMessage, this.origin);
  342.                 WindowBase.postMessage(this.window, 'disqus.' + msg.event, this.origin);
  343.             })(message);
  344.         },
  345.  
  346.         /**
  347.          * Generates a Jester reporting event.
  348.          *
  349.          * @param {Object} data - data to be passed to jester
  350.          * @param {string} data.object_id - unique identifier for this object
  351.          * @param {string} data.object_type - classifying group for this object
  352.          * @param {string} data.product - application generating this event i.e. embed, admin, etc.
  353.          * @param {string} data.verb - what the object is doing
  354.          * @param {string} data.zone - area of this application relevant to the event
  355.          *
  356.          * @param {Object} options - options
  357.          * @param {bool} [options.usePOST] - if true, a POST request will be used, which supports more data
  358.          */
  359.         _report: function (data, options = {}) {
  360.             const settings = this.settings;
  361.             const provider = options.provider || this.getProvider();
  362.  
  363.             data.forum_id = settings.forumId || this.forumId;
  364.  
  365.             const method = options.usePOST ? 'reportJesterPOST' : 'reportJester';
  366.             reporting[method](extend({
  367.                 imp: settings.impressionId,
  368.  
  369.                 experiment: settings.experiment.experiment,
  370.                 variant: settings.experiment.variant,
  371.                 service: settings.experiment.service,
  372.  
  373.                 area: settings.placement,
  374.  
  375.                 product: 'embed',
  376.                 forum: settings.forum,
  377.                 zone: 'thread',
  378.                 version: settings.loaderVersion,
  379.                 page_url: settings.referrer || window.document.location.href,
  380.                 page_referrer: settings.hostReferrer || window.document.referrer,
  381.  
  382.                 object_type: 'advertisement',
  383.  
  384.                 provider: provider,
  385.  
  386.                 event: 'activity',
  387.             }, data));
  388.         },
  389.  
  390.         _reportLegacy: function (options) {
  391.             var settings = this.settings;
  392.  
  393.             this._report(extend({
  394.                 // TODO: this needs to default to iab_display for reporting events but we should fix this someday
  395.                 ad_product_name: 'iab_display',
  396.                 ad_product_layout: 'iab_display',
  397.                 // TODO: remove our dependency on sending bin - it's redundant
  398.                 bin: 'embed:promoted_discovery:' +
  399.                     settings.experiment.service + ':' +
  400.                     settings.experiment.experiment + ':' +
  401.                     settings.experiment.variant,
  402.                 object_id: options.advertisement_id ? '[' + options.advertisement_id + ']' : '',
  403.                 section: 'default',
  404.             }, options));
  405.         },
  406.  
  407.         _reportOnce: function (options, id) {
  408.             if (this._reportOnceHistory[id]) {
  409.                 return;
  410.             }
  411.  
  412.             // TODO: point to this._report once we've deprecated the legacy params
  413.             this._reportLegacy(options);
  414.             this._reportOnceHistory[id] = true;
  415.         },
  416.  
  417.         getFrameSettings: function () {
  418.             var frameSettings = WindowedApp.prototype.getFrameSettings.call(this);
  419.  
  420.             frameSettings.insertBeforeEl = this.settings.insertBeforeEl;
  421.             frameSettings.insertAfterEl = this.settings.insertAfterEl;
  422.  
  423.             return frameSettings;
  424.         },
  425.     });
  426.  
  427.  
  428.     var AdsPublic = function (settings) {
  429.         settings = settings || {};
  430.         if (!settings.experiment) {
  431.             // Set an `experiment` object to keep access consistent across use cases.
  432.             // Some places have a dedicated experiment object and others just set
  433.             // keys in the settings object
  434.             settings.experiment = {
  435.                 experiment: settings.experimentName,
  436.                 variant: settings.experimentVariant,
  437.                 service: settings.experimentService,
  438.             };
  439.         }
  440.  
  441.         return new AdsApp(settings);
  442.     };
  443.  
  444.     return {
  445.         Ads: AdsPublic,
  446.     };
  447. });
  448.  
  449. // https://c.disquscdn.com/next/next-core/core/ads/ads.js

Replies to Re: Re: ads.js rss

Title Name Language When
Re: Re: domUtils.js disqus.com javascript 2 Months ago.

Reply to "Re: Re: ads.js"

Here you can reply to the paste above