<commit_before>M.wrap('github/jillix/bind-filter/dev/filter.js', function (require, module, exports) {
var Events = require('github/jillix/events');
var find = require('./find');
var ui = require('./ui');
var validate = require('./validate');
var templateCache = {};
var defaultOptions = {
    limit: 33
};
var operatorConfig = {
    '=':        ['',        'mixed'],               // or
    '!=':       ['$ne',     'mixed'],               // and
    '>':        ['$gt',     'number'],              // and
    '<':        ['$lt',     'number'],              // and
    '>=':       ['$gte',    'number'],              // and
    '<=':       ['$lte',    'number'],              // and
    'all':      ['$all',    'array',    'split'],   // or ('and' can be achieved by concatenating the arrays)
    'in':       ['$in',     'mixed',    'split'],   // and ('or' can be achieved by concatenating the arrays)
    'notin':    ['$nin',    'mixed',    'split'],   // or ('and' can be achieved by concatenating the arrays)
    'regExp':   ['$regex',  'string'],              // and ('or' is built in the regex syntax)
    'exists':   ['$exists', 'mixed',    'boolean']  // makes no sense
};

function uid (len, uid) {
    uid = "";
    for (var i = 0, l = len || 24; i < l; ++i) {
        uid += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[0 | Math.random() * 62];
    }
    return uid;
};

function setFilters (filters, reset) {
    var self = this;

    // reset filters if reset is true
    if (reset) {
        self.filters = {};
    }

    // create and buffer filters
    for (var i = 0, l = filters.length; i < l; ++i) {

        // validate field
        if (validate.validate.call(self, filters[i])) {

            // convert value from value field
            filters[i] = validate.convert.call(self, filters[i]);

            var hash = filters[i].hash || uid(4);
            self.filters[hash] = self.filters[hash] || {};

            // merge filter
            for (var key in filters[i]) {
                self.filters[hash][key] = filters[i][key];
            }
        }
    }

    // emit filters cahed event
    self.emit('filtersCached', self.filters, reset);

    // find data in db
    find.call(self);
}

function getTemplates (templates, reset, callback) {
    var self = this;

    // get templates to fetch from server
    var resultTemplates = {};
    var templatesToFetch = [];
    for (var i = 0, l = templates.length; i < l; ++i) {
        if (self.templates[templates[i]]) {
            resultTemplates[templates[i]] = self.templates[templates[i]];
        } else {
            templatesToFetch.push(templates[i]);
        }
    }

    if (templates.length === 0 || templatesToFetch.length > 0) {
        self.emit('getTemplates', templates, function (err, templates) {

            self.emit('templateResult', err, templates);

            if (err) {
                return callback(err);
            }

            // merge fetched templates into result templates
            for (var template in templates) {
               self.templates[template] = resultTemplates[template] = templates[template];
            }

            // reset cache
            if (reset) {
                self.templates = resultTemplates;
            }

            callback(null);
        });
    } else {
        // reset cache
        if (reset) {
            self.templates = resultTemplates;
        }
        callback(null);
    }
}

function setTemplates (templates, callback) {
    var self = this;

    if (templates instanceof Array) {
        getTemplates.call(self, templates, true, function (err) {
            if (err) {
                // TODO handle error
                return console.error(err);
            }

            // select a template
            if (!self.template) {
                for (template in self.templates) {
                    self.template = template;
                    self.emit('template', self.templates[template]);
                    break;
                }
            }

            if (callback) {
                callback();
            }

            // emit the templates
            self.emit('templates', self.templates);
        });
    }
}

function setTemplate (template, callback) {
    var self = this;

    // set sort options
    var sort = template.sort;
    var options = { sort: sort };
    if (sort) {
        self.emit("setOptions", options);
    }

    // TODO this is a hack until bind know how select keys in parameters
    if (typeof template === 'object') {
        template = template._id;
    }

    if (typeof template !== 'string' || !template) {
        return;
    }

    // get template from server or cache
    getTemplates.call(self, [template], false, function (err) {

        if (err) {
            // TODO handle error
            return console.error(err);
        }

        // set current template
        self.template = template;

        // reset predefined filters

        setFilters.call(self, (self.config.setFilters || []).concat(self.templates[template].filters || []), true);

        // emit the template
        self.emit('template', self.templates[template]);
    });
}

function setOptions (options, reset) {
    var self = this;

    if (typeof options !== 'object') {
        return;
    }

    // reset options
    if (reset) {
        self.options = options;
    // merge options
    } else {
        for (var option in options) {
            var value = options[option];
            self.options[option] = value
        }
    }
}

function getFilters (callback) {
    var self = this;
    var filters = [];
    for (var id in self.filters) {
        var filter = self.filters[id];
        filter.item = null;
        filters.push(filter);
    }
    callback(filters);
}

function initInterface () {
    var self = this;

    // listen to interface events
    self.on('setFilters', setFilters);
    self.on('setTemplate', setTemplate);
    self.on('setTemplates', setTemplates);
    self.on('setOptions', setOptions);
    self.on('getFilters', getFilters);
}

function init (config) {

    var self = this;

    // prepare module
    self.config = config;
    self.filters = {};
    self.templates = templateCache;
    self.options = defaultOptions;
    self.config.operators = operatorConfig;

    if (!config.waitFor) {
        return console.error('At least a CRUD mofule must be a dependency of the bind-filter module.');
    }

    // setup interface
    initInterface.call(self);

    // listen to external events
    Events.call(self, config);

    // i18n for operators
    if (self.config.i18n === true) {

        // cache for translated operators
        self.config.i18n = {};

        var operators = self.config.operators;
        for (var operator in operators) {
            (function (op) {
                self.emit("message", op, function (err, newOperator) {
                    if (err) { return; }
                    // cache the translated operator
                    self.config.i18n[op] = newOperator.message;;
                });
            })(operator);
        }
    }

    if (self.config.ui) {
        ui.call(self);
    }

    // init templates
    if (self.config.setTemplates) {
        self.emit('setTemplates', self.config.setTemplates, function () {
            // init template
            if (self.config.template) {
                self.emit('setTemplate', self.config.template);
            }
        });
    // init template
    } else if (self.config.template) {
        self.emit('setTemplate', self.config.template);
    }

    self.emit('ready');
}

module.exports = init;

return module; });
<commit_msg>emit optionsSet<commit_after>M.wrap('github/jillix/bind-filter/dev/filter.js', function (require, module, exports) {
var Events = require('github/jillix/events');
var find = require('./find');
var ui = require('./ui');
var validate = require('./validate');
var templateCache = {};
var defaultOptions = {
    limit: 33
};
var operatorConfig = {
    '=':        ['',        'mixed'],               // or
    '!=':       ['$ne',     'mixed'],               // and
    '>':        ['$gt',     'number'],              // and
    '<':        ['$lt',     'number'],              // and
    '>=':       ['$gte',    'number'],              // and
    '<=':       ['$lte',    'number'],              // and
    'all':      ['$all',    'array',    'split'],   // or ('and' can be achieved by concatenating the arrays)
    'in':       ['$in',     'mixed',    'split'],   // and ('or' can be achieved by concatenating the arrays)
    'notin':    ['$nin',    'mixed',    'split'],   // or ('and' can be achieved by concatenating the arrays)
    'regExp':   ['$regex',  'string'],              // and ('or' is built in the regex syntax)
    'exists':   ['$exists', 'mixed',    'boolean']  // makes no sense
};

function uid (len, uid) {
    uid = "";
    for (var i = 0, l = len || 24; i < l; ++i) {
        uid += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[0 | Math.random() * 62];
    }
    return uid;
};

function setFilters (filters, reset) {
    var self = this;

    // reset filters if reset is true
    if (reset) {
        self.filters = {};
    }

    // create and buffer filters
    for (var i = 0, l = filters.length; i < l; ++i) {

        // validate field
        if (validate.validate.call(self, filters[i])) {

            // convert value from value field
            filters[i] = validate.convert.call(self, filters[i]);

            var hash = filters[i].hash || uid(4);
            self.filters[hash] = self.filters[hash] || {};

            // merge filter
            for (var key in filters[i]) {
                self.filters[hash][key] = filters[i][key];
            }
        }
    }

    // emit filters cahed event
    self.emit('filtersCached', self.filters, reset);

    // find data in db
    find.call(self);
}

function getTemplates (templates, reset, callback) {
    var self = this;

    // get templates to fetch from server
    var resultTemplates = {};
    var templatesToFetch = [];
    for (var i = 0, l = templates.length; i < l; ++i) {
        if (self.templates[templates[i]]) {
            resultTemplates[templates[i]] = self.templates[templates[i]];
        } else {
            templatesToFetch.push(templates[i]);
        }
    }

    if (templates.length === 0 || templatesToFetch.length > 0) {
        self.emit('getTemplates', templates, function (err, templates) {

            self.emit('templateResult', err, templates);

            if (err) {
                return callback(err);
            }

            // merge fetched templates into result templates
            for (var template in templates) {
               self.templates[template] = resultTemplates[template] = templates[template];
            }

            // reset cache
            if (reset) {
                self.templates = resultTemplates;
            }

            callback(null);
        });
    } else {
        // reset cache
        if (reset) {
            self.templates = resultTemplates;
        }
        callback(null);
    }
}

function setTemplates (templates, callback) {
    var self = this;

    if (templates instanceof Array) {
        getTemplates.call(self, templates, true, function (err) {
            if (err) {
                // TODO handle error
                return console.error(err);
            }

            // select a template
            if (!self.template) {
                for (template in self.templates) {
                    self.template = template;
                    self.emit('template', self.templates[template]);
                    break;
                }
            }

            if (callback) {
                callback();
            }

            // emit the templates
            self.emit('templates', self.templates);
        });
    }
}

function setTemplate (template, callback) {
    var self = this;

    // set sort options
    var sort = template.sort;
    var options = { sort: sort };
    if (sort) {
        self.emit("setOptions", options);
    }

    // TODO this is a hack until bind know how select keys in parameters
    if (typeof template === 'object') {
        template = template._id;
    }

    if (typeof template !== 'string' || !template) {
        return;
    }

    // get template from server or cache
    getTemplates.call(self, [template], false, function (err) {

        if (err) {
            // TODO handle error
            return console.error(err);
        }

        // set current template
        self.template = template;

        // reset predefined filters

        setFilters.call(self, (self.config.setFilters || []).concat(self.templates[template].filters || []), true);

        // emit the template
        self.emit('template', self.templates[template]);
    });
}

function setOptions (options, reset) {
    var self = this;

    if (typeof options !== 'object') {
        return;
    }

    // reset options
    if (reset) {
        self.options = options;
    // merge options
    } else {
        for (var option in options) {
            var value = options[option];
            // TODO value can be an object, merge it
            self.options[option] = value
        }
    }

    self.emit("optionsSet");
}

function getFilters (callback) {
    var self = this;
    var filters = [];
    for (var id in self.filters) {
        var filter = self.filters[id];
        filter.item = null;
        filters.push(filter);
    }
    callback(filters);
}

function initInterface () {
    var self = this;

    // listen to interface events
    self.on('setFilters', setFilters);
    self.on('setTemplate', setTemplate);
    self.on('setTemplates', setTemplates);
    self.on('setOptions', setOptions);
    self.on('getFilters', getFilters);
}

function init (config) {

    var self = this;

    // prepare module
    self.config = config;
    self.filters = {};
    self.templates = templateCache;
    self.options = defaultOptions;
    self.config.operators = operatorConfig;

    if (!config.waitFor) {
        return console.error('At least a CRUD mofule must be a dependency of the bind-filter module.');
    }

    // setup interface
    initInterface.call(self);

    // listen to external events
    Events.call(self, config);

    // i18n for operators
    if (self.config.i18n === true) {

        // cache for translated operators
        self.config.i18n = {};

        var operators = self.config.operators;
        for (var operator in operators) {
            (function (op) {
                self.emit("message", op, function (err, newOperator) {
                    if (err) { return; }
                    // cache the translated operator
                    self.config.i18n[op] = newOperator.message;;
                });
            })(operator);
        }
    }

    if (self.config.ui) {
        ui.call(self);
    }

    // init templates
    if (self.config.setTemplates) {
        self.emit('setTemplates', self.config.setTemplates, function () {
            // init template
            if (self.config.template) {
                self.emit('setTemplate', self.config.template);
            }
        });
    // init template
    } else if (self.config.template) {
        self.emit('setTemplate', self.config.template);
    }

    self.emit('ready');
}

module.exports = init;

return module; });
<|endoftext|>


