<commit_before>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false, require: false */

require('../styles/app.page.post.less');

(function (f, define) {
    'use strict';
    define([
        './window.assert',
        './window.logger',
        './app.logger',
        './app.i18n',
        './app.common',
        './app.menu'
    ], f);
})(function () {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var app = window.app;
        var assert = window.assert;
        var logger = new window.Logger('app.post');
        var i18n = app.i18n;
        var CLICK = 'click';
        var POST_WRAPPER_SELECTOR = '#post-wrapper';
        var SOCIAL_SELECTOR = '.social';
        var COMMAND = {
            FACEBOOK: 'facebook',
            GOOGLE: 'google',
            LINKEDIN: 'linkedin',
            PINTEREST: 'pinterest',
            TWITTER: 'twitter',
            EMAIL: 'email'
        };

        /**
         * Initialize social buttons
         * @see http://www.sharelinkgenerator.com/
         * Also check Kidoju.WebApp -> app.summary.js
         */
        function initSocialButtons() {

            /* This function's cyclomatic complexity is too high. */
            /* jshint -W074 */

            $(POST_WRAPPER_SELECTOR).find(SOCIAL_SELECTOR)
                .on(CLICK, function (e) {
                    assert.instanceof($.Event, e, kendo.format(assert.messages.instanceof.default, 'e', 'default'));
                    assert.instanceof(window.HTMLAnchorElement, e.currentTarget, kendo.format(assert.messages.instanceof.default, 'e.currentTarget', 'window.HTMLAnchorElement'));
                    var sharedUrl = window.encodeURIComponent($('meta[property="og:url"]').attr('content'));
                    var source = window.encodeURIComponent($('meta[property="og:site_name"]').attr('content'));
                    var title = window.encodeURIComponent($('meta[property="og:title"]').attr('content'));
                    var description = window.encodeURIComponent($('meta[property="og:description"]').attr('content'));
                    var image = window.encodeURIComponent($('meta[property="og:image"]').attr('content'));
                    var command = $(e.currentTarget).attr(kendo.attr('command'));
                    var openUrl;
                    switch (command) {
                        case COMMAND.FACEBOOK:
                            // Facebook share dialog
                            // @ see https://developers.facebook.com/docs/sharing/web
                            // @ see https://developers.facebook.com/docs/sharing/reference/share-dialog
                            // @ see https://developers.facebook.com/docs/sharing/best-practices
                            // @see https://developers.facebook.com/tools/debug/ <---------------- DEBUG
                            openUrl = 'https://www.facebook.com/dialog/share' +
                                '?display=popup' +
                                '&app_id=' + app.facebook.clientID +
                                '&href=' + sharedUrl +
                                '&redirect_uri=' + sharedUrl;
                            /*
                            openUrl = 'https://www.facebook.com/sharer/sharer.php' +
                                '?u=' + sharedUrl;
                            */
                            break;
                        case COMMAND.GOOGLE:
                            // @see https://developers.google.com/+/web/share/
                            openUrl = 'https://plus.google.com/share' +
                                '?url=' + sharedUrl +
                                '&hl=' + i18n.locale();
                            break;
                        case COMMAND.LINKEDIN:
                            // @see https://developer.linkedin.com/docs/share-on-linkedin
                            // Note Linkedin uses open graph meta tags
                            openUrl = 'https://www.linkedin.com/shareArticle' +
                                '?mini=true' +
                                '&source=' + source +
                                '&summary=' + description +
                                '&title=' + title +
                                '&url=' + sharedUrl;

                            break;
                        case COMMAND.PINTEREST:
                            // @see https://developers.pinterest.com/docs/widgets/pin-it/
                            openUrl = 'https://pinterest.com/pin/create/button/' +
                                '?url=' + sharedUrl +
                                '&media=' + image +
                                '&description=' + description;
                            break;
                        case COMMAND.TWITTER:
                            // Twitter web intent
                            // @ see https://dev.twitter.com/web/tweet-button/web-intent
                            openUrl = 'https://twitter.com/intent/tweet' +
                                '?text=' + title +
                                '&url=' + sharedUrl +
                                '&via=' + app.twitter.account;
                            // TODO: hashtags (message size limit)?
                            break;
                        case COMMAND.EMAIL:
                            // TODO add icon in summary.ejs
                            openUrl = 'mailto:fastlec@memba.org?&subject=Shared Link&body=Hey%20loojk%20at%20that';
                            break;
                    }
                    if (socialWindow === null || socialWindow.closed || socialUrl !== openUrl) {
                        // Most social share dialogs resize themselves from a smaller window (not from a larger one)
                        // We might want to improve the (top, left) position
                        socialWindow = window.open(openUrl, 'social', 'toolbar=0,status=0,menubar=0,height=450,width=600');
                    }
                    socialUrl = openUrl;
                    socialWindow.focus();
                });

            /* jshint +W074 */
        }
        var socialWindow = null;
        var socialUrl;

        $(function () {

            initSocialButtons();

            // Log page readiness
            logger.info({
                message: 'post page initialized in ' + i18n.locale(),
                method: 'document.ready'
            });

        });

    }(window.jQuery));

    return window.app;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<commit_msg>Fixed issue where focus triggers en exception with mobile apps.<commit_after>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false, require: false */

require('../styles/app.page.post.less');

(function (f, define) {
    'use strict';
    define([
        './window.assert',
        './window.logger',
        './app.logger',
        './app.i18n',
        './app.common',
        './app.menu'
    ], f);
})(function () {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var app = window.app;
        var assert = window.assert;
        var logger = new window.Logger('app.post');
        var i18n = app.i18n;
        var CLICK = 'click';
        var POST_WRAPPER_SELECTOR = '#post-wrapper';
        var SOCIAL_SELECTOR = '.social';
        var COMMAND = {
            FACEBOOK: 'facebook',
            GOOGLE: 'google',
            LINKEDIN: 'linkedin',
            PINTEREST: 'pinterest',
            TWITTER: 'twitter',
            EMAIL: 'email'
        };

        /**
         * Initialize social buttons
         * @see http://www.sharelinkgenerator.com/
         * Also check Kidoju.WebApp -> app.summary.js
         */
        function initSocialButtons() {

            /* This function's cyclomatic complexity is too high. */
            /* jshint -W074 */

            $(POST_WRAPPER_SELECTOR).find(SOCIAL_SELECTOR)
                .on(CLICK, function (e) {
                    assert.instanceof($.Event, e, kendo.format(assert.messages.instanceof.default, 'e', 'default'));
                    assert.instanceof(window.HTMLAnchorElement, e.currentTarget, kendo.format(assert.messages.instanceof.default, 'e.currentTarget', 'window.HTMLAnchorElement'));
                    var sharedUrl = window.encodeURIComponent($('meta[property="og:url"]').attr('content'));
                    var source = window.encodeURIComponent($('meta[property="og:site_name"]').attr('content'));
                    var title = window.encodeURIComponent($('meta[property="og:title"]').attr('content'));
                    var description = window.encodeURIComponent($('meta[property="og:description"]').attr('content'));
                    var image = window.encodeURIComponent($('meta[property="og:image"]').attr('content'));
                    var command = $(e.currentTarget).attr(kendo.attr('command'));
                    var openUrl;
                    switch (command) {
                        case COMMAND.FACEBOOK:
                            // Facebook share dialog
                            // @ see https://developers.facebook.com/docs/sharing/web
                            // @ see https://developers.facebook.com/docs/sharing/reference/share-dialog
                            // @ see https://developers.facebook.com/docs/sharing/best-practices
                            // @see https://developers.facebook.com/tools/debug/ <---------------- DEBUG
                            openUrl = 'https://www.facebook.com/dialog/share' +
                                '?display=popup' +
                                '&app_id=' + app.facebook.clientID +
                                '&href=' + sharedUrl +
                                '&redirect_uri=' + sharedUrl;
                            /*
                            openUrl = 'https://www.facebook.com/sharer/sharer.php' +
                                '?u=' + sharedUrl;
                            */
                            break;
                        case COMMAND.GOOGLE:
                            // @see https://developers.google.com/+/web/share/
                            openUrl = 'https://plus.google.com/share' +
                                '?url=' + sharedUrl +
                                '&hl=' + i18n.locale();
                            break;
                        case COMMAND.LINKEDIN:
                            // @see https://developer.linkedin.com/docs/share-on-linkedin
                            // Note Linkedin uses open graph meta tags
                            openUrl = 'https://www.linkedin.com/shareArticle' +
                                '?mini=true' +
                                '&source=' + source +
                                '&summary=' + description +
                                '&title=' + title +
                                '&url=' + sharedUrl;

                            break;
                        case COMMAND.PINTEREST:
                            // @see https://developers.pinterest.com/docs/widgets/pin-it/
                            openUrl = 'https://pinterest.com/pin/create/button/' +
                                '?url=' + sharedUrl +
                                '&media=' + image +
                                '&description=' + description;
                            break;
                        case COMMAND.TWITTER:
                            // Twitter web intent
                            // @ see https://dev.twitter.com/web/tweet-button/web-intent
                            openUrl = 'https://twitter.com/intent/tweet' +
                                '?text=' + title +
                                '&url=' + sharedUrl +
                                '&via=' + app.twitter.account;
                            // TODO: hashtags (message size limit)?
                            break;
                        case COMMAND.EMAIL:
                            // TODO add icon in summary.ejs
                            openUrl = 'mailto:info@memba.org?&subject=Shared Link&body=Hey%20loojk%20at%20that';
                            break;
                    }
                    if (socialWindow === null || socialWindow.closed || socialUrl !== openUrl) {
                        // Most social share dialogs resize themselves from a smaller window (not from a larger one)
                        // We might want to improve the (top, left) position
                        socialWindow = window.open(openUrl, 'social', 'toolbar=0,status=0,menubar=0,height=450,width=600');
                    }
                    socialUrl = openUrl;
                    if (socialWindow && $.isFunction(socialWindow.focus)) {
                        // focus not avilable when this triggers mobile apps
                        socialWindow.focus();
                    }
                });

            /* jshint +W074 */
        }
        var socialWindow = null;
        var socialUrl;

        $(function () {

            initSocialButtons();

            // Log page readiness
            logger.info({
                message: 'post page initialized in ' + i18n.locale(),
                method: 'document.ready'
            });

        });

    }(window.jQuery));

    return window.app;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<|endoftext|>


