<commit_before>/*
 *   Copyright (c) 2011-2015 The original author or authors
 *   ------------------------------------------------------
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *   You may elect to redistribute this code under either of these licenses.
 */
!function (factory) {
  if (typeof require === 'function') {
    // Even if it is in the global namespace,
    // prefer the CommonJS loader
    var SockJS = require('sockjs-client');
    if(!SockJS) {
      throw new Error('vertxbus.js requires sockjs-client, see http://sockjs.org');
    }
    factory(SockJS);
  } else if (typeof define === 'function' && define.amd) {
    // Expose as an AMD module with SockJS dependency.
    // 'vertxbus' and 'sockjs' names are used because
    // AMD module names are derived from file names.
    define('vertxbus', ['sockjs'], factory);
  } else {
    // No AMD or commonJS compliant loader
    // Verify if SockJS is already in the global context
    if (typeof this.SockJS === 'undefined') {
      // cannot continue
      throw new Error('vertxbus.js requires sockjs-client, see http://sockjs.org');
    }

    factory(this.SockJS);
  }
}(function (SockJS) {

  function makeUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (a, b) {
      return b = Math.random() * 16, (a == 'y' ? b & 3 | 8 : b | 0).toString(16);
    });
  }

  /**
   * EventBus
   *
   * @param url
   * @param options
   * @constructor
   */
  var EventBus = function (url, options) {
    var self = this;

    options = options || {};

    var pingInterval = options.vertxbus_ping_interval || 5000;
    var pingTimerID;

    // attributes
    this.sockJSConn = new SockJS(url, null, options);
    this.state = EventBus.CONNECTING;
    this.handlers = {};
    this.replyHandlers = {};

    // default event handlers
    this.onerror = console.error;

    var sendPing = function () {
      self.sockJSConn.send(JSON.stringify({type: 'ping'}));
    };

    this.sockJSConn.onopen = function () {
      // Send the first ping then send a ping every pingInterval milliseconds
      sendPing();
      pingTimerID = setInterval(sendPing, pingInterval);
      self.state = EventBus.OPEN;
      self.onopen && self.onopen();
    };

    this.sockJSConn.onclose = function () {
      self.state = EventBus.CLOSED;
      if (pingTimerID) clearInterval(pingTimerID);
      self.onclose && self.onclose();
    };

    this.sockJSConn.onmessage = function (e) {
      var json = JSON.parse(e.data);

      // define a reply function on the message itself
      if (json.replyAddress) {
        Object.defineProperty(json, 'reply', {
          value: function (message, headers, callback) {
            self.send(json.replyAddress, message, headers, callback);
          }
        });
      }

      if (self.handlers[json.address]) {
        // iterate all registered handlers
        var handlers = self.handlers[json.address];
        for (var i = 0; i < handlers.length; i++) {
          if (json.type === 'err') {
            handlers[i](json.body);
          } else {
            handlers[i](null, json);
          }
        }
      } else if (self.replyHandlers[json.address]) {
        // Might be a reply message
        var handler = self.replyHandlers[json.address];
        delete self.replyHandlers[json.address];
        if (json.type === 'err') {
          handler({failureCode: json.failureCode, failureType: json.failureType, message: json.message});
        } else {
          handler(null, json);
        }
      } else {
        if (json.type === 'err') {
          self.onerror(json);
        } else {
          console.warn('No handler found for message: ', json);
        }
      }
    }
  };

  /**
   * Send a message
   *
   * @param {String} address
   * @param {Object} message
   * @param {Object} [headers]
   * @param {Function} [callback]
   */
  EventBus.prototype.send = function (address, message, headers, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    if (typeof headers === 'function') {
      callback = headers;
      headers = {};
    }

    var envelope = {
      type: 'send',
      address: address,
      headers: headers || {},
      body: message
    };

    if (callback) {
      var replyAddress = makeUUID();
      envelope.replyAddress = replyAddress;
      this.replyHandlers[replyAddress] = callback;
    }

    this.sockJSConn.send(JSON.stringify(envelope));
  };

  /**
   * Publish a message
   *
   * @param {String} address
   * @param {Object} message
   * @param {Object} [headers]
   */
  EventBus.prototype.publish = function (address, message, headers) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    this.sockJSConn.send(JSON.stringify({
      type: 'publish',
      address: address,
      headers: headers || {},
      body: message
    }));
  };

  /**
   * Register a new handler
   *
   * @param {String} address
   * @param {Function} callback
   */
  EventBus.prototype.registerHandler = function (address, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }
    // ensure it is an array
    if (!this.handlers[address]) {
      this.handlers[address] = [];
      // First handler for this address so we should register the connection
      this.sockJSConn.send(JSON.stringify({
        type: 'register',
        address: address
      }));
    }

    this.handlers[address].push(callback);
  };

  /**
   * Unregister a handler
   *
   * @param {String} address
   * @param {Function} callback
   */
  EventBus.prototype.unregisterHandler = function (address, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    var handlers = this.handlers[address];

    if (!handlers) {
      var idx = handlers.indexOf(callback);
      if (idx != -1) {
        handlers.splice(idx, 1);
        if (handlers.length === 0) {
          // No more local handlers so we should unregister the connection
          this.sockJSConn.send(JSON.stringify({
            type: 'unregister',
            address: address
          }));

          delete this.handlers[address];
        }
      }
    }
  };

  /**
   * Closes the connection to the EvenBus Bridge.
   */
  EventBus.prototype.close = function () {
    state = vertx.EventBus.CLOSING;
    this.sockJSConn.close();
  };

  EventBus.CONNECTING = 0;
  EventBus.OPEN = 1;
  EventBus.CLOSING = 2;
  EventBus.CLOSED = 3;

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = EventBus;
    } else {
      exports.EventBus = EventBus;
    }
  } else {
    return EventBus;
  }
});<commit_msg>tested agains commonJS, AMD, WebPack and plain HTML include<commit_after>/*
 *   Copyright (c) 2011-2015 The original author or authors
 *   ------------------------------------------------------
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *   You may elect to redistribute this code under either of these licenses.
 */
!function (factory) {
  if (typeof require === 'function' && typeof module !== 'undefined') {
    // CommonJS loader
    var SockJS = require('sockjs-client');
    if(!SockJS) {
      throw new Error('vertxbus.js requires sockjs-client, see http://sockjs.org');
    }
    factory(SockJS);
  } else if (typeof define === 'function' && define.amd) {
    // AMD loader
    define('vertxbus', ['sockjs'], factory);
  } else {
    // plain old include
    if (typeof this.SockJS === 'undefined') {
      throw new Error('vertxbus.js requires sockjs-client, see http://sockjs.org');
    }

    EventBus = factory(this.SockJS);
  }
}(function (SockJS) {

  function makeUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (a, b) {
      return b = Math.random() * 16, (a == 'y' ? b & 3 | 8 : b | 0).toString(16);
    });
  }

  /**
   * EventBus
   *
   * @param url
   * @param options
   * @constructor
   */
  var EventBus = function (url, options) {
    var self = this;

    options = options || {};

    var pingInterval = options.vertxbus_ping_interval || 5000;
    var pingTimerID;

    // attributes
    this.sockJSConn = new SockJS(url, null, options);
    this.state = EventBus.CONNECTING;
    this.handlers = {};
    this.replyHandlers = {};

    // default event handlers
    this.onerror = console.error;

    var sendPing = function () {
      self.sockJSConn.send(JSON.stringify({type: 'ping'}));
    };

    this.sockJSConn.onopen = function () {
      // Send the first ping then send a ping every pingInterval milliseconds
      sendPing();
      pingTimerID = setInterval(sendPing, pingInterval);
      self.state = EventBus.OPEN;
      self.onopen && self.onopen();
    };

    this.sockJSConn.onclose = function () {
      self.state = EventBus.CLOSED;
      if (pingTimerID) clearInterval(pingTimerID);
      self.onclose && self.onclose();
    };

    this.sockJSConn.onmessage = function (e) {
      var json = JSON.parse(e.data);

      // define a reply function on the message itself
      if (json.replyAddress) {
        Object.defineProperty(json, 'reply', {
          value: function (message, headers, callback) {
            self.send(json.replyAddress, message, headers, callback);
          }
        });
      }

      if (self.handlers[json.address]) {
        // iterate all registered handlers
        var handlers = self.handlers[json.address];
        for (var i = 0; i < handlers.length; i++) {
          if (json.type === 'err') {
            handlers[i](json.body);
          } else {
            handlers[i](null, json.body);
          }
        }
      } else if (self.replyHandlers[json.address]) {
        // Might be a reply message
        var handler = self.replyHandlers[json.address];
        delete self.replyHandlers[json.address];
        if (json.type === 'err') {
          handler({failureCode: json.failureCode, failureType: json.failureType, message: json.message});
        } else {
          handler(null, json.body);
        }
      } else {
        if (json.type === 'err') {
          self.onerror(json);
        } else {
          console.warn('No handler found for message: ', json);
        }
      }
    }
  };

  /**
   * Send a message
   *
   * @param {String} address
   * @param {Object} message
   * @param {Object} [headers]
   * @param {Function} [callback]
   */
  EventBus.prototype.send = function (address, message, headers, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    if (typeof headers === 'function') {
      callback = headers;
      headers = {};
    }

    var envelope = {
      type: 'send',
      address: address,
      headers: headers || {},
      body: message
    };

    if (callback) {
      var replyAddress = makeUUID();
      envelope.replyAddress = replyAddress;
      this.replyHandlers[replyAddress] = callback;
    }

    this.sockJSConn.send(JSON.stringify(envelope));
  };

  /**
   * Publish a message
   *
   * @param {String} address
   * @param {Object} message
   * @param {Object} [headers]
   */
  EventBus.prototype.publish = function (address, message, headers) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    this.sockJSConn.send(JSON.stringify({
      type: 'publish',
      address: address,
      headers: headers || {},
      body: message
    }));
  };

  /**
   * Register a new handler
   *
   * @param {String} address
   * @param {Function} callback
   */
  EventBus.prototype.registerHandler = function (address, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }
    // ensure it is an array
    if (!this.handlers[address]) {
      this.handlers[address] = [];
      // First handler for this address so we should register the connection
      this.sockJSConn.send(JSON.stringify({
        type: 'register',
        address: address
      }));
    }

    this.handlers[address].push(callback);
  };

  /**
   * Unregister a handler
   *
   * @param {String} address
   * @param {Function} callback
   */
  EventBus.prototype.unregisterHandler = function (address, callback) {
    // are we ready?
    if (this.state != EventBus.OPEN) {
      throw new Error('INVALID_STATE_ERR');
    }

    var handlers = this.handlers[address];

    if (!handlers) {
      var idx = handlers.indexOf(callback);
      if (idx != -1) {
        handlers.splice(idx, 1);
        if (handlers.length === 0) {
          // No more local handlers so we should unregister the connection
          this.sockJSConn.send(JSON.stringify({
            type: 'unregister',
            address: address
          }));

          delete this.handlers[address];
        }
      }
    }
  };

  /**
   * Closes the connection to the EvenBus Bridge.
   */
  EventBus.prototype.close = function () {
    this.state = vertx.EventBus.CLOSING;
    this.sockJSConn.close();
  };

  EventBus.CONNECTING = 0;
  EventBus.OPEN = 1;
  EventBus.CLOSING = 2;
  EventBus.CLOSED = 3;

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = EventBus;
    } else {
      exports.EventBus = EventBus;
    }
  } else {
    return EventBus;
  }
});<|endoftext|>