<commit_before>AirbnbTechnical.js
<commit_msg>fill file<commit_after>// var choices =
//   {Fruit: 2.15,
//   Fries: 2.75,
//   Salad: 3.35,
//   Wings: 3.55,
//   Stick: 4.20,
//   Plate: 5.80}

// https://en.wikipedia.org/wiki/Change-making_problem
// https://www.amazon.com/Cracking-Coding-Interview-Programming-Questions/dp/0984782850/ref=dp_ob_title_bk

function appetize(money_left, cart=[]){
  if( money_left < 0 ){
    return;
  }
  if( money_left === 0 ) {
    results.push(cart);
    return;
  }
  var i =0;
  while( i< items.length ){
    cart.push(items[i])
    // if( prices[i] === money_left )
    appetize( money_left - prices[i], cart )
    cart.pop()
    i++;
  }
}

//appetize(-1)   // returns: nothing
//appetize(0)    // prints: []
//appetize(2.15) // prints: "Fruit"
//appetize(3.35) // prints: "Salad"
//appetize(4.30)
appetize(15.05)

console.log(results[0])

// return names
<|endoftext|>


<commit_before>/*globals document,window,$,jQuery */
/*jslint white: true, onevar: true, undef: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true, indent: 2 */

"use strict";

/*
 * jQuery UI Lightbox
 *
 * Copyright (c) 2009 Benjamin Doherty
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Depends:
 *  ui.core.js
 *  ui.dialog.js
 *  jquery.mousewheel.js (optional)
 */
(function ($) {

  $.widget('ui.lightbox', {
    _init: function () {
      var self = this,
        lightbox = (this.lightbox = $('<div/>')
          .dialog({
            autoOpen: false,
            closeOnEscape: this.options.closeOnEscape,
            modal: this.options.overlay,
            dialogClass: this.options.dialogClass,
            position: this.options.position,
            resizable: this.options.resizable,
            draggable: this.options.draggable,
            height: this.options.height,
            width: this.options.width,
            open: function (event, ui) {
              var type = self._deriveType(self.getCurrentAnchor());

              $('.ui-dialog-buttonpane button', $(this).parents('.ui-dialog'))
                .each(function (index, domElement) {
                  $(domElement).addClass('button-' + index);
                });
              self._hideLoadingIndicator();
            },
            resize: function (event, ui) {
              var type = self._deriveType(self.getCurrentAnchor());

              if (type == 'image') {
                self._resize();
                $(this).dialog('option', 'position', self.options.position);
              }
            }
          }));

      // consider event delegation to make this more dynamic
      $(this.options.selector, this.element).click(function (event) {
        event.preventDefault();
        self._showLoadingIndicator();

        var content,
          viewer = self.lightbox;

        viewer.dialog('option', 'show', self.options.show);

        content = self._loadContent(this);
        self.setCurrentAnchor(this);
        self.setContent(content);
        self._display();
        return false;
      });
      $(document).keydown(function (event) {
        if (!self.getCurrentAnchor()) {
          return;
        }
        switch (event.keyCode) {
        case $.ui.keyCode.ESCAPE:
          self.close();
          break;
        case $.ui.keyCode.LEFT:
          self.prev("left");
          event.preventDefault();
          break;
        case $.ui.keyCode.UP:
          self.prev("up");
          event.preventDefault();
          break;
        case $.ui.keyCode.RIGHT:
          self.next("right");
          event.preventDefault();
          break;
        case $.ui.keyCode.DOWN:
          self.next("down");
          event.preventDefault();
          break;
        }
      });
      $(window).resize(function () {
        if (!self.getCurrentAnchor()) {
          return;
        }
        var type = self._deriveType(self.getCurrentAnchor());

        if (type == 'image') {
          self._resize();
        }
        self.lightbox.dialog('option', 'position', self.options.position);
      });
      if ($.fn.mousewheel) {
        $(document).mousewheel(function (event, delta) {
          if (!self.getCurrentAnchor()) {
            return;
          }
          event.preventDefault();
          if (self.viewerElement.is(":animated")) {
            return;
          }
          if (delta < 0) {
            self.next("down");
          }
          if (delta > 0) {
            self.prev("up");
          }
        });
      }
    },

    _showLoadingIndicator: function () {
      var self = this;

      this.loadingIndicatorTimeout = setTimeout(function() {
        if (!self.loadingIndicator) {
          self.loadingIndicator = self._element("div", "ui-loading-indicator ui-corner-all").appendTo(document.body);
        }
        self.loadingIndicator.fadeIn("slow");
      }, 250);
    },

    _hideLoadingIndicator: function () {
      clearTimeout(this.loadingIndicatorTimeout);
      if (this.loadingIndicator) {
        this.loadingIndicator.hide();
      }
    },

    close: function () {
      if (!this.getCurrentAnchor()) {
        return;
      }
      var self = this,
        anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      // TODO: these need to be destroyed with the widget.
      viewer.dialog('close');
    },

    next: function (direction) {
      this._rotate(":gt(", ":first", direction || "up");
    },

    prev: function (direction) {
      this._rotate(":lt(", ":last", direction || "down");
    },

    _anchors: function () {
      // if deemed necessary, cache selection here
      return this.element.find(this.options.selector);
    },

    _display: function (direction) {
      if (!this.getContent()) {
        return;
      }

      var self = this,
        visible = this.lightbox.dialog('isOpen'),
        anchor = this.getCurrentAnchor(),
        type = this._deriveType(this.getCurrentAnchor()),
        content = this.getContent(),
        viewer = this.lightbox;

      viewer.dialog('option', 'title', $(anchor).attr('title') + this.options.titleSuffix);

      if (visible) {
        viewer.dialog('close');
      }
      viewer.empty();
      viewer.append(content.show());
      this._resize();
      viewer.dialog('open');
      viewer.dialog('option', 'hide', self.options.hide);
    },

    _loadContent: function (anchor) {
      var self = this,
        content = 'BUG',
        type = this.options.type ? this.options.type : this._deriveType(anchor);

      switch (type) {
      case "image":
        content = this._element('img')
          .attr("src", anchor.href)
          .load(function (event) {
            self.lightbox.dialog('option', 'position', self.options.position);
          });
        break;
      case "flash":
      case "flashvideo":
      case "quicktime":
      case "realplayer":
      case "windowsmedia":
        $(anchor).media({
          width: this.options.width,
          height: this.options.height,
          src: anchor.href,
          autoplay: 1
        }, function (element, options) {
        }, function (element, data, options, playerName) {
          content = $(data).clone();
          $(data).media('undo');
        });
        break;
      case "iframe":
        content = this._element('iframe').attr('src', anchor.href).attr('frameborder', 0).attr('border', 0);
        break;
      case "html":
      case "dom":
        var reference = $($(anchor).attr('href'));

        content = $(reference).clone();
        break;
      case "ajax":
      case "script":
        $.ajax({
          url: anchor.href,
          type: (parseInt(self.options.post, 10) === 1) ? "POST" : "GET",
          cache: true,
          async: false,
          data: self.options.parameters,
          dataType: (type === "ajax") ? "html" : "script",
          success: function (data, textStatus) {
            content = $(data);
          }
        });
        break;
      }

      return content;
    },

    _deriveType: function (anchor) {
      var reference = anchor.href;
      if (reference.toLowerCase().match(/\.(gif|jpg|jpeg|png)(\?[0123456789]+)?$/)) {
        return "image";
      }
      if (reference.toLowerCase().match(/\.(swf)(\?[0123456789]+)?$/)) {
        return "flash";
      }
      if (reference.toLowerCase().match(/\.(flv)(\?[0123456789]+)?$/)) {
        return "flashvideo";
      }
      if (reference.toLowerCase().match(/\.(aif|aiff|aac|au|bmp|gsm|mov|mid|midi|mpg|mpeg|m4a|m4v|mp4|psd|qt|qtif|qif|qti|snd|tif|tiff|wav|3g2|3gp|wbmp)(\?[0123456789]+)?$/)) {
        return "quicktime";
      }
      if (reference.toLowerCase().match(/\.(ra|ram|rm|rpm|rv|smi|smil)(\?[0123456789]+)?$/)) {
        return "realplayer";
      }
      if (reference.toLowerCase().match(/\.(asf|avi|wma|wmv)(\?[0123456789]+)?$/)) {
        return "windowsmedia";
      }
      return "ajax";
    },

    _preloadNeighbours: function () {
      var anchors = this._anchors(),
        index = anchors.index(this.getCurrentAnchor());
      anchors.filter(this._neighbours(anchors.length, index)).each(function () {
        //new Image().src = this.href;
      });
    },

    _neighbours: function (index, length) {
      return ":eq(" + (index === 0 ? length - 1 : index - 1) + "), :eq(" + (index === length - 1 ? 0 : index + 1) + ")";
    },

    _position: function (img) {
    },

    _resize: function () {
      var content = this.getContent(),
        viewer = this.lightbox,
        dialog = this.lightbox.data('dialog'),
        offset = 20,
        type = this._deriveType(this.getCurrentAnchor()),
        cWidth,cHeight,finalWidth,finalHeight,
        // difference
        deltaContentWidth = viewer.outerWidth() - viewer.width(),
        deltaContentHeight = viewer.outerHeight() - viewer.height(),

        dialogTitlebarWidth = dialog.uiDialogTitlebar.outerWidth(),
        dialogTitlebarHeight = dialog.uiDialogTitlebar.outerHeight(),

        // Window
        wWidth = $(window).width(),
        wHeight = $(window).height(),

        size = (this.size = {});

      $.swap(content[0], {
        position: "absolute",
        visibility: "hidden",
        display: "block"
      }, function () {
        cWidth = $(this).attr('width') || $(this).width(),
        cHeight = $(this).attr('height') || $(this).height();
      });

      // Desired width
      finalWidth = cWidth + deltaContentWidth,
      finalHeight = cHeight + deltaContentHeight + dialogTitlebarHeight,

      ratio = Math.min(
        Math.min(
          Math.min(wWidth - deltaContentWidth - offset, cWidth) / cWidth,
          Math.min(wHeight - deltaContentHeight - dialogTitlebarHeight - offset, cHeight) / cHeight, 1)),

      $.extend(size, {
        width: Math.round(ratio * cWidth),
        height: Math.round(ratio * cHeight)
      });

      if (type == 'image') {
        content.css('width', size.width);
        content.css('height', size.height);
      }

      viewer.dialog('option', 'width', size.width + deltaContentWidth);
      viewer.dialog('option', 'height', size.height + deltaContentHeight + dialogTitlebarHeight);
      viewer.css({
        width: size.width + deltaContentWidth,
        height: size.height + deltaContentHeight
      });
    },

    setContent: function (content) {
      this._setData('content', content);
    },
    getContent: function () {
      return this._getData('content');
    },

    setCurrentAnchor: function (anchor) {
      this._setData('currentAnchor', anchor);
    },
    getCurrentAnchor: function () {
      return this._getData('currentAnchor');
    },

    _rotate: function (selectorA, selectorB, direction) {
      var self = this,
        content,
        anchors = this._anchors(),
        target = current = this.getCurrentAnchor(),
        viewer = this.lightbox;

      if (!this.getCurrentAnchor()) {
        console.log('Called _rotate without an anchor');
        return;
      }

      if (anchors.length === 1) {
        return;
      }

      this._showLoadingIndicator();

      target = anchors.filter(selectorA + anchors.index(current) + ")" + selectorB)[0];
      if (!target && this.options.loop && anchors.length > 1) {
        target = anchors.filter(selectorB)[0];
      }

      viewer.dialog('option', 'hide', this.options.rotateOut);
      viewer.dialog('option', 'show', this.options.rotateIn);
      this.setCurrentAnchor(target);
      content = this._loadContent(target);
      this.setContent(content);
      this._display(direction);
    },

    _element: function (type, clazz) {
      return $("<" + type + "/>").addClass(clazz).hide();
    }
  });

  $.extend($.ui.lightbox, {
    defaults: {
      loop: true,
      overlay: true,
      post: 0,
      dialogClass: 'ui-lightbox',
      closeOnEscape: true,
      resizable: false,
      draggable: false,
      selector: "a[href]:has(img[src])",
      titleSuffix: "",
      position: 'center',
      width: 'auto',
      height: 'auto',
      parameters: {},
      rotateIn: '',
      rotateOut: '',
      show: '',
      hide: ''
    }
  });

})(jQuery);
<commit_msg>slick animations that don't work<commit_after>/*globals document,window,$,jQuery */
/*jslint white: true, onevar: true, undef: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true, indent: 2 */