<commit_before>var express = require('express')
var router = express.Router()
var fs = require('fs')
var async = require('async')
var passport = require('passport')

const schema_file = 'public/schemas/entry.json'

/* GET home page - list entries */
/* Could contain a serach term in s */
router.get('/', function (req, res, next) {
  var db = req.db
  async.parallel({
      entries: function (callback) {
        var conds = {}
        var opts = {
          'sort': {
            'root.radicals': 1,
            'lemma': 1,
          }
        }
        if (req.query.s) {
          conds['lemma'] = {'$regex': req.query.s}
        }
        db.get('entries').find(conds, opts, callback)
      },
      languages: function (callback) {
        db.get('languages').find({}, function (err, data) {
          var assoc = {} // abbrev : obj
          data.forEach(function (item) {
            assoc[item.abbrev] = item
          })
          callback(err, assoc)
        })
      },
      references: function (callback) {
        db.get('references').find({}, function (err, data) {
          var assoc = {} // abbrev : obj
          data.forEach(function (item) {
            assoc[item.abbrev] = item
          })
          callback(err, assoc)
        })
      }
    },

    // All tasks done
    function (err, data) {
      if (err) {
        console.log(err)
      }

      var groups = {}
      for (var abbrev in data.languages) {
        var item = data.languages[abbrev]
        if (!groups.hasOwnProperty(item.class)) {
          groups[item.class] = []
        }
        groups[item.class].push(item.abbrev)
      }

      var title
      if (req.query.s) {
        title = 'Entries matching "' + req.query.s + '"'
      } else {
        title = 'All entries'
      }
      res.render('index', {
        title: title,
        query: req.query,
        data: data.entries,
        groups: groups,
        languages: data.languages,
        references: data.references
      })

    })

})

/* Load stuff we need for add/edit */
var add_edit = function (req, res, next, params) {
  async.parallel({
    schema: function (callback) {
      fs.readFile(schema_file, 'utf8', function (err, data) {
        if (err) data = '{}'
        callback(err, data)
      })
    },
    languages: function (callback) {
      var collection = req.db.get('languages')
      collection.find({}, function (err, data) {
        var names = []
        if (!err) {
          names = data.map(function (item) {
            return item.abbrev
          })
        }
        callback(err, names)
      })
    },
    references: function (callback) {
      var collection = req.db.get('references')
      collection.find({}, function (err, data) {
        var names = []
        if (!err) {
          names = data.map(function (item) {
            return item.abbrev
          })
        }
        callback(err, names)
      })
    }},

    // All tasks done
    function (err, data) {
      if (err) {
        console.log(err)
      }
      res.render('edit', {
        title: params.title,
        schema: data.schema,
        languages: data.languages,
        references: data.references,
        id: params.id
      })
    }
  )
}

var ensureLogin = require('connect-ensure-login')

/* GET add */
router.get('/add',
  ensureLogin.ensureLoggedIn(),
  function (req, res, next) {
    add_edit(req, res, next, {
      'title': 'New entry',
      'id': null
    })
  }
)

/* GET edit */
router.get('/edit/:id',
  ensureLogin.ensureLoggedIn(),
  function (req, res, next) {
    add_edit(req, res, next, {
      'title': 'Edit entry',
      'id': req.params.id
    })
  }
)

/* GET references */
router.get('/references',
  function (req, res, next) {
    var collection = req.db.get('references')
    collection.find({}, {'sort': {'abbrev': 1, 'year': 1}}, function (err, data) {
      if (err) {
        res.status(500).send(err)
      }
      res.render('references', {
        title: 'References',
        data: data
      })
    })
  }
)

// --- Login stuff

/* GET login */
router.get('/login',
  function (req, res, next) {
    res.render('login', {
      title: 'Login',
      messages: req.flash()
    })
  }
)

/* POST login */
router.post('/login',
  passport.authenticate('local', {
    failureRedirect: '/login',
    failureFlash: true
  }),
  function(req, res) {
    res.redirect('/')
  }
)

/* GET logout */
router.get('/logout',
  function (req, res) {
    req.logout()
    res.redirect('/')
  }
)

module.exports = router
<commit_msg>Make login/logout URLs use baseURL<commit_after>var express = require('express')
var router = express.Router()
var fs = require('fs')
var async = require('async')
var passport = require('passport')

const schema_file = 'public/schemas/entry.json'

/* GET home page - list entries */
/* Could contain a serach term in s */
router.get('/', function (req, res, next) {
  var db = req.db
  async.parallel({
      entries: function (callback) {
        var conds = {}
        var opts = {
          'sort': {
            'root.radicals': 1,
            'lemma': 1,
          }
        }
        if (req.query.s) {
          conds['lemma'] = {'$regex': req.query.s}
        }
        db.get('entries').find(conds, opts, callback)
      },
      languages: function (callback) {
        db.get('languages').find({}, function (err, data) {
          var assoc = {} // abbrev : obj
          data.forEach(function (item) {
            assoc[item.abbrev] = item
          })
          callback(err, assoc)
        })
      },
      references: function (callback) {
        db.get('references').find({}, function (err, data) {
          var assoc = {} // abbrev : obj
          data.forEach(function (item) {
            assoc[item.abbrev] = item
          })
          callback(err, assoc)
        })
      }
    },

    // All tasks done
    function (err, data) {
      if (err) {
        console.log(err)
      }

      var groups = {}
      for (var abbrev in data.languages) {
        var item = data.languages[abbrev]
        if (!groups.hasOwnProperty(item.class)) {
          groups[item.class] = []
        }
        groups[item.class].push(item.abbrev)
      }

      var title
      if (req.query.s) {
        title = 'Entries matching "' + req.query.s + '"'
      } else {
        title = 'All entries'
      }
      res.render('index', {
        title: title,
        query: req.query,
        data: data.entries,
        groups: groups,
        languages: data.languages,
        references: data.references
      })

    })

})

/* Load stuff we need for add/edit */
var add_edit = function (req, res, next, params) {
  async.parallel({
    schema: function (callback) {
      fs.readFile(schema_file, 'utf8', function (err, data) {
        if (err) data = '{}'
        callback(err, data)
      })
    },
    languages: function (callback) {
      var collection = req.db.get('languages')
      collection.find({}, function (err, data) {
        var names = []
        if (!err) {
          names = data.map(function (item) {
            return item.abbrev
          })
        }
        callback(err, names)
      })
    },
    references: function (callback) {
      var collection = req.db.get('references')
      collection.find({}, function (err, data) {
        var names = []
        if (!err) {
          names = data.map(function (item) {
            return item.abbrev
          })
        }
        callback(err, names)
      })
    }},

    // All tasks done
    function (err, data) {
      if (err) {
        console.log(err)
      }
      res.render('edit', {
        title: params.title,
        schema: data.schema,
        languages: data.languages,
        references: data.references,
        id: params.id
      })
    }
  )
}

var ensureLogin = require('connect-ensure-login')

/* GET add */
router.get('/add',
  ensureLogin.ensureLoggedIn(),
  function (req, res, next) {
    add_edit(req, res, next, {
      'title': 'New entry',
      'id': null
    })
  }
)

/* GET edit */
router.get('/edit/:id',
  ensureLogin.ensureLoggedIn(),
  function (req, res, next) {
    add_edit(req, res, next, {
      'title': 'Edit entry',
      'id': req.params.id
    })
  }
)

/* GET references */
router.get('/references',
  function (req, res, next) {
    var collection = req.db.get('references')
    collection.find({}, {'sort': {'abbrev': 1, 'year': 1}}, function (err, data) {
      if (err) {
        res.status(500).send(err)
      }
      res.render('references', {
        title: 'References',
        data: data
      })
    })
  }
)

// --- Login stuff
var config = require('../server-config')

/* GET login */
router.get('/login',
  function (req, res, next) {
    res.render('login', {
      title: 'Login',
      messages: req.flash()
    })
  }
)

/* POST login */
router.post('/login',
  passport.authenticate('local', {
    failureRedirect: config.baseURL+'/login',
    failureFlash: true
  }),
  function(req, res) {
    res.redirect(config.baseURL+'/')
  }
)

/* GET logout */
router.get('/logout',
  function (req, res) {
    req.logout()
    res.redirect(config.baseURL+'/')
  }
)

module.exports = router
<|endoftext|>


<commit_before>var ui = {
    alertTemplate: undefined,
    showAlert: function(alertContainerId, success, message) {
        var alertLevel = (success) ? "success" : "danger";
        var prefix = (success) ? "Success!" : "Error!";

        // Compile the template for the alert if it has not already been compiled
        var html = ui.compileAndRenderTemplate("template-alert", {"alert_level": alertLevel, "prefix": prefix, "message": message});

        $("#" + alertContainerId).hide();
        $("#" + alertContainerId).html(html);
        $("#" + alertContainerId).fadeIn();
    },
    compiledTemplates: {},
    compileTemplate: function(templateId) {
        var source = $("#" + templateId).html();
        ui.compiledTemplates[templateId] = Handlebars.compile(source);
    },
    compileAndRenderTemplate: function(templateID, context) {
        // If the template has not yet been compiled, compile it, then render it and return the HTML
        if (ui.compiledTemplates[templateID] == undefined) {
            ui.compileTemplate(templateID);
        }
        var html = ui.compiledTemplates[templateID](context);

        return html;
    }
}
<commit_msg>Any visible alerts are hidden when another alert is shown to prevent confusion of having two alerts on the screen at any one time<commit_after>var ui = {
    alertTemplate: undefined,
    showAlert: function(alertContainerId, success, message) {
        // Hide any alerts that are currently being displayed to prevent confusion
        $(".alert").parent().hide()

        var alertLevel = (success) ? "success" : "danger";
        var prefix = (success) ? "Success!" : "Error!";

        // Compile the template for the alert if it has not already been compiled
        var html = ui.compileAndRenderTemplate("template-alert", {"alert_level": alertLevel, "prefix": prefix, "message": message});

        $("#" + alertContainerId).hide();
        $("#" + alertContainerId).html(html);
        $("#" + alertContainerId).fadeIn();
    },
    compiledTemplates: {},
    compileTemplate: function(templateId) {
        var source = $("#" + templateId).html();
        ui.compiledTemplates[templateId] = Handlebars.compile(source);
    },
    compileAndRenderTemplate: function(templateID, context) {
        // If the template has not yet been compiled, compile it, then render it and return the HTML
        if (ui.compiledTemplates[templateID] == undefined) {
            ui.compileTemplate(templateID);
        }
        var html = ui.compiledTemplates[templateID](context);

        return html;
    }
}
<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2015 The Pycroft Authors. See the AUTHORS file.
 * This file is part of the Pycroft project and licensed under the terms of
 * the Apache License, Version 2.0. See the LICENSE file for details.
 */