<commit_before>import run from "ember-metal/run_loop";
import { Mixin as EmberMixin } from "ember-metal/mixin";
import View from "ember-views/views/view";

var parentView, view;

QUnit.module("View#nearest*", {
  teardown() {
    run(function() {
      if (parentView) { parentView.destroy(); }
      if (view) { view.destroy(); }
    });
  }
});

(function() {
  var Mixin = EmberMixin.create({});
  var Parent = View.extend(Mixin, {
    render(buffer) {
      this.appendChild(View.create());
    }
  });

  QUnit.skip("nearestOfType should find the closest view by view class", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    equal(child.nearestOfType(Parent), parentView, "finds closest view in the hierarchy by class");
  });

  QUnit.skip("nearestOfType should find the closest view by mixin", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    equal(child.nearestOfType(Mixin), parentView, "finds closest view in the hierarchy by class");
  });

  QUnit.skip("nearestWithProperty should search immediate parent", function() {
    var childView;

    view = View.create({
      myProp: true,

      render(buffer) {
        this.appendChild(View.create());
      }
    });

    run(function() {
      view.appendTo('#qunit-fixture');
    });

    childView = view.get('childViews')[0];
    equal(childView.nearestWithProperty('myProp'), view);

  });

  QUnit.skip("nearestChildOf should be deprecated", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    expectDeprecation(function() {
      child.nearestChildOf(Parent);
    }, 'nearestChildOf has been deprecated.');
  });
}());
<commit_msg>Use templates to test View.nearestTypeOf.<commit_after>import run from "ember-metal/run_loop";
import { Mixin as EmberMixin } from "ember-metal/mixin";
import View from "ember-views/views/view";
import compile from "ember-template-compiler/system/compile";

var parentView, view;

QUnit.module("View#nearest*", {
  teardown() {
    run(function() {
      if (parentView) { parentView.destroy(); }
      if (view) { view.destroy(); }
    });
  }
});

(function() {
  var Mixin = EmberMixin.create({});
  var Parent = View.extend(Mixin, {
    template: compile(`{{view}}`)
  });

  QUnit.test("nearestOfType should find the closest view by view class", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    equal(child.nearestOfType(Parent), parentView, "finds closest view in the hierarchy by class");
  });

  QUnit.test("nearestOfType should find the closest view by mixin", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    equal(child.nearestOfType(Mixin), parentView, "finds closest view in the hierarchy by class");
  });

  QUnit.test("nearestWithProperty should search immediate parent", function() {
    var childView;

    view = View.create({
      myProp: true,
      template: compile('{{view}}')
    });

    run(function() {
      view.appendTo('#qunit-fixture');
    });

    childView = view.get('childViews')[0];
    equal(childView.nearestWithProperty('myProp'), view);

  });

  QUnit.test("nearestChildOf should be deprecated", function() {
    var child;

    run(function() {
      parentView = Parent.create();
      parentView.appendTo('#qunit-fixture');
    });

    child = parentView.get('childViews')[0];
    expectDeprecation(function() {
      child.nearestChildOf(Parent);
    }, 'nearestChildOf has been deprecated.');
  });
}());
<|endoftext|>


<commit_before>/////////////////////////////////////////
//
//	MasonJS
//	Version 1.5
//	Author: Drew Dahlman ( www.drewdahlman.com )
// 	MIT License
//
/////////////////////////////////////////