"use strict";

/*
 * jQuery UI Lightbox
 *
 * Copyright (c) 2009 Benjamin Doherty
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Depends:
 *  ui.core.js
 *  ui.dialog.js
 *  jquery.mousewheel.js (optional)
 */
(function ($) {

  $.widget('ui.lightbox', {
    _init: function () {
      var self = this,
        lightbox = (this.lightbox = $('<div/>')
          .dialog({
            autoOpen: false,
            closeOnEscape: this.options.closeOnEscape,
            modal: this.options.overlay,
            dialogClass: this.options.dialogClass,
            position: this.options.position,
            resizable: this.options.resizable,
            draggable: this.options.draggable,
            height: this.options.height,
            width: this.options.width,
            show: null,
            hide: null,
            open: function (event, ui) {
              var type = self._deriveType(self.getCurrentAnchor());

              $('.ui-dialog-buttonpane button', $(this).parents('.ui-dialog'))
                .each(function (index, domElement) {
                  $(domElement).addClass('button-' + index);
                });
              self._hideLoadingIndicator();
            },
            resize: function (event, ui) {
              var type = self._deriveType(self.getCurrentAnchor());

              if (type == 'image') {
                self._resize();
                $(this).dialog('option', 'position', self.options.position);
              }
            }
          }));

      // consider event delegation to make this more dynamic
      $(this.options.selector, this.element).click(function (event) {
        event.preventDefault();
        self._showLoadingIndicator();

        var content,
          viewer = self.lightbox;

        content = self._loadContent(this);
        self.setCurrentAnchor(this);
        self.setContent(content);
        self._display();
        return false;
      });
      $(document).keydown(function (event) {
        if (!self.getCurrentAnchor()) {
          return;
        }
        switch (event.keyCode) {
        case $.ui.keyCode.ESCAPE:
          self.close();
          break;
        case $.ui.keyCode.LEFT:
          self.prev("left");
          event.preventDefault();
          break;
        case $.ui.keyCode.UP:
          self.prev("up");
          event.preventDefault();
          break;
        case $.ui.keyCode.RIGHT:
          self.next("right");
          event.preventDefault();
          break;
        case $.ui.keyCode.DOWN:
          self.next("down");
          event.preventDefault();
          break;
        }
      });
      $(window).resize(function () {
        if (!self.getCurrentAnchor()) {
          return;
        }
        var type = self._deriveType(self.getCurrentAnchor());

        if (type == 'image') {
          self._resize();
        }
        self.lightbox.dialog('option', 'position', self.options.position);
      });
      if ($.fn.mousewheel) {
        $(document).mousewheel(function (event, delta) {
          if (!self.getCurrentAnchor()) {
            return;
          }
          event.preventDefault();
          if (self.viewerElement.is(":animated")) {
            return;
          }
          if (delta < 0) {
            self.next("down");
          }
          if (delta > 0) {
            self.prev("up");
          }
        });
      }
    },

    _showLoadingIndicator: function () {
      var self = this;

      this.loadingIndicatorTimeout = setTimeout(function() {
        if (!self.loadingIndicator) {
          self.loadingIndicator = self._element("div", "ui-loading-indicator ui-corner-all").appendTo(document.body);
        }
        self.loadingIndicator.fadeIn("slow");
      }, 250);
    },

    _hideLoadingIndicator: function () {
      clearTimeout(this.loadingIndicatorTimeout);
      if (this.loadingIndicator) {
        this.loadingIndicator.hide();
      }
    },

    close: function () {
      if (!this.getCurrentAnchor()) {
        return;
      }
      var self = this,
        anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      // TODO: these need to be destroyed with the widget.
      viewer.dialog('close');
    },

    next: function (direction) {
      this._rotate(":gt(", ":first", direction || "up");
    },

    prev: function (direction) {
      this._rotate(":lt(", ":last", direction || "down");
    },

    _anchors: function () {
      // if deemed necessary, cache selection here
      return this.element.find(this.options.selector);
    },

    _display: function (direction) {
      if (!this.getContent()) {
        return;
      }

      var self = this,
        visible = this.lightbox.dialog('isOpen'),
        anchor = this.getCurrentAnchor(),
        type = this._deriveType(this.getCurrentAnchor()),
        content = this.getContent(),
        viewer = this.lightbox;

      viewer.dialog('option', 'title', $(anchor).attr('title') + this.options.titleSuffix);

      viewer.empty();
      viewer.append(content.show());
      //self._resize();
      if (visible && direction) {
        this.options.rotateIn.call(viewer.data('dialog').uiDialog, {
          up: "down",
          down: "up",
          left: "right",
          right: "left"
        }[direction]);
      }
      else {
        self.options.show.call(viewer.data('dialog').uiDialog, anchor);
      }
      viewer.dialog('open');

      // Default close animation. Rotate actions have opportunity to disable this.
      viewer.dialog('option', 'beforeclose', function (event, ui) {
        self.options.hide.call($(this).data('dialog').uiDialog, self.getCurrentAnchor(), function() {
        });
      });
    },

    _loadContent: function (anchor) {
      var self = this,
        content = 'BUG',
        type = this.options.type ? this.options.type : this._deriveType(anchor);

      switch (type) {
      case "image":
        content = this._element('img')
          .attr("src", anchor.href)
          .load(function (event) {
            self.lightbox.dialog('option', 'position', self.options.position);
          });
        break;
      case "flash":
      case "flashvideo":
      case "quicktime":
      case "realplayer":
      case "windowsmedia":
        $(anchor).media({
          width: this.options.width,
          height: this.options.height,
          src: anchor.href,
          autoplay: 1
        }, function (element, options) {
        }, function (element, data, options, playerName) {
          content = $(data).clone();
          $(data).media('undo');
        });
        break;
      case "iframe":
        content = this._element('iframe').attr('src', anchor.href).attr('frameborder', 0).attr('border', 0);
        break;
      case "html":
      case "dom":
        var reference = $($(anchor).attr('href'));

        content = $(reference).clone();
        break;
      case "ajax":
      case "script":
        $.ajax({
          url: anchor.href,
          type: (parseInt(self.options.post, 10) === 1) ? "POST" : "GET",
          cache: true,
          async: false,
          data: self.options.parameters,
          dataType: (type === "ajax") ? "html" : "script",
          success: function (data, textStatus) {
            content = $(data);
          }
        });
        break;
      }

      return content;
    },

    _deriveType: function (anchor) {
      var reference = anchor.href;
      if (reference.toLowerCase().match(/\.(gif|jpg|jpeg|png)(\?[0123456789]+)?$/)) {
        return "image";
      }
      if (reference.toLowerCase().match(/\.(swf)(\?[0123456789]+)?$/)) {
        return "flash";
      }
      if (reference.toLowerCase().match(/\.(flv)(\?[0123456789]+)?$/)) {
        return "flashvideo";
      }
      if (reference.toLowerCase().match(/\.(aif|aiff|aac|au|bmp|gsm|mov|mid|midi|mpg|mpeg|m4a|m4v|mp4|psd|qt|qtif|qif|qti|snd|tif|tiff|wav|3g2|3gp|wbmp)(\?[0123456789]+)?$/)) {
        return "quicktime";
      }
      if (reference.toLowerCase().match(/\.(ra|ram|rm|rpm|rv|smi|smil)(\?[0123456789]+)?$/)) {
        return "realplayer";
      }
      if (reference.toLowerCase().match(/\.(asf|avi|wma|wmv)(\?[0123456789]+)?$/)) {
        return "windowsmedia";
      }
      return "ajax";
    },

    _preloadNeighbours: function () {
      var anchors = this._anchors(),
        index = anchors.index(this.getCurrentAnchor());
      anchors.filter(this._neighbours(anchors.length, index)).each(function () {
        //new Image().src = this.href;
      });
    },

    _neighbours: function (index, length) {
      return ":eq(" + (index === 0 ? length - 1 : index - 1) + "), :eq(" + (index === length - 1 ? 0 : index + 1) + ")";
    },

    _position: function (img) {
    },

    _resize: function () {
      var content = this.getContent(),
        viewer = this.lightbox,
        dialog = this.lightbox.data('dialog'),
        offset = 20,
        type = this._deriveType(this.getCurrentAnchor()),
        cWidth,cHeight,finalWidth,finalHeight,
        // difference
        deltaContentWidth = viewer.outerWidth() - viewer.width(),
        deltaContentHeight = viewer.outerHeight() - viewer.height(),

        dialogTitlebarWidth = dialog.uiDialogTitlebar.outerWidth(),
        dialogTitlebarHeight = dialog.uiDialogTitlebar.outerHeight(),

        // Window
        wWidth = $(window).width(),
        wHeight = $(window).height(),

        size = (this.size = {});

      $.swap(content[0], {
        position: "absolute",
        visibility: "hidden",
        display: "block"
      }, function () {
        cWidth = $(this).attr('width') || $(this).width(),
        cHeight = $(this).attr('height') || $(this).height();
      });

      // Desired width
      finalWidth = cWidth + deltaContentWidth,
      finalHeight = cHeight + deltaContentHeight + dialogTitlebarHeight,

      ratio = Math.min(
        Math.min(
          Math.min(wWidth - deltaContentWidth - offset, cWidth) / cWidth,
          Math.min(wHeight - deltaContentHeight - dialogTitlebarHeight - offset, cHeight) / cHeight, 1)),

      $.extend(size, {
        width: Math.round(ratio * cWidth),
        height: Math.round(ratio * cHeight)
      });

      if (type == 'image') {
        content.css('width', size.width);
        content.css('height', size.height);
      }

      viewer.dialog('option', 'width', size.width + deltaContentWidth);
      viewer.dialog('option', 'height', size.height + deltaContentHeight + dialogTitlebarHeight);
      viewer.css({
        width: size.width + deltaContentWidth,
        height: size.height + deltaContentHeight
      });
    },

    setContent: function (content) {
      this._setData('content', content);
    },
    getContent: function () {
      return this._getData('content');
    },

    setCurrentAnchor: function (anchor) {
      this._setData('currentAnchor', anchor);
    },
    getCurrentAnchor: function () {
      return this._getData('currentAnchor');
    },

    _rotate: function (selectorA, selectorB, direction) {
      var self = this,
        content,
        anchors = this._anchors(),
        target = current = this.getCurrentAnchor(),
        viewer = this.lightbox;

      if (!this.getCurrentAnchor()) {
        console.log('Called _rotate without an anchor');
        return;
      }

      if (anchors.length === 1) {
        return;
      }

      this._showLoadingIndicator();

      target = anchors.filter(selectorA + anchors.index(current) + ")" + selectorB)[0];
      if (!target && this.options.loop && anchors.length > 1) {
        target = anchors.filter(selectorB)[0];
      }

      this.options.rotateOut.call(viewer.data('dialog').uiDialog, direction, function() {
        // Dialog's default close animation must be disabled.
        viewer.dialog('option', 'beforeclose', null).dialog('close');
        self.setCurrentAnchor(target);
        content = self._loadContent(target);
        self.setContent(content);
        self._display(direction);
      });
    },

    _element: function (type, clazz) {
      return $("<" + type + "/>").addClass(clazz).hide();
    }
  });

  $.extend($.ui.lightbox, {
    defaults: {
      loop: true,
      overlay: true,
      post: 0,
      dialogClass: 'ui-lightbox',
      closeOnEscape: true,
      resizable: false,
      draggable: false,
      selector: "a[href]:has(img[src])",
      titleSuffix: "",
      position: 'center',
      width: 'auto',
      height: 'auto',
      parameters: {},

      rotateIn: function(direction, finished) {
        $(this).effect("drop", {
          direction: direction,
          mode: "show"
        }, "normal", finished);
      },
      rotateOut: function(direction, finished) {
        $(this).effect("drop", {
          direction: direction
        }, "normal", finished);
      },
      show: function (anchor) {
        var thumb = $(anchor),
          offset = thumb.offset();
        // TODO refactor
        var start = {
          left: offset.left,
          top: offset.top,
          width: thumb.width(),
          height: thumb.height(),
          opacity: 0
        }
        var img = $(this);
        var stop = {
          left: img.css("left"),
          top: img.css("top"),
          width: img.width(),
          height: img.height(),
          opacity: 1
        }
        $(this).css(start).show().animate(stop);
      },
      hide: function (anchor, finished) {
        var thumb = $(anchor),
          offset = thumb.offset();
        // TODO refactor (see above)
        var stop = {
          left: offset.left,
          top: offset.top,
          width: thumb.width(),
          height: thumb.height(),
          opacity: 0
        }
        $(this).animate(stop, finished);
      }
    }
  });

})(jQuery);
<|endoftext|>