import jQuery from 'jquery';

/**
 * The LazyLoadSelect plugin!
 *
 * This Plugin is used with the LazyLoadSelectField from web.form.fields.
 * It fetches new option values if one of the dependencies changes.
 */
!function ($) {

    var LazyLoadSelect = function (element, options) {
        this.element = $(element);
        this.options = $.extend({
            field_ids: [],
            item_attr: "items",
        }, options);
        this.fields = [];
        this.itemAttr = this.options.item_attr;
        this.dataUrl = this.element.data("url");

        var field_ids = [];
        if (undefined !== this.element.data("fieldids"))
            field_ids = field_ids.concat(this.element.data("fieldids").split(","));
        if (undefined !== this.options.field_ids)
            field_ids = field_ids.concat(this.options.field_ids);

        for (var i = 0; i < field_ids.length; i++) {
            this.fields.push($("#" + field_ids[i]));
        }
        this.bind();
    };

    LazyLoadSelect.prototype = {
        constructor: LazyLoadSelect,

        bind: function () {
            for (var i = 0; i < this.fields.length; i++) {
                this.fields[i].on("change", $.proxy(this.reload, this));
            }
        },

        queryData: function () {
            var query_data = {};
            for (var i = 0; i < this.fields.length; i++) {
                var field = this.fields[i];
                query_data[field.attr("id")] = field.val();
            }
            return query_data;
        },

        reload: function (ev, cb) {
            var self = this;
            $.getJSON(this.dataUrl, this.queryData(), function (data) {
                self.replaceOptions.call(self, data);
                if (cb) cb();
            });
        },

        replaceOptions: function (data) {
            var items = data[this.itemAttr];
            this.element.find("option").remove();
            for (var i = 0; i < items.length; i++) {
                if (typeof items[i] === 'object')
                    this.element.append('<option value="' + items[i][0] + '">' + items[i][1] + '</option>');
                else
                    this.element.append('<option value="' + items[i] + '">' + items[i] + '</option>');
            }

            if (!this.oldvalue_loaded) {
                this.oldvalue_loaded = true;
                this.element.val(this.element.attr("value"));
            }

            //this.element.trigger('change');
        },
    };

    $.fn.lazyLoadSelect = function (options) {
        var toPreload = [];

        function loadNext() {
            var next = toPreload.shift();
            if (next) next.reload.call(next, null, loadNext);
        }

        var result = this.each(function () {
            if (undefined === $(this).data('lazyLoadSelect')) {
                var plugin = new LazyLoadSelect(this, options);
                $(this).data('lazyLoadSelect', plugin);
                toPreload.push(plugin);
            }
        });

        loadNext();

        return result;
    };

    $.fn.lazyLoadSelect.defaults = {};
    $.fn.lazyLoadSelect.Constructor = LazyLoadSelect;

    $('[data-role=lazy-load-select]').lazyLoadSelect();
}(jQuery);
<commit_msg>Fix bug in room selection correctly<commit_after>/*!
 * Copyright (c) 2015 The Pycroft Authors. See the AUTHORS file.
 * This file is part of the Pycroft project and licensed under the terms of
 * the Apache License, Version 2.0. See the LICENSE file for details.
 */

import jQuery from 'jquery';

/**
 * The LazyLoadSelect plugin!
 *
 * This Plugin is used with the LazyLoadSelectField from web.form.fields.
 * It fetches new option values if one of the dependencies changes.
 */
!function ($) {

    var LazyLoadSelect = function (element, options) {
        this.element = $(element);
        this.options = $.extend({
            field_ids: [],
            item_attr: "items",
        }, options);
        this.fields = [];
        this.itemAttr = this.options.item_attr;
        this.dataUrl = this.element.data("url");

        var field_ids = [];
        if (undefined !== this.element.data("fieldids"))
            field_ids = field_ids.concat(this.element.data("fieldids").split(","));
        if (undefined !== this.options.field_ids)
            field_ids = field_ids.concat(this.options.field_ids);

        for (var i = 0; i < field_ids.length; i++) {
            this.fields.push($("#" + field_ids[i]));
        }
        this.bind();
    };

    LazyLoadSelect.prototype = {
        constructor: LazyLoadSelect,

        bind: function () {
            for (var i = 0; i < this.fields.length; i++) {
                this.fields[i].on("change", $.proxy(this.reload, this));
            }
        },

        queryData: function () {
            var query_data = {};
            for (var i = 0; i < this.fields.length; i++) {
                var field = this.fields[i];
                query_data[field.attr("id")] = field.val();
            }
            return query_data;
        },

        reload: function (ev, cb) {
            var self = this;
            $.getJSON(this.dataUrl, this.queryData(), function (data) {
                self.replaceOptions.call(self, data, ev);
                if (cb) cb();
            });
        },

        replaceOptions: function (data, ev) {
            var items = data[this.itemAttr];
            this.element.find("option").remove();
            for (var i = 0; i < items.length; i++) {
                if (typeof items[i] === 'object')
                    this.element.append('<option value="' + items[i][0] + '">' + items[i][1] + '</option>');
                else
                    this.element.append('<option value="' + items[i] + '">' + items[i] + '</option>');
            }

            if (!this.oldvalue_loaded) {
                this.oldvalue_loaded = true;
                this.element.val(this.element.attr("value"));
            }

            if(ev !== null && ev.originalEvent){
                this.element.trigger('change');
            }
        },
    };

    $.fn.lazyLoadSelect = function (options) {
        var toPreload = [];

        function loadNext() {
            var next = toPreload.shift();
            if (next) next.reload.call(next, null, loadNext);
        }

        var result = this.each(function () {
            if (undefined === $(this).data('lazyLoadSelect')) {
                var plugin = new LazyLoadSelect(this, options);
                $(this).data('lazyLoadSelect', plugin);
                toPreload.push(plugin);
            }
        });

        loadNext();

        return result;
    };

    $.fn.lazyLoadSelect.defaults = {};
    $.fn.lazyLoadSelect.Constructor = LazyLoadSelect;

    $('[data-role=lazy-load-select]').lazyLoadSelect();
}(jQuery);
<|endoftext|>


<commit_before>/* eslint-env jest */
import { getDefaultTabGlobal } from 'js/utils/test-utils'
import getGoogleTag, {
  __setPubadsRefreshMock,
} from 'js/ads/google/getGoogleTag'
import getAmazonTag from 'js/ads/amazon/getAmazonTag'
import getPrebidPbjs from 'js/ads/prebid/getPrebidPbjs'

jest.mock('js/ads/prebid/prebid')
jest.mock('js/ads/google/getGoogleTag')
jest.mock('js/ads/amazon/getAmazonTag')
jest.mock('js/ads/prebid/getPrebidPbjs')
jest.mock('js/ads/prebid/prebidConfig')
jest.mock('js/ads/amazon/amazonBidder')
jest.mock('js/ads/indexExchange/indexExchangeBidder')
jest.mock('js/utils/client-location')
jest.mock('js/ads/handleAdsLoaded')
jest.mock('js/ads/adsEnabledStatus')
jest.mock('js/ads/google/setUpGoogleAds')
jest.mock('js/utils/feature-flags')

beforeAll(() => {
  jest.useFakeTimers()
})

beforeEach(() => {
  // Enable ads by default.
  const adsEnabledStatus = require('js/ads/adsEnabledStatus').default
  adsEnabledStatus.mockReturnValue(true)

  // Mock apstag
  delete window.apstag
  window.apstag = getAmazonTag()

  // Mock Prebid global
  delete window.pbjs
  window.pbjs = getPrebidPbjs()

  // Mock tabforacause global
  window.tabforacause = getDefaultTabGlobal()

  // Set up googletag
  delete window.googletag
  window.googletag = getGoogleTag()
})

afterEach(() => {
  jest.clearAllMocks()
  jest.resetModules()
})

afterAll(() => {
  delete window.googletag
  delete window.apstag
  delete window.pbjs
  delete window.tabforacause
})