(function($) {
	$.fn.mason = function(options, complete) {

		var defaults = {
			itemSelector: null,
			ratio: 0,
			sizes: [],
			columns: [
				[0, 480, 1],
				[480, 780, 2],
				[780, 1080, 3],
				[1080, 1320, 4],
				[1320, 1680, 5]
			],
			promoted: [],
			filler: {
				itemSelector: options.itemSelector,
				filler_class: 'mason_filler'
			},
			randomSizes:true,
			randomFillers:true,
			layout: 'none',
			gutter: 0
		};

		/*
		 * Complete Callback
		 */
		if (complete) {
			var callback = {
				complete: complete
			}
		}

		var elements = {
			block: {
				height: 0,
				width: 0
			},
			matrix: []
		};

		return this.each(function() {
			var settings, callbacks, $self;

			settings = $.extend(defaults, options);
			callbacks = $.extend(callback, complete);

			$self = $(this);

			/*
			 * Create Blocks and give dimensions
			 */

			function setup() {

				/*
				 * Define our container element.
				 * Note we append a clear div in order to get a height later on, VERY IMPORTANT!
				 */
				if ($self.children(".mason_clear").length < 1) {
					$self.append("

");
				}

				elements.block.height = parseFloat((($self.width() / columnSize()) / settings.ratio).toFixed(0));
				elements.block.width = parseFloat(($self.width() / columnSize()));

				// Size Elements
				sizeElements();
			};

			/*
			 * Size elements according to block size and column count
			 */

			function sizeElements() {
				var col = columnSize();

				if (col == 1) {
					$sel = $self.children(settings.itemSelector);
					$sel.height(elements.block.height);
					$sel.width(elements.block.width);
					$sel.css({
						'margin': '0px'
					});
				} else {

					/*
					 * Push our promoted sizes into our sizes array ( this is for counting )
					 */
					for (var i = 0; i < settings.promoted.length; i++) {
						settings.sizes.push([settings.promoted[i][0], settings.promoted[i][1]])
					}

					/*
					 * Loop over each element, size, place, and fill out matrix information.
					 */

					$self.children(settings.itemSelector).each(function() {
						$sel = $(this);

						// pick a random number between 0 and the length of sizes ( - the promoted size! )
						//ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
						if(settings.randomSizes){
							ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
						}else{
							ran = $sel.data("layout");
							if(typeof(ran)=='undefined' || !ran){
								ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
							}
						}
						ranSize = settings.sizes[ran];

						for (var i = 0; i < settings.promoted.length; i++) {
							if ($sel.hasClass(settings.promoted[i][2])) {
								ranSize = [settings.promoted[i][0], settings.promoted[i][1]];
								ran = (settings.sizes.length - settings.promoted.length) + i;
							}
						}

						$sel.data('size', ran);

						var h = parseFloat((elements.block.height * ranSize[1]).toFixed(2));
						h = h - (settings.gutter * 2);

						var w = parseFloat((elements.block.width * ranSize[0]));
						w = w - (settings.gutter * 2);

						$sel.height(h + 'px');
						$sel.width(w + 'px');

						$sel.css({
							'margin': (settings.gutter)
						});
					});

					/*
					 * Build a matrix of our data and space
					 * On inital build the grid is set to false
					 * we need to measure our blocks and determine
					 * what elements fall where
					 */
					var el_h = $self.height();
					var block_h = (el_h / elements.block.height);

					elements.matrix = [];
					for (var i = 0; i < block_h; i++) {
						elements.matrix[i] = [];
						for (var c = 0; c < col; c++) {
							elements.matrix[i][c] = false;
						}
					}

					/*
					 * Populate the matrix
					 */
					$self.children(settings.itemSelector).each(function() {
						$sel = $(this);
						// Start by calculating the position based on block dimensions
						// @ t = top ( row )
						// @ l = left ( column )
						var l = Math.round($sel.position().left / elements.block.width);
						var t = Math.round($sel.position().top / elements.block.height);

						// turn the data size into a number
						var s = parseFloat($sel.data('size'));

						// now determine size of the element based on block dimensions and total area
						var h = settings.sizes[s][1];
						var w = settings.sizes[s][0];
						var a = h * w;

						// Loop through the elements area and based on the size
						// populate the matrix.
						// Start with rows move to columns
						for (var i = 0; i < a; i++) {
							for (var bh = 0; bh < h; bh++) {
								elements.matrix[t + bh][l] = true;
								for (var bw = 0; bw < w; bw++) {
									elements.matrix[t + bh][l + bw] = true;
								}
							}
						}
					});

					/*
					 * Create filler blocks to seal up empty spaces based on matrix
					 * This goes column by column to analyze true / false booleans in matrix
					 */
					var fillerNum = $(settings.filler.itemSelector).length;
					for (var i = 0; i < elements.matrix.length; i++) {
						for (var c = 0; c < elements.matrix[i].length; c++) {

							/*
							 * Blank space detected
							 */
							if (elements.matrix[i][c] == false) {

								// get block dimensions
								var h = parseFloat(elements.block.height),
									w = parseFloat(elements.block.width);

								// determine position
								var x = parseFloat((i * h).toFixed(2)) + settings.gutter,
									y = parseFloat((c * w)) + settings.gutter,
									ran, filler;

								h = h - (settings.gutter * 2);
								w = w - (settings.gutter * 2);

								if(settings.randomFillers){
									ran = Math.floor(Math.random() * $(settings.filler.itemSelector).length);
								}else{
									ran =  fillerNum -1;
								}

								filler = $(settings.filler.itemSelector).eq(ran).clone();

								filler.addClass(settings.filler.filler_class);
								filler.css({
									'position': 'absolute',
									'top': x + 'px',
									'left': y + 'px',
									'height': h + 'px',
									'width': w + 'px',
									'margin': '0px'
								});

								filler.appendTo($self);
							}
						}
					}
					if (callbacks.complete != null) {
						callbacks.complete();
					}
				}
			};

			/*
			 * Determine Our Columns
			 */

			function columnSize() {
				var w = Math.floor($self.width()),
					cols = 0,
					colsCount = settings.columns.length - 1;

				if (w >= settings.columns[colsCount][1]) {
					cols = settings.columns[colsCount][2];
				} else {
					for (var i = 0; i <= colsCount; i++) {
						if (w > settings.columns[i][0] && w < settings.columns[i][1]) {
							cols = settings.columns[i][2]
						}
					}
				}
				return cols;
			};

			/*
			 * Baked in utils
			 */
			var waitForFinalEvent = (function() {
				var timers = {};
				return function(callback, ms, uniqueId) {
					if (!uniqueId) {
						uniqueId = random();
					}
					if (timers[uniqueId]) {
						clearTimeout(timers[uniqueId]);
					}
					timers[uniqueId] = setTimeout(callback, ms);
				};
			})();
			var random = function() {
				var text = "";
				var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

				for (var i = 0; i < 5; i++)
					text += possible.charAt(Math.floor(Math.random() * possible.length));

				return text;
			}
			// check layout
			if (settings.layout == "fluid") {
				$(window).resize(function() {
					$('.' + settings.filler.filler_class).remove();
					elements.matrix = [];
					waitForFinalEvent(function() {
						$('.' + settings.filler.filler_class).remove();
						setup();
					}, 150)
				});
			}
			setup();
		});
	};
})(jQuery);
<commit_msg>forgot to save...<commit_after>/////////////////////////////////////////
//
//	MasonJS
//	Version 1.5
//	Author: Drew Dahlman ( www.drewdahlman.com )
// 	MIT License
//
/////////////////////////////////////////

(function($) {
	$.fn.mason = function(options, complete) {

		var defaults = {
			itemSelector: null,
			ratio: 0,
			sizes: [],
			columns: [
				[0, 480, 1],
				[480, 780, 2],
				[780, 1080, 3],
				[1080, 1320, 4],
				[1320, 1680, 5]
			],
			promoted: [],
			filler: {
				itemSelector: options.itemSelector,
				filler_class: 'mason_filler'
			},
			randomSizes:false,
			randomFillers:false,
			layout: 'none',
			gutter: 0
		};

		/*
		 * Complete Callback
		 */
		if (complete) {
			var callback = {
				complete: complete
			}
		}

		var elements = {
			block: {
				height: 0,
				width: 0
			},
			matrix: []
		};

		return this.each(function() {
			var settings, callbacks, $self;

			settings = $.extend(defaults, options);
			callbacks = $.extend(callback, complete);

			$self = $(this);

			/*
			 * Create Blocks and give dimensions
			 */

			function setup() {

				/*
				 * Define our container element.
				 * Note we append a clear div in order to get a height later on, VERY IMPORTANT!
				 */
				if ($self.children(".mason_clear").length < 1) {
					$self.append("

");
				}

				elements.block.height = parseFloat((($self.width() / columnSize()) / settings.ratio).toFixed(0));
				elements.block.width = parseFloat(($self.width() / columnSize()));

				// Size Elements
				sizeElements();
			};

			/*
			 * Size elements according to block size and column count
			 */

			function sizeElements() {
				var col = columnSize();

				if (col == 1) {
					$sel = $self.children(settings.itemSelector);
					$sel.height(elements.block.height);
					$sel.width(elements.block.width);
					$sel.css({
						'margin': '0px'
					});
				} else {

					/*
					 * Push our promoted sizes into our sizes array ( this is for counting )
					 */
					for (var i = 0; i < settings.promoted.length; i++) {
						settings.sizes.push([settings.promoted[i][0], settings.promoted[i][1]])
					}

					/*
					 * Loop over each element, size, place, and fill out matrix information.
					 */

					$self.children(settings.itemSelector).each(function() {
						$sel = $(this);

						// pick a random number between 0 and the length of sizes ( - the promoted size! )
						//ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
						var ran;
						if(settings.randomSizes){
							ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
						}else{

							ran = $sel.data("layout");
							console.log('1'+ran);
							if(typeof(ran)=='undefined'){
								ran = Math.floor(Math.random() * (settings.sizes.length - settings.promoted.length));
							}
							console.log('2'+ran);
						}
						console.log('3'+ran);
						ranSize = settings.sizes[ran];

						for (var i = 0; i < settings.promoted.length; i++) {
							if ($sel.hasClass(settings.promoted[i][2])) {
								ranSize = [settings.promoted[i][0], settings.promoted[i][1]];
								ran = (settings.sizes.length - settings.promoted.length) + i;
							}
						}

						$sel.data('size', ran);

						var h = parseFloat((elements.block.height * ranSize[1]).toFixed(2));
						h = h - (settings.gutter * 2);

						var w = parseFloat((elements.block.width * ranSize[0]));
						w = w - (settings.gutter * 2);

						$sel.height(h + 'px');
						$sel.width(w + 'px');

						$sel.css({
							'margin': (settings.gutter)
						});
					});

					/*
					 * Build a matrix of our data and space
					 * On inital build the grid is set to false
					 * we need to measure our blocks and determine
					 * what elements fall where
					 */
					var el_h = $self.height();
					var block_h = (el_h / elements.block.height);

					elements.matrix = [];
					for (var i = 0; i < block_h; i++) {
						elements.matrix[i] = [];
						for (var c = 0; c < col; c++) {
							elements.matrix[i][c] = false;
						}
					}

					/*
					 * Populate the matrix
					 */
					$self.children(settings.itemSelector).each(function() {
						$sel = $(this);
						// Start by calculating the position based on block dimensions
						// @ t = top ( row )
						// @ l = left ( column )
						var l = Math.round($sel.position().left / elements.block.width);
						var t = Math.round($sel.position().top / elements.block.height);

						// turn the data size into a number
						var s = parseFloat($sel.data('size'));

						// now determine size of the element based on block dimensions and total area
						var h = settings.sizes[s][1];
						var w = settings.sizes[s][0];
						var a = h * w;

						// Loop through the elements area and based on the size
						// populate the matrix.
						// Start with rows move to columns
						for (var i = 0; i < a; i++) {
							for (var bh = 0; bh < h; bh++) {
								elements.matrix[t + bh][l] = true;
								for (var bw = 0; bw < w; bw++) {
									elements.matrix[t + bh][l + bw] = true;
								}
							}
						}
					});

					/*
					 * Create filler blocks to seal up empty spaces based on matrix
					 * This goes column by column to analyze true / false booleans in matrix
					 */
					var fillerNum = $(settings.filler.itemSelector).length;
					for (var i = 0; i < elements.matrix.length; i++) {
						for (var c = 0; c < elements.matrix[i].length; c++) {

							/*
							 * Blank space detected
							 */
							if (elements.matrix[i][c] == false) {

								// get block dimensions
								var h = parseFloat(elements.block.height),
									w = parseFloat(elements.block.width);

								// determine position
								var x = parseFloat((i * h).toFixed(2)) + settings.gutter,
									y = parseFloat((c * w)) + settings.gutter,
									ran, filler;

								h = h - (settings.gutter * 2);
								w = w - (settings.gutter * 2);

								if(settings.randomFillers){
									ran = Math.floor(Math.random() * $(settings.filler.itemSelector).length);
								}else{
									ran =  fillerNum -1;
								}

								filler = $(settings.filler.itemSelector).eq(ran).clone();

								filler.addClass(settings.filler.filler_class);
								filler.css({
									'position': 'absolute',
									'top': x + 'px',
									'left': y + 'px',
									'height': h + 'px',
									'width': w + 'px',
									'margin': '0px'
								});

								filler.appendTo($self);
							}
						}
					}
					if (callbacks.complete != null) {
						callbacks.complete();
					}
				}
			};

			/*
			 * Determine Our Columns
			 */

			function columnSize() {
				var w = Math.floor($self.width()),
					cols = 0,
					colsCount = settings.columns.length - 1;

				if (w >= settings.columns[colsCount][1]) {
					cols = settings.columns[colsCount][2];
				} else {
					for (var i = 0; i <= colsCount; i++) {
						if (w > settings.columns[i][0] && w < settings.columns[i][1]) {
							cols = settings.columns[i][2]
						}
					}
				}
				return cols;
			};

			/*
			 * Baked in utils
			 */
			var waitForFinalEvent = (function() {
				var timers = {};
				return function(callback, ms, uniqueId) {
					if (!uniqueId) {
						uniqueId = random();
					}
					if (timers[uniqueId]) {
						clearTimeout(timers[uniqueId]);
					}
					timers[uniqueId] = setTimeout(callback, ms);
				};
			})();
			var random = function() {
				var text = "";
				var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

				for (var i = 0; i < 5; i++)
					text += possible.charAt(Math.floor(Math.random() * possible.length));

				return text;
			}
			// check layout
			if (settings.layout == "fluid") {
				$(window).resize(function() {
					$('.' + settings.filler.filler_class).remove();
					elements.matrix = [];
					waitForFinalEvent(function() {
						$('.' + settings.filler.filler_class).remove();
						setup();
					}, 150)
				});
			}
			setup();
		});
	};
})(jQuery);
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2013 The Tagspaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */

define(function(require, exports, module) {
"use strict";

	var extensionTitle = "Standard"
	var extensionID = "perspectiveDefault";  // ID should be equal to the directory name where the ext. is located
	var extensionType =  "view";
	var extensionIcon = "icon-list";
	var extensionVersion = "1.0";
	var extensionManifestVersion = 1;
	var extensionLicense = "AGPL";

	console.debug("Loading "+extensionID);

	var TSCORE = require("tscore");

	var extensionDirectory = TSCORE.Config.getExtensionPath()+"/"+extensionID;
	var UI = undefined;

	function init() {
		console.debug("Initializing perspective "+extensionID);

		// TODO use css require extension for loading 'css!datatablescss'
		require([
			extensionDirectory+'/perspectiveUI',
			'datatables'
		 	], function(extUI) {
				UI = new extUI.ExtUI(extensionID);
				UI.buildUI();
				UI.initTable();
		});
	}

	var load = function () {
		console.debug("Loading perspective "+extensionID);

		if(UI != undefined) {
		    UI.reInitTableWithData(TSCORE.fileList);
		}

		TSCORE.hideLoadingAnimation();
	}

	var setFileFilter = function (filter) {
		$( "#"+extensionID+"FilterBox").val(filter);
		UI.fileTable.fnFilter(filter);
	}

	var clearSelectedFiles = function() {
	    TSCORE.selectedFiles = [];
	    $('#'+extensionID+'FileTable tbody tr').each(function(){
	        $(this).removeClass('ui-selected');
	    });
	}

	var getNextFile = function (filePath) {
		var nextFilePath = undefined;
		var data = UI.fileTable._('tr', {"filter":"applied"});
		data.forEach(function(entry, index) {
    		if(entry[4] == filePath) {
    			var nextIndex = index+1;
    			if(nextIndex < data.length) {
    				nextFilePath = data[nextIndex][4];
    			} else {
    				nextFilePath = data[0][4];
    			}
    		}
    		console.log("Path: "+entry[4]);
		});
		TSCORE.ViewManager.clearSelectedFiles();
		console.debug("Next file: "+nextFilePath);
		return nextFilePath;
	}

	var getPrevFile = function (filePath) {
		var prevFilePath = undefined;
		var data = UI.fileTable._('tr', {"filter":"applied"});
		data.forEach(function(entry, index) {
    		if(entry[4] == filePath) {
    			var prevIndex = index-1;
    			if(prevIndex >= 0) {
    				prevFilePath = data[prevIndex][4];
    			} else {
    				prevFilePath = data[data.length-1][4];
    			}
    		}
    		console.log("Path: "+entry[4]);
		});
		TSCORE.ViewManager.clearSelectedFiles();
		console.debug("Prev file: "+prevFilePath);
		return prevFilePath;
	}

	// Vars
	exports.Title 					= extensionTitle;
	exports.ID 						= extensionID;
	exports.Type 					= extensionType;
	exports.Icon 					= extensionIcon;
	exports.Version 				= extensionVersion;
	exports.ManifestVersion 		= extensionManifestVersion;
	exports.License 				= extensionLicense;

	// Methods
	exports.init					= init;
	exports.load					= load;
	exports.setFileFilter			= setFileFilter;
	exports.clearSelectedFiles		= clearSelectedFiles;
	exports.getNextFile				= getNextFile;
	exports.getPrevFile				= getPrevFile;

});<commit_msg>Lazy loading of the default perspective main js<commit_after>/* Copyright (c) 2012-2013 The Tagspaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */

define(function(require, exports, module) {
"use strict";

	var extensionTitle = "Standard"
	var extensionID = "perspectiveDefault";  // ID should be equal to the directory name where the ext. is located
	var extensionType =  "view";
	var extensionIcon = "icon-list";
	var extensionVersion = "1.0";
	var extensionManifestVersion = 1;
	var extensionLicense = "AGPL";

	console.debug("Loading "+extensionID);

	var TSCORE = require("tscore");

	var extensionDirectory = TSCORE.Config.getExtensionPath()+"/"+extensionID;
	var UI = undefined;

	function init() {
		console.debug("Initializing perspective "+extensionID);
	}

	var load = function () {
		console.debug("Loading perspective "+extensionID);

        // TODO use css require extension for loading 'css!datatablescss'
        require([
            extensionDirectory+'/perspectiveUI',
            'datatables'
            ], function(extUI) {
                UI = new extUI.ExtUI(extensionID);
                UI.buildUI();
                UI.initTable();
                UI.reInitTableWithData(TSCORE.fileList);
                TSCORE.hideLoadingAnimation();
            }
        );
	}

	var setFileFilter = function (filter) {
		$( "#"+extensionID+"FilterBox").val(filter);
		UI.fileTable.fnFilter(filter);
	}

	var clearSelectedFiles = function() {
	    TSCORE.selectedFiles = [];
	    $('#'+extensionID+'FileTable tbody tr').each(function(){
	        $(this).removeClass('ui-selected');
	    });
	}

	var getNextFile = function (filePath) {
		var nextFilePath = undefined;
		var data = UI.fileTable._('tr', {"filter":"applied"});
		data.forEach(function(entry, index) {
    		if(entry[4] == filePath) {
    			var nextIndex = index+1;
    			if(nextIndex < data.length) {
    				nextFilePath = data[nextIndex][4];
    			} else {
    				nextFilePath = data[0][4];
    			}
    		}
    		console.log("Path: "+entry[4]);
		});
		TSCORE.ViewManager.clearSelectedFiles();
		console.debug("Next file: "+nextFilePath);
		return nextFilePath;
	}

	var getPrevFile = function (filePath) {
		var prevFilePath = undefined;
		var data = UI.fileTable._('tr', {"filter":"applied"});
		data.forEach(function(entry, index) {
    		if(entry[4] == filePath) {
    			var prevIndex = index-1;
    			if(prevIndex >= 0) {
    				prevFilePath = data[prevIndex][4];
    			} else {
    				prevFilePath = data[data.length-1][4];
    			}
    		}
    		console.log("Path: "+entry[4]);
		});
		TSCORE.ViewManager.clearSelectedFiles();
		console.debug("Prev file: "+prevFilePath);
		return prevFilePath;
	}

	// Vars
	exports.Title 					= extensionTitle;
	exports.ID 						= extensionID;
	exports.Type 					= extensionType;
	exports.Icon 					= extensionIcon;
	exports.Version 				= extensionVersion;
	exports.ManifestVersion 		= extensionManifestVersion;
	exports.License 				= extensionLicense;

	// Methods
	exports.init					= init;
	exports.load					= load;
	exports.setFileFilter			= setFileFilter;
	exports.clearSelectedFiles		= clearSelectedFiles;
	exports.getNextFile				= getNextFile;
	exports.getPrevFile				= getPrevFile;

});<|endoftext|>


<commit_before>import m from "mithril";
import Stream from "mithril/stream";
import { assoc, prop, tap } from "ramda";
import { run } from "stags";

import { createApp, App } from "./app";
import { router } from "./router";

// Only for using Meiosis Tracer in development.
import meiosisTracer from "meiosis-tracer";

const app = createApp(router.initialRoute);

const states = Stream();
const update = Stream();

// Only for using Meiosis Tracer in development.
meiosisTracer({
  selector: "#tracer",
  rows: 30,
  streams: [{ stream: states, label: "states" }]
});

const services = [app.validate, app.onRouteChange];
const service = context =>
  services.reduce(
    (result, service) => ({
      state: run(result.state, service(result)),
      previousState: context.previousState
    }),
    context
  );

const fn = context => run(context, service, prop("state"), tap(states));

let state = fn({ state: app.initial, previousState: {} });

// update
update.map(patch =>
  run(fn({ previousState: state, state: patch(state) }), updatedState => {
    state = updatedState;
  })
);

const actions = app.Actions(update);
m.mount(document.getElementById("app"), { view: () => m(App, { state: states(), actions }) });

states.map(state => {
  m.redraw();
  router.locationBarSync(state.route);
  app.next({ state, update });
});

router.start({ navigateTo: route => update(assoc("route", route)) });
<commit_msg>Experimenting with superouter and stags<commit_after>import m from "mithril";
import Stream from "mithril/stream";
import { assoc } from "ramda";
import { run } from "stags";

import { createApp, App } from "./app";
import { router } from "./router";

// Only for using Meiosis Tracer in development.
import meiosisTracer from "meiosis-tracer";

const app = createApp(router.initialRoute);

const update = Stream();

const services = [app.validate, app.onRouteChange];
const service = context =>
  services.reduce(
    (result, service) => ({
      state: run(result.state, service(result)),
      previousState: context.previousState
    }),
    context
  ).state;

const states = Stream.scan(
  (state, patch) => service({ previousState: state, state: patch(state) }),
  service({ state: app.initial, previousState: {} }),
  update
);

// Only for using Meiosis Tracer in development.
meiosisTracer({
  selector: "#tracer",
  rows: 30,
  streams: [{ stream: states, label: "states" }]
});

const actions = app.Actions(update);
m.mount(document.getElementById("app"), { view: () => m(App, { state: states(), actions }) });

states.map(state => {
  m.redraw();
  router.locationBarSync(state.route);
  app.next({ state, update });
});

router.start({ navigateTo: route => update(assoc("route", route)) });
<|endoftext|>


<commit_before>/**
 * Kaltura style analytics reporting class
 */
( function( mw, $ ) { "use strict";

// Avoid undefined symbol for javascript response "Kaltura" from the api
window['Kaltura'] = true;

// KAnalytics Constructor
mw.KAnalytics = function( embedPlayer ){
	this.init( embedPlayer );
};

// Add analytics to the embed player:
mw.addKAnalytics = function( embedPlayer ) {
	embedPlayer.kAnalytics = new mw.KAnalytics( embedPlayer );
}

mw.KAnalytics.prototype = {

	// The version of html5 player
	version : window['MWEMBED_VERSION'],

	// Local reference to embedPlayer
	embedPlayer: null,

	// Report Set object
	reportSet : null,

	// Stores the last time we issued a seek event
	// avoids sending lots of seeks while scrubbing
	lastSeekEventTime: 0,

	bindPostFix: '.kAnalytics',

	// Start Time
	startReportTime: 0,

	kEventTypes : {
		'WIDGET_LOADED' : 1,
		'MEDIA_LOADED' : 2,
		'PLAY' : 3,
		'PLAY_REACHED_25' : 4,
		'PLAY_REACHED_50' : 5,
		'PLAY_REACHED_75' : 6,
		'PLAY_REACHED_100' : 7,
		'OPEN_EDIT' : 8,
		'OPEN_VIRAL' : 9,
		'OPEN_DOWNLOAD' : 10,
		'OPEN_REPORT' : 11,
		'BUFFER_START' : 12,
		'BUFFER_END' : 13,
		'OPEN_FULL_SCREEN' : 14,
		'CLOSE_FULL_SCREEN' : 15,
		'REPLAY' : 16,
		'SEEK' : 17,
		'OPEN_UPLOAD' : 18,
		'SAVE_PUBLISH' : 19,
		'CLOSE_EDITOR' : 20,
		'PRE_BUMPER_PLAYED' : 21,
		'POST_BUMPER_PLAYED' : 22,
		'BUMPER_CLICKED' : 23,
		'FUTURE_USE_1' : 24,
		'FUTURE_USE_2' : 25,
		'FUTURE_USE_3' : 26
	},

	/**
	 * Constructor for kAnalytics
	 *
	 * @param {Object}
	 *          embedPlayer Player to apply Kaltura analytics to.
	 * @parma {Object}
	 * 			kalturaClient Kaltura client object for the api session.
	 */
	init: function( embedPlayer ) {
		// Setup the local reference to the embed player
		this.embedPlayer = embedPlayer;
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( embedPlayer.kwidgetid );
		}
		// Remove any old bindings:
		$( embedPlayer ).unbind( this.bindPostFix );

		// Setup the initial state of some flags
		this.resetPlayerflags();

		// Add relevant hooks for reporting beacons
		this.bindPlayerEvents();
	},
	resetPlayerflags:function(){
		this._p25Once = false;
		this._p50Once = false;
		this._p75Once = false;
		this._p100Once = false;
		this.hasSeeked = false;
		this.lastSeek = 0;
	},
	/**
	 * Get the current report set
	 *
	 * @param {Number}
	 *            KalturaStatsEventType The eventType number.
	 */
	sendAnalyticsEvent: function( KalturaStatsEventKey ){
		var _this = this;
		// make sure we have a KS
		this.kClient.getKS( function( ks ){
			_this.doSendAnalyticsEvent( ks, KalturaStatsEventKey );
		});
	},
	doSendAnalyticsEvent: function( ks, KalturaStatsEventKey ){
		var _this = this;
		mw.log("KAnalytics :: doSendAnalyticsEvent > " + KalturaStatsEventKey );
		// Kalutra analytics does not collect info for ads:
		if( this.embedPlayer.evaluate('{sequenceProxy.isInSequence}') ){
			return ;
		}

		// get the id for the given event:
		var eventKeyId = this.kEventTypes[ KalturaStatsEventKey ];

		// Generate the status event
		var eventSet = {
			'eventType'			: eventKeyId,
			'clientVer'			: this.version,
			'currentPoint'		: parseInt( this.embedPlayer.currentTime * 1000 ),
			'duration'			: this.embedPlayer.getDuration(),
			'eventTimestamp'	: new Date().getTime(),
			'isFirstInSession'	: 'false',
			'objectType'		: 'KalturaStatsEvent',
			'partnerId'			: this.kClient.getPartnerId(),
			'sessionId'			: this.embedPlayer.evaluate('{configProxy.sessionId}'),
			'uiconfId'			: 0
		};

		if( isNaN( eventSet.duration )  ){
			eventSet.duration = 0;
		}

		// Set the seek condition:
		eventSet[ 'seek' ] = ( this.hasSeeked ) ? 'true' : 'false';

		// Set the 'event:entryId'
		if( this.embedPlayer.kentryid ){
			eventSet[ 'entryId' ] = this.embedPlayer.kentryid;
		} else {
			// if kentryid is not set, use the selected source url
			eventSet[ 'entryId' ] = this.embedPlayer.getSrc();
		}

		// Set the 'event:uiconfId'
		if( this.embedPlayer.kuiconfid ) {
			eventSet[ 'uiconfId' ] = this.embedPlayer.kuiconfid;
		}
		// Set the 'event:widgetId'
		if( this.embedPlayer.kwidgetid ) {
			eventSet[ 'widgetId' ] = this.embedPlayer.kwidgetid;
		}
		var flashVarEvents = {
				'playbackContext' : 'contextId',
				'originFeature' : 'featureType',
				'applicationName' : 'applicationId',
				'userId' : 'userId'
		}
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( '', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = this.embedPlayer.getKalturaConfig('', fvKey );
			}
		}

		// Add referrer parameter
		eventSet[ 'referrer' ] = encodeURIComponent( mw.getConfig('EmbedPlayer.IframeParentUrl') );

		// Add in base service and action calls:
		var eventRequest = {'service' : 'stats', 'action' : 'collect'};
		// Add event parameters
		for( var i in eventSet){
			eventRequest[ 'event:' + i] = eventSet[i];
		}

		// Send events for this player:
		$( this.embedPlayer ).trigger( 'KalturaSendAnalyticEvent', [ KalturaStatsEventKey, eventSet ] );

		// Also trigger the event on the parent document ( for audits and alternate statistic packages )
		if( window.parent['kalturaSendAnalyticEvent'] ){
			try{
				 window.parent.kalturaSendAnalyticEvent( KalturaStatsEventKey, eventSet );
			} catch( e ){

			}
		}

		// Do the api request:
		this.kClient.doRequest( eventRequest );
	},

	/**
	 * Binds player events for analytics reporting
	 */
	bindPlayerEvents: function(){

		// Setup local reference to embedPlayer
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Setup shortcut anonymous function for player bindings
		var b = function( hookName, eventType ){
			$( _this.embedPlayer ).bind( hookName + _this.bindPostFix, function(){
				_this.sendAnalyticsEvent( eventType );
			});
		};

		// When the player is ready
		b( 'widgetLoaded', 'WIDGET_LOADED' );

		// When the poster or video ( when autoplay ) media is loaded
		b( 'KalturaSupport_EntryDataReady', 'MEDIA_LOADED' );

		// When the play button is pressed or called from javascript
		b( 'firstPlay', 'PLAY' );

		// When the show Share menu is displayed
		b( 'showShareEvent', 'OPEN_VIRAL' );

		// When the show download menu is displayed
		b( 'showDownloadEvent', 'OPEN_DOWNLOAD' );

		// When the clip starts to buffer ( not all player types )
		b( 'bufferStartEvent', 'BUFFER_START' );

		// When the clip is full buffered
		b( 'bufferEndEvent', 'BUFFER_END' );

		// When the fullscreen button is pressed
		// ( presently does not register iPhone / iPad until it has js bindings )
		b( 'onOpenFullScreen', 'OPEN_FULL_SCREEN' );

		// When the close fullscreen button is pressed.
		// ( presently does not register iphone / ipad until it has js bindings )
		b( 'onCloseFullScreen', 'CLOSE_FULL_SCREEN' );

		// When the user plays (after the ondone event was fired )
		b( 'replayEvent', 'REPLAY' );

		// Bind on the seek event
		$( embedPlayer ).bind( 'seeked' + this.bindPostFix, function( seekTarget ) {
			// Don't send a bunch of seeks on scrub:
			if( _this.lastSeekEventTime == 0 ||
				_this.lastSeekEventTime + 2000	< new Date().getTime() )
			{
				_this.sendAnalyticsEvent( 'SEEK' );
			}

			// Update the last seekTime
			_this.lastSeekEventTime =  new Date().getTime();

			// Then set local seek flags
			this.hasSeeked = true;
			this.lastSeek = seekTarget;
		} );

		// Let updateTimeStats handle the currentTime monitor timing

		$( embedPlayer ).bind( 'monitorEvent' + this.bindPostFix, function(){
			_this.updateTimeStats();
		});

		/*
		 * Other kaltura event types that are presently not usable in the
		 * html5 player at this point in time:
		 *
		 * OPEN_EDIT = 8;
		 * OPEN_REPORT = 11;
		 * OPEN_UPLOAD = 18;
		 * SAVE_PUBLISH = 19;
		 * CLOSE_EDITOR = 20;
		 *
		 * PRE_BUMPER_PLAYED = 21;
		 * POST_BUMPER_PLAYED = 22;
		 * BUMPER_CLICKED = 23;
		 *
		 * FUTURE_USE_1 = 24;
		 * FUTURE_USE_2 = 25;
		 * FUTURE_USE_3 = 26;
		 */
	},

	/**
	 * Send updates for time stats
	 */
	updateTimeStats: function() {
		// Setup local references:
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Set the seek and time percent:
		var percent = embedPlayer.currentTime / embedPlayer.duration;
		var seekPercent = this.lastSeek/ embedPlayer.duration;

		// Send updates based on logic present in StatisticsMediator.as
		if( !_this._p25Once && percent >= .25  &&  seekPercent <= .25 ) {

			_this._p25Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_25' );

		} else if ( !_this._p50Once && percent >= .50 && seekPercent < .50 ) {

			_this._p50Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_50' );

		} else if( !_this._p75Once && percent >= .75 && seekPercent < .75 ) {

			_this._p75Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_75' );

		} else if(  !_this._p100Once && percent >= .98 && seekPercent < 1) {

			_this._p100Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_100' );

		}
	}
};

})( window.mw, window.jQuery );<commit_msg>wrap conditional parent iframe check<commit_after>/**
 * Kaltura style analytics reporting class
 */