<commit_before>/*globals document,window,$,jQuery */
/*jslint white: true, onevar: true, undef: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true, indent: 2 */

"use strict";

/*
 * jQuery UI Lightbox
 *
 * Copyright (c) 2009 Benjamin Doherty
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Depends:
 *  ui.core.js
 *  ui.dialog.js
 *  jquery.mousewheel.js (optional)
 */
(function ($) {

  $.widget('ui.lightbox', {
    _init: function () {
      var self = this;

      // consider event delegation to make this more dynamic
      $(this.options.selector, this.element).click(function (event) {
        event.preventDefault();
        self.open(this);
      });
      $(document).keydown(function (event) {
        if (!self.lightbox.dialog('isOpen')) {
          return;
        }
        switch (event.keyCode) {
        case $.ui.keyCode.ESCAPE:
          if (self.options.closeOnEscape) {
            self.close();
          }
          break;
        case $.ui.keyCode.LEFT:
          self.prev("left");
          event.preventDefault();
          break;
        case $.ui.keyCode.UP:
          self.prev("up");
          event.preventDefault();
          break;
        case $.ui.keyCode.RIGHT:
          self.next("right");
          event.preventDefault();
          break;
        case $.ui.keyCode.DOWN:
          self.next("down");
          event.preventDefault();
          break;
        }
      });
      if ($.fn.mousewheel) {
        $(document).mousewheel(function (event, delta) {
          if (!self.lightbox.dialog('isOpen')) {
            return;
          }
          event.preventDefault();
          if (self.lightbox.is(":animated")) {
            return;
          }
          if (delta < 0) {
            self.next("down");
          }
          if (delta > 0) {
            self.prev("up");
          }
        });
      }
    },

    _makeDialog: function () {
      return $('<div/>').dialog({
        autoOpen: false,
        closeOnEscape: false,
        modal: this.options.overlay,
        dialogClass: this.options.dialogClass,
        position: this.options.position,
        resizable: this.options.resizable,
        draggable: this.options.draggable,
        height: this.options.height,
        width: this.options.width,
        open: function (event, ui) {
          $('.ui-dialog-buttonpane button', $(this).parents('.ui-dialog'))
            .each(function (index, domElement) {
              $(domElement).addClass('button-' + index);
            });
        },
        close: function (event, ui) {
          $(this).empty();
        }
      });
    },

    _buttons: {
      'Previous': function (eventObject) {
        $(this).dialog('option', '_lightbox').prev("right");
      },
      'Next': function (eventObject) {
        $(this).dialog('option', '_lightbox').next("right");
      }
    },

    _showLoadingIndicator: function () {
      var self = this;

      this.loadingIndicatorTimeout = setTimeout(function() {
        if (!self.loadingIndicator) {
          self.loadingIndicator = self._element("div", "ui-loading-indicator ui-corner-all").appendTo(document.body);
        }
        self.loadingIndicator.fadeIn("slow");
      }, 250);
    },

    _hideLoadingIndicator: function () {
      clearTimeout(this.loadingIndicatorTimeout);
      if (this.loadingIndicator) {
        this.loadingIndicator.hide();
      }
    },

    destroy: function () {
      this.element
        .unbind('.lightbox')
        .removeData('lightbox');
    },

    open: function (anchor) {
      var viewer = (this.lightbox = this._makeDialog());

      this.setCurrentAnchor(anchor);

      viewer.dialog('option', 'show', this.options.show)
        .dialog('option', 'hide', this.options.hide)
        .dialog('option', 'buttons', this._buttons)
        .dialog('open');

      viewer.dialog('option', '_lightbox', this);
    },

    close: function () {
      if (!this.lightbox.dialog('isOpen')) {
        return;
      }
      var self = this,
        anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      // TODO: these need to be destroyed with the widget.
      viewer.dialog('close').dialog('destroy').remove();
    },

    next: function (direction) {
      this._rotate(":gt(", ":first", direction || "up");
    },

    prev: function (direction) {
      this._rotate(":lt(", ":last", direction || "down");
    },

    _anchors: function () {
      // if deemed necessary, cache selection here
      return this.element.find(this.options.selector);
    },

    _setData: function (key, value) {
      switch (key) {
      case "cursor":
        this.options[key] = value;
        this._showLoadingIndicator();
        this._display(this._loadContent(value));
        this._hideLoadingIndicator();
        break;
      }

      $.widget.prototype._setData.apply(this, arguments);
    },

    _display: function (content) {
      var anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      viewer.dialog('option', 'title', $(anchor).attr('title') + this.options.titleSuffix);

      viewer.empty();
      viewer.append(content.show());
    },

    _loadContent: function (anchor) {
      var self = this,
        content = 'BUG',
        type = this.options.type ? this.options.type : this._deriveType(anchor);

      switch (type) {
      case "image":
        content = this._element('img')
          .attr("src", anchor.href)
          .load(function (event) {
            self.lightbox.dialog('option', 'position', self.options.position);
          });
        break;
      case "flash":
      case "flashvideo":
      case "quicktime":
      case "realplayer":
      case "windowsmedia":
        $(anchor).media({
          width: this.options.width,
          height: this.options.height,
          src: anchor.href,
          autoplay: 1
        }, function (element, options) {
        }, function (element, data, options, playerName) {
          content = $(data).clone();
          $(data).media('undo');
        });
        break;
      case "iframe":
        content = this._element('iframe').attr('src', anchor.href).attr('frameborder', 0).attr('border', 0);
        break;
      case "html":
      case "dom":
        var reference = $($(anchor).attr('href'));

        content = $(reference).clone();
        break;
      case "ajax":
      case "script":
        $.ajax({
          url: anchor.href,
          type: (parseInt(self.options.post, 10) === 1) ? "POST" : "GET",
          cache: true,
          async: false,
          data: self.options.parameters,
          dataType: (type === "ajax") ? "html" : "script",
          success: function (data, textStatus) {
            content = $(data);
          }
        });
        break;
      }

      return content;
    },

    _deriveType: function (anchor) {
      var reference = anchor.href;
      if (reference.toLowerCase().match(/\.(gif|jpg|jpeg|png)(\?[0123456789]+)?$/)) {
        return "image";
      }
      if (reference.toLowerCase().match(/\.(swf)(\?[0123456789]+)?$/)) {
        return "flash";
      }
      if (reference.toLowerCase().match(/\.(flv)(\?[0123456789]+)?$/)) {
        return "flashvideo";
      }
      if (reference.toLowerCase().match(/\.(aif|aiff|aac|au|bmp|gsm|mov|mid|midi|mpg|mpeg|m4a|m4v|mp4|psd|qt|qtif|qif|qti|snd|tif|tiff|wav|3g2|3gp|wbmp)(\?[0123456789]+)?$/)) {
        return "quicktime";
      }
      if (reference.toLowerCase().match(/\.(ra|ram|rm|rpm|rv|smi|smil)(\?[0123456789]+)?$/)) {
        return "realplayer";
      }
      if (reference.toLowerCase().match(/\.(asf|avi|wma|wmv)(\?[0123456789]+)?$/)) {
        return "windowsmedia";
      }
      return "ajax";
    },

    _preloadNeighbours: function () {
      var anchors = this._anchors(),
        index = anchors.index(this.getCurrentAnchor());
      anchors.filter(this._neighbours(anchors.length, index)).each(function () {
        //new Image().src = this.href;
      });
    },

    _neighbours: function (index, length) {
      return ":eq(" + (index === 0 ? length - 1 : index - 1) + "), :eq(" + (index === length - 1 ? 0 : index + 1) + ")";
    },

    _position: function (img) {
    },

    _resize: function (content) {
      var viewer = this.lightbox,
        dialog = this.lightbox.data('dialog'),
        offset = 20,
        type = this._deriveType(this.getCurrentAnchor()),
        cWidth,cHeight,finalWidth,finalHeight,
        // difference
        deltaContentWidth = viewer.outerWidth() - viewer.width(),
        deltaContentHeight = viewer.outerHeight() - viewer.height(),

        dialogTitlebarWidth = dialog.uiDialogTitlebar.outerWidth(),
        dialogTitlebarHeight = dialog.uiDialogTitlebar.outerHeight(),

        // Window
        wWidth = $(window).width(),
        wHeight = $(window).height(),

        size = (this.size = {});

      $.swap(content[0], {
        position: "absolute",
        visibility: "hidden",
        display: "block"
      }, function () {
        cWidth = $(this).attr('width') || $(this).width(),
        cHeight = $(this).attr('height') || $(this).height();
      });

      // Desired width
      finalWidth = cWidth + deltaContentWidth,
      finalHeight = cHeight + deltaContentHeight + dialogTitlebarHeight,

      ratio = Math.min(
        Math.min(
          Math.min(wWidth - deltaContentWidth - offset, cWidth) / cWidth,
          Math.min(wHeight - deltaContentHeight - dialogTitlebarHeight - offset, cHeight) / cHeight, 1)),

      $.extend(size, {
        width: Math.round(ratio * cWidth),
        height: Math.round(ratio * cHeight)
      });

      if (type == 'image') {
        content.css('width', size.width);
        content.css('height', size.height);
      }

      viewer.dialog('option', 'width', size.width + deltaContentWidth);
      viewer.dialog('option', 'height', size.height + deltaContentHeight + dialogTitlebarHeight);
      viewer.css({
        width: size.width + deltaContentWidth,
        height: size.height + deltaContentHeight
      });
    },

    setCurrentAnchor: function (anchor) {
      this._setData('cursor', anchor);
    },
    getCurrentAnchor: function () {
      return this._getData('cursor');
    },

    _rotate: function (selectorA, selectorB, direction) {
      var self = this,
        content,
        anchors = this._anchors(),
        target = current = this.getCurrentAnchor(),
        viewer = this.lightbox,
        dialog = viewer.data('dialog').uiDialog;

      if (!this.getCurrentAnchor()) {
        console.log('Called _rotate without an anchor');
        return;
      }

      if (anchors.length === 1) {
        return;
      }

      target = anchors.filter(selectorA + anchors.index(current) + ")" + selectorB)[0];
      if (!target && this.options.loop && anchors.length > 1) {
        target = anchors.filter(selectorB)[0];
      }

      dialog.hide(this.options.rotateOut, {
        direction: direction
      }, this.options.duration, function () {
        viewer.dialog('close');
        self.setCurrentAnchor(target);
        $(this).show(self.options.rotateIn, {
          direction: {
            up: "down",
            down: "up",
            left: "right",
            right: "left"
          }[direction]
        }, self.options.duration, function () {
          viewer.dialog('open');
        });
      });
    },

    _element: function (type, clazz) {
      return $("<" + type + "/>").addClass(clazz).hide();
    }
  });

  $.extend($.ui.lightbox, {
    defaults: {
      loop: true,
      overlay: true,
      post: 0,
      dialogClass: 'ui-lightbox',
      closeOnEscape: true,
      resizable: false,
      draggable: false,
      selector: "a[href]:has(img[src])",
      titleSuffix: "",
      position: 'center',
      width: 'auto',
      height: 'auto',
      parameters: {},
      duration: 1000,
      rotateIn: 'slide',
      rotateOut: 'slide',
      show: '',
      hide: ''
    }
  });
})(jQuery);
<commit_msg>lightbox-wide overlay from ui.dialog.<commit_after>/*globals document,window,$,jQuery */
/*jslint white: true, onevar: true, undef: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true, indent: 2 */