describe('ads script', () => {
  it('sets up the Google ad slots', async () => {
    expect.assertions(1)
    const setUpGoogleAds = require('js/ads/google/setUpGoogleAds').default
    require('js/ads/ads')
    expect(setUpGoogleAds).toHaveBeenCalledTimes(1)
  })

  it('calls the expected bidders and ad server', async () => {
    expect.assertions(4)

    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')

    // Flush all promises
    await new Promise(resolve => setImmediate(resolve))

    expect(amazonBidder).toHaveBeenCalledTimes(1)
    expect(prebidConfig).toHaveBeenCalledTimes(1)
    expect(indexExchangeBidder).toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('does not call expected bidders or ad server when ads are not enabled', async () => {
    expect.assertions(4)
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default

    // Disable ads.
    const adsEnabledStatus = require('js/ads/adsEnabledStatus').default
    adsEnabledStatus.mockReturnValue(false)

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')

    // Flush all promises
    await new Promise(resolve => setImmediate(resolve))

    expect(amazonBidder).not.toHaveBeenCalled()
    expect(prebidConfig).not.toHaveBeenCalled()
    expect(indexExchangeBidder).not.toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).not.toHaveBeenCalled()
  })

  it('sets ad server targeting before calling the ad server', async () => {
    expect.assertions(3)
    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(window.pbjs.setTargetingForGPTAsync).toHaveBeenCalledTimes(1)
    expect(window.pbjs.setTargetingForGPTAsync).toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server even when all bidders time out', async () => {
    expect.assertions(2)

    // Mock that Prebid is very slow to respond
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Amazon is very slow to respond
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Index Exchange is very slow to respond
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).not.toHaveBeenCalled()

    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server when one bidder times out', async () => {
    expect.assertions(2)

    // Mock that Prebid is very slow to respond
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).not.toHaveBeenCalled()
    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server immediately when all bidders respond before the timeout', async () => {
    expect.assertions(1)

    // Mock that Prebid responds quickly
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    jest.advanceTimersByTime(41)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('only calls the ad server once when all bidders respond before the timeout', async () => {
    expect.assertions(2)

    // Mock that Prebid responds quickly
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    jest.advanceTimersByTime(41)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)

    jest.advanceTimersByTime(20e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls to store Amazon bids on the window for analytics (if Amazon is included in the auction)', async () => {
    expect.assertions(1)
    const storeAmazonBids = require('js/ads/amazon/amazonBidder')
      .storeAmazonBids

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    require('js/ads/ads')
    jest.advanceTimersByTime(100)
    await new Promise(resolve => setImmediate(resolve))
    expect(storeAmazonBids).toHaveBeenCalledTimes(1)
  })

  it('does not call to store Amazon bids on the window for analytics (if Amazon is not included in the auction)', async () => {
    expect.assertions(1)
    const storeAmazonBids = require('js/ads/amazon/amazonBidder')
      .storeAmazonBids

    // Mock that Amazon responds slowly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    require('js/ads/ads')
    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))
    expect(storeAmazonBids).not.toHaveBeenCalled()
  })

  it('calls handleAdsLoaded', async () => {
    expect.assertions(1)
    const handleAdsLoaded = require('js/ads/handleAdsLoaded').default
    require('js/ads/ads')
    expect(handleAdsLoaded).toHaveBeenCalledTimes(1)
  })
})
<commit_msg>Remove unused tab global<commit_after>/* eslint-env jest */
import { getDefaultTabGlobal } from 'js/utils/test-utils'
import getGoogleTag, {
  __setPubadsRefreshMock,
} from 'js/ads/google/getGoogleTag'
import getAmazonTag from 'js/ads/amazon/getAmazonTag'
import getPrebidPbjs from 'js/ads/prebid/getPrebidPbjs'

jest.mock('js/ads/prebid/prebid')
jest.mock('js/ads/google/getGoogleTag')
jest.mock('js/ads/amazon/getAmazonTag')
jest.mock('js/ads/prebid/getPrebidPbjs')
jest.mock('js/ads/prebid/prebidConfig')
jest.mock('js/ads/amazon/amazonBidder')
jest.mock('js/ads/indexExchange/indexExchangeBidder')
jest.mock('js/utils/client-location')
jest.mock('js/ads/handleAdsLoaded')
jest.mock('js/ads/adsEnabledStatus')
jest.mock('js/ads/google/setUpGoogleAds')
jest.mock('js/utils/feature-flags')

beforeAll(() => {
  jest.useFakeTimers()
})

beforeEach(() => {
  // Enable ads by default.
  const adsEnabledStatus = require('js/ads/adsEnabledStatus').default
  adsEnabledStatus.mockReturnValue(true)

  // Mock apstag
  delete window.apstag
  window.apstag = getAmazonTag()

  // Mock Prebid global
  delete window.pbjs
  window.pbjs = getPrebidPbjs()

  // Set up googletag
  delete window.googletag
  window.googletag = getGoogleTag()
})

afterEach(() => {
  jest.clearAllMocks()
  jest.resetModules()
})

afterAll(() => {
  delete window.googletag
  delete window.apstag
  delete window.pbjs
})

describe('ads script', () => {
  it('sets up the Google ad slots', async () => {
    expect.assertions(1)
    const setUpGoogleAds = require('js/ads/google/setUpGoogleAds').default
    require('js/ads/ads')
    expect(setUpGoogleAds).toHaveBeenCalledTimes(1)
  })

  it('calls the expected bidders and ad server', async () => {
    expect.assertions(4)

    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')

    // Flush all promises
    await new Promise(resolve => setImmediate(resolve))

    expect(amazonBidder).toHaveBeenCalledTimes(1)
    expect(prebidConfig).toHaveBeenCalledTimes(1)
    expect(indexExchangeBidder).toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('does not call expected bidders or ad server when ads are not enabled', async () => {
    expect.assertions(4)
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default

    // Disable ads.
    const adsEnabledStatus = require('js/ads/adsEnabledStatus').default
    adsEnabledStatus.mockReturnValue(false)

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')

    // Flush all promises
    await new Promise(resolve => setImmediate(resolve))

    expect(amazonBidder).not.toHaveBeenCalled()
    expect(prebidConfig).not.toHaveBeenCalled()
    expect(indexExchangeBidder).not.toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).not.toHaveBeenCalled()
  })

  it('sets ad server targeting before calling the ad server', async () => {
    expect.assertions(3)
    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(window.pbjs.setTargetingForGPTAsync).toHaveBeenCalledTimes(1)
    expect(window.pbjs.setTargetingForGPTAsync).toHaveBeenCalledTimes(1)
    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server even when all bidders time out', async () => {
    expect.assertions(2)

    // Mock that Prebid is very slow to respond
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Amazon is very slow to respond
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Index Exchange is very slow to respond
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).not.toHaveBeenCalled()

    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server when one bidder times out', async () => {
    expect.assertions(2)

    // Mock that Prebid is very slow to respond
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).not.toHaveBeenCalled()
    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls the ad server immediately when all bidders respond before the timeout', async () => {
    expect.assertions(1)

    // Mock that Prebid responds quickly
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    jest.advanceTimersByTime(41)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('only calls the ad server once when all bidders respond before the timeout', async () => {
    expect.assertions(2)

    // Mock that Prebid responds quickly
    const prebidConfig = require('js/ads/prebid/prebidConfig').default
    prebidConfig.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    // Mock that Index Exchange responds quickly
    const indexExchangeBidder = require('js/ads/indexExchange/indexExchangeBidder')
      .default
    indexExchangeBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 40)
      })
    })

    const googletagMockRefresh = jest.fn()
    __setPubadsRefreshMock(googletagMockRefresh)

    require('js/ads/ads')
    jest.advanceTimersByTime(41)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)

    jest.advanceTimersByTime(20e3)
    await new Promise(resolve => setImmediate(resolve))

    expect(googletagMockRefresh).toHaveBeenCalledTimes(1)
  })

  it('calls to store Amazon bids on the window for analytics (if Amazon is included in the auction)', async () => {
    expect.assertions(1)
    const storeAmazonBids = require('js/ads/amazon/amazonBidder')
      .storeAmazonBids

    // Mock that Amazon responds quickly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 80)
      })
    })

    require('js/ads/ads')
    jest.advanceTimersByTime(100)
    await new Promise(resolve => setImmediate(resolve))
    expect(storeAmazonBids).toHaveBeenCalledTimes(1)
  })

  it('does not call to store Amazon bids on the window for analytics (if Amazon is not included in the auction)', async () => {
    expect.assertions(1)
    const storeAmazonBids = require('js/ads/amazon/amazonBidder')
      .storeAmazonBids

    // Mock that Amazon responds slowly
    const amazonBidder = require('js/ads/amazon/amazonBidder').default
    amazonBidder.mockImplementationOnce(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, 15e3)
      })
    })

    require('js/ads/ads')
    jest.advanceTimersByTime(3e3)
    await new Promise(resolve => setImmediate(resolve))
    expect(storeAmazonBids).not.toHaveBeenCalled()
  })

  it('calls handleAdsLoaded', async () => {
    expect.assertions(1)
    const handleAdsLoaded = require('js/ads/handleAdsLoaded').default
    require('js/ads/ads')
    expect(handleAdsLoaded).toHaveBeenCalledTimes(1)
  })
})
<|endoftext|>


<commit_before>var text = []; //"content of text here";
var delay = 50;
var currentWord = 0;
var currentChar = 1;
var destination = "[set in call to type]";
var dest = null;

console.log("testing - 2");

function type() {
    if (document.getElementById) {
        dest = document.getElementById(destination);
        if (dest) {
            dest.innerHTML = text[currentWord].substr(0, currentChar);
            ++currentChar;
            if (currentChar > text[currentWord].length) {

                setTimeout("unType()", 2500);

                currentChar = 1;
                if (++currentWord === text.length) {
                    currentWord = 0;
                }

            }
            else
                setTimeout("type()", delay);
        }
    }
}

function unType() {
    console.log("unType()");
    dest.innerHTML = text[currentWord].substr(0, currentChar - 2);

    if (currentChar === 1)
        type();
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    currentChar = 1;
    destination = destinationParam;
    type();
}

startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages");<commit_msg>changed type order<commit_after>var text = []; //"content of text here";
var delay = 50;
var currentWord = 0;
var currentChar = 1;
var destination = "[set in call to type]";
var dest = null;

console.log("testing - 3");

function type() {
    if (document.getElementById) {
        dest = document.getElementById(destination);
        if (dest) {
            dest.innerHTML = text[currentWord].substr(0, currentChar);
            ++currentChar;
            if (currentChar > text[currentWord].length) {

                unType();

                currentChar = 1;
                if (++currentWord === text.length) {
                    currentWord = 0;
                }

            }
            else
                setTimeout("type()", delay);
        }
    }
}

function unType() {
    console.log("unType()");
    dest.innerHTML = text[currentWord].substr(0, currentChar - 2);

    if (currentChar === 1)
        type();//setTimeout("type()", 2500);
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    currentChar = 1;
    destination = destinationParam;
    type();
}

startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages");<|endoftext|>


<commit_before>var Promise = require('es6-promise').Promise;
var deferred =  require('../src/lib/deferred');
var path = require('path');
var spawn = require('child_process').spawn;
var fs = require('fs');

/**
 * Provides two tasks for setup and tear down of integration tests. For instance
 * processes like wspr can be spawned & then killed in setup and teardown
 * @param {object} grunt the Grunt module
 */