( function( mw, $ ) { "use strict";

// Avoid undefined symbol for javascript response "Kaltura" from the api
window['Kaltura'] = true;

// KAnalytics Constructor
mw.KAnalytics = function( embedPlayer ){
	this.init( embedPlayer );
};

// Add analytics to the embed player:
mw.addKAnalytics = function( embedPlayer ) {
	embedPlayer.kAnalytics = new mw.KAnalytics( embedPlayer );
}

mw.KAnalytics.prototype = {

	// The version of html5 player
	version : window['MWEMBED_VERSION'],

	// Local reference to embedPlayer
	embedPlayer: null,

	// Report Set object
	reportSet : null,

	// Stores the last time we issued a seek event
	// avoids sending lots of seeks while scrubbing
	lastSeekEventTime: 0,

	bindPostFix: '.kAnalytics',

	// Start Time
	startReportTime: 0,

	kEventTypes : {
		'WIDGET_LOADED' : 1,
		'MEDIA_LOADED' : 2,
		'PLAY' : 3,
		'PLAY_REACHED_25' : 4,
		'PLAY_REACHED_50' : 5,
		'PLAY_REACHED_75' : 6,
		'PLAY_REACHED_100' : 7,
		'OPEN_EDIT' : 8,
		'OPEN_VIRAL' : 9,
		'OPEN_DOWNLOAD' : 10,
		'OPEN_REPORT' : 11,
		'BUFFER_START' : 12,
		'BUFFER_END' : 13,
		'OPEN_FULL_SCREEN' : 14,
		'CLOSE_FULL_SCREEN' : 15,
		'REPLAY' : 16,
		'SEEK' : 17,
		'OPEN_UPLOAD' : 18,
		'SAVE_PUBLISH' : 19,
		'CLOSE_EDITOR' : 20,
		'PRE_BUMPER_PLAYED' : 21,
		'POST_BUMPER_PLAYED' : 22,
		'BUMPER_CLICKED' : 23,
		'FUTURE_USE_1' : 24,
		'FUTURE_USE_2' : 25,
		'FUTURE_USE_3' : 26
	},

	/**
	 * Constructor for kAnalytics
	 *
	 * @param {Object}
	 *          embedPlayer Player to apply Kaltura analytics to.
	 * @parma {Object}
	 * 			kalturaClient Kaltura client object for the api session.
	 */
	init: function( embedPlayer ) {
		// Setup the local reference to the embed player
		this.embedPlayer = embedPlayer;
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( embedPlayer.kwidgetid );
		}
		// Remove any old bindings:
		$( embedPlayer ).unbind( this.bindPostFix );

		// Setup the initial state of some flags
		this.resetPlayerflags();

		// Add relevant hooks for reporting beacons
		this.bindPlayerEvents();
	},
	resetPlayerflags:function(){
		this._p25Once = false;
		this._p50Once = false;
		this._p75Once = false;
		this._p100Once = false;
		this.hasSeeked = false;
		this.lastSeek = 0;
	},
	/**
	 * Get the current report set
	 *
	 * @param {Number}
	 *            KalturaStatsEventType The eventType number.
	 */
	sendAnalyticsEvent: function( KalturaStatsEventKey ){
		var _this = this;
		// make sure we have a KS
		this.kClient.getKS( function( ks ){
			_this.doSendAnalyticsEvent( ks, KalturaStatsEventKey );
		});
	},
	doSendAnalyticsEvent: function( ks, KalturaStatsEventKey ){
		var _this = this;
		mw.log("KAnalytics :: doSendAnalyticsEvent > " + KalturaStatsEventKey );
		// Kalutra analytics does not collect info for ads:
		if( this.embedPlayer.evaluate('{sequenceProxy.isInSequence}') ){
			return ;
		}

		// get the id for the given event:
		var eventKeyId = this.kEventTypes[ KalturaStatsEventKey ];

		// Generate the status event
		var eventSet = {
			'eventType'			: eventKeyId,
			'clientVer'			: this.version,
			'currentPoint'		: parseInt( this.embedPlayer.currentTime * 1000 ),
			'duration'			: this.embedPlayer.getDuration(),
			'eventTimestamp'	: new Date().getTime(),
			'isFirstInSession'	: 'false',
			'objectType'		: 'KalturaStatsEvent',
			'partnerId'			: this.kClient.getPartnerId(),
			'sessionId'			: this.embedPlayer.evaluate('{configProxy.sessionId}'),
			'uiconfId'			: 0
		};

		if( isNaN( eventSet.duration )  ){
			eventSet.duration = 0;
		}

		// Set the seek condition:
		eventSet[ 'seek' ] = ( this.hasSeeked ) ? 'true' : 'false';

		// Set the 'event:entryId'
		if( this.embedPlayer.kentryid ){
			eventSet[ 'entryId' ] = this.embedPlayer.kentryid;
		} else {
			// if kentryid is not set, use the selected source url
			eventSet[ 'entryId' ] = this.embedPlayer.getSrc();
		}

		// Set the 'event:uiconfId'
		if( this.embedPlayer.kuiconfid ) {
			eventSet[ 'uiconfId' ] = this.embedPlayer.kuiconfid;
		}
		// Set the 'event:widgetId'
		if( this.embedPlayer.kwidgetid ) {
			eventSet[ 'widgetId' ] = this.embedPlayer.kwidgetid;
		}
		var flashVarEvents = {
				'playbackContext' : 'contextId',
				'originFeature' : 'featureType',
				'applicationName' : 'applicationId',
				'userId' : 'userId'
		}
		for( var fvKey in flashVarEvents){
			if( this.embedPlayer.getKalturaConfig( '', fvKey ) ){
				eventSet[ flashVarEvents[ fvKey ] ] = this.embedPlayer.getKalturaConfig('', fvKey );
			}
		}

		// Add referrer parameter
		eventSet[ 'referrer' ] = encodeURIComponent( mw.getConfig('EmbedPlayer.IframeParentUrl') );

		// Add in base service and action calls:
		var eventRequest = {'service' : 'stats', 'action' : 'collect'};
		// Add event parameters
		for( var i in eventSet){
			eventRequest[ 'event:' + i] = eventSet[i];
		}

		// Send events for this player:
		$( this.embedPlayer ).trigger( 'KalturaSendAnalyticEvent', [ KalturaStatsEventKey, eventSet ] );

		// Also trigger the event on the parent document ( for audits and alternate statistic packages )
		try {
			if( window.parent['kalturaSendAnalyticEvent'] ){
				 window.parent.kalturaSendAnalyticEvent( KalturaStatsEventKey, eventSet );
			}
		} catch( e ){
			// error in calling parent page event
		}

		// Do the api request:
		this.kClient.doRequest( eventRequest );
	},

	/**
	 * Binds player events for analytics reporting
	 */
	bindPlayerEvents: function(){

		// Setup local reference to embedPlayer
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Setup shortcut anonymous function for player bindings
		var b = function( hookName, eventType ){
			$( _this.embedPlayer ).bind( hookName + _this.bindPostFix, function(){
				_this.sendAnalyticsEvent( eventType );
			});
		};

		// When the player is ready
		b( 'widgetLoaded', 'WIDGET_LOADED' );

		// When the poster or video ( when autoplay ) media is loaded
		b( 'KalturaSupport_EntryDataReady', 'MEDIA_LOADED' );

		// When the play button is pressed or called from javascript
		b( 'firstPlay', 'PLAY' );

		// When the show Share menu is displayed
		b( 'showShareEvent', 'OPEN_VIRAL' );

		// When the show download menu is displayed
		b( 'showDownloadEvent', 'OPEN_DOWNLOAD' );

		// When the clip starts to buffer ( not all player types )
		b( 'bufferStartEvent', 'BUFFER_START' );

		// When the clip is full buffered
		b( 'bufferEndEvent', 'BUFFER_END' );

		// When the fullscreen button is pressed
		// ( presently does not register iPhone / iPad until it has js bindings )
		b( 'onOpenFullScreen', 'OPEN_FULL_SCREEN' );

		// When the close fullscreen button is pressed.
		// ( presently does not register iphone / ipad until it has js bindings )
		b( 'onCloseFullScreen', 'CLOSE_FULL_SCREEN' );

		// When the user plays (after the ondone event was fired )
		b( 'replayEvent', 'REPLAY' );

		// Bind on the seek event
		$( embedPlayer ).bind( 'seeked' + this.bindPostFix, function( seekTarget ) {
			// Don't send a bunch of seeks on scrub:
			if( _this.lastSeekEventTime == 0 ||
				_this.lastSeekEventTime + 2000	< new Date().getTime() )
			{
				_this.sendAnalyticsEvent( 'SEEK' );
			}

			// Update the last seekTime
			_this.lastSeekEventTime =  new Date().getTime();

			// Then set local seek flags
			this.hasSeeked = true;
			this.lastSeek = seekTarget;
		} );

		// Let updateTimeStats handle the currentTime monitor timing

		$( embedPlayer ).bind( 'monitorEvent' + this.bindPostFix, function(){
			_this.updateTimeStats();
		});

		/*
		 * Other kaltura event types that are presently not usable in the
		 * html5 player at this point in time:
		 *
		 * OPEN_EDIT = 8;
		 * OPEN_REPORT = 11;
		 * OPEN_UPLOAD = 18;
		 * SAVE_PUBLISH = 19;
		 * CLOSE_EDITOR = 20;
		 *
		 * PRE_BUMPER_PLAYED = 21;
		 * POST_BUMPER_PLAYED = 22;
		 * BUMPER_CLICKED = 23;
		 *
		 * FUTURE_USE_1 = 24;
		 * FUTURE_USE_2 = 25;
		 * FUTURE_USE_3 = 26;
		 */
	},

	/**
	 * Send updates for time stats
	 */
	updateTimeStats: function() {
		// Setup local references:
		var embedPlayer = this.embedPlayer;
		var _this = this;

		// Set the seek and time percent:
		var percent = embedPlayer.currentTime / embedPlayer.duration;
		var seekPercent = this.lastSeek/ embedPlayer.duration;

		// Send updates based on logic present in StatisticsMediator.as
		if( !_this._p25Once && percent >= .25  &&  seekPercent <= .25 ) {

			_this._p25Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_25' );

		} else if ( !_this._p50Once && percent >= .50 && seekPercent < .50 ) {

			_this._p50Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_50' );

		} else if( !_this._p75Once && percent >= .75 && seekPercent < .75 ) {

			_this._p75Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_75' );

		} else if(  !_this._p100Once && percent >= .98 && seekPercent < 1) {

			_this._p100Once = true;
			_this.sendAnalyticsEvent( 'PLAY_REACHED_100' );

		}
	}
};

})( window.mw, window.jQuery );<|endoftext|>