"use strict";

/*
 * jQuery UI Lightbox
 *
 * Copyright (c) 2009 Benjamin Doherty
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Depends:
 *  ui.core.js
 *  ui.dialog.js
 *  jquery.mousewheel.js (optional)
 */
(function ($) {

  $.widget('ui.lightbox', {
    _init: function () {
      var self = this;

      // consider event delegation to make this more dynamic
      $(this.options.selector, this.element).click(function (event) {
        event.preventDefault();
        self.open(this);
      });
      $(document).keydown(function (event) {
        if (!self.lightbox.dialog('isOpen')) {
          return;
        }
        switch (event.keyCode) {
        case $.ui.keyCode.ESCAPE:
          if (self.options.closeOnEscape) {
            self.close();
          }
          break;
        case $.ui.keyCode.LEFT:
          self.prev("left");
          event.preventDefault();
          break;
        case $.ui.keyCode.UP:
          self.prev("up");
          event.preventDefault();
          break;
        case $.ui.keyCode.RIGHT:
          self.next("right");
          event.preventDefault();
          break;
        case $.ui.keyCode.DOWN:
          self.next("down");
          event.preventDefault();
          break;
        }
      });
      if ($.fn.mousewheel) {
        $(document).mousewheel(function (event, delta) {
          if (!self.lightbox.dialog('isOpen')) {
            return;
          }
          event.preventDefault();
          if (self.lightbox.is(":animated")) {
            return;
          }
          if (delta < 0) {
            self.next("down");
          }
          if (delta > 0) {
            self.prev("up");
          }
        });
      }
    },

    _makeDialog: function () {
      return $('<div/>').dialog({
        autoOpen: false,
        closeOnEscape: false,
        modal: false,
        dialogClass: this.options.dialogClass,
        position: this.options.position,
        resizable: this.options.resizable,
        draggable: this.options.draggable,
        height: this.options.height,
        width: this.options.width,
        // TODO: Support overlay by implementing focus,dragstop,resizestop
        open: function (event, ui) {
          $('.ui-dialog-buttonpane button', $(this).parents('.ui-dialog'))
            .each(function (index, domElement) {
              $(domElement).addClass('button-' + index);
            });
        },
        close: function (event, ui) {
          $(this).empty();
        }
      });
    },

    _buttons: {
      'Previous': function (eventObject) {
        $(this).dialog('option', '_lightbox').prev("right");
      },
      'Next': function (eventObject) {
        $(this).dialog('option', '_lightbox').next("right");
      }
    },

    _showLoadingIndicator: function () {
      var self = this;

      this.loadingIndicatorTimeout = setTimeout(function() {
        if (!self.loadingIndicator) {
          self.loadingIndicator = self._element("div", "ui-loading-indicator ui-corner-all").appendTo(document.body);
        }
        self.loadingIndicator.fadeIn("slow");
      }, 250);
    },

    _hideLoadingIndicator: function () {
      clearTimeout(this.loadingIndicatorTimeout);
      if (this.loadingIndicator) {
        this.loadingIndicator.hide();
      }
    },

    destroy: function () {
      (this.overlay && this.overlay.destroy());
      this.element
        .unbind('.lightbox')
        .removeData('lightbox');
    },

    open: function (anchor) {
      var viewer = (this.lightbox = this._makeDialog());

      this.overlay = this.options.modal ? new $.ui.lightbox.overlay(viewer.data('dialog')) : null;
      this.setCurrentAnchor(anchor);

      viewer.dialog('option', 'show', this.options.show)
        .dialog('option', 'hide', this.options.hide)
        .dialog('option', 'buttons', this._buttons)
        .dialog('open');

      viewer.dialog('option', '_lightbox', this);
    },

    close: function () {
      if (!this.lightbox.dialog('isOpen')) {
        return;
      }
      var self = this,
        anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      (this.overlay && this.overlay.destroy());

      $.ui.lightbox.overlay.resize();

      // TODO: these need to be destroyed with the widget.
      viewer.dialog('close').dialog('destroy').remove();
    },

    next: function (direction) {
      this._rotate(":gt(", ":first", direction || "up");
    },

    prev: function (direction) {
      this._rotate(":lt(", ":last", direction || "down");
    },

    _anchors: function () {
      // if deemed necessary, cache selection here
      return this.element.find(this.options.selector);
    },

    _setData: function (key, value) {
      switch (key) {
      case "cursor":
        this.options[key] = value;
        this._showLoadingIndicator();
        this._display(this._loadContent(value));
        this._hideLoadingIndicator();
        break;
      }

      $.widget.prototype._setData.apply(this, arguments);
    },

    _display: function (content) {
      var anchor = this.getCurrentAnchor(),
        viewer = this.lightbox;

      viewer.dialog('option', 'title', $(anchor).attr('title') + this.options.titleSuffix);

      viewer.empty();
      viewer.append(content.show());
    },

    _loadContent: function (anchor) {
      var self = this,
        content = 'BUG',
        type = this.options.type ? this.options.type : this._deriveType(anchor);

      switch (type) {
      case "image":
        content = this._element('img')
          .attr("src", anchor.href)
          .load(function (event) {
            self.lightbox.dialog('option', 'position', self.options.position);
          });
        break;
      case "flash":
      case "flashvideo":
      case "quicktime":
      case "realplayer":
      case "windowsmedia":
        $(anchor).media({
          width: this.options.width,
          height: this.options.height,
          src: anchor.href,
          autoplay: 1
        }, function (element, options) {
        }, function (element, data, options, playerName) {
          content = $(data).clone();
          $(data).media('undo');
        });
        break;
      case "iframe":
        content = this._element('iframe').attr('src', anchor.href).attr('frameborder', 0).attr('border', 0);
        break;
      case "html":
      case "dom":
        var reference = $($(anchor).attr('href'));

        content = $(reference).clone();
        break;
      case "ajax":
      case "script":
        $.ajax({
          url: anchor.href,
          type: (parseInt(self.options.post, 10) === 1) ? "POST" : "GET",
          cache: true,
          async: false,
          data: self.options.parameters,
          dataType: (type === "ajax") ? "html" : "script",
          success: function (data, textStatus) {
            content = $(data);
          }
        });
        break;
      }

      return content;
    },

    _deriveType: function (anchor) {
      var reference = anchor.href;
      if (reference.toLowerCase().match(/\.(gif|jpg|jpeg|png)(\?[0123456789]+)?$/)) {
        return "image";
      }
      if (reference.toLowerCase().match(/\.(swf)(\?[0123456789]+)?$/)) {
        return "flash";
      }
      if (reference.toLowerCase().match(/\.(flv)(\?[0123456789]+)?$/)) {
        return "flashvideo";
      }
      if (reference.toLowerCase().match(/\.(aif|aiff|aac|au|bmp|gsm|mov|mid|midi|mpg|mpeg|m4a|m4v|mp4|psd|qt|qtif|qif|qti|snd|tif|tiff|wav|3g2|3gp|wbmp)(\?[0123456789]+)?$/)) {
        return "quicktime";
      }
      if (reference.toLowerCase().match(/\.(ra|ram|rm|rpm|rv|smi|smil)(\?[0123456789]+)?$/)) {
        return "realplayer";
      }
      if (reference.toLowerCase().match(/\.(asf|avi|wma|wmv)(\?[0123456789]+)?$/)) {
        return "windowsmedia";
      }
      return "ajax";
    },

    _preloadNeighbours: function () {
      var anchors = this._anchors(),
        index = anchors.index(this.getCurrentAnchor());
      anchors.filter(this._neighbours(anchors.length, index)).each(function () {
        //new Image().src = this.href;
      });
    },

    _neighbours: function (index, length) {
      return ":eq(" + (index === 0 ? length - 1 : index - 1) + "), :eq(" + (index === length - 1 ? 0 : index + 1) + ")";
    },

    _position: function (img) {
    },

    _resize: function (content) {
      var viewer = this.lightbox,
        dialog = this.lightbox.data('dialog'),
        offset = 20,
        type = this._deriveType(this.getCurrentAnchor()),
        cWidth,cHeight,finalWidth,finalHeight,
        // difference
        deltaContentWidth = viewer.outerWidth() - viewer.width(),
        deltaContentHeight = viewer.outerHeight() - viewer.height(),

        dialogTitlebarWidth = dialog.uiDialogTitlebar.outerWidth(),
        dialogTitlebarHeight = dialog.uiDialogTitlebar.outerHeight(),

        // Window
        wWidth = $(window).width(),
        wHeight = $(window).height(),

        size = (this.size = {});

      $.swap(content[0], {
        position: "absolute",
        visibility: "hidden",
        display: "block"
      }, function () {
        cWidth = $(this).attr('width') || $(this).width(),
        cHeight = $(this).attr('height') || $(this).height();
      });

      // Desired width
      finalWidth = cWidth + deltaContentWidth,
      finalHeight = cHeight + deltaContentHeight + dialogTitlebarHeight,

      ratio = Math.min(
        Math.min(
          Math.min(wWidth - deltaContentWidth - offset, cWidth) / cWidth,
          Math.min(wHeight - deltaContentHeight - dialogTitlebarHeight - offset, cHeight) / cHeight, 1)),

      $.extend(size, {
        width: Math.round(ratio * cWidth),
        height: Math.round(ratio * cHeight)
      });

      if (type == 'image') {
        content.css('width', size.width);
        content.css('height', size.height);
      }

      viewer.dialog('option', 'width', size.width + deltaContentWidth);
      viewer.dialog('option', 'height', size.height + deltaContentHeight + dialogTitlebarHeight);
      viewer.css({
        width: size.width + deltaContentWidth,
        height: size.height + deltaContentHeight
      });
    },

    setCurrentAnchor: function (anchor) {
      this._setData('cursor', anchor);
    },
    getCurrentAnchor: function () {
      return this._getData('cursor');
    },

    _rotate: function (selectorA, selectorB, direction) {
      var self = this,
        content,
        anchors = this._anchors(),
        target = current = this.getCurrentAnchor(),
        viewer = this.lightbox,
        dialog = viewer.data('dialog').uiDialog;

      if (!this.getCurrentAnchor()) {
        console.log('Called _rotate without an anchor');
        return;
      }

      if (anchors.length === 1) {
        return;
      }

      target = anchors.filter(selectorA + anchors.index(current) + ")" + selectorB)[0];
      if (!target && this.options.loop && anchors.length > 1) {
        target = anchors.filter(selectorB)[0];
      }

      dialog.hide(this.options.rotateOut, {
        direction: direction
      }, this.options.duration, function () {
        viewer.dialog('close');
        self.setCurrentAnchor(target);
        $(this).show(self.options.rotateIn, {
          direction: {
            up: "down",
            down: "up",
            left: "right",
            right: "left"
          }[direction]
        }, self.options.duration, function () {
          viewer.dialog('open');
        });
      });
    },

    _element: function (type, clazz) {
      return $("<" + type + "/>").addClass(clazz).hide();
    }
  });

  $.extend($.ui.lightbox, {
    defaults: {
      loop: true,
      modal: true,
      overlay: {},
      post: 0,
      dialogClass: 'ui-lightbox',
      closeOnEscape: true,
      resizable: false,
      draggable: false,
      selector: "a[href]:has(img[src])",
      titleSuffix: "",
      position: 'center',
      width: 'auto',
      height: 'auto',
      parameters: {},
      duration: 1000,
      rotateIn: 'slide',
      rotateOut: 'slide',
      show: '',
      hide: ''
    },
    uuid: 0,
    overlay: function (dialog) {
      this.$el = $.ui.lightbox.overlay.create(dialog);
    }
  });

  $.extend($.ui.lightbox.overlay, $.ui.dialog.overlay, {});

  $.extend($.ui.lightbox.overlay.prototype, $.ui.dialog.overlay.prototype, {
    destroy: function() {
      $.ui.lightbox.overlay.destroy(this.$el);
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>const OMeta = imports.standalone;
const Utils = imports.Utils;

//
let _commands = {};
let _registerCommand = function(name, callback) { _commands[name] = callback; };
let executeCommand = function(name, data, callback) {
  try {
    if (!_commands[name]) throw new Error('Unknown command: ' + name);
    let ret = _commands[name](data);
    callback(null, ret);
  } catch (error) {
    callback(error);
  }
};

//
let _compilers = {
  OMeta: {
    generatedCode: null,
    map: JSON.parse(Utils.loadFile('standalone.js.map')),
    rule: 'topLevel',
    run: function(rule, input) {
      return OMeta.BSOMetaJSParser.matchAllStructure(input, rule, undefined);
    },
  },
};

// Create a new compiler and store it.
_registerCommand('compile', function(data) {
  resetSourceMap();

  let result = null;
  let structure = null;
  OMeta.BSOMetaJSParser.matchAll(data.source, "topLevel", undefined, function(err, struct, tree) {
    if (err)
      throw err;

    structure = struct;
    OMeta.BSOMetaJSTranslator.match(tree, "trans", undefined, function(err, struct, code) {
      if (err) {
        log("Translation error - please tell Alex about this!");
        throw err;
      }
      result = code;
    });
  });

  _compilers[data.name] = {
    generatedCode: result,
    structure: structure,
    map: getSourceMap(),
  };

  // TODO: return map
  return _compilers[data.name].map;
});

_registerCommand('compiler-configure', function(data) {
  _compilers[data.name].rule = data.main.rule;
  _compilers[data.name].run = eval(['(function () { ', result, '; return function(rule, input) { return', data.main.variable, '.matchAll(input, rule, undefined); }; })()'].join(''));
});

let _findMatchingStructureChild = function(parent, startOffset, endOffset) {
  for (let i = 0; i < parent.children.length; i++) {
    let child = parent.children[i];
    if (child.start.idx <= startOffset && child.stop.idx >= endOffset)
      return child;
  }
  return null;
};
let _getMatchStructure = function(structure, startOffset, endOffset) {
  let matches = [], child = structure;
  let iter = 0;
  do {
    for (let i = 0; i < child.ids.length; i++)
      matches.unshift({ id: child.ids[i], start: child.start, stop: child.stop, value: child.value });
    child = _findMatchingStructureChild(child, startOffset, endOffset);
    iter++;
  } while (child);
  return matches;
};
let _bestNamedStructureMatch = function(matches) {
  for (let i = 0; i < matches.length; i++)
    if (matches[i].id != -1 &&
        (matches[i].stop.idx - matches[i].start.idx) >= 2)
      return [i, matches[i]];
  return [matches.length - 1, matches[matches.length - 1]];
};

let _structures = {};
let _matchedStructures = {};
// Match a structre given a particular region.
_registerCommand('match-structure', function(data) {
  let structure = _structures[data.input];
  let matches = _getMatchStructure(structure, data.offset.start, data.offset.end);
  _matchedStructures[data.output] = matches;
  return matches.length;
});

// Get the best match.
_registerCommand('get-best-match', function(data) {
  let ret = _bestNamedStructureMatch(_matchedStructures[data.input]);
  return [ret[0], Utils.copyObjectBut(ret[1], 'children')];
});

// Get a matched structure.
_registerCommand('get-match', function(data) {
  let matches = _matchedStructures[data.input];
  let idx = Utils.clamp(data.index, 0, matches.length - 1);
  return [idx, Utils.copyObjectBut(matches[idx], 'children')];
});

// Translate input to output for a given compiler.
_registerCommand('translate', function(data) {
  let compiler = _compilers[data.name];
  _structures[data.output] = compiler.run(data.rule, data.input);
  return true;
});

// Find main rule & compiler variable from offset.
_registerCommand('find-compiler', function(data) {
  let structure = _structures[data.input];
  let matches = _getMatchStructure(structure, data.offset.start, data.offset.end);
  let ret = { variable: null, rule: null };
  for (let i in matches) {
    let val = matches[i].value;
    if (val) {
      if (val[1] == 'Rule')
        ret.rule = val[2];
      else if (val[0] == 'assignVar') {
        ret.variable = val[1];
        break;
      }
    }
  }
  return ret;
});
<commit_msg>ui: ui-helper: remove unnamed nodes from structure matching<commit_after>const OMeta = imports.standalone;
const Utils = imports.Utils;

//
let _commands = {};
let _registerCommand = function(name, callback) { _commands[name] = callback; };
let executeCommand = function(name, data, callback) {
  try {
    if (!_commands[name]) throw new Error('Unknown command: ' + name);
    let ret = _commands[name](data);
    callback(null, ret);
  } catch (error) {
    callback(error);
  }
};

//
let _compilers = {
  OMeta: {
    generatedCode: null,
    map: JSON.parse(Utils.loadFile('standalone.js.map')),
    rule: 'topLevel',
    run: function(rule, input) {
      return OMeta.BSOMetaJSParser.matchAllStructure(input, rule, undefined);
    },
  },
};

// Create a new compiler and store it.
_registerCommand('compile', function(data) {
  resetSourceMap();

  let result = null;
  let structure = null;
  OMeta.BSOMetaJSParser.matchAll(data.source, "topLevel", undefined, function(err, struct, tree) {
    if (err)
      throw err;

    structure = struct;
    OMeta.BSOMetaJSTranslator.match(tree, "trans", undefined, function(err, struct, code) {
      if (err) {
        log("Translation error - please tell Alex about this!");
        throw err;
      }
      result = code;
    });
  });

  _compilers[data.name] = {
    generatedCode: result,
    structure: structure,
    map: getSourceMap(),
  };

  // TODO: return map
  return _compilers[data.name].map;
});

_registerCommand('compiler-configure', function(data) {
  _compilers[data.name].rule = data.main.rule;
  _compilers[data.name].run = eval(['(function () { ', result, '; return function(rule, input) { return', data.main.variable, '.matchAll(input, rule, undefined); }; })()'].join(''));
});

let _findMatchingStructureChild = function(parent, startOffset, endOffset) {
  for (let i = 0; i < parent.children.length; i++) {
    let child = parent.children[i];
    if (child.start.idx <= startOffset && child.stop.idx >= endOffset)
      return child;
  }
  return null;
};
let _getMatchStructure = function(structure, startOffset, endOffset) {
  let matches = [], child = structure;
  let iter = 0;
  do {
    for (let i = 0; i < child.ids.length; i++)
      if (child.ids[i] != -1 && child.start.idx <= startOffset && child.stop.idx >= endOffset)
        matches.unshift({ id: child.ids[i], start: child.start, stop: child.stop, value: child.value });
    child = _findMatchingStructureChild(child, startOffset, endOffset);
    iter++;
  } while (child);
  return matches;
};
let _bestNamedStructureMatch = function(matches) {
  for (let i = 0; i < matches.length; i++)
    if ((matches[i].stop.idx - matches[i].start.idx) >= 2)
      return [i, matches[i]];
  return [matches.length - 1, matches[matches.length - 1]];
};

let _structures = {};
let _matchedStructures = {};
// Match a structre given a particular region.
_registerCommand('match-structure', function(data) {
  let structure = _structures[data.input];
  let matches = _getMatchStructure(structure, data.offset.start, data.offset.end);
  _matchedStructures[data.output] = matches;
  return matches.length;
});

// Get the best match.
_registerCommand('get-best-match', function(data) {
  let ret = _bestNamedStructureMatch(_matchedStructures[data.input]);
  return [ret[0], Utils.copyObjectBut(ret[1], 'children')];
});

// Get a matched structure.
_registerCommand('get-match', function(data) {
  let matches = _matchedStructures[data.input];
  let idx = Utils.clamp(data.index, 0, matches.length - 1);
  return [idx, Utils.copyObjectBut(matches[idx], 'children')];
});

// Translate input to output for a given compiler.
_registerCommand('translate', function(data) {
  let compiler = _compilers[data.name];
  _structures[data.output] = compiler.run(data.rule, data.input);
  return true;
});

// Find main rule & compiler variable from offset.
_registerCommand('find-compiler', function(data) {
  let structure = _structures[data.input];
  let matches = _getMatchStructure(structure, data.offset.start, data.offset.end);
  let ret = { variable: null, rule: null };
  for (let i in matches) {
    let val = matches[i].value;
    if (val) {
      if (val[1] == 'Rule')
        ret.rule = val[2];
      else if (val[0] == 'assignVar') {
        ret.variable = val[1];
        break;
      }
    }
  }
  return ret;
});
<|endoftext|>


<commit_before>function save () {
    var self = this;
}

function remove () {
    var self = this;
}

function cancel () {
    var self = this;
}

function init () {
    var self = this;

    self.on('uiSave', save);
    self.on('uiRm', remove);
    self.on('uiCancel', cancel);
}

module.exports = init;
<commit_msg>auto generated mono wrapping code<commit_after>M.wrap('github/jillix/bind-form/dev/ui/controls.js', function (require, module, exports) {
function save () {
    var self = this;
}

function remove () {
    var self = this;
}

function cancel () {
    var self = this;
}

function init () {
    var self = this;

    self.on('uiSave', save);
    self.on('uiRm', remove);
    self.on('uiCancel', cancel);
}

module.exports = init;

return module; });<|endoftext|>


<commit_before>if(window.confirm('Are you a terrorist or otherwise associated with ISIS?')) {
  document.write('');
	document.write('


<commit_before>import assert from 'assert';
import { Adapters } from '../src/utils';

describe.only('Adapters', () => {

  it("doesnt return something undefined", () => {
    assert.equal(Adapters.somethingNotDefined, undefined);
  });

  it('returns scrollCalc', () => {
    assert.equal(typeof Adapters.scrollCalc, 'function');
  });

  it('returns vchange', () => {
    assert(Adapters.vchange);
  });

  it('returns vhidden', () => {
    assert(Adapters.vhidden);
  });

});
<commit_msg>revert line for testing<commit_after>import assert from 'assert';
import { Adapters } from '../src/utils';

describe('Adapters', () => {

  it("doesnt return something undefined", () => {
    assert.equal(Adapters.somethingNotDefined, undefined);
  });

  it('returns scrollCalc', () => {
    assert.equal(typeof Adapters.scrollCalc, 'function');
  });

  it('returns vchange', () => {
    assert(Adapters.vchange);
  });

  it('returns vhidden', () => {
    assert(Adapters.vhidden);
  });

});
<|endoftext|>


<commit_before>'use strict';
const expect = require('chai').expect;
const sinon = require('sinon');
const BootBot = require('../lib/BootBot');

describe('BootBot', () => {
  let server;
  let userId;
  let bot;

  beforeEach(() => {
    const options = {
      accessToken: '1234',
      verifyToken: '5678',
      appSecret: 'foobar'
    };
    userId = 1234;
    bot = new BootBot(options);
    server = sinon.fakeServer.create();
    server.autoRespond = true;
  });

  afterEach(() => {
    server.restore();
  });

  it('creates a bot instance', () => {
    expect(bot instanceof BootBot).to.equal(true);
  });

  it('throws an error if there are missing tokens', () => {
    expect(() => new BootBot()).to.throw(Error);
  });

  it('can send a text message', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Hello world!';
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        text
      }
    };

    bot.sendTextMessage(userId, text);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a text message with quick replies', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Hello world!';

    // Quick Replies as strings with auto-generated payload
    const quickReplies1 = ['Red', 'Green', 'Blue'];
    const expected1 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'text',
          title: 'Red',
          payload: 'BOOTBOT_QR_RED'
        }, {
          content_type: 'text',
          title: 'Green',
          payload: 'BOOTBOT_QR_GREEN'
        }, {
          content_type: 'text',
          title: 'Blue',
          payload: 'BOOTBOT_QR_BLUE'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies1);
    expect(spy.calledWith(expected1)).to.equal(true);

    // Quick Replies as objects with partial information
    const quickReplies2 = [{
      title: 'Purple'
    }, {
      title: 'Yellow',
      payload: 'CUSTOM_YELLOW'
    }, {
      title: 'Image',
      image_url: 'http://google.com/image.png'
    }];
    const expected2 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'text',
          title: 'Purple',
          payload: 'BOOTBOT_QR_PURPLE'
        }, {
          content_type: 'text',
          title: 'Yellow',
          payload: 'CUSTOM_YELLOW'
        }, {
          content_type: 'text',
          title: 'Image',
          payload: 'BOOTBOT_QR_IMAGE',
          image_url: 'http://google.com/image.png'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies2);
    expect(spy.calledWith(expected2)).to.equal(true);

    // Quick Replies as custom object
    const quickReplies3 = [{
      content_type: 'location'
    }, {
      content_type: 'bootbot',
      payload: 'THIS_IS_JUST_A_TEST'
    }, {
      foo: 'bar'
    }];
    const expected3 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'location'
        }, {
          content_type: 'bootbot',
          payload: 'THIS_IS_JUST_A_TEST'
        }, {
          foo: 'bar'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies3);
    expect(spy.calledWith(expected3)).to.equal(true);
  });

  it('can send a button template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Choose an option';
    const buttons = [
      { type: 'postback', title: 'Red', payload: 'COLOR_RED' },
      { type: 'postback', title: 'Green', payload: 'COLOR_GREEN' },
      { type: 'postback', title: 'Blue', payload: 'COLOR_BLUE' }
    ];
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'button',
            text,
            buttons
          }
        }
      }
    };

    bot.sendButtonTemplate(userId, text, buttons);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a generic template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const elements = [
      {
        "title": "Welcome to Peter\'s Hats",
        "image_url": "http://petersapparel.parseapp.com/img/item100-thumb.png",
        "subtitle": "We\'ve got the right hat for everyone.",
        "buttons": [
          {
            "type": "web_url",
            "url": "https://petersapparel.parseapp.com/view_item?item_id=100",
            "title": "View Website"
          },
          {
            "type": "postback",
            "title": "Start Chatting",
            "payload": "USER_DEFINED_PAYLOAD"
          }
        ]
      }
    ];
    const options = {
      imageAspectRatio: 'horizontal'
    };
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'generic',
            image_aspect_ratio: 'horizontal',
            elements
          }
        }
      }
    };

    bot.sendGenericTemplate(userId, elements, options);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a list template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const elements = [{
      "title": "Classic T-Shirt Collection",
      "image_url": "https://peterssendreceiveapp.ngrok.io/img/collection.png",
      "subtitle": "See all our colors",
      "default_action": {
        "type": "web_url",
        "url": "https://peterssendreceiveapp.ngrok.io/shop_collection",
        "messenger_extensions": true,
        "webview_height_ratio": "tall",
        "fallback_url": "https://peterssendreceiveapp.ngrok.io/"
      },
      "buttons": [{
        "title": "View",
        "type": "web_url",
        "url": "https://peterssendreceiveapp.ngrok.io/collection",
        "messenger_extensions": true,
        "webview_height_ratio": "tall",
        "fallback_url": "https://peterssendreceiveapp.ngrok.io/"
      }]
    }];
    const buttons = [{
      "title": "View More",
      "type": "postback",
      "payload": "payload"
    }]
    const options = {
      topElementStyle: 'compact'
    };
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'list',
            top_element_style: 'compact',
            elements,
            buttons
          }
        }
      }
    };

    bot.sendListTemplate(userId, elements, buttons, options);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send an attachment', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const type = 'image';
    const url = 'http://petersapparel.parseapp.com/img/item100-thumb.png';
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type,
          payload: {
            url
          }
        }
      }
    };

    bot.sendAttachment(userId, type, url);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('emits a referral event', () => {
    const callback = sinon.spy();
    const event = {
      "sender": {
        "id": "USER_ID"
      },
      "recipient": {
        "id": "PAGE_ID"
      },
      "timestamp": 1458692752478,
      "referral": {
        "ref": "MY_REF",
        "source": "SHORTLINK",
        "type": "OPEN_THREAD"
      }
    };
    bot.on('referral', callback);
    bot._handleEvent('referral', event);
    expect(callback.calledWith(event)).to.equal(true);
  });

  describe('Checkbox Plugin support', () => {
    it('uses the user_ref param as the recipient when replying to a checkbox authentication event', () => {
      const spy = sinon.spy(bot, 'sendMessage');
      const event = {
        "recipient": {
          "id": "PAGE_ID"
        },
        "timestamp": 1234567890,
        "optin": {
          "ref": "PASS_THROUGH_PARAM",
          "user_ref": "UNIQUE_REF_PARAM"
        }
      };
      const expectedRecipient = { user_ref: 'UNIQUE_REF_PARAM' };
      const expectedMessage = { text: 'hello' };

      bot.on('authentication', (payload, chat) => {
        chat.say('hello');
      });
      bot._handleEvent('authentication', event);
      expect(spy.calledWith(expectedRecipient, expectedMessage)).to.equal(true);
    });

    it('uses the sender ID if the authentication event contains one', () => {
      const spy = sinon.spy(bot, 'sendMessage');
      const event = {
        "sender": {
          "id": "USER_ID"
        },
        "recipient": {
          "id": "PAGE_ID"
        },
        "timestamp": 1234567890,
        "optin": {
          "ref":"PASS_THROUGH_PARAM"
        }
      };
      const expectedRecipient = 'USER_ID';
      const expectedMessage = { text: 'hello' };

      bot.on('authentication', (payload, chat) => {
        chat.say('hello');
      });
      bot._handleEvent('authentication', event);
      expect(spy.calledWith(expectedRecipient, expectedMessage)).to.equal(true);
    });
  });
});
<commit_msg>Added tests for Messenger Profile API<commit_after>'use strict';
const expect = require('chai').expect;
const sinon = require('sinon');
const BootBot = require('../lib/BootBot');