module.exports = function(grunt) {
  // List of processes we have spawned so we can kill them on teardown
  var runningChildProcesses = [];
  var cleaningUp;
  var addListeners = function(runningProcess, resolve, reject) {
    var stderr = '';
    if (resolve) {
      runningProcess.stderr.once('data', function() {
        resolve();
      });
    }
    runningProcess.stderr.on('data', function(d) {
      stderr += d;
      grunt.log.debug(d);
    });
    runningProcess.on('exit', function (code) {
      if (!cleaningUp) {
        reject(runningProcess.title +
          ' crashed before tests finish with code: ' + code +
          ' here is the stderr:\n' + stderr);
      }
    });
  };

  // Constants
  // Binary location of wspr and other processes to run
  var VEYRON_ROOT = process.env.VEYRON_ROOT;

  if (! VEYRON_ROOT) {
    grunt.fail.fatal('Please export $VEYRON_ROOT to proceed');
  }

  var VEYRON_BIN_DIR = path.join(VEYRON_ROOT, 'veyron/go/bin');

  var VEYRON_PROXY_BIN = path.join(VEYRON_BIN_DIR, 'proxyd');
  var MOUNTTABLE_BIN = path.join(VEYRON_BIN_DIR, 'mounttabled')
  var WSPR_BIN = path.join(VEYRON_BIN_DIR, 'wsprd')
  var IDENTITYD_BIN = path.join(VEYRON_BIN_DIR, 'identityd')
  var STORED_BIN = path.join(VEYRON_BIN_DIR, 'stored')
  var SAMPLE_GO_SERVICE_BIN = path.join(VEYRON_BIN_DIR, 'sampled')

  var BINARIES = [VEYRON_PROXY_BIN, MOUNTTABLE_BIN, WSPR_BIN, IDENTITYD_BIN,
   SAMPLE_GO_SERVICE_BIN, STORED_BIN];

  var WSPR_PORT = 3224; // The port for WSPR.
  var IDENTITYD_PORT = 8125; // The port for the identityd server.

  var LOGS_DIR = path.resolve('logs');
  // TODO(bprosnitz) Currently we generate a *.ERROR sym link when there is an
  // error. However this is not removed when the most recent logged version has
  // no errors so it points to stale data.

  /**
   * Starts a process that depends on the mounttable root and returns
   * a handle the process.
   * @param {string} mounttableRoot the veyron endpoint of the mounttable.
   * @param {string} bin the path to the binary.
   * @param {array} extraArgs an array of args that are binary specific. The
   * logging flags will already be set.
   * @return {Process} the process handle for the command.
   */
  var startProcessWithMounttableRoot = function(mounttableRoot, bin, name,
   extraArgs) {
    var envWithMount = {
      VEYRON_IDENTITY: process.env.IDENTITY_FILE,
      NAMESPACE_ROOT: mounttableRoot,
    };
    var args = ['-v=3', '-vv=3', '-log_dir=' + LOGS_DIR];
    args = args.concat(extraArgs);
    // Run process
    var runningProcess = spawn(bin, args, { env: envWithMount});
    runningProcess.title = name;
    runningChildProcesses.push(runningProcess);
    return runningProcess;
  };

  /**
   * Starts a process that depends on the mounttable root and returns
   * a promise that will be resolved when the process has started.
   * @param {string} mounttableRoot the veyron endpoint of the mounttable.
   * @param {string} bin the path to the binary.
   * @param {array} extraArgs an array of args that are binary specific. The
   * logging flags will already be set.
   * @return {Promise} a promise that will be resolved when the process has
   * been started.
   */
  var startProcessWithMounttableAndAddHandlers = function(mounttableRoot, bin,
   name, extraArgs) {
    var process = startProcessWithMounttableRoot(mounttableRoot, bin, name,
     extraArgs);
    var def = new deferred();
    addListeners(process, def.resolve, def.reject);
    return def.promise;
  };

  // Starts WSPR taking in the mounttable root and returns a promise that
  // will be resolved when WSPR is ready to accept requests.
  var startWSPR = function(mounttable) {
    grunt.testConfigs['WSPR_SERVER_URL'] = 'http://localhost:' +
        WSPR_PORT;
    return startProcessWithMounttableAndAddHandlers(
      mounttable, WSPR_BIN,
      'WSPR', ['-port=' + WSPR_PORT, '-vproxy=test/proxy']);
  };

  // Starts the Veyron Proxy taking in the mounttable root and returns
  // a promise that will be resolved when the proxy. is ready to accept requests.
  var startProxy = function(mounttable) {
    return startProcessWithMounttableAndAddHandlers(
      mounttable, VEYRON_PROXY_BIN, 'Veyron Proxy',
      ['-address=127.0.0.1:0', '-name=test/proxy']);
  };

  var startStored = function(mounttable) {
    var storePath = 'dist/test/store_integration';
    grunt.file.delete(storePath);
    var process = startProcessWithMounttableRoot(
      mounttable, STORED_BIN, 'stored', ['--address=127.0.0.1:0',
      '--db=' + storePath]);
    var def = new deferred();
    addListeners(process, null, def.reject);
    // Wait until we get the stored service endpoint from the process stdout
    // TODO(bprosnitz) Talk to storage people about STDOUT/STDERR output.
    process.stderr.on('data', function(data) {
      var mountMatch = /Mounting store on (.*?), endpoint/g.exec(
        data.toString());
      if (mountMatch) {
        var endpoint = mountMatch[1];
        grunt.testConfigs['STORED_ENDPOINT'] = endpoint;
        def.resolve();
      }
      // TODO(bprosnitz) Add timeout and error if not found.
    });
    return def.promise;
  };

  // Starts sampled taking in the mounttable root and returns a ppromise
  // that will resolved when sampled is up and running.
  var startSampled = function(mounttable) {
    var process =  startProcessWithMounttableRoot(
      mounttable, SAMPLE_GO_SERVICE_BIN, 'Sampled', []);
    var def = new deferred();
    addListeners(process, null, def.reject);
    // Wait until we get the sample service endpoint from the process stdout
    process.stdout.on('data', function(data) {
      var endpoint = data.toString().replace('Listening at: ', '').trim();
      if (!endpoint.match(/^@.*@$/)) {
        var errorMessage = SAMPLE_GO_SERVICE_BIN + ' did not print the ' +
          'endpoint address on stdout. Expected stdout: ' +
          'Listening at: <VeyronEndPointAddress> but got ' +
          data;

        fail(errorMessage);
      }

      // Success, set the config vars that tests rely on and return
      grunt.testConfigs['SAMPLE_VEYRON_GO_SERVICE_ENDPOINT'] = endpoint;
      def.resolve();
    });
    return def.promise;
  };

  var startMounttable = function() {
    var mounttableDef = new deferred();
    var mounttablePromise = mounttableDef.promise;

    var mounttable_process = spawn(MOUNTTABLE_BIN,
      ['-log_dir=' + LOGS_DIR, '-address=127.0.0.1:0'], {
        env: {
          VEYRON_IDENTITY: process.env.IDENTITY_FILE
        }
      });
    mounttable_process.title = 'MountTable';
    var endpointRe = /@.*@@\S*/;
    var mounttableEndpoint = '';
    mounttable_process.stderr.on('data', function(data) {
      var string = data.toString();
      if (mounttableEndpoint !== '') {
        return;
      }
      var match = string.match(endpointRe);
      if (!match) {
	console.log('Did not find a match');
        return
      }
      mounttableEndpoint = match[0];
      mounttableDef.resolve('/' + mounttableEndpoint);
    });

    runningChildProcesses.push(mounttable_process);
    addListeners(mounttable_process, null, mounttableDef.reject);
    return mounttablePromise;
  };

  var startIdentityd = function() {
    var identityd_process = spawn(IDENTITYD_BIN, ['-httpaddr=localhost:' + IDENTITYD_PORT], {
      env: {
          VEYRON_IDENTITY: process.env.IDENTITY_FILE
        }
    });
    identityd_process.title = 'Identity Server';
    runningChildProcesses.push(identityd_process);
    var identityDef = new deferred();
    addListeners(identityd_process, identityDef.resolve, identityDef.reject);
    grunt.testConfigs['IDENTITY_SERVER_URL'] = 'http://localhost:' +
        IDENTITYD_PORT + '/random/';
    return identityDef.promise;
  };
  /**
   * Setups the required environment for integration testing such as
   * running wspr and sample Veyron services written in Go that are
   * expected in the integration tests.
   */
  grunt.registerTask('subtask_setupIntegrationTestEnvironment', function() {
    // Indicate this is a async grunt task
    var done = this.async();

    // Reset state
    runningChildProcesses = [];
    cleaningUp = false;

    // Ensure binaries exist
    BINARIES.forEach(function(bin) {
      if (!fs.existsSync(bin)) {
        var errorMessage = 'Veyron binaries not found. Ensure "veyron" and ' +
        '"veyron2" are built and installed in ' + VEYRON_BIN_DIR + ' by ' +
        'running go-amd64 install\n The following binaries are needed:\n' +
        BINARIES.join('\n');
        fail(errorMessage);
      }
    });

    var basicEnv = {
      VEYRON_IDENTITY: process.env.IDENTITY_FILE
    };

    var servicePromises = [];
    var mounttablePromise = startMounttable();
    servicePromises.push(mounttablePromise);

    servicePromises.push(startIdentityd());

    servicePromises.push(mounttablePromise.then(startWSPR));

    servicePromises.push(mounttablePromise.then(startProxy));

    servicePromises.push(mounttablePromise.then(startSampled));

    servicePromises.push(mounttablePromise.then(startStored));

    Promise.all(servicePromises).then(function() {
      if (BINARIES.length != runningChildProcesses.length) {
        fail('Not all binaries were started');
        done(false);
      } else {
        done(true);
      }
    }).catch(function(err) {
      fail(err);
      done(false);
    });
  });

  // Kills any running process we started and calls done when all finish
  var cleanUp = function(done) {
    cleaningUp = true;
    var numExited = 0;
    for(var i = 0; i < runningChildProcesses.length; i++) {
      runningChildProcesses[i].kill('SIGTERM');
      // wait until all exit
      runningChildProcesses[i].on('exit', function (code) {
        numExited++;
        if (done !== undefined && numExited == runningChildProcesses.length) {
          done(true);
        }
      });
    }
  };

  // Fails the task after cleaning up
  var fail = function(message) {
    cleanUp();
    grunt.fail.fatal(message);
  };

  // Cleanup in case Grunt fails or is forced to exit
  process.on('exit', function() {
    cleanUp();
  });

  /**
   * Tears down anything setup in subtask_setupIntegrationTestEnvironment
   * such as killing wspr and other services spawned for testing
   */
  grunt.registerTask('subtask_teardownIntegrationTestEnvironment', function() {
    // Indicate this is a async grunt task
    var done = this.async();
    cleanUp(done);
  });
};
<commit_msg>WSPR needs an "identd" argument.  This fixes the tests.<commit_after>var Promise = require('es6-promise').Promise;
var deferred =  require('../src/lib/deferred');
var path = require('path');
var spawn = require('child_process').spawn;
var fs = require('fs');