<commit_before>/*
 * blueimp Gallery Fullscreen JS
 * https://github.com/blueimp/Gallery
 *
 * Copyright 2013, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

/* global define, window, document */

;(function (factory) {
  'use strict'
  if (typeof define === 'function' && define.amd) {
    // Register as an anonymous AMD module:
    define([
      './blueimp-helper',
      './blueimp-gallery'
    ], factory)
  } else {
    // Browser globals:
    factory(
      window.blueimp.helper || window.jQuery,
      window.blueimp.Gallery
    )
  }
}(function ($, Gallery) {
  'use strict'

  $.extend(Gallery.prototype.options, {
    // Defines if the gallery should open in fullscreen mode:
    fullScreen: false
  })

  var initialize = Gallery.prototype.initialize
  var close = Gallery.prototype.close

  $.extend(Gallery.prototype, {
    getFullScreenElement: function () {
      return document.fullscreenElement ||
      document.webkitFullscreenElement ||
      document.mozFullScreenElement ||
      document.msFullscreenElement
    },

    requestFullScreen: function (element) {
      if (element.requestFullscreen) {
        element.requestFullscreen()
      } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen()
      } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen()
      } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen()
      }
    },

    exitFullScreen: function () {
      if (document.exitFullscreen) {
        document.exitFullscreen()
      } else if (document.webkitCancelFullScreen) {
        document.webkitCancelFullScreen()
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen()
      } else if (document.msExitFullscreen) {
        document.msExitFullscreen()
      }
    },

    initialize: function () {
      initialize.call(this)
      if (this.options.fullScreen && !this.getFullScreenElement()) {
        this.requestFullScreen(this.container[0])
      }
    },

    close: function () {
      if (this.getFullScreenElement() === this.container[0]) {
        this.exitFullScreen()
      }
      close.call(this)
    }

  })

  return Gallery
}))
<commit_msg>Delete blueimp-gallery-fullscreen.js<commit_after><|endoftext|>