describe('BootBot', () => {
  let server;
  let userId;
  let bot;

  beforeEach(() => {
    const options = {
      accessToken: '1234',
      verifyToken: '5678',
      appSecret: 'foobar'
    };
    userId = 1234;
    bot = new BootBot(options);
    server = sinon.fakeServer.create();
    server.autoRespond = true;
  });

  afterEach(() => {
    server.restore();
  });

  it('creates a bot instance', () => {
    expect(bot instanceof BootBot).to.equal(true);
  });

  it('throws an error if there are missing tokens', () => {
    expect(() => new BootBot()).to.throw(Error);
  });

  it('can send a text message', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Hello world!';
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        text
      }
    };

    bot.sendTextMessage(userId, text);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a text message with quick replies', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Hello world!';

    // Quick Replies as strings with auto-generated payload
    const quickReplies1 = ['Red', 'Green', 'Blue'];
    const expected1 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'text',
          title: 'Red',
          payload: 'BOOTBOT_QR_RED'
        }, {
          content_type: 'text',
          title: 'Green',
          payload: 'BOOTBOT_QR_GREEN'
        }, {
          content_type: 'text',
          title: 'Blue',
          payload: 'BOOTBOT_QR_BLUE'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies1);
    expect(spy.calledWith(expected1)).to.equal(true);

    // Quick Replies as objects with partial information
    const quickReplies2 = [{
      title: 'Purple'
    }, {
      title: 'Yellow',
      payload: 'CUSTOM_YELLOW'
    }, {
      title: 'Image',
      image_url: 'http://google.com/image.png'
    }];
    const expected2 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'text',
          title: 'Purple',
          payload: 'BOOTBOT_QR_PURPLE'
        }, {
          content_type: 'text',
          title: 'Yellow',
          payload: 'CUSTOM_YELLOW'
        }, {
          content_type: 'text',
          title: 'Image',
          payload: 'BOOTBOT_QR_IMAGE',
          image_url: 'http://google.com/image.png'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies2);
    expect(spy.calledWith(expected2)).to.equal(true);

    // Quick Replies as custom object
    const quickReplies3 = [{
      content_type: 'location'
    }, {
      content_type: 'bootbot',
      payload: 'THIS_IS_JUST_A_TEST'
    }, {
      foo: 'bar'
    }];
    const expected3 = {
      recipient: {
        id: userId
      },
      message: {
        text,
        quick_replies: [{
          content_type: 'location'
        }, {
          content_type: 'bootbot',
          payload: 'THIS_IS_JUST_A_TEST'
        }, {
          foo: 'bar'
        }]
      }
    };

    bot.sendTextMessage(userId, text, quickReplies3);
    expect(spy.calledWith(expected3)).to.equal(true);
  });

  it('can send a button template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const text = 'Choose an option';
    const buttons = [
      { type: 'postback', title: 'Red', payload: 'COLOR_RED' },
      { type: 'postback', title: 'Green', payload: 'COLOR_GREEN' },
      { type: 'postback', title: 'Blue', payload: 'COLOR_BLUE' }
    ];
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'button',
            text,
            buttons
          }
        }
      }
    };

    bot.sendButtonTemplate(userId, text, buttons);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a generic template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const elements = [
      {
        "title": "Welcome to Peter\'s Hats",
        "image_url": "http://petersapparel.parseapp.com/img/item100-thumb.png",
        "subtitle": "We\'ve got the right hat for everyone.",
        "buttons": [
          {
            "type": "web_url",
            "url": "https://petersapparel.parseapp.com/view_item?item_id=100",
            "title": "View Website"
          },
          {
            "type": "postback",
            "title": "Start Chatting",
            "payload": "USER_DEFINED_PAYLOAD"
          }
        ]
      }
    ];
    const options = {
      imageAspectRatio: 'horizontal'
    };
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'generic',
            image_aspect_ratio: 'horizontal',
            elements
          }
        }
      }
    };

    bot.sendGenericTemplate(userId, elements, options);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send a list template', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const elements = [{
      "title": "Classic T-Shirt Collection",
      "image_url": "https://peterssendreceiveapp.ngrok.io/img/collection.png",
      "subtitle": "See all our colors",
      "default_action": {
        "type": "web_url",
        "url": "https://peterssendreceiveapp.ngrok.io/shop_collection",
        "messenger_extensions": true,
        "webview_height_ratio": "tall",
        "fallback_url": "https://peterssendreceiveapp.ngrok.io/"
      },
      "buttons": [{
        "title": "View",
        "type": "web_url",
        "url": "https://peterssendreceiveapp.ngrok.io/collection",
        "messenger_extensions": true,
        "webview_height_ratio": "tall",
        "fallback_url": "https://peterssendreceiveapp.ngrok.io/"
      }]
    }];
    const buttons = [{
      "title": "View More",
      "type": "postback",
      "payload": "payload"
    }]
    const options = {
      topElementStyle: 'compact'
    };
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type: 'template',
          payload: {
            template_type: 'list',
            top_element_style: 'compact',
            elements,
            buttons
          }
        }
      }
    };

    bot.sendListTemplate(userId, elements, buttons, options);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('can send an attachment', () => {
    const spy = sinon.spy(bot, 'sendRequest');
    const type = 'image';
    const url = 'http://petersapparel.parseapp.com/img/item100-thumb.png';
    const expected = {
      recipient: {
        id: userId
      },
      message: {
        attachment: {
          type,
          payload: {
            url
          }
        }
      }
    };

    bot.sendAttachment(userId, type, url);
    expect(spy.calledWith(expected)).to.equal(true);
  });

  it('emits a referral event', () => {
    const callback = sinon.spy();
    const event = {
      "sender": {
        "id": "USER_ID"
      },
      "recipient": {
        "id": "PAGE_ID"
      },
      "timestamp": 1458692752478,
      "referral": {
        "ref": "MY_REF",
        "source": "SHORTLINK",
        "type": "OPEN_THREAD"
      }
    };
    bot.on('referral', callback);
    bot._handleEvent('referral', event);
    expect(callback.calledWith(event)).to.equal(true);
  });

  describe('Messenger Profile API', () => {
    it('can set a greeting text', () => {
      const spy = sinon.spy(bot, 'sendProfileRequest');
      const text = 'Hello, world!';
      const expected = {
        greeting: [{
          locale: 'default',
          text
        }]
      };

      bot.setGreetingText(text);
      expect(spy.calledWith(expected)).to.equal(true);
    });

    it('can set the Get Started button', () => {
      const spy = sinon.spy(bot, 'sendProfileRequest');
      const callback = () => {};
      const expected = {
        get_started: {
          payload: 'BOOTBOT_GET_STARTED'
        }
      };

      // With a callback
      bot.setGetStartedButton(callback);
      expect(spy.calledWith(expected)).to.equal(true);

      const payload = 'CUSTOM_GET_STARTED_PAYLOAD';
      const expected2 = {
        get_started: {
          payload
        }
      };

      // With a payload
      bot.setGetStartedButton(payload);
      expect(spy.calledWith(expected)).to.equal(true);
    });

    it('can delete the Get Started button', () => {
      const spy = sinon.spy(bot, 'sendProfileRequest');
      const expected = {
        fields: [ 'get_started' ]
      };

      bot.deleteGetStartedButton();
      expect(spy.calledWith(expected, 'DELETE')).to.equal(true);
    });

    it('can set the Persistent Menu', () => {
      const spy = sinon.spy(bot, 'sendProfileRequest');
      const buttons = [
        {
          title: 'My Account',
          type: 'nested',
          call_to_actions: [
            {
              title: 'Pay Bill',
              type: 'postback',
              payload: 'PAYBILL_PAYLOAD'
            },
            {
              title: 'History',
              type: 'postback',
              payload: 'HISTORY_PAYLOAD'
            },
            {
              title: 'Contact Info',
              type: 'postback',
              payload: 'CONTACT_INFO_PAYLOAD'
            }
          ]
        },
        {
          title: 'Go to Website',
          type: 'web_url',
          url: 'http://purple.com'
        }
      ];
      const disableInput = false;
      const expected = {
        persistent_menu: [{
          locale: 'default',
          composer_input_disabled: disableInput,
          call_to_actions: buttons
        }]
      };

      bot.setPersistentMenu(buttons, disableInput);
      expect(spy.calledWith(expected)).to.equal(true);
    });

    it('can delete the Persistent Menu', () => {
      const spy = sinon.spy(bot, 'sendProfileRequest');
      const expected = {
        fields: [ 'persistent_menu' ]
      };

      bot.deletePersistentMenu();
      expect(spy.calledWith(expected, 'DELETE')).to.equal(true);
    });
  });

  describe('Checkbox Plugin support', () => {
    it('uses the user_ref param as the recipient when replying to a checkbox authentication event', () => {
      const spy = sinon.spy(bot, 'sendMessage');
      const event = {
        "recipient": {
          "id": "PAGE_ID"
        },
        "timestamp": 1234567890,
        "optin": {
          "ref": "PASS_THROUGH_PARAM",
          "user_ref": "UNIQUE_REF_PARAM"
        }
      };
      const expectedRecipient = { user_ref: 'UNIQUE_REF_PARAM' };
      const expectedMessage = { text: 'hello' };

      bot.on('authentication', (payload, chat) => {
        chat.say('hello');
      });
      bot._handleEvent('authentication', event);
      expect(spy.calledWith(expectedRecipient, expectedMessage)).to.equal(true);
    });

    it('uses the sender ID if the authentication event contains one', () => {
      const spy = sinon.spy(bot, 'sendMessage');
      const event = {
        "sender": {
          "id": "USER_ID"
        },
        "recipient": {
          "id": "PAGE_ID"
        },
        "timestamp": 1234567890,
        "optin": {
          "ref":"PASS_THROUGH_PARAM"
        }
      };
      const expectedRecipient = 'USER_ID';
      const expectedMessage = { text: 'hello' };

      bot.on('authentication', (payload, chat) => {
        chat.say('hello');
      });
      bot._handleEvent('authentication', event);
      expect(spy.calledWith(expectedRecipient, expectedMessage)).to.equal(true);
    });
  });
});
<|endoftext|>