/**
 * Provides two tasks for setup and tear down of integration tests. For instance
 * processes like wspr can be spawned & then killed in setup and teardown
 * @param {object} grunt the Grunt module
 */
module.exports = function(grunt) {
  // List of processes we have spawned so we can kill them on teardown
  var runningChildProcesses = [];
  var cleaningUp;
  var addListeners = function(runningProcess, resolve, reject) {
    var stderr = '';
    if (resolve) {
      runningProcess.stderr.once('data', function() {
        resolve();
      });
    }
    runningProcess.stderr.on('data', function(d) {
      stderr += d;
      grunt.log.debug(d);
    });
    runningProcess.on('exit', function (code) {
      if (!cleaningUp) {
        reject(runningProcess.title +
          ' crashed before tests finish with code: ' + code +
          ' here is the stderr:\n' + stderr);
      }
    });
  };

  // Constants
  // Binary location of wspr and other processes to run
  var VEYRON_ROOT = process.env.VEYRON_ROOT;

  if (! VEYRON_ROOT) {
    grunt.fail.fatal('Please export $VEYRON_ROOT to proceed');
  }

  var VEYRON_BIN_DIR = path.join(VEYRON_ROOT, 'veyron/go/bin');

  var VEYRON_PROXY_BIN = path.join(VEYRON_BIN_DIR, 'proxyd');
  var MOUNTTABLE_BIN = path.join(VEYRON_BIN_DIR, 'mounttabled')
  var WSPR_BIN = path.join(VEYRON_BIN_DIR, 'wsprd')
  var IDENTITYD_BIN = path.join(VEYRON_BIN_DIR, 'identityd')
  var STORED_BIN = path.join(VEYRON_BIN_DIR, 'stored')
  var SAMPLE_GO_SERVICE_BIN = path.join(VEYRON_BIN_DIR, 'sampled')

  var BINARIES = [VEYRON_PROXY_BIN, MOUNTTABLE_BIN, WSPR_BIN, IDENTITYD_BIN,
   SAMPLE_GO_SERVICE_BIN, STORED_BIN];

  var WSPR_PORT = 3224; // The port for WSPR.
  var IDENTITYD_PORT = 8125; // The port for the identityd server.

  var LOGS_DIR = path.resolve('logs');
  // TODO(bprosnitz) Currently we generate a *.ERROR sym link when there is an
  // error. However this is not removed when the most recent logged version has
  // no errors so it points to stale data.

  /**
   * Starts a process that depends on the mounttable root and returns
   * a handle the process.
   * @param {string} mounttableRoot the veyron endpoint of the mounttable.
   * @param {string} bin the path to the binary.
   * @param {array} extraArgs an array of args that are binary specific. The
   * logging flags will already be set.
   * @return {Process} the process handle for the command.
   */
  var startProcessWithMounttableRoot = function(mounttableRoot, bin, name,
   extraArgs) {
    var envWithMount = {
      VEYRON_IDENTITY: process.env.IDENTITY_FILE,
      NAMESPACE_ROOT: mounttableRoot,
    };
    var args = ['-v=3', '-vv=3', '-log_dir=' + LOGS_DIR];
    args = args.concat(extraArgs);
    // Run process
    var runningProcess = spawn(bin, args, { env: envWithMount});
    runningProcess.title = name;
    runningChildProcesses.push(runningProcess);
    return runningProcess;
  };

  /**
   * Starts a process that depends on the mounttable root and returns
   * a promise that will be resolved when the process has started.
   * @param {string} mounttableRoot the veyron endpoint of the mounttable.
   * @param {string} bin the path to the binary.
   * @param {array} extraArgs an array of args that are binary specific. The
   * logging flags will already be set.
   * @return {Promise} a promise that will be resolved when the process has
   * been started.
   */
  var startProcessWithMounttableAndAddHandlers = function(mounttableRoot, bin,
   name, extraArgs) {
    var process = startProcessWithMounttableRoot(mounttableRoot, bin, name,
     extraArgs);
    var def = new deferred();
    addListeners(process, def.resolve, def.reject);
    return def.promise;
  };

  // Starts WSPR taking in the mounttable root and returns a promise that
  // will be resolved when WSPR is ready to accept requests.
  var startWSPR = function(mounttable) {
    grunt.testConfigs['WSPR_SERVER_URL'] = 'http://localhost:' +
        WSPR_PORT;
    return startProcessWithMounttableAndAddHandlers(
      mounttable, WSPR_BIN,
      'WSPR', ['-port=' + WSPR_PORT, '-vproxy=test/proxy', '-identd=test/identd']);
  };

  // Starts the Veyron Proxy taking in the mounttable root and returns
  // a promise that will be resolved when the proxy. is ready to accept requests.
  var startProxy = function(mounttable) {
    return startProcessWithMounttableAndAddHandlers(
      mounttable, VEYRON_PROXY_BIN, 'Veyron Proxy',
      ['-address=127.0.0.1:0', '-name=test/proxy']);
  };

  var startStored = function(mounttable) {
    var storePath = 'dist/test/store_integration';
    grunt.file.delete(storePath);
    var process = startProcessWithMounttableRoot(
      mounttable, STORED_BIN, 'stored', ['--address=127.0.0.1:0',
      '--db=' + storePath]);
    var def = new deferred();
    addListeners(process, null, def.reject);
    // Wait until we get the stored service endpoint from the process stdout
    // TODO(bprosnitz) Talk to storage people about STDOUT/STDERR output.
    process.stderr.on('data', function(data) {
      var mountMatch = /Mounting store on (.*?), endpoint/g.exec(
        data.toString());
      if (mountMatch) {
        var endpoint = mountMatch[1];
        grunt.testConfigs['STORED_ENDPOINT'] = endpoint;
        def.resolve();
      }
      // TODO(bprosnitz) Add timeout and error if not found.
    });
    return def.promise;
  };

  // Starts sampled taking in the mounttable root and returns a ppromise
  // that will resolved when sampled is up and running.
  var startSampled = function(mounttable) {
    var process =  startProcessWithMounttableRoot(
      mounttable, SAMPLE_GO_SERVICE_BIN, 'Sampled', []);
    var def = new deferred();
    addListeners(process, null, def.reject);
    // Wait until we get the sample service endpoint from the process stdout
    process.stdout.on('data', function(data) {
      var endpoint = data.toString().replace('Listening at: ', '').trim();
      if (!endpoint.match(/^@.*@$/)) {
        var errorMessage = SAMPLE_GO_SERVICE_BIN + ' did not print the ' +
          'endpoint address on stdout. Expected stdout: ' +
          'Listening at: <VeyronEndPointAddress> but got ' +
          data;

        fail(errorMessage);
      }

      // Success, set the config vars that tests rely on and return
      grunt.testConfigs['SAMPLE_VEYRON_GO_SERVICE_ENDPOINT'] = endpoint;
      def.resolve();
    });
    return def.promise;
  };

  var startMounttable = function() {
    var mounttableDef = new deferred();
    var mounttablePromise = mounttableDef.promise;

    var mounttable_process = spawn(MOUNTTABLE_BIN,
      ['-log_dir=' + LOGS_DIR, '-address=127.0.0.1:0'], {
        env: {
          VEYRON_IDENTITY: process.env.IDENTITY_FILE
        }
      });
    mounttable_process.title = 'MountTable';
    var endpointRe = /@.*@@\S*/;
    var mounttableEndpoint = '';
    mounttable_process.stderr.on('data', function(data) {
      var string = data.toString();
      if (mounttableEndpoint !== '') {
        return;
      }
      var match = string.match(endpointRe);
      if (!match) {
	console.log('Did not find a match');
        return
      }
      mounttableEndpoint = match[0];
      mounttableDef.resolve('/' + mounttableEndpoint);
    });

    runningChildProcesses.push(mounttable_process);
    addListeners(mounttable_process, null, mounttableDef.reject);
    return mounttablePromise;
  };

  var startIdentityd = function() {
    var identityd_process = spawn(IDENTITYD_BIN, ['-httpaddr=localhost:' + IDENTITYD_PORT], {
      env: {
          VEYRON_IDENTITY: process.env.IDENTITY_FILE
        }
    });
    identityd_process.title = 'Identity Server';
    runningChildProcesses.push(identityd_process);
    var identityDef = new deferred();
    addListeners(identityd_process, identityDef.resolve, identityDef.reject);
    grunt.testConfigs['IDENTITY_SERVER_URL'] = 'http://localhost:' +
        IDENTITYD_PORT + '/random/';
    return identityDef.promise;
  };
  /**
   * Setups the required environment for integration testing such as
   * running wspr and sample Veyron services written in Go that are
   * expected in the integration tests.
   */
  grunt.registerTask('subtask_setupIntegrationTestEnvironment', function() {
    // Indicate this is a async grunt task
    var done = this.async();

    // Reset state
    runningChildProcesses = [];
    cleaningUp = false;

    // Ensure binaries exist
    BINARIES.forEach(function(bin) {
      if (!fs.existsSync(bin)) {
        var errorMessage = 'Veyron binaries not found. Ensure "veyron" and ' +
        '"veyron2" are built and installed in ' + VEYRON_BIN_DIR + ' by ' +
        'running go-amd64 install\n The following binaries are needed:\n' +
        BINARIES.join('\n');
        fail(errorMessage);
      }
    });

    var basicEnv = {
      VEYRON_IDENTITY: process.env.IDENTITY_FILE
    };

    var servicePromises = [];
    var mounttablePromise = startMounttable();
    servicePromises.push(mounttablePromise);

    servicePromises.push(startIdentityd());

    servicePromises.push(mounttablePromise.then(startWSPR));

    servicePromises.push(mounttablePromise.then(startProxy));

    servicePromises.push(mounttablePromise.then(startSampled));

    servicePromises.push(mounttablePromise.then(startStored));

    Promise.all(servicePromises).then(function() {
      if (BINARIES.length != runningChildProcesses.length) {
        fail('Not all binaries were started');
        done(false);
      } else {
        done(true);
      }
    }).catch(function(err) {
      fail(err);
      done(false);
    });
  });

  // Kills any running process we started and calls done when all finish
  var cleanUp = function(done) {
    cleaningUp = true;
    var numExited = 0;
    for(var i = 0; i < runningChildProcesses.length; i++) {
      runningChildProcesses[i].kill('SIGTERM');
      // wait until all exit
      runningChildProcesses[i].on('exit', function (code) {
        numExited++;
        if (done !== undefined && numExited == runningChildProcesses.length) {
          done(true);
        }
      });
    }
  };

  // Fails the task after cleaning up
  var fail = function(message) {
    cleanUp();
    grunt.fail.fatal(message);
  };

  // Cleanup in case Grunt fails or is forced to exit
  process.on('exit', function() {
    cleanUp();
  });

  /**
   * Tears down anything setup in subtask_setupIntegrationTestEnvironment
   * such as killing wspr and other services spawned for testing
   */
  grunt.registerTask('subtask_teardownIntegrationTestEnvironment', function() {
    // Indicate this is a async grunt task
    var done = this.async();
    cleanUp(done);
  });
};
<|endoftext|>