<commit_before>'use strict';

var Ajv = require('./ajv')
  , Promise = require('./promise')
  , getAjvInstances = require('./ajv_async_instances')
  , should = require('./chai').should()
  , co = require('co')
  , setupAsync = require('ajv-async');

describe('async schemas, formats and keywords', function() {
  this.timeout(30000);
  var ajv, instances;

  beforeEach(function () {
    instances = getAjvInstances();
    ajv = instances[0];
  });

  function useCo(_ajv) {
    var async = _ajv._opts.async;
    return async == 'es7' || async == 'co*' ? identity : co;
  }

  function identity(x) { return x; }

  describe('async schemas without async elements', function() {
    it('should return result as promise', function() {
      var schema = {
        $async: true,
        type: 'string',
        maxLength: 3
      };

      return repeat(function() { return Promise.all(instances.map(test)); });

      function test(_ajv) {
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);

        return Promise.all([
          shouldBeValid(   _co(validate('abc')), 'abc' ),
          shouldBeInvalid( _co(validate('abcd')) ),
          shouldBeInvalid( _co(validate(1)) ),
        ]);
      }
    });

    it('should fail compilation if async schema is inside sync schema', function() {
      var schema = {
        properties: {
          foo: {
            $async: true,
            type: 'string',
            maxLength: 3
          }
        }
      };

      shouldThrowFunc('async schema in sync schema', function() {
        ajv.compile(schema);
      });

      schema.$async = true;

      ajv.compile(schema);
    });
  });

  describe('async formats', function() {
    beforeEach(addFormatEnglishWord);

    it('should fail compilation if async format is inside sync schema', function() {
      instances.forEach(function (_ajv) {
        var schema = {
          type: 'string',
          format: 'english_word'
        };

        shouldThrowFunc('async format in sync schema', function() {
          _ajv.compile(schema);
        });
        schema.$async = true;
        _ajv.compile(schema);
      });
    });
  });

  describe('async custom keywords', function() {
    beforeEach(function() {
      instances.forEach(function (_ajv) {
        _ajv.addKeyword('idExists', {
          async: true,
          type: 'number',
          validate: checkIdExists,
          errors: false
        });

        _ajv.addKeyword('idExistsWithError', {
          async: true,
          type: 'number',
          validate: checkIdExistsWithError,
          errors: true
        });
      });
    });

    it('should fail compilation if async keyword is inside sync schema', function() {
      instances.forEach(function (_ajv) {
        var schema = {
          type: 'object',
          properties: {
            userId: {
              type: 'integer',
              idExists: { table: 'users' }
            }
          }
        };

        shouldThrowFunc('async keyword in sync schema', function() {
          _ajv.compile(schema);
        });

        schema.$async = true;
        _ajv.compile(schema);
      });
    });

    it('should return custom error', function() {
      return Promise.all(instances.map(function (_ajv) {
        var schema = {
          $async: true,
          type: 'object',
          properties: {
            userId: {
              type: 'integer',
              idExistsWithError: { table: 'users' }
            },
            postId: {
              type: 'integer',
              idExistsWithError: { table: 'posts' }
            }
          }
        };

        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);

        return Promise.all([
          shouldBeInvalid(_co(validate({ userId: 5, postId: 10 })), [ 'id not found in table posts' ]),
          shouldBeInvalid(_co(validate({ userId: 9, postId: 25 })), [ 'id not found in table users' ])
        ]);
      }));
    });

    function checkIdExists(schema, data) {
      switch (schema.table) {
        case 'users': return check([1, 5, 8]);
        case 'posts': return check([21, 25, 28]);
        default: throw new Error('no such table');
      }

      function check(IDs) {
        return Promise.resolve(IDs.indexOf(data) >= 0);
      }
    }

    function checkIdExistsWithError(schema, data) {
      var table = schema.table;
      switch (table) {
        case 'users': return check(table, [1, 5, 8]);
        case 'posts': return check(table, [21, 25, 28]);
        default: throw new Error('no such table');
      }

      function check(_table, IDs) {
        if (IDs.indexOf(data) >= 0) return Promise.resolve(true);
        var error = {
          keyword: 'idExistsWithError',
          message: 'id not found in table ' + _table
        };
        return Promise.reject(new Ajv.ValidationError([error]));
      }
    }
  });

  describe('async referenced schemas', function() {
    beforeEach(function() {
      instances = getAjvInstances({ inlineRefs: false, extendRefs: 'ignore' });
      addFormatEnglishWord();
    });

    it('should validate referenced async schema', function() {
      var schema = {
        $async: true,
        definitions: {
          english_word: {
            $async: true,
            type: 'string',
            format: 'english_word'
          }
        },
        properties: {
          word: { $ref: '#/definitions/english_word' }
        }
      };

      return repeat(function() { return Promise.all(instances.map(function (_ajv) {
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);
        var validData = { word: 'tomorrow' };

        return Promise.all([
          shouldBeValid(   _co(validate(validData)), validData ),
          shouldBeInvalid( _co(validate({ word: 'manana' })) ),
          shouldBeInvalid( _co(validate({ word: 1 })) ),
          shouldThrow(     _co(validate({ word: 'today' })), 'unknown word' )
        ]);
      })); });
    });

    it('should validate recursive async schema', function() {
      var schema = {
        $async: true,
        definitions: {
          english_word: {
            $async: true,
            type: 'string',
            format: 'english_word'
          }
        },
        type: 'object',
        properties: {
          foo: {
            anyOf: [
              { $ref: '#/definitions/english_word' },
              { $ref: '#' }
            ]
          }
        }
      };

      return recursiveTest(schema);
    });

    it('should validate ref from referenced async schema to root schema', function() {
      var schema = {
        $async: true,
        definitions: {
          wordOrRoot: {
            $async: true,
            anyOf: [
              {
                type: 'string',
                format: 'english_word'
              },
              { $ref: '#' }
            ]
          }
        },
        type: 'object',
        properties: {
          foo: { $ref: '#/definitions/wordOrRoot' }
        }
      };

      return recursiveTest(schema);
    });

    it('should validate refs between two async schemas', function() {
      var schemaObj = {
        id: 'http://e.com/obj.json#',
        $async: true,
        type: 'object',
        properties: {
          foo: { $ref: 'http://e.com/word.json#' }
        }
      };

      var schemaWord = {
        id: 'http://e.com/word.json#',
        $async: true,
        anyOf: [
          {
            type: 'string',
            format: 'english_word'
          },
          { $ref: 'http://e.com/obj.json#' }
        ]
      };

      return recursiveTest(schemaObj, schemaWord);
    });

    it('should fail compilation if sync schema references async schema', function() {
      var schema = {
        id: 'http://e.com/obj.json#',
        type: 'object',
        properties: {
          foo: { $ref: 'http://e.com/word.json#' }
        }
      };

      var schemaWord = {
        id: 'http://e.com/word.json#',
        $async: true,
        anyOf: [
          {
            type: 'string',
            format: 'english_word'
          },
          { $ref: 'http://e.com/obj.json#' }
        ]
      };

      ajv.addSchema(schemaWord);
      ajv.addFormat('english_word', {
        async: true,
        validate: checkWordOnServer
      });

      shouldThrowFunc('async schema referenced by sync schema', function() {
        ajv.compile(schema);
      });

      schema.id = 'http://e.com/obj2.json#';
      schema.$async = true;

      ajv.compile(schema);
    });

    function recursiveTest(schema, refSchema) {
      return repeat(function() { return Promise.all(instances.map(function (_ajv) {
        if (refSchema) try { _ajv.addSchema(refSchema); } catch(e) {}
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);
        var data;

        return Promise.all([
          shouldBeValid(   _co(validate(data = { foo: 'tomorrow' })), data ),
          shouldBeInvalid( _co(validate({ foo: 'manana' })) ),
          shouldBeInvalid( _co(validate({ foo: 1 })) ),
          shouldThrow(     _co(validate({ foo: 'today' })), 'unknown word' ),
          shouldBeValid(   _co(validate(data = { foo: { foo: 'tomorrow' }})), data ),
          shouldBeInvalid( _co(validate({ foo: { foo: 'manana' }})) ),
          shouldBeInvalid( _co(validate({ foo: { foo: 1 }})) ),
          shouldThrow(     _co(validate({ foo: { foo: 'today' }})), 'unknown word' ),
          shouldBeValid(   _co(validate(data = { foo: { foo: { foo: 'tomorrow' }}})), data ),
          shouldBeInvalid( _co(validate({ foo: { foo: { foo: 'manana' }}})) ),
          shouldBeInvalid( _co(validate({ foo: { foo: { foo: 1 }}})) ),
          shouldThrow(     _co(validate({ foo: { foo: { foo: 'today' }}})), 'unknown word' )
        ]);
      })); });
    }
  });

  function addFormatEnglishWord() {
    instances.forEach(function (_ajv) {
      _ajv.addFormat('english_word', {
        async: true,
        validate: checkWordOnServer
      });
    });
  }
});