<commit_before>var text = []; //"content of text here";
var delay = 50;
var currentWord = 0;
var currentChar = 1;
var destination = "[set in call to type]";
var dest = null;

console.log("testing - 7");

function type() {
    if (document.getElementById) {
        dest = document.getElementById(destination);
        if (dest) {
            dest.innerHTML = text[currentWord].substr(0, currentChar);
            ++currentChar;
            if (currentChar > text[currentWord].length) {

                unType();

            }
            else
                setTimeout("type()", delay);
        }
    }
}

function unType() {
    console.log("unType()");

    /*if (currentChar === 1) {
        type();//setTimeout("type()", 2500);
        return;
    }*/

    setTimeout(
        function () {
            console.log("lambda");
            dest.innerHTML = text[currentWord].substr(0, currentChar-3);

            /* currentChar = 1;
            if (++currentWord === text.length) {
                currentWord = 0;
            }*/

        },
        1000);
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    currentChar = 1;
    destination = destinationParam;
    type();
}

startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages");<commit_msg>added recursion<commit_after>var text = []; //"content of text here";
var delay = 50;
var currentWord = 0;
var currentChar = 1;
var destination = "[set in call to type]";
var dest = null;

console.log("testing - 8");

function type() {
    if (document.getElementById) {
        dest = document.getElementById(destination);
        if (dest) {
            dest.innerHTML = text[currentWord].substr(0, currentChar);
            ++currentChar;
            if (currentChar > text[currentWord].length) {

                unType();

            }
            else
                setTimeout("type()", delay);
        }
    }
}

function unType() {
    console.log("unType()");

    /*if (currentChar === 1) {
        type();//setTimeout("type()", 2500);
        return;
    }*/

    setTimeout(
        function () {
            console.log("lambda");
            dest.innerHTML = text[currentWord].substr(0, currentChar - 3);

            unType();

            /* currentChar = 1;
            if (++currentWord === text.length) {
                currentWord = 0;
            }*/

        },
        1000);
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    currentChar = 1;
    destination = destinationParam;
    type();
}

startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages");<|endoftext|>


<commit_before>( function(){
    var autoload = {

        /***************************
         * DatePicker - Default CSS selector is .ink-datepicker
         ***************************/
         'Close_1': '.ink-dismiss',

        /***************************
         * DatePicker - Default CSS selector is .ink-datepicker
         ***************************/
         'DatePicker_1': '.ink-datepicker',

        /***************************
         * Gallery - Default CSS selector is ul.ink-gallery-source
         ***************************/
         'Gallery_1': 'ul.ink-gallery-source',

        /***************************
         * Modal - Default CSS selector is .ink-modal
         ***************************/
         'Modal_1': '.ink-modal',

        /***************************
         * ProgressBar - Default CSS selector is .ink-progress-bar
         ***************************/
         'ProgressBar_1': '.ink-progress-bar',

        /***************************
         * SortableList - Default CSS selector is .ink-sortable-list
         ***************************/
         'SortableList_1': '.ink-sortable-list',

        /***************************
         * Spy - Default CSS selector is *[data-spy="true"]
         ***************************/
         'Spy_1': '*[data-spy="true"]',

        /***************************
         * Sticky - Default CSS selector is .ink-navigation.sticky
         ***************************/
         'Sticky_1': '.ink-navigation.sticky',

        /***************************
         * Table - Default CSS selector is .ink-table
         ***************************/
         'Table_1': '.ink-table',

        /***************************
         * Tabs - Default CSS selector is .ink-tabs
         ***************************/
         'Tabs_1': '.ink-tabs',

        /***************************
         * TreeView - Default CSS selector is .ink-tree-view
         ***************************/
         'TreeView_1': '.ink-tree-view',

        /***************************
         * Toggle - Default CSS selector is .toggle
         ***************************/
         'Toggle_1': '.toggle'

    };

    Ink.requireModules(['Ink.Dom.Selector_1', 'Ink.Dom.Loaded_1', 'Ink.Util.Array_1', 'Ink.UI.SmoothScroller_1'],function( Selector, Loaded, InkArray, Scroller ){
        Loaded.run(function(){
            for( var module in autoload ){
                (function(mod){
                    var elements = Selector.select( autoload[mod] );
                    if( elements.length ){
                        Ink.requireModules( ['Ink.UI.' + mod ], function( Component ) {
                            InkArray.each(elements, function( element ){
                                new Component(element);
                            });
                        });
                    }
                })(module);
            }
            Scroller.init();
        });
    });
})();
<commit_msg>Fixed issue with Loaded.run() in the autoload<commit_after>( function(){
    var autoload = {

        /***************************
         * DatePicker - Default CSS selector is .ink-datepicker
         ***************************/
         'Close_1': '.ink-dismiss',

        /***************************
         * DatePicker - Default CSS selector is .ink-datepicker
         ***************************/
         'DatePicker_1': '.ink-datepicker',

        /***************************
         * Gallery - Default CSS selector is ul.ink-gallery-source
         ***************************/
         'Gallery_1': 'ul.ink-gallery-source',

        /***************************
         * Modal - Default CSS selector is .ink-modal
         ***************************/
         'Modal_1': '.ink-modal',

        /***************************
         * ProgressBar - Default CSS selector is .ink-progress-bar
         ***************************/
         'ProgressBar_1': '.ink-progress-bar',

        /***************************
         * SortableList - Default CSS selector is .ink-sortable-list
         ***************************/
         'SortableList_1': '.ink-sortable-list',

        /***************************
         * Spy - Default CSS selector is *[data-spy="true"]
         ***************************/
         'Spy_1': '*[data-spy="true"]',

        /***************************
         * Sticky - Default CSS selector is .ink-navigation.sticky
         ***************************/
         'Sticky_1': '.ink-navigation.sticky',

        /***************************
         * Table - Default CSS selector is .ink-table
         ***************************/
         'Table_1': '.ink-table',

        /***************************
         * Tabs - Default CSS selector is .ink-tabs
         ***************************/
         'Tabs_1': '.ink-tabs',

        /***************************
         * TreeView - Default CSS selector is .ink-tree-view
         ***************************/
         'TreeView_1': '.ink-tree-view',

        /***************************
         * Toggle - Default CSS selector is .toggle
         ***************************/
         'Toggle_1': '.toggle'

    };

    Ink.requireModules(['Ink.Dom.Selector_1', 'Ink.Dom.Loaded_1', 'Ink.Util.Array_1', 'Ink.UI.SmoothScroller_1'],function( Selector, Loaded, InkArray, Scroller ){
        for( var module in autoload ){
            (function(mod){
                var elements = Selector.select( autoload[mod] );
                if( elements.length ){
                    Ink.requireModules( ['Ink.UI.' + mod ], function( Component ) {
                        InkArray.each(elements, function( element ){
                            Loaded.run(function(){
                                new Component(element);
                            });
                        });
                    });
                }
            })(module);
        }
        Loaded.run(function(){
            Scroller.init();
        });
    });
})();
<|endoftext|>


<commit_before>/*global $, document, alert*/

(function () {

  //Pad a number with leading zeros
  function zeroPad(number, places) {
    var zeros = places - number.toString().length + 1;
    return new Array(+(zeros > 0 && zeros)).join("0") + number;
  }

  // Convert seconds to mm:ss format
  function toTimeString(seconds) {
    if (seconds === NaN) {
      return "--:--";
    }
    var minutes = Math.floor(seconds / 60);
    seconds = seconds - minutes * 60;
    return zeroPad(minutes, 2) + ":" + zeroPad(seconds, 2);
  }

  // Parse out file name from path, unescape %20
  function parseTitle(path) {
    path = path.replace(/%20/g, " ");
    return path.split('/').pop().split('.').shift();
  }

  // Object to represent bbplayer
  var BBPlayer = function (bbplayer) {
    this.bbplayer  = bbplayer;
    this.bbaudio   = bbplayer.find("audio");
    this.bbaudio.get(0).preload="auto";
    this.state     = "paused"; // TODO enum states
    this.trackList = [];
    this.init();
  };

  // say if audio element can play file type
  BBPlayer.prototype.canPlay = function (extension) {
    var audioElem = this.bbaudio.get(0);
    if ((/mp3/i).test(extension) && audioElem.canPlayType('audio/mpeg')) {
      return true;
    }
    if ((/ogg/i).test(extension) && audioElem.canPlayType('audio/ogg')) {
      return true;
    }
    return false;
  };

  // Set up multiple sources as track list,
  // Remove duplicate and unplayable sources
  BBPlayer.prototype.loadSources = function () {
    var self = this;
    self.bbaudio.find("source").each(function (x) {
      var fileName  = $(this).attr('src').split('/').pop();
      var extension = fileName.split('.').pop();
      var trackName = fileName.split('.').shift();
      var playable  = self.canPlay(extension);
      var audioElem = self.bbaudio.get(0);
      if ($.inArray(trackName, self.trackList) === -1 && playable === true) {
        self.trackList.push(trackName);
      } else {
        $(this).remove();
      }
    });
  };

  // Update display
  BBPlayer.prototype.updateDisplay = function () {
    var audioElem = this.bbaudio.get(0);
    var duration  = toTimeString(Math.ceil(audioElem.duration));
    var elapsed   = toTimeString(Math.ceil(audioElem.currentTime));
    var title     = parseTitle(audioElem.currentSrc);
    this.bbplayer.find('.bb-trackLength').html(duration);
    this.bbplayer.find('.bb-trackTime').html(elapsed);
    this.bbplayer.find('.bb-trackTitle').html(title);
  };

  // Set current source for audio to given track number
  BBPlayer.prototype.loadTrack = function (trackNumber) {
    var source  = this.bbaudio.find("source").eq(trackNumber).attr('src');
    this.bbaudio.get(0).src = source;
    this.currentTrack = trackNumber;
  };

  // Load next track in playlist
  BBPlayer.prototype.loadNext = function () {
    var trackCount   = this.bbaudio.find("source").length;
    this.loadTrack((1 + this.currentTrack) % trackCount);
  };

  // Load previous track in playlist
  BBPlayer.prototype.loadPrevious = function () {
    var trackCount = this.bbaudio.find('source').length;
    var newTrack = (this.currentTrack + (trackCount - 1)) % trackCount;
    this.loadTrack(newTrack);
  };

  // Set up event handlers for audio element events
  BBPlayer.prototype.setAudioEventHandlers = function () {

    // Update display and continue play when song has loaded
    var self = this;
    self.bbaudio.on('canplay', function () {
      if (self.state === 'playing') {
        $(this).get(0).play();
       }
      self.updateDisplay();
    });

    // Load next track when current one ends
    self.bbaudio.on('ended', function () {
      self.loadNext();
    });
  };

  BBPlayer.prototype.play = function () {
    this.bbaudio.get(0).play();
    this.state = "playing";
    var playButton = this.bbplayer.find(".bb-play");
    playButton.removeClass("bb-paused");
    playButton.addClass("bb-playing");
  };

  BBPlayer.prototype.pause = function () {
    this.bbaudio.get(0).pause();
    this.state = "paused";
    var playButton = this.bbplayer.find(".bb-play");
    playButton.removeClass("bb-playing");
    playButton.addClass("bb-paused");
  };

  // Set up button click handlers
  BBPlayer.prototype.setClickHandlers = function () {

    var self = this;
    var audioElem = self.bbaudio.get(0);

    // Activate fast-forward
    self.bbplayer.find('.bb-forward').click(function () {
      self.loadNext();
    });

    // Toggle play / pause
    self.bbplayer.find('.bb-play').click(function () {
      if (self.state === "paused") { //(audioElem.paused) {
        stopAllBBPlayers();
        self.state = "playing";
        self.play();
      } else {
        self.state = "paused";
        self.pause();
      }
      self.updateDisplay();
    });

    // Activate rewind
    self.bbplayer.find('.bb-rewind').click(function () {
      var time = audioElem.currentTime;
      if (time > 1.5) {
        audioElem.currentTime = 0;
      } else {
        self.loadPrevious();
      }
    });
  };

  BBPlayer.prototype.init = function () {
    var self = this;
    self.setAudioEventHandlers();
    self.loadSources();
    // self.loadTrack (0);
    self.currentTrack = 0;
    self.setClickHandlers();
    self.displayTimer = setInterval(function () { self.updateDisplay(); }, 1000);
  };

  var bbplayers = [];

  function stopAllBBPlayers() {
    var i = 0;
    for (i = 0; i < bbplayers.length; i++) {
      bbplayers[i].pause();
      bbplayers[i].updateDisplay();
    }
  }

  $(document).ready(function () {
    $(".bbplayer").each(function (x) {
      bbplayers[x] = new BBPlayer($(this));
    });
  });

}());
<commit_msg>Use isNan to check for NaN on toTimeString method<commit_after>/*global $, document, alert*/

(function () {

  //Pad a number with leading zeros
  function zeroPad(number, places) {
    var zeros = places - number.toString().length + 1;
    return new Array(+(zeros > 0 && zeros)).join("0") + number;
  }

  // Convert seconds to mm:ss format
  function toTimeString(seconds) {
    if (isNan(seconds)) {
      return "--:--";
    }
    var minutes = Math.floor(seconds / 60);
    seconds = seconds - minutes * 60;
    return zeroPad(minutes, 2) + ":" + zeroPad(seconds, 2);
  }

  // Parse out file name from path, unescape %20
  function parseTitle(path) {
    path = path.replace(/%20/g, " ");
    return path.split('/').pop().split('.').shift();
  }

  // Object to represent bbplayer
  var BBPlayer = function (bbplayer) {
    this.bbplayer  = bbplayer;
    this.bbaudio   = bbplayer.find("audio");
    this.bbaudio.get(0).preload="auto";
    this.state     = "paused"; // TODO enum states
    this.trackList = [];
    this.init();
  };

  // say if audio element can play file type
  BBPlayer.prototype.canPlay = function (extension) {
    var audioElem = this.bbaudio.get(0);
    if ((/mp3/i).test(extension) && audioElem.canPlayType('audio/mpeg')) {
      return true;
    }
    if ((/ogg/i).test(extension) && audioElem.canPlayType('audio/ogg')) {
      return true;
    }
    return false;
  };

  // Set up multiple sources as track list,
  // Remove duplicate and unplayable sources
  BBPlayer.prototype.loadSources = function () {
    var self = this;
    self.bbaudio.find("source").each(function (x) {
      var fileName  = $(this).attr('src').split('/').pop();
      var extension = fileName.split('.').pop();
      var trackName = fileName.split('.').shift();
      var playable  = self.canPlay(extension);
      var audioElem = self.bbaudio.get(0);
      if ($.inArray(trackName, self.trackList) === -1 && playable === true) {
        self.trackList.push(trackName);
      } else {
        $(this).remove();
      }
    });
  };

  // Update display
  BBPlayer.prototype.updateDisplay = function () {
    var audioElem = this.bbaudio.get(0);
    var duration  = toTimeString(Math.ceil(audioElem.duration));
    var elapsed   = toTimeString(Math.ceil(audioElem.currentTime));
    var title     = parseTitle(audioElem.currentSrc);
    this.bbplayer.find('.bb-trackLength').html(duration);
    this.bbplayer.find('.bb-trackTime').html(elapsed);
    this.bbplayer.find('.bb-trackTitle').html(title);
  };

  // Set current source for audio to given track number
  BBPlayer.prototype.loadTrack = function (trackNumber) {
    var source  = this.bbaudio.find("source").eq(trackNumber).attr('src');
    this.bbaudio.get(0).src = source;
    this.currentTrack = trackNumber;
  };

  // Load next track in playlist
  BBPlayer.prototype.loadNext = function () {
    var trackCount   = this.bbaudio.find("source").length;
    this.loadTrack((1 + this.currentTrack) % trackCount);
  };

  // Load previous track in playlist
  BBPlayer.prototype.loadPrevious = function () {
    var trackCount = this.bbaudio.find('source').length;
    var newTrack = (this.currentTrack + (trackCount - 1)) % trackCount;
    this.loadTrack(newTrack);
  };

  // Set up event handlers for audio element events
  BBPlayer.prototype.setAudioEventHandlers = function () {

    // Update display and continue play when song has loaded
    var self = this;
    self.bbaudio.on('canplay', function () {
      if (self.state === 'playing') {
        $(this).get(0).play();
       }
      self.updateDisplay();
    });

    // Load next track when current one ends
    self.bbaudio.on('ended', function () {
      self.loadNext();
    });
  };

  BBPlayer.prototype.play = function () {
    this.bbaudio.get(0).play();
    this.state = "playing";
    var playButton = this.bbplayer.find(".bb-play");
    playButton.removeClass("bb-paused");
    playButton.addClass("bb-playing");
  };

  BBPlayer.prototype.pause = function () {
    this.bbaudio.get(0).pause();
    this.state = "paused";
    var playButton = this.bbplayer.find(".bb-play");
    playButton.removeClass("bb-playing");
    playButton.addClass("bb-paused");
  };

  // Set up button click handlers
  BBPlayer.prototype.setClickHandlers = function () {

    var self = this;
    var audioElem = self.bbaudio.get(0);

    // Activate fast-forward
    self.bbplayer.find('.bb-forward').click(function () {
      self.loadNext();
    });

    // Toggle play / pause
    self.bbplayer.find('.bb-play').click(function () {
      if (self.state === "paused") { //(audioElem.paused) {
        stopAllBBPlayers();
        self.state = "playing";
        self.play();
      } else {
        self.state = "paused";
        self.pause();
      }
      self.updateDisplay();
    });

    // Activate rewind
    self.bbplayer.find('.bb-rewind').click(function () {
      var time = audioElem.currentTime;
      if (time > 1.5) {
        audioElem.currentTime = 0;
      } else {
        self.loadPrevious();
      }
    });
  };

  BBPlayer.prototype.init = function () {
    var self = this;
    self.setAudioEventHandlers();
    self.loadSources();
    // self.loadTrack (0);
    self.currentTrack = 0;
    self.setClickHandlers();
    self.displayTimer = setInterval(function () { self.updateDisplay(); }, 1000);
  };

  var bbplayers = [];

  function stopAllBBPlayers() {
    var i = 0;
    for (i = 0; i < bbplayers.length; i++) {
      bbplayers[i].pause();
      bbplayers[i].updateDisplay();
    }
  }

  $(document).ready(function () {
    $(".bbplayer").each(function (x) {
      bbplayers[x] = new BBPlayer($(this));
    });
  });

}());
<|endoftext|>