describe('async/transpile option', function() {
  it('should throw error with unknown async option', function() {
    shouldThrowFunc('bad async mode: es8', function() {
      setupAsync(new Ajv({ async: 'es8' }));
    });
  });

  it('should throw error with unknown transpile option', function() {
    shouldThrowFunc('bad transpiler: babel', function() {
      setupAsync(new Ajv({ transpile: 'babel' }));
    });

    shouldThrowFunc('bad transpiler: [object Object]', function() {
      setupAsync(new Ajv({ transpile: {} }));
    });
  });

  it('should set async option to es7 if tranpiler is nodent', function() {
    var ajv1 = setupAsync(new Ajv({ transpile: 'nodent' }));
    ajv1._opts.async .should.equal('es7');

    var ajv2 = setupAsync(new Ajv({ async: '*', transpile: 'nodent' }));
    ajv2._opts.async .should.equal('es7');
  });
});

function checkWordOnServer(str) {
  return str == 'tomorrow' ? Promise.resolve(true)
          : str == 'manana' ? Promise.resolve(false)
          : Promise.reject(new Error('unknown word'));
}

function shouldThrowFunc(message, func) {
  var err;
  should.throw(function() {
    try { func(); }
    catch(e) { err = e; throw e; }
  });

  err.message .should.equal(message);
}

function shouldBeValid(p, data) {
  return p.then(function (valid) {
    valid .should.equal(data);
  });
}

var SHOULD_BE_INVALID = 'test: should be invalid';
function shouldBeInvalid(p, expectedMessages) {
  return checkNotValid(p)
  .then(function (err) {
    err .should.be.instanceof(Ajv.ValidationError);
    err.errors .should.be.an('array');
    err.validation .should.equal(true);
    if (expectedMessages) {
      var messages = err.errors.map(function (e) {
        return e.message;
      });
      messages .should.eql(expectedMessages);
    }
  });
}

function shouldThrow(p, exception) {
  return checkNotValid(p)
  .then(function (err) {
    err.message .should.equal(exception);
  });
}

function checkNotValid(p) {
  return p.then(function (/* valid */) {
    throw new Error(SHOULD_BE_INVALID);
  })
  .catch(function (err) {
    err. should.be.instanceof(Error);
    if (err.message == SHOULD_BE_INVALID) throw err;
    return err;
  });
}

function repeat(func) {
  return func();
  // var promises = [];
  // for (var i=0; i<1000; i++) promises.push(func());
  // return Promise.all(promises);
}
<commit_msg>test: failing test for #612<commit_after>'use strict';

var Ajv = require('./ajv')
  , Promise = require('./promise')
  , getAjvInstances = require('./ajv_async_instances')
  , should = require('./chai').should()
  , co = require('co')
  , setupAsync = require('ajv-async');

describe('async schemas, formats and keywords', function() {
  this.timeout(30000);
  var ajv, instances;

  beforeEach(function () {
    instances = getAjvInstances();
    ajv = instances[0];
  });

  function useCo(_ajv) {
    var async = _ajv._opts.async;
    return async == 'es7' || async == 'co*' ? identity : co;
  }

  function identity(x) { return x; }

  describe('async schemas without async elements', function() {
    it('should return result as promise', function() {
      var schema = {
        $async: true,
        type: 'string',
        maxLength: 3
      };

      return repeat(function() { return Promise.all(instances.map(test)); });

      function test(_ajv) {
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);

        return Promise.all([
          shouldBeValid(   _co(validate('abc')), 'abc' ),
          shouldBeInvalid( _co(validate('abcd')) ),
          shouldBeInvalid( _co(validate(1)) ),
        ]);
      }
    });

    it('should fail compilation if async schema is inside sync schema', function() {
      var schema = {
        properties: {
          foo: {
            $async: true,
            type: 'string',
            maxLength: 3
          }
        }
      };

      shouldThrowFunc('async schema in sync schema', function() {
        ajv.compile(schema);
      });

      schema.$async = true;

      ajv.compile(schema);
    });
  });

  describe('async formats', function() {
    beforeEach(addFormatEnglishWord);

    it('should fail compilation if async format is inside sync schema', function() {
      instances.forEach(function (_ajv) {
        var schema = {
          type: 'string',
          format: 'english_word'
        };

        shouldThrowFunc('async format in sync schema', function() {
          _ajv.compile(schema);
        });
        schema.$async = true;
        _ajv.compile(schema);
      });
    });
  });

  describe('async custom keywords', function() {
    beforeEach(function() {
      instances.forEach(function (_ajv) {
        _ajv.addKeyword('idExists', {
          async: true,
          type: 'number',
          validate: checkIdExists,
          errors: false
        });

        _ajv.addKeyword('idExistsWithError', {
          async: true,
          type: 'number',
          validate: checkIdExistsWithError,
          errors: true
        });
      });
    });

    it('should fail compilation if async keyword is inside sync schema', function() {
      instances.forEach(function (_ajv) {
        var schema = {
          type: 'object',
          properties: {
            userId: {
              type: 'integer',
              idExists: { table: 'users' }
            }
          }
        };

        shouldThrowFunc('async keyword in sync schema', function() {
          _ajv.compile(schema);
        });

        schema.$async = true;
        _ajv.compile(schema);
      });
    });

    it('should return custom error', function() {
      return Promise.all(instances.map(function (_ajv) {
        var schema = {
          $async: true,
          type: 'object',
          properties: {
            userId: {
              type: 'integer',
              idExistsWithError: { table: 'users' }
            },
            postId: {
              type: 'integer',
              idExistsWithError: { table: 'posts' }
            }
          }
        };

        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);

        return Promise.all([
          shouldBeInvalid(_co(validate({ userId: 5, postId: 10 })), [ 'id not found in table posts' ]),
          shouldBeInvalid(_co(validate({ userId: 9, postId: 25 })), [ 'id not found in table users' ])
        ]);
      }));
    });

    function checkIdExists(schema, data) {
      switch (schema.table) {
        case 'users': return check([1, 5, 8]);
        case 'posts': return check([21, 25, 28]);
        default: throw new Error('no such table');
      }

      function check(IDs) {
        return Promise.resolve(IDs.indexOf(data) >= 0);
      }
    }

    function checkIdExistsWithError(schema, data) {
      var table = schema.table;
      switch (table) {
        case 'users': return check(table, [1, 5, 8]);
        case 'posts': return check(table, [21, 25, 28]);
        default: throw new Error('no such table');
      }

      function check(_table, IDs) {
        if (IDs.indexOf(data) >= 0) return Promise.resolve(true);
        var error = {
          keyword: 'idExistsWithError',
          message: 'id not found in table ' + _table
        };
        return Promise.reject(new Ajv.ValidationError([error]));
      }
    }
  });

  describe('async referenced schemas', function() {
    beforeEach(function() {
      instances = getAjvInstances({ inlineRefs: false, extendRefs: 'ignore' });
      addFormatEnglishWord();
    });

    it('should validate referenced async schema', function() {
      var schema = {
        $async: true,
        definitions: {
          english_word: {
            $async: true,
            type: 'string',
            format: 'english_word'
          }
        },
        properties: {
          word: { $ref: '#/definitions/english_word' }
        }
      };

      return repeat(function() { return Promise.all(instances.map(function (_ajv) {
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);
        var validData = { word: 'tomorrow' };

        return Promise.all([
          shouldBeValid(   _co(validate(validData)), validData ),
          shouldBeInvalid( _co(validate({ word: 'manana' })) ),
          shouldBeInvalid( _co(validate({ word: 1 })) ),
          shouldThrow(     _co(validate({ word: 'today' })), 'unknown word' )
        ]);
      })); });
    });

    it('should validate recursive async schema', function() {
      var schema = {
        $async: true,
        definitions: {
          english_word: {
            $async: true,
            type: 'string',
            format: 'english_word'
          }
        },
        type: 'object',
        properties: {
          foo: {
            anyOf: [
              { $ref: '#/definitions/english_word' },
              { $ref: '#' }
            ]
          }
        }
      };

      return recursiveTest(schema);
    });

    it.skip('should validate recursive ref to async sub-schema, issue #612', function() {
      var schema = {
        $async: true,
        type: 'object',
        properties: {
          foo: {
            $async: true,
            anyOf: [
              {
                type: 'string',
                format: 'english_word'
              },
              {
                type: 'object',
                properties: {
                  foo: { $ref: '#/properties/foo' }
                }
              }
            ]
          }
        }
      };

      return recursiveTest(schema);
    });

    it('should validate ref from referenced async schema to root schema', function() {
      var schema = {
        $async: true,
        definitions: {
          wordOrRoot: {
            $async: true,
            anyOf: [
              {
                type: 'string',
                format: 'english_word'
              },
              { $ref: '#' }
            ]
          }
        },
        type: 'object',
        properties: {
          foo: { $ref: '#/definitions/wordOrRoot' }
        }
      };

      return recursiveTest(schema);
    });

    it('should validate refs between two async schemas', function() {
      var schemaObj = {
        id: 'http://e.com/obj.json#',
        $async: true,
        type: 'object',
        properties: {
          foo: { $ref: 'http://e.com/word.json#' }
        }
      };

      var schemaWord = {
        id: 'http://e.com/word.json#',
        $async: true,
        anyOf: [
          {
            type: 'string',
            format: 'english_word'
          },
          { $ref: 'http://e.com/obj.json#' }
        ]
      };

      return recursiveTest(schemaObj, schemaWord);
    });

    it('should fail compilation if sync schema references async schema', function() {
      var schema = {
        id: 'http://e.com/obj.json#',
        type: 'object',
        properties: {
          foo: { $ref: 'http://e.com/word.json#' }
        }
      };

      var schemaWord = {
        id: 'http://e.com/word.json#',
        $async: true,
        anyOf: [
          {
            type: 'string',
            format: 'english_word'
          },
          { $ref: 'http://e.com/obj.json#' }
        ]
      };

      ajv.addSchema(schemaWord);
      ajv.addFormat('english_word', {
        async: true,
        validate: checkWordOnServer
      });

      shouldThrowFunc('async schema referenced by sync schema', function() {
        ajv.compile(schema);
      });

      schema.id = 'http://e.com/obj2.json#';
      schema.$async = true;

      ajv.compile(schema);
    });

    function recursiveTest(schema, refSchema) {
      return repeat(function() { return Promise.all(instances.map(function (_ajv) {
        if (refSchema) try { _ajv.addSchema(refSchema); } catch(e) {}
        var validate = _ajv.compile(schema);
        var _co = useCo(_ajv);
        var data;

        return Promise.all([
          shouldBeValid(   _co(validate(data = { foo: 'tomorrow' })), data ),
          shouldBeInvalid( _co(validate({ foo: 'manana' })) ),
          shouldBeInvalid( _co(validate({ foo: 1 })) ),
          shouldThrow(     _co(validate({ foo: 'today' })), 'unknown word' ),
          shouldBeValid(   _co(validate(data = { foo: { foo: 'tomorrow' }})), data ),
          shouldBeInvalid( _co(validate({ foo: { foo: 'manana' }})) ),
          shouldBeInvalid( _co(validate({ foo: { foo: 1 }})) ),
          shouldThrow(     _co(validate({ foo: { foo: 'today' }})), 'unknown word' ),
          shouldBeValid(   _co(validate(data = { foo: { foo: { foo: 'tomorrow' }}})), data ),
          shouldBeInvalid( _co(validate({ foo: { foo: { foo: 'manana' }}})) ),
          shouldBeInvalid( _co(validate({ foo: { foo: { foo: 1 }}})) ),
          shouldThrow(     _co(validate({ foo: { foo: { foo: 'today' }}})), 'unknown word' )
        ]);
      })); });
    }
  });

  function addFormatEnglishWord() {
    instances.forEach(function (_ajv) {
      _ajv.addFormat('english_word', {
        async: true,
        validate: checkWordOnServer
      });
    });
  }
});

describe('async/transpile option', function() {
  it('should throw error with unknown async option', function() {
    shouldThrowFunc('bad async mode: es8', function() {
      setupAsync(new Ajv({ async: 'es8' }));
    });
  });

  it('should throw error with unknown transpile option', function() {
    shouldThrowFunc('bad transpiler: babel', function() {
      setupAsync(new Ajv({ transpile: 'babel' }));
    });

    shouldThrowFunc('bad transpiler: [object Object]', function() {
      setupAsync(new Ajv({ transpile: {} }));
    });
  });

  it('should set async option to es7 if tranpiler is nodent', function() {
    var ajv1 = setupAsync(new Ajv({ transpile: 'nodent' }));
    ajv1._opts.async .should.equal('es7');

    var ajv2 = setupAsync(new Ajv({ async: '*', transpile: 'nodent' }));
    ajv2._opts.async .should.equal('es7');
  });
});

function checkWordOnServer(str) {
  return str == 'tomorrow' ? Promise.resolve(true)
          : str == 'manana' ? Promise.resolve(false)
          : Promise.reject(new Error('unknown word'));
}

function shouldThrowFunc(message, func) {
  var err;
  should.throw(function() {
    try { func(); }
    catch(e) { err = e; throw e; }
  });

  err.message .should.equal(message);
}

function shouldBeValid(p, data) {
  return p.then(function (valid) {
    valid .should.equal(data);
  });
}

var SHOULD_BE_INVALID = 'test: should be invalid';
function shouldBeInvalid(p, expectedMessages) {
  return checkNotValid(p)
  .then(function (err) {
    err .should.be.instanceof(Ajv.ValidationError);
    err.errors .should.be.an('array');
    err.validation .should.equal(true);
    if (expectedMessages) {
      var messages = err.errors.map(function (e) {
        return e.message;
      });
      messages .should.eql(expectedMessages);
    }
  });
}

function shouldThrow(p, exception) {
  return checkNotValid(p)
  .then(function (err) {
    err.message .should.equal(exception);
  });
}

function checkNotValid(p) {
  return p.then(function (/* valid */) {
    throw new Error(SHOULD_BE_INVALID);
  })
  .catch(function (err) {
    err. should.be.instanceof(Error);
    if (err.message == SHOULD_BE_INVALID) throw err;
    return err;
  });
}

function repeat(func) {
  return func();
  // var promises = [];
  // for (var i=0; i<1000; i++) promises.push(func());
  // return Promise.all(promises);
}
<|endoftext|>