<commit_before>/**
 *
 * jQuery.AjaxQueuer
 *
 * @FileName: jquery.ajaxqueuer.js
 * @Auther: Pandao
 * @version: 0.1.0
 * @License: MIT
 * Copyright@2014 all right reserved.
 */

;(function(ajaxQueuer) {

	// CommonJS/Node.js
	if(typeof require === 'function' && typeof exports === "object" && typeof module === "object") {
		ajaxQueuer(require, exports, module);
	}
	// AMD/CMD/Sea.js
	else if(typeof define === "function") {

		if(define.amd) { // for Require.js

			define(["jquery"], ajaxQueuer);

		} else { // for Sea.js
			define(ajaxQueuer);
		}
	}
	else
	{
		ajaxQueuer(function(){}, window['ajaxQueuer']={}, {});
	}

}(function(require, exports, module) {

	(function ($) {

		var ajaxQueuer = function() {

			if(arguments.length == 1 && typeof (arguments[0].length) == "undefined") {

				return new ajaxQueuer.queue([], arguments[0]);

			} else {

				return new ajaxQueuer.queue(arguments[0], arguments[1]);

			}
		};

		ajaxQueuer.queue = function(queue, options) {

			queue   = queue   || [];
			options = options || {};
			var _this = this;

			if (typeof (queue) == "object") {
				this.queue = queue;
				this.count = queue.length;
				this.nowIndex = 0;
			}

			var defaults = {
				type    : "GET",
				async   : false,           // default false
				timeout : 3000,            // global setting
				namePrefix : 'ajaxQueuer'
			};

			this.settings = $.extend(defaults, options);

			this.qid      = this.settings.namePrefix + (new Date).getTime();

			this.add = function(queue) {
				queue = queue || {};

				if(typeof (queue.length) != "undefined" && queue.length > 1)
				{
					for (var i = 0, len = queue.length; i < len; i++)
					{
						_this.count += 1;
						_this.queue.push(queue[i]);
					}
				}
				else
				{
					_this.count += 1;
					_this.queue.push(queue);
				}

				return _this;
			};

			this.async = function() {

				_this.settings.async = true;

				ajaxQueuer.prioritySort(_this);

				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.synch = function() {

				_this.settings.async = false;

				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.run = function() {
				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.last = function() {

				_this.nowIndex = _this.queue.length-1;

				ajaxQueuer.request(_this, _this.queue[_this.nowIndex], true);

				return _this;
			};

			this.getQueues = function() {
				return _this.queue;
			};

			this.stop = function() {
				_this.nowIndex = _this.queue.length;

				return _this;
			};

			return this;
		};

		ajaxQueuer.prioritySort = function(_this) {

			for (var i in _this.queue) {
				var queue = _this.queue[i];

				if(typeof (queue.priority) == "undefined") {
					queue.priority = 0;
				}
				//console.log("i : ", _this.queue[i]);
			}

			_this.queue.sort(function(a, b) {
				//console.log(a.priority, b.priority);

				return (a.priority > b.priority) ? -1 : 1;
			});
		};

		ajaxQueuer.request = function(_this, queue, isLast) {

			if (_this.nowIndex >= _this.count) return ;

			isLast = isLast || false;

			var defaults = {
				before      : new Function,
				beforeSend  : new Function,
				contentType : "application/x-www-form-urlencoded; charset=UTF-8",
				crossDomain : false,
				complete    : new Function,
				done        : false,
				data        : {},
				dataType    : "text html",
				error       : new Function,
				headers     : {},
				index       : _this.nowIndex,
				jsonp       : "callback",
				name        : _this.qid + "[" + _this.nowIndex + "]",
				processData : true,
				startTime   : (new Date).getTime(),
				statusCode  : {},
				success     : new Function,
				status      : ""
			};

			_this.queue[_this.nowIndex] = queue = $.extend(defaults, queue);

			queue.before(queue);

			var async = (typeof (queue.async) == "undefined")   ? _this.settings.async   : queue.async;

			$.ajax({
				url         : queue.url,
				data        : queue.data,
				type        : (typeof (queue.type) == "undefined")    ? _this.settings.type    : queue.type,
				async       : async,
				timeout     : (typeof (queue.timeout) == "undefined") ? _this.settings.timeout : queue.timeout,
				contentType : queue.contentType,
				crossDomain : queue.crossDomain,
				dataType    : queue.dataType,
				headers     : queue.headers,
				jsonp       : queue.jsonp,
				statusCode  : queue.statusCode,
				processData : queue.processData,

				beforeSend  : function(xhr) {
					queue.beforeSend(xhr, queue, this);
				},

				error       : function (xhr, status) {
					queue.errorTime = (new Date).getTime();
					queue.error(xhr, status, queue, this);
				},

				success     : function(data, status, xhr) {

					queue.result = data;
					queue.successTime = (new Date).getTime();
					queue.success(data, status, xhr, queue, this);
				},

				complete    : function(xhr, status) {

					queue.status = status;
					queue.completeTime = (new Date).getTime();
					queue.complete(xhr, status, queue, this);

					if(!this.async && queue.status == "success" && !isLast)
					{
						queue.done      = true;
						_this.nowIndex += 1;

						ajaxQueuer.request(_this, _this.queue[_this.nowIndex]);
					}
				}
			});

			if(async)
			{
				_this.nowIndex += 1;

				ajaxQueuer.request(_this, _this.queue[_this.nowIndex]);
			}
		};

		$.ajaxQueuer = ajaxQueuer;

	})(jQuery);

}));<commit_msg>add flush queue method<commit_after>/**
 *
 * jQuery.AjaxQueuer
 *
 * @FileName: jquery.ajaxqueuer.js
 * @Auther: Pandao
 * @version: 0.1.0
 * @License: MIT
 * Copyright@2014 all right reserved.
 */

;(function(ajaxQueuer) {

	// CommonJS/Node.js
	if(typeof require === 'function' && typeof exports === "object" && typeof module === "object") {
		ajaxQueuer(require, exports, module);
	}
	// AMD/CMD/Sea.js
	else if(typeof define === "function") {

		if(define.amd) { // for Require.js

			define(["jquery"], ajaxQueuer);

		} else { // for Sea.js
			define(ajaxQueuer);
		}
	}
	else
	{
		ajaxQueuer(function(){}, window['ajaxQueuer']={}, {});
	}

}(function(require, exports, module) {

	(function ($) {

		var ajaxQueuer = function() {

			if(arguments.length == 1 && typeof (arguments[0].length) == "undefined") {

				return new ajaxQueuer.queue([], arguments[0]);

			} else {

				return new ajaxQueuer.queue(arguments[0], arguments[1]);

			}
		};

		ajaxQueuer.queue = function(queue, options) {

			queue   = queue   || [];
			options = options || {};
			var _this = this;

			if (typeof (queue) == "object") {
				this.queue = queue;
				this.count = queue.length;
				this.nowIndex = 0;
			}

			var defaults = {
				type    : "GET",
				async   : false,           // default false
				timeout : 3000,            // global setting
				namePrefix : 'ajaxQueuer'
			};

			this.settings = $.extend(defaults, options);

			this.qid      = this.settings.namePrefix + (new Date).getTime();

			this.add = function(queue) {
				queue = queue || {};

				if(typeof (queue.length) != "undefined" && queue.length > 1)
				{
					for (var i = 0, len = queue.length; i < len; i++)
					{
						_this.count += 1;
						_this.queue.push(queue[i]);
					}
				}
				else
				{
					_this.count += 1;
					_this.queue.push(queue);
				}

				return _this;
			};

			this.async = function() {

				_this.settings.async = true;

				ajaxQueuer.prioritySort(_this);

				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.synch = function() {

				_this.settings.async = false;

				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.run = function() {
				var queue = _this.queue[_this.nowIndex];

				ajaxQueuer.request(_this, queue);

				return _this;
			};

			this.last = function() {

				_this.nowIndex = _this.queue.length-1;

				ajaxQueuer.request(_this, _this.queue[_this.nowIndex], true);

				return _this;
			};

			this.getQueues = function() {
				return _this.queue;
			};

			this.stop = function() {
				_this.nowIndex = _this.queue.length;

				return _this;
			};

			this.flush = function() {
				_this.queue = [];

				return _this;
			};

			return this;
		};

		ajaxQueuer.prioritySort = function(_this) {

			for (var i in _this.queue) {
				var queue = _this.queue[i];

				if(typeof (queue.priority) == "undefined") {
					queue.priority = 0;
				}
				//console.log("i : ", _this.queue[i]);
			}

			_this.queue.sort(function(a, b) {
				//console.log(a.priority, b.priority);

				return (a.priority > b.priority) ? -1 : 1;
			});
		};

		ajaxQueuer.request = function(_this, queue, isLast) {

			if (_this.nowIndex >= _this.count) return ;

			isLast = isLast || false;

			var defaults = {
				before      : new Function,
				beforeSend  : new Function,
				contentType : "application/x-www-form-urlencoded; charset=UTF-8",
				crossDomain : false,
				complete    : new Function,
				done        : false,
				data        : {},
				dataType    : "text html",
				error       : new Function,
				headers     : {},
				index       : _this.nowIndex,
				jsonp       : "callback",
				name        : _this.qid + "[" + _this.nowIndex + "]",
				processData : true,
				startTime   : (new Date).getTime(),
				statusCode  : {},
				success     : new Function,
				status      : ""
			};

			_this.queue[_this.nowIndex] = queue = $.extend(defaults, queue);

			queue.before(queue);

			var async = (typeof (queue.async) == "undefined")   ? _this.settings.async   : queue.async;

			$.ajax({
				url         : queue.url,
				data        : queue.data,
				type        : (typeof (queue.type) == "undefined")    ? _this.settings.type    : queue.type,
				async       : async,
				timeout     : (typeof (queue.timeout) == "undefined") ? _this.settings.timeout : queue.timeout,
				contentType : queue.contentType,
				crossDomain : queue.crossDomain,
				dataType    : queue.dataType,
				headers     : queue.headers,
				jsonp       : queue.jsonp,
				statusCode  : queue.statusCode,
				processData : queue.processData,

				beforeSend  : function(xhr) {
					queue.beforeSend(xhr, queue, this);
				},

				error       : function (xhr, status) {
					queue.errorTime = (new Date).getTime();
					queue.error(xhr, status, queue, this);
				},

				success     : function(data, status, xhr) {

					queue.result = data;
					queue.successTime = (new Date).getTime();
					queue.success(data, status, xhr, queue, this);
				},

				complete    : function(xhr, status) {

					queue.status = status;
					queue.completeTime = (new Date).getTime();
					queue.complete(xhr, status, queue, this);

					if(!this.async && queue.status == "success" && !isLast)
					{
						queue.done      = true;
						_this.nowIndex += 1;

						ajaxQueuer.request(_this, _this.queue[_this.nowIndex]);
					}
				}
			});

			if(async)
			{
				_this.nowIndex += 1;

				ajaxQueuer.request(_this, _this.queue[_this.nowIndex]);
			}
		};

		$.ajaxQueuer = ajaxQueuer;

	})(jQuery);

}));<|endoftext|>


<commit_before>export class VertxProtoStub {
  /* private
    _continuousOpen: boolean

    _runtimeProtoStubURL: string
    _bus: MiniBus
    _msgCallback: (Message) => void
    _config: { url, runtimeURL }

    _sock: (WebSocket | SockJS)
    _reOpen: boolean
  */

  /**
   * Vertx ProtoStub creation
   * @param  {string} runtimeProtoStubURL - URL used internally for message delivery point. Not used for MessageNode deliver.
   * @param  {MiniBus} bus - MiniBus used to send/receive messages. Normally connected to the MessageBus.
   * @param  {Object} config - Mandatory fields are: "url" of the MessageNode address and "runtimeURL".
   * @return {VertxProtoStub}
   */
  constructor(runtimeProtoStubURL, bus, config) {
    let _this = this;

    this._id = 0;
    this._continuousOpen = true;

    this._runtimeProtoStubURL = runtimeProtoStubURL;
    this._bus = bus;
    this._config = config;

    this._runtimeSessionURL = config.runtimeURL;
    this._reOpen = false;

    bus.addListener('*', (msg) => {
      _this._open(() => {
        _this._sock.send(JSON.stringify(msg));
      });
    });
  }

  /**
   * Get the configuration for this ProtoStub
   * @return {Object} - Mandatory fields are: "url" of the MessageNode address and "runtimeURL".
   */
  get config() { return this._config; }

  get runtimeSession() { return this._runtimeSessionURL; }

  /**
   * Try to open the connection to the MessageNode. Connection is auto managed, there is no need to call this explicitly.
   * However, if "disconnect()" is called, it's necessary to call this to enable connections again.
   * A status message is sent to "runtimeProtoStubURL/status", containing the value "connected" if successful, or "disconnected" if some error occurs.
   */
  connect() {
    let _this = this;

    _this._continuousOpen = true;
    _this._open(() => {});
  }

  /**
   * It will disconnect and order to stay disconnected. Reconnection tries, will not be attempted, unless "connect()" is called.
   * A status message is sent to "runtimeProtoStubURL/status" with value "disconnected".
   */
  disconnect() {
    let _this = this;

    _this._continuousOpen = false;
    if (_this._sock) {
      _this._sendClose();
    }
  }

  _sendOpen(callback) {
    let _this = this;

    _this._id++;
    let msg = {
      id: _this._id, type: 'open', from: _this._runtimeSessionURL, to: 'mn:/session'
    };

    if (_this._reOpen) {
      msg.type = 're-open';
    }

    //register and wait for open reply...
    let hasResponse = false;
    _this._sessionCallback = function(reply) {
      if (reply.type === 'response' & reply.id === msg.id) {
        hasResponse = true;
        if (reply.body.code === 200) {
          if (reply.body.runtimeToken) {
            //setup runtimeSession
            _this._reOpen = true;
            _this._runtimeSessionURL = _this._config.runtimeURL + '/' + reply.body.runtimeToken;
          }

          _this._sendStatus('connected');
          callback();
        } else {
          _this._sendStatus('disconnected', reply.body.desc);
        }
      }
    };

    _this._sock.send(JSON.stringify(msg));
    setTimeout(() => {
      if (!hasResponse) {
        //no response after x seconds...
        _this._sendStatus('disconnected', 'Timeout from mn:/session');
      }
    }, 3000);
  }

  _sendClose() {
    let _this = this;

    _this._id++;
    let msg = {
      id: _this._id, type: 'close', from: _this._runtimeSessionURL, to: 'mn:/session'
    };

    //invalidate runtimeSession
    _this._reOpen = false;
    _this._runtimeSessionURL = _this._config._runtimeURL;

    _this._sock.send(JSON.stringify(msg));
  }

  _sendStatus(value, reason) {
    let _this = this;

    let msg = {
      type: 'update',
      from: _this._runtimeProtoStubURL,
      to: _this._runtimeProtoStubURL + '/status',
      body: {
        value: value
      }
    };

    if (reason) {
      msg.body.desc = reason;
    }

    _this._bus.postMessage(msg);
  }

  _waitReady(callback) {
    let _this = this;

    if (_this._sock.readyState === 1) {
      callback();
    } else {
      setTimeout(() => {
        _this._waitReady(callback);
      });
    }
  }

  _open(callback) {
    let _this = this;

    if (!this._continuousOpen) {
      //TODO: send status (sent message error - disconnected)
      return;
    }

    if (!_this._sock) {
      if (_this._config.url.substring(0, 2) === 'ws') {
        _this._sock = new WebSocket(_this._config.url);
      } else {
        _this._sock = new SockJS(_this._config.url);
      }

      _this._sock.onopen = function() {
        _this._sendOpen(() => {
          callback();
        });
      };

      _this._sock.onmessage = function(e) {
        var msg = JSON.parse(e.data);
        if (msg.from === 'mn:/session') {
          if (_this._sessionCallback) {
            _this._sessionCallback(msg);
          }
        } else {
          _this._bus.postMessage(msg);
        }
      };

      _this._sock.onclose = function(event) {
        let reason;

        //See https://tools.ietf.org/html/rfc6455#section-7.4
        if (event.code === 1000) {
          reason = 'Normal closure, meaning that the purpose for which the connection was established has been fulfilled.';
        } else if (event.code === 1001) {
          reason = 'An endpoint is \'going away\', such as a server going down or a browser having navigated away from a page.';
        } else if (event.code === 1002) {
          reason = 'An endpoint is terminating the connection due to a protocol error';
        } else if (event.code === 1003) {
          reason = 'An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message).';
        } else if (event.code === 1004) {
          reason = 'Reserved. The specific meaning might be defined in the future.';
        } else if (event.code === 1005) {
          reason = 'No status code was actually present.';
        } else if (event.code === 1006) {
          reason = 'The connection was closed abnormally, e.g., without sending or receiving a Close control frame';
        } else if (event.code === 1007) {
          reason = 'An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [http://tools.ietf.org/html/rfc3629] data within a text message).';
        } else if (event.code === 1008) {
          reason = 'An endpoint is terminating the connection because it has received a message that "violates its policy". This reason is given either if there is no other sutible reason, or if there is a need to hide specific details about the policy.';
        } else if (event.code === 1009) {
          reason = 'An endpoint is terminating the connection because it has received a message that is too big for it to process.';
        } else if (event.code === 1010) {
          reason = 'An endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn\'t return them in the response message of the WebSocket handshake.
 Specifically, the extensions that are needed are: ' + event.reason;
        } else if (event.code === 1011) {
          reason = 'A server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.';
        } else if (event.code === 1015) {
          reason = 'The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can\'t be verified).';
        } else {
          reason = 'Unknown reason';
        }

        delete _this._sock;
        _this._sendStatus('disconnected', reason);
      };
    } else {
      _this._waitReady(callback);
    }
  }
}

export default function activate(url, bus, config) {
  return {
    name: 'VertxProtoStub',
    instance: new VertxProtoStub(url, bus, config)
  };
}

/**
* Callback used to send messages
* @callback PostMessage
* @param {Message} msg - Message to send
*/
<commit_msg>Update VertxProtoStub.js<commit_after>class VertxProtoStub {
  /* private
    _continuousOpen: boolean

    _runtimeProtoStubURL: string
    _bus: MiniBus
    _msgCallback: (Message) => void
    _config: { url, runtimeURL }

    _sock: (WebSocket | SockJS)
    _reOpen: boolean
  */

  /**
   * Vertx ProtoStub creation
   * @param  {string} runtimeProtoStubURL - URL used internally for message delivery point. Not used for MessageNode deliver.
   * @param  {MiniBus} bus - MiniBus used to send/receive messages. Normally connected to the MessageBus.
   * @param  {Object} config - Mandatory fields are: "url" of the MessageNode address and "runtimeURL".
   * @return {VertxProtoStub}
   */
  constructor(runtimeProtoStubURL, bus, config) {
    let _this = this;

    this._id = 0;
    this._continuousOpen = true;

    this._runtimeProtoStubURL = runtimeProtoStubURL;
    this._bus = bus;
    this._config = config;

    this._runtimeSessionURL = config.runtimeURL;
    this._reOpen = false;

    bus.addListener('*', (msg) => {
      _this._open(() => {
        _this._sock.send(JSON.stringify(msg));
      });
    });
  }

  /**
   * Get the configuration for this ProtoStub
   * @return {Object} - Mandatory fields are: "url" of the MessageNode address and "runtimeURL".
   */
  get config() { return this._config; }

  get runtimeSession() { return this._runtimeSessionURL; }

  /**
   * Try to open the connection to the MessageNode. Connection is auto managed, there is no need to call this explicitly.
   * However, if "disconnect()" is called, it's necessary to call this to enable connections again.
   * A status message is sent to "runtimeProtoStubURL/status", containing the value "connected" if successful, or "disconnected" if some error occurs.
   */
  connect() {
    let _this = this;

    _this._continuousOpen = true;
    _this._open(() => {});
  }

  /**
   * It will disconnect and order to stay disconnected. Reconnection tries, will not be attempted, unless "connect()" is called.
   * A status message is sent to "runtimeProtoStubURL/status" with value "disconnected".
   */
  disconnect() {
    let _this = this;

    _this._continuousOpen = false;
    if (_this._sock) {
      _this._sendClose();
    }
  }

  _sendOpen(callback) {
    let _this = this;

    _this._id++;
    let msg = {
      id: _this._id, type: 'open', from: _this._runtimeSessionURL, to: 'mn:/session'
    };

    if (_this._reOpen) {
      msg.type = 're-open';
    }

    //register and wait for open reply...
    let hasResponse = false;
    _this._sessionCallback = function(reply) {
      if (reply.type === 'response' & reply.id === msg.id) {
        hasResponse = true;
        if (reply.body.code === 200) {
          if (reply.body.runtimeToken) {
            //setup runtimeSession
            _this._reOpen = true;
            _this._runtimeSessionURL = _this._config.runtimeURL + '/' + reply.body.runtimeToken;
          }

          _this._sendStatus('connected');
          callback();
        } else {
          _this._sendStatus('disconnected', reply.body.desc);
        }
      }
    };

    _this._sock.send(JSON.stringify(msg));
    setTimeout(() => {
      if (!hasResponse) {
        //no response after x seconds...
        _this._sendStatus('disconnected', 'Timeout from mn:/session');
      }
    }, 3000);
  }

  _sendClose() {
    let _this = this;

    _this._id++;
    let msg = {
      id: _this._id, type: 'close', from: _this._runtimeSessionURL, to: 'mn:/session'
    };

    //invalidate runtimeSession
    _this._reOpen = false;
    _this._runtimeSessionURL = _this._config._runtimeURL;

    _this._sock.send(JSON.stringify(msg));
  }

  _sendStatus(value, reason) {
    let _this = this;

    let msg = {
      type: 'update',
      from: _this._runtimeProtoStubURL,
      to: _this._runtimeProtoStubURL + '/status',
      body: {
        value: value
      }
    };

    if (reason) {
      msg.body.desc = reason;
    }

    _this._bus.postMessage(msg);
  }

  _waitReady(callback) {
    let _this = this;

    if (_this._sock.readyState === 1) {
      callback();
    } else {
      setTimeout(() => {
        _this._waitReady(callback);
      });
    }
  }

  _open(callback) {
    let _this = this;

    if (!this._continuousOpen) {
      //TODO: send status (sent message error - disconnected)
      return;
    }

    if (!_this._sock) {
      if (_this._config.url.substring(0, 2) === 'ws') {
        _this._sock = new WebSocket(_this._config.url);
      } else {
        _this._sock = new SockJS(_this._config.url);
      }

      _this._sock.onopen = function() {
        _this._sendOpen(() => {
          callback();
        });
      };

      _this._sock.onmessage = function(e) {
        var msg = JSON.parse(e.data);
        if (msg.from === 'mn:/session') {
          if (_this._sessionCallback) {
            _this._sessionCallback(msg);
          }
        } else {
          _this._bus.postMessage(msg);
        }
      };

      _this._sock.onclose = function(event) {
        let reason;

        //See https://tools.ietf.org/html/rfc6455#section-7.4
        if (event.code === 1000) {
          reason = 'Normal closure, meaning that the purpose for which the connection was established has been fulfilled.';
        } else if (event.code === 1001) {
          reason = 'An endpoint is \'going away\', such as a server going down or a browser having navigated away from a page.';
        } else if (event.code === 1002) {
          reason = 'An endpoint is terminating the connection due to a protocol error';
        } else if (event.code === 1003) {
          reason = 'An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message).';
        } else if (event.code === 1004) {
          reason = 'Reserved. The specific meaning might be defined in the future.';
        } else if (event.code === 1005) {
          reason = 'No status code was actually present.';
        } else if (event.code === 1006) {
          reason = 'The connection was closed abnormally, e.g., without sending or receiving a Close control frame';
        } else if (event.code === 1007) {
          reason = 'An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [http://tools.ietf.org/html/rfc3629] data within a text message).';
        } else if (event.code === 1008) {
          reason = 'An endpoint is terminating the connection because it has received a message that "violates its policy". This reason is given either if there is no other sutible reason, or if there is a need to hide specific details about the policy.';
        } else if (event.code === 1009) {
          reason = 'An endpoint is terminating the connection because it has received a message that is too big for it to process.';
        } else if (event.code === 1010) {
          reason = 'An endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn\'t return them in the response message of the WebSocket handshake.
 Specifically, the extensions that are needed are: ' + event.reason;
        } else if (event.code === 1011) {
          reason = 'A server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.';
        } else if (event.code === 1015) {
          reason = 'The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can\'t be verified).';
        } else {
          reason = 'Unknown reason';
        }

        delete _this._sock;
        _this._sendStatus('disconnected', reason);
      };
    } else {
      _this._waitReady(callback);
    }
  }
}

export default function activate(url, bus, config) {
  return {
    name: 'VertxProtoStub',
    instance: new VertxProtoStub(url, bus, config)
  };
}

/**
* Callback used to send messages
* @callback PostMessage
* @param {Message} msg - Message to send
*/
<|endoftext|>


<commit_before>'use strict';

import $ from 'jquery';

import Modal from './modal';
import Backend from '../backend';
import { baseUrl, restart } from '../lib/utils';

import support from '../lib/support';
import { version } from '../../../../package.json';

const contents = `\

\

Landmarker.io
\

v${version}
\

\

\

Connect to Dropbox
\

\

\
            \

Connect to a landmarker server
\

\

\
            See a demo\

\

\
    \
        \
        More info on Github\
    \

\
`;

const lsWarning = `\

\
    Your browser doesn't support LocalStorage, so Dropbox login has been\
    disabled.\

`;

const httpsWarning = `\

\
    You are currently on an non-https connection. For security reasons Dropbox integration has been disabled.

`;

const Intro = Modal.extend({

    closable: false,
    modifiers: ['Small'],

    events: {
        'click .IntroItem--Dropbox': 'startDropbox',
        'click .IntroItem--Server': 'startServer',
        'click .IntroItem--Demo': 'startDemo'
    },

    init: function ({cfg}) {
        this._cfg = cfg;
    },

    content: function () {
        const $contents = $(contents);

        if (!support.localstorage) {
            $contents.find('.IntroItem--Dropbox').remove();
            $contents.find('.IntroItems').append($(lsWarning));
        }

        if (
            !support.https &&
            window.location.origin !== "http://localhost:4000"
        ) {
            $contents.find('.IntroItem--Dropbox').remove();
            $contents.find('.IntroItems').append($(httpsWarning));
        }

        return $contents;
    },

    startDropbox: function () {
        this._cfg.clear();
        const [dropUrl, state] = Backend.Dropbox.authorize();
        this._cfg.set({
            'OAUTH_STATE': state,
            'BACKEND_TYPE': Backend.Dropbox.Type
        }, true);
        window.location.replace(dropUrl);
    },

    startDemo: function () {
        restart('demo');
    },

    startServer: function () {
        Modal.prompt('Where is your server located ?', (value) => {
            restart(value);
        }, () => {
            this.open();
        });
    }
});

let instance;
export default {
    init: function (opts) { instance = new Intro(opts); },

    open: function () {
        instance._cfg.clear();
        history.replaceState(null, null, baseUrl());
        instance.open();
    },

    close: function () { instance.close(); },
    initialized: function () { return !!instance; }
};
<commit_msg>Link from the version string to the release notes<commit_after>'use strict';

import $ from 'jquery';

import Modal from './modal';
import Backend from '../backend';
import { baseUrl, restart } from '../lib/utils';

import support from '../lib/support';
import { version } from '../../../../package.json';

const contents = `\

\

Landmarker.io
\

v${version}
\

\

\

Connect to Dropbox
\

\

\
            \

Connect to a landmarker server
\

\

\
            See a demo\

\

\
    \
        \
        More info on Github\
    \

\
`;

const lsWarning = `\

\
    Your browser doesn't support LocalStorage, so Dropbox login has been\
    disabled.\

`;

const httpsWarning = `\

\
    You are currently on an non-https connection. For security reasons Dropbox integration has been disabled.

`;

const Intro = Modal.extend({

    closable: false,
    modifiers: ['Small'],

    events: {
        'click .IntroItem--Dropbox': 'startDropbox',
        'click .IntroItem--Server': 'startServer',
        'click .IntroItem--Demo': 'startDemo'
    },

    init: function ({cfg}) {
        this._cfg = cfg;
    },

    content: function () {
        const $contents = $(contents);

        if (!support.localstorage) {
            $contents.find('.IntroItem--Dropbox').remove();
            $contents.find('.IntroItems').append($(lsWarning));
        }

        if (
            !support.https &&
            window.location.origin !== "http://localhost:4000"
        ) {
            $contents.find('.IntroItem--Dropbox').remove();
            $contents.find('.IntroItems').append($(httpsWarning));
        }

        return $contents;
    },

    startDropbox: function () {
        this._cfg.clear();
        const [dropUrl, state] = Backend.Dropbox.authorize();
        this._cfg.set({
            'OAUTH_STATE': state,
            'BACKEND_TYPE': Backend.Dropbox.Type
        }, true);
        window.location.replace(dropUrl);
    },

    startDemo: function () {
        restart('demo');
    },

    startServer: function () {
        Modal.prompt('Where is your server located ?', (value) => {
            restart(value);
        }, () => {
            this.open();
        });
    }
});

let instance;
export default {
    init: function (opts) { instance = new Intro(opts); },

    open: function () {
        instance._cfg.clear();
        history.replaceState(null, null, baseUrl());
        instance.open();
    },

    close: function () { instance.close(); },
    initialized: function () { return !!instance; }
};
<|endoftext|>


<commit_before>import React from 'react'
import { inject, observer } from 'mobx-react'
import { LinearProgress } from 'material-ui/Progress'
import Window from './Window'
import Search from './Search'
import Tools from './Tools'

@inject('windowStore')
@inject('searchStore')
@observer
export default class App extends React.Component {
  componentDidMount () {
    const { windowStore: { updateAllWindows } } = this.props
    chrome.windows.onCreated.addListener(updateAllWindows)
    chrome.windows.onRemoved.addListener(updateAllWindows)
    chrome.tabs.onCreated.addListener(updateAllWindows)
    chrome.tabs.onUpdated.addListener(updateAllWindows)
    chrome.tabs.onMoved.addListener(updateAllWindows)
    chrome.tabs.onDetached.addListener(updateAllWindows)
    chrome.tabs.onRemoved.addListener(updateAllWindows)
    chrome.tabs.onReplaced.addListener(updateAllWindows)
    document.addEventListener('keydown', this.onKeyDown, false)
  }

  onKeyDown = (e) => {
    const {
      searchStore: { up, down, enter, select, typing }
    } = this.props
    console.log(e.keyCode)
    switch (e.keyCode) {
      // DOWN
      case 40:
        e.preventDefault()
        down()
        break
      // UP
      case 38:
        e.preventDefault()
        up()
        break
      // Enter
      case 13:
        e.preventDefault()
        enter()
        break
      default:
        break
    }
    console.log(typing)
    if (typing) {
      return
    }
    switch (e.keyCode) {
      // X
      case 88:
        e.preventDefault()
        select()
        break
      // j
      case 74:
        e.preventDefault()
        down()
        break
      // k
      case 75:
        e.preventDefault()
        up()
        break
      // /
      case 191:
        e.preventDefault()
        this.search.focus()
        break
      default:
        break
    }
  }

  render () {
    const { windowStore: { tabCount, windows } } = this.props
    if (!tabCount) {
      return (<LinearProgress />)
    }
    const winList = windows.map((win) => (
      <Window key={win.id} {...win} containment={() => this.refs.containment} />
    ))
    return (

          <Search inputRef={(input) => { this.search = input }} />
          <Tools />

          {winList}

    )
  }
}
<commit_msg>Add Escape to only blur input if typing<commit_after>import React from 'react'
import { inject, observer } from 'mobx-react'
import { LinearProgress } from 'material-ui/Progress'
import Window from './Window'
import Search from './Search'
import Tools from './Tools'

@inject('windowStore')
@inject('searchStore')
@observer
export default class App extends React.Component {
  componentDidMount () {
    const { windowStore: { updateAllWindows } } = this.props
    chrome.windows.onCreated.addListener(updateAllWindows)
    chrome.windows.onRemoved.addListener(updateAllWindows)
    chrome.tabs.onCreated.addListener(updateAllWindows)
    chrome.tabs.onUpdated.addListener(updateAllWindows)
    chrome.tabs.onMoved.addListener(updateAllWindows)
    chrome.tabs.onDetached.addListener(updateAllWindows)
    chrome.tabs.onRemoved.addListener(updateAllWindows)
    chrome.tabs.onReplaced.addListener(updateAllWindows)
    document.addEventListener('keydown', this.onKeyDown, false)
  }

  onKeyDown = (e) => {
    const {
      searchStore: { up, down, enter, select, typing }
    } = this.props
    console.log(e.keyCode)
    switch (e.keyCode) {
      // DOWN
      case 40:
        e.preventDefault()
        down()
        break
      // UP
      case 38:
        e.preventDefault()
        up()
        break
      // Enter
      case 13:
        e.preventDefault()
        enter()
        break
      // Escape
      case 27:
        if (typing) {
          e.preventDefault()
          this.search.blur()
        }
        break
      default:
        break
    }
    console.log(typing)
    if (typing) {
      return
    }
    switch (e.keyCode) {
      // X
      case 88:
        e.preventDefault()
        select()
        break
      // j
      case 74:
        e.preventDefault()
        down()
        break
      // k
      case 75:
        e.preventDefault()
        up()
        break
      // /
      case 191:
        e.preventDefault()
        this.search.focus()
        break
      default:
        break
    }
  }

  render () {
    const { windowStore: { tabCount, windows } } = this.props
    if (!tabCount) {
      return (<LinearProgress />)
    }
    const winList = windows.map((win) => (
      <Window key={win.id} {...win} containment={() => this.refs.containment} />
    ))
    return (

          <Search inputRef={(input) => { this.search = input }} />
          <Tools />

          {winList}

    )
  }
}
<|endoftext|>


<commit_before>var NO_DATA = 'no data';

module.exports = {

  prepareModuleForRender: function (dashboardConfig, module) {
    var data = {
      departmentCode: dashboardConfig.department.abbr.toLowerCase(),
      dashboardSlug: dashboardConfig.slug,
      dashboardTitle: dashboardConfig.title,
      moduleType: module['module-type'],
      slug: module.slug,
      title: module.title,
      latest: module.data[0] || null,
      previous: module.data[1] || null
    };

    data.displaySlide = this.displaySlide(data);
    if (data.displaySlide) {
      data = this.missingDataFlags(data);
      data = this.dataConversions(data);
    }
    return data;
  },

  displaySlide: function (data) {
    var returnVal = true;

    // we're going to display realtime slides even if prior data was missing, as data might reappear
    if (data.moduleType !== 'realtime') {
      if (((data.latest === null) && (data.previous === null)) ||
        ((data.latest.formatted_value === NO_DATA) &&
        (data.previous.formatted_value === NO_DATA))) {
        returnVal = false;
      }
    }
    return returnVal;
  },

  missingDataFlags: function (data) {
    if (data.latest.formatted_value !== NO_DATA) {
      data.latestAvailable = true;
    }
    if (data.previous && (data.previous.formatted_value !== NO_DATA)) {
      data.previousAvailable = true;
    }
    data.showChange = data.latestAvailable && data.previousAvailable &&
      data.latest.formatted_change_from_previous;
    data.showPrevious = !data.latestAvailable && data.previousAvailable;

    return data;
  },

  dataConversions: function (data) {
    if (data.latest.formatted_change_from_previous &&
      data.latest.formatted_change_from_previous.change === '0%') {
      data.latest.formatted_change_from_previous.change = 'No change';
    }
    return data;
  }

};
<commit_msg>Reminder to move logic to client<commit_after>var NO_DATA = 'no data';

module.exports = {

  prepareModuleForRender: function (dashboardConfig, module) {
    var data = {
      departmentCode: dashboardConfig.department.abbr.toLowerCase(),
      dashboardSlug: dashboardConfig.slug,
      dashboardTitle: dashboardConfig.title,
      moduleType: module['module-type'],
      slug: module.slug,
      title: module.title,
      latest: module.data[0] || null,
      previous: module.data[1] || null
    };

    data.displaySlide = this.displaySlide(data);
    if (data.displaySlide) {
      data = this.missingDataFlags(data);
      data = this.dataConversions(data);
    }
    return data;
  },

  displaySlide: function (data) {
    var returnVal = true;

    // we're going to display realtime slides even if prior data was missing, as data might reappear
    if (data.moduleType !== 'realtime') {
      if (((data.latest === null) && (data.previous === null)) ||
        ((data.latest.formatted_value === NO_DATA) &&
        (data.previous.formatted_value === NO_DATA))) {
        returnVal = false;
      }
    }
    return returnVal;
  },

  missingDataFlags: function (data) {
    if (data.latest.formatted_value !== NO_DATA) {
      data.latestAvailable = true;
    }
    if (data.previous && (data.previous.formatted_value !== NO_DATA)) {
      data.previousAvailable = true;
    }
    data.showChange = data.latestAvailable && data.previousAvailable &&
      data.latest.formatted_change_from_previous;
    data.showPrevious = !data.latestAvailable && data.previousAvailable;

    return data;
  },

  dataConversions: function (data) {
    //TODO - move to client / API
    if (data.latest.formatted_change_from_previous &&
      data.latest.formatted_change_from_previous.change === '0%') {
      data.latest.formatted_change_from_previous.change = 'No change';
    }
    return data;
  }

};
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var utils = require('../utils');
var filterIceServers = require('./filtericeservers');
var shimRTCPeerConnection = require('rtcpeerconnection-shim');

module.exports = {
  shimGetUserMedia: require('./getusermedia'),
  shimPeerConnection: function(window) {
    var browserDetails = utils.detectBrowser(window);

    if (window.RTCIceGatherer) {
      if (!window.RTCIceCandidate) {
        window.RTCIceCandidate = function(args) {
          return args;
        };
      }
      if (!window.RTCSessionDescription) {
        window.RTCSessionDescription = function(args) {
          return args;
        };
      }
      // this adds an additional event listener to MediaStrackTrack that signals
      // when a tracks enabled property was changed. Workaround for a bug in
      // addStream, see below. No longer required in 15025+
      if (browserDetails.version < 15025) {
        var origMSTEnabled = Object.getOwnPropertyDescriptor(
            window.MediaStreamTrack.prototype, 'enabled');
        Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', {
          set: function(value) {
            origMSTEnabled.set.call(this, value);
            var ev = new Event('enabled');
            ev.enabled = value;
            this.dispatchEvent(ev);
          }
        });
      }
    }

    // ORTC defines the DTMF sender a bit different.
    // https://github.com/w3c/ortc/issues/714
    if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {
      Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
        get: function() {
          if (this._dtmf === undefined) {
            if (this.track.kind === 'audio') {
              this._dtmf = new window.RTCDtmfSender(this);
            } else if (this.track.kind === 'video') {
              this._dtmf = null;
            }
          }
          return this._dtmf;
        }
      });
    }
    // Edge currently only implements the RTCDtmfSender, not the
    // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2*
    if (window.RTCDtmfSender && !window.RTCDTMFSender) {
      window.RTCDTMFSender = window.RTCDtmfSender;
    }

    var RTCPeerConnectionShim = shimRTCPeerConnection(window,
        browserDetails.version);
    window.RTCPeerConnection = function(config) {
      if (config.iceServers) {
        config.iceServers = filterIceServers(config.iceServers);
      }
      return new RTCPeerConnectionShim(config);
    };
    window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype;
  },
  shimReplaceTrack: function(window) {
    // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
    if (window.RTCRtpSender &&
        !('replaceTrack' in window.RTCRtpSender.prototype)) {
      window.RTCRtpSender.prototype.replaceTrack =
          window.RTCRtpSender.prototype.setTrack;
    }
  }
};
<commit_msg>fix edge regression<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var utils = require('../utils');
var filterIceServers = require('./filtericeservers');
var shimRTCPeerConnection = require('rtcpeerconnection-shim');

module.exports = {
  shimGetUserMedia: require('./getusermedia'),
  shimPeerConnection: function(window) {
    var browserDetails = utils.detectBrowser(window);

    if (window.RTCIceGatherer) {
      if (!window.RTCIceCandidate) {
        window.RTCIceCandidate = function(args) {
          return args;
        };
      }
      if (!window.RTCSessionDescription) {
        window.RTCSessionDescription = function(args) {
          return args;
        };
      }
      // this adds an additional event listener to MediaStrackTrack that signals
      // when a tracks enabled property was changed. Workaround for a bug in
      // addStream, see below. No longer required in 15025+
      if (browserDetails.version < 15025) {
        var origMSTEnabled = Object.getOwnPropertyDescriptor(
            window.MediaStreamTrack.prototype, 'enabled');
        Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', {
          set: function(value) {
            origMSTEnabled.set.call(this, value);
            var ev = new Event('enabled');
            ev.enabled = value;
            this.dispatchEvent(ev);
          }
        });
      }
    }

    // ORTC defines the DTMF sender a bit different.
    // https://github.com/w3c/ortc/issues/714
    if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {
      Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
        get: function() {
          if (this._dtmf === undefined) {
            if (this.track.kind === 'audio') {
              this._dtmf = new window.RTCDtmfSender(this);
            } else if (this.track.kind === 'video') {
              this._dtmf = null;
            }
          }
          return this._dtmf;
        }
      });
    }
    // Edge currently only implements the RTCDtmfSender, not the
    // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2*
    if (window.RTCDtmfSender && !window.RTCDTMFSender) {
      window.RTCDTMFSender = window.RTCDtmfSender;
    }

    var RTCPeerConnectionShim = shimRTCPeerConnection(window,
        browserDetails.version);
    window.RTCPeerConnection = function(config) {
      if (config && config.iceServers) {
        config.iceServers = filterIceServers(config.iceServers);
      }
      return new RTCPeerConnectionShim(config);
    };
    window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype;
  },
  shimReplaceTrack: function(window) {
    // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
    if (window.RTCRtpSender &&
        !('replaceTrack' in window.RTCRtpSender.prototype)) {
      window.RTCRtpSender.prototype.replaceTrack =
          window.RTCRtpSender.prototype.setTrack;
    }
  }
};
<|endoftext|>


<commit_before>this.mmooc = this.mmooc || {};

this.mmooc.enroll = (function() {
  return {
    changeEnrollConfirmationButton: function() {
      var enrollForm = $('#enroll_form');
      enrollForm
        .find('.btn')
        .text('Gå til mine ' + mmooc.i18n.CoursePlural.toLowerCase());
      enrollForm.find('.btn').attr('href', '/courses');
      enrollForm.find('.btn-primary').hide();
    },
    changeEnrollTitle: function(s) {
      var headline = $('.ic-Login-confirmation__headline');
      headline.text(s);
    },
    getEnrollInformationElement: function() {
      //There might be several p elements, depending on which self registration screen we are on.
      //Only return the first one.
      return $('#enroll_form > p:first');
    },
    getEnrollAction: function() {
      return $('#enroll_form').attr('action');
    },
    changeEnrollInformation: function(from, to) {
      var confirmEnrollmentElement = this.getEnrollInformationElement();
      confirmEnrollmentElement.text(
        confirmEnrollmentElement.text().replace(from, to)
      );
    },
    hideEnrollInformationPolicy: function() {
      var informationPolicy = $('.ic-Self-enrollment-footer__Secondary');
      informationPolicy.hide();
    },
    changeEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.text('Ja takk, jeg vil registrere meg!');
    },
    hideEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.hide();
    },
    isAlreadyEnrolled: function() {
      confirmEnrollmentElement = this.getEnrollInformationElement();
      var i = confirmEnrollmentElement
        .text()
        .indexOf('Du er allerede registrert i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    selectRegisterUserCheckbox: function() {
      //The checkbox is hidden by canvas-enroll.less, but we need to check it to get the right fields to display.
      setTimeout(function() {
        var createNewUserRadioButton = $('#selfEnrollmentAuthRegCreate');
        createNewUserRadioButton.click();
      }, 1000); // set timeout in ms
    },
    updatePrivacyPolicyLinks: function() {
      html = mmooc.util.renderTemplateWithData('enrollprivacypolicy', {
        privacypolicylink: mmooc.settings.privacyPolicyLink
      });
      $("label[for='selfEnrollmentAuthRegLoginAgreeTerms']").html(html);
    },
    isSelfEnrollmentPage: function() {
      var i = this.getEnrollInformationElement()
        .text()
        .indexOf('Du registrerer deg i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    changeEnrollPage: function() {
      this.changeEnrollTitle('Påmelding');
      if (this.isAlreadyEnrolled()) {
        this.changeEnrollConfirmationButton();
      } else {
        this.hideEnrollInformationPolicy();
        if (this.isSelfEnrollmentPage()) {
          //When self enrolling, give the user the impression of registering on the platform, and not on the course
          //we use to make self enrollment possible. See settings.js/selfRegisterCourseCode
          this.getEnrollInformationElement().text('');
          $('#enroll_form > p:nth-child(2)').text(
            'Vennligst fyll inn informasjonen nedenfor for å registrere deg på ' +
              mmooc.settings.platformName
          );
          this.selectRegisterUserCheckbox();
          this.updatePrivacyPolicyLinks();
          this.changeEnrollButton();
        } else {
          this.hideEnrollButton();
          this.changeEnrollInformation(
            'Du registrere deg på ',
            'Vi registrerer deg på ' +
              mmooc.i18n.CourseDefinite.toLowerCase() +
              ' '
          );
          var enrollInformationElement = this.getEnrollInformationElement();
          enrollInformationElement.html(" ");
          var enrollAction = this.getEnrollAction();
          mmooc.api.enrollUser(enrollAction, function(data) {
            $('.loading-gif').remove();
            window.location.href = '/search/all_courses' + mmooc.hrefQueryString;
          });
        }
      }
    },
    printAllCoursesContainer: function() {
      html = mmooc.util.renderTemplateWithData('allcoursescontainer', {
        courseLabel: mmooc.i18n.CoursePlural.toLowerCase(),
        allAvailableCoursesIngress: mmooc.i18n.AllAvailableCoursesIngress,
        linkToMyCourses: mmooc.utilRoot.getLinkToMyCourses()
      });
      document.title = 'Tilgjengelige ' + mmooc.i18n.CoursePlural.toLowerCase();
      document.getElementById('content').innerHTML = html;
    },
    printAllCourses: function() {
      var self = this;
      html = "

";
      $('.mmooc-all-courses-list').append(html);
      mmooc.api.getAllPublicCourses(function(allCourses) {
        mmooc.api.getEnrolledCourses(function(enrolledCourses) {
          var allCoursesWithStatus = mmooc.enroll.setCourseEnrolledStatus(
            allCourses,
            enrolledCourses
          );

          var categorys = mmooc.util.getCourseCategories(allCoursesWithStatus);

          /* If the amount of courses is large, the filter select box and corresponding javascript code in allcoursescontainer.hbs should be enabled

          mmooc.enroll.populateFilter(categorys);

          $("#filter").change(function () {
            mmooc.enroll.applyFilter();
          });

          */

          var coursesCategorized = mmooc.util.getCoursesCategorized(
            allCoursesWithStatus,
            categorys
          );

          $('.mmooc-loader-wrapper').remove();

          for (var i = 0; i < coursesCategorized.length; i++) {
            const coursesCategory = coursesCategorized[i];
            const coursesEnrolledAmount = mmooc.util.filter(
              coursesCategory.courses,
              function(course) {
                return course.enrolled === true
            }).length;
            const coursesAmount = coursesCategory.courses && coursesCategory.courses.length;

            html = mmooc.util.renderTemplateWithData('allcourseslist', {
              queryString: mmooc.hrefQueryString,
              title: coursesCategory.title,
              isAuthenticated: mmooc.util.isAuthenticated(),
              courses: coursesCategory.courses,
              coursesEnrolledAmount: coursesEnrolledAmount,
              coursesAmount: coursesAmount,
              coursesAmountText: mmooc.i18n.CoursesAmount(coursesAmount),
              courseLabel: mmooc.i18n.Course.toLowerCase(),
              goToCourse: mmooc.i18n.GoToCourse,
              courseRegister: mmooc.i18n.CourseRegister,
              courseRegisterFeide: mmooc.i18n.CourseRegisterFeide,
              openCoursesGroupText: mmooc.i18n.OpenCoursesGroup,
              closeCoursesGroupText: mmooc.i18n.CloseCoursesGroup,
              YouAreRegisteredToXCoursesText: mmooc.i18n.YouAreRegisteredToXCourses(coursesEnrolledAmount),
              index: i
            });
            $('.mmooc-all-courses-list').append(html);
            self.createHashTags();
            self.scrollToCourse();
          }

          // Displays information, that there is no current courses available to enroll
          if (coursesCategorized.length == 0) {
            html = '
' + mmooc.i18n.NoCoursesInfo + '
';
            $('.mmooc-all-courses-list').append(html);
          }

          mmooc.enroll.insertModalAndOverlay();
          mmooc.enroll.setClickHandlers();

          // TODO: move if there is a better place for this code - it handles course list UI
          // accordion UI
          $('.mmooc-accordion-header').click(event => {
            let accordionIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-accordion-header-${accordionIndex}`).hasClass(
                'mmooc-accordion-header-active'
              )
            ) {
              $(`#mmooc-accordion-header-${accordionIndex}`).toggleClass(
                'mmooc-accordion-header-active'
              );
            } else {
              $('.mmooc-accordion-header-active').removeClass(
                'mmooc-accordion-header-active'
              );

              $(`#mmooc-accordion-header-${accordionIndex}`).addClass(
                'mmooc-accordion-header-active'
              );
            }

            // remove active tabs when new accordion element is clicked
            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $('.mmooc-tabs-mobile-header-active').removeClass(
              'mmooc-tabs-mobile-header-active'
            );
            $('.mmooc-tabs-mobile-content-active').removeClass(
              'mmooc-tabs-mobile-content-active'
            );

            // add active class to first tab when the accordion element is opened
            $('.mmooc-tab-head-0').addClass('mmooc-tab-head-active');
            $('.mmooc-tab-content-0').addClass('mmooc-tab-content-active');
          });

          // tabs
          $('.mmooc-tab-head').click(event => {
            let tabIndex = event.target.getAttribute('index');

            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $(`#mmooc-tab-head-${tabIndex}`).addClass('mmooc-tab-head-active');

            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $(`#mmooc-tab-content-${tabIndex}`).addClass(
              'mmooc-tab-content-active'
            );
          });

          // tabs-mobile

          $('.mmooc-tabs-mobile-header').click(event => {
            let mobileTabIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).hasClass(
                'mmooc-tabs-mobile-header-active'
              )
            ) {
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-content-active'
              );
            } else {
              $('.mmooc-tabs-mobile-header-active').removeClass(
                'mmooc-tabs-mobile-header-active'
              );
              $('.mmooc-tabs-mobile-content-active').removeClass(
                'mmooc-tabs-mobile-content-active'
              );

              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-content-active'
              );
            }
          });
        });
      });
    },
    createHashTags: function() {
        $('span').click(function(e) {
          if ($(this).filter("[data-name='course']")) {
            var courseGroupId = $(this).closest('section').find('button[index=0]').attr('data-title');
            var hashTag = courseGroupId + "::" + e.currentTarget.id;
            window.location.hash = hashTag;
          }
        });

        $("button[data-title]").click(function(e){
          var categoryName = $(this).attr("data-title");
          var firstCourseId = $(this).siblings().find('span').eq(0).attr('id');
          var hashTag = categoryName + "::" + firstCourseId;
          window.location.hash = hashTag;
        })
    },
    scrollToCourse: function () {
      setTimeout(function() {
        var currentHash = window.location.hash;
        var courses = $('span').filter("[data-name='course']")

        courses.each(function (i, el) {
          var currentElementId = $(el).attr('id');
          if (currentHash.includes(currentElementId)) {

            var categoryElement = $(el).closest('section').find('button[index=0]');
            categoryElement.trigger("click");

            $([document.documentElement, document.body]).animate({
              scrollTop: $("#" + currentElementId).offset().top
            }, 500);

            var courseTab = $(el).find('button');
            courseTab.trigger("click");
          }
        })
      },100)
    },
    setCourseEnrolledStatus: function(allCourses, enrolledCourses) {
      var allCoursesWithStatus = [];
      for (var i = 0; i < allCourses.length; i++) {
        allCourses[i].course.enrolled = false;
        for (var j = 0; j < enrolledCourses.length; j++) {
          if (allCourses[i].course.id == enrolledCourses[j].id) {
            allCourses[i].course.enrolled = true;
          }
        }
        allCoursesWithStatus.push(allCourses[i].course);
      }
      return allCoursesWithStatus;
    },
    insertModalAndOverlay: function() {
      $('body').append("

");
      $('body').append("

");
    },
    handleEnrollClick: function(e, html) {
      $('.mmooc-modal').html(html);
      $('.mmooc-modal-overlay').show();
      $('.mmooc-modal').show();
      $('.mmooc-modal .modal-back').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
    },
    setClickHandlers: function() {
      $('.notenrolled').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.all-courses-show-modal').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .parent()
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.mmooc-modal-overlay').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
      $(document).on('keydown', function(e) {
        if (e.keyCode === 27) {
          $('.mmooc-modal-overlay').hide();
          $('.mmooc-modal').hide();
        }
      });
    },
    populateFilter: function(categorys) {
      var options =
        '<option value="Alle">Alle tilgjengelige ' +
        mmooc.i18n.CoursePlural.toLowerCase() +
        '</option>';
      for (var i = 0; i < categorys.length; i++) {
        options +=
          '<option value="' + categorys[i] + '">' + categorys[i] + '</option>';
      }
      $('#filter').append(options);
    },
    applyFilter: function() {
      var value = $('#filter').val();
      if (value == 'Alle') {
        $('.mmooc-all-courses-list').removeClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          $(this).show();
          $(this)
            .next()
            .show();
        });
      } else {
        $('.mmooc-all-courses-list').addClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          if ($(this).text() == value) {
            $(this).show();
            $(this)
              .next()
              .show();
          } else {
            $(this).hide();
            $(this)
              .next()
              .hide();
          }
        });
      }
    }
  };
})();
<commit_msg>small code refactor<commit_after>this.mmooc = this.mmooc || {};

this.mmooc.enroll = (function() {
  return {
    changeEnrollConfirmationButton: function() {
      var enrollForm = $('#enroll_form');
      enrollForm
        .find('.btn')
        .text('Gå til mine ' + mmooc.i18n.CoursePlural.toLowerCase());
      enrollForm.find('.btn').attr('href', '/courses');
      enrollForm.find('.btn-primary').hide();
    },
    changeEnrollTitle: function(s) {
      var headline = $('.ic-Login-confirmation__headline');
      headline.text(s);
    },
    getEnrollInformationElement: function() {
      //There might be several p elements, depending on which self registration screen we are on.
      //Only return the first one.
      return $('#enroll_form > p:first');
    },
    getEnrollAction: function() {
      return $('#enroll_form').attr('action');
    },
    changeEnrollInformation: function(from, to) {
      var confirmEnrollmentElement = this.getEnrollInformationElement();
      confirmEnrollmentElement.text(
        confirmEnrollmentElement.text().replace(from, to)
      );
    },
    hideEnrollInformationPolicy: function() {
      var informationPolicy = $('.ic-Self-enrollment-footer__Secondary');
      informationPolicy.hide();
    },
    changeEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.text('Ja takk, jeg vil registrere meg!');
    },
    hideEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.hide();
    },
    isAlreadyEnrolled: function() {
      confirmEnrollmentElement = this.getEnrollInformationElement();
      var i = confirmEnrollmentElement
        .text()
        .indexOf('Du er allerede registrert i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    selectRegisterUserCheckbox: function() {
      //The checkbox is hidden by canvas-enroll.less, but we need to check it to get the right fields to display.
      setTimeout(function() {
        var createNewUserRadioButton = $('#selfEnrollmentAuthRegCreate');
        createNewUserRadioButton.click();
      }, 1000); // set timeout in ms
    },
    updatePrivacyPolicyLinks: function() {
      html = mmooc.util.renderTemplateWithData('enrollprivacypolicy', {
        privacypolicylink: mmooc.settings.privacyPolicyLink
      });
      $("label[for='selfEnrollmentAuthRegLoginAgreeTerms']").html(html);
    },
    isSelfEnrollmentPage: function() {
      var i = this.getEnrollInformationElement()
        .text()
        .indexOf('Du registrerer deg i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    changeEnrollPage: function() {
      this.changeEnrollTitle('Påmelding');
      if (this.isAlreadyEnrolled()) {
        this.changeEnrollConfirmationButton();
      } else {
        this.hideEnrollInformationPolicy();
        if (this.isSelfEnrollmentPage()) {
          //When self enrolling, give the user the impression of registering on the platform, and not on the course
          //we use to make self enrollment possible. See settings.js/selfRegisterCourseCode
          this.getEnrollInformationElement().text('');
          $('#enroll_form > p:nth-child(2)').text(
            'Vennligst fyll inn informasjonen nedenfor for å registrere deg på ' +
              mmooc.settings.platformName
          );
          this.selectRegisterUserCheckbox();
          this.updatePrivacyPolicyLinks();
          this.changeEnrollButton();
        } else {
          this.hideEnrollButton();
          this.changeEnrollInformation(
            'Du registrere deg på ',
            'Vi registrerer deg på ' +
              mmooc.i18n.CourseDefinite.toLowerCase() +
              ' '
          );
          var enrollInformationElement = this.getEnrollInformationElement();
          enrollInformationElement.html(" ");
          var enrollAction = this.getEnrollAction();
          mmooc.api.enrollUser(enrollAction, function(data) {
            $('.loading-gif').remove();
            window.location.href = '/search/all_courses' + mmooc.hrefQueryString;
          });
        }
      }
    },
    printAllCoursesContainer: function() {
      html = mmooc.util.renderTemplateWithData('allcoursescontainer', {
        courseLabel: mmooc.i18n.CoursePlural.toLowerCase(),
        allAvailableCoursesIngress: mmooc.i18n.AllAvailableCoursesIngress,
        linkToMyCourses: mmooc.utilRoot.getLinkToMyCourses()
      });
      document.title = 'Tilgjengelige ' + mmooc.i18n.CoursePlural.toLowerCase();
      document.getElementById('content').innerHTML = html;
    },
    printAllCourses: function() {
      var self = this;
      html = "

";
      $('.mmooc-all-courses-list').append(html);
      mmooc.api.getAllPublicCourses(function(allCourses) {
        mmooc.api.getEnrolledCourses(function(enrolledCourses) {
          var allCoursesWithStatus = mmooc.enroll.setCourseEnrolledStatus(
            allCourses,
            enrolledCourses
          );

          var categorys = mmooc.util.getCourseCategories(allCoursesWithStatus);

          /* If the amount of courses is large, the filter select box and corresponding javascript code in allcoursescontainer.hbs should be enabled

          mmooc.enroll.populateFilter(categorys);

          $("#filter").change(function () {
            mmooc.enroll.applyFilter();
          });

          */

          var coursesCategorized = mmooc.util.getCoursesCategorized(
            allCoursesWithStatus,
            categorys
          );

          $('.mmooc-loader-wrapper').remove();

          for (var i = 0; i < coursesCategorized.length; i++) {
            const coursesCategory = coursesCategorized[i];
            const coursesEnrolledAmount = mmooc.util.filter(
              coursesCategory.courses,
              function(course) {
                return course.enrolled === true
            }).length;
            const coursesAmount = coursesCategory.courses && coursesCategory.courses.length;

            html = mmooc.util.renderTemplateWithData('allcourseslist', {
              queryString: mmooc.hrefQueryString,
              title: coursesCategory.title,
              isAuthenticated: mmooc.util.isAuthenticated(),
              courses: coursesCategory.courses,
              coursesEnrolledAmount: coursesEnrolledAmount,
              coursesAmount: coursesAmount,
              coursesAmountText: mmooc.i18n.CoursesAmount(coursesAmount),
              courseLabel: mmooc.i18n.Course.toLowerCase(),
              goToCourse: mmooc.i18n.GoToCourse,
              courseRegister: mmooc.i18n.CourseRegister,
              courseRegisterFeide: mmooc.i18n.CourseRegisterFeide,
              openCoursesGroupText: mmooc.i18n.OpenCoursesGroup,
              closeCoursesGroupText: mmooc.i18n.CloseCoursesGroup,
              YouAreRegisteredToXCoursesText: mmooc.i18n.YouAreRegisteredToXCourses(coursesEnrolledAmount),
              index: i
            });
            $('.mmooc-all-courses-list').append(html);
            self.createHashTags();
            self.scrollToCourse();
          }

          // Displays information, that there is no current courses available to enroll
          if (coursesCategorized.length == 0) {
            html = '
' + mmooc.i18n.NoCoursesInfo + '
';
            $('.mmooc-all-courses-list').append(html);
          }

          mmooc.enroll.insertModalAndOverlay();
          mmooc.enroll.setClickHandlers();

          // TODO: move if there is a better place for this code - it handles course list UI
          // accordion UI
          $('.mmooc-accordion-header').click(event => {
            let accordionIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-accordion-header-${accordionIndex}`).hasClass(
                'mmooc-accordion-header-active'
              )
            ) {
              $(`#mmooc-accordion-header-${accordionIndex}`).toggleClass(
                'mmooc-accordion-header-active'
              );
            } else {
              $('.mmooc-accordion-header-active').removeClass(
                'mmooc-accordion-header-active'
              );

              $(`#mmooc-accordion-header-${accordionIndex}`).addClass(
                'mmooc-accordion-header-active'
              );
            }

            // remove active tabs when new accordion element is clicked
            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $('.mmooc-tabs-mobile-header-active').removeClass(
              'mmooc-tabs-mobile-header-active'
            );
            $('.mmooc-tabs-mobile-content-active').removeClass(
              'mmooc-tabs-mobile-content-active'
            );

            // add active class to first tab when the accordion element is opened
            $('.mmooc-tab-head-0').addClass('mmooc-tab-head-active');
            $('.mmooc-tab-content-0').addClass('mmooc-tab-content-active');
          });

          // tabs
          $('.mmooc-tab-head').click(event => {
            let tabIndex = event.target.getAttribute('index');

            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $(`#mmooc-tab-head-${tabIndex}`).addClass('mmooc-tab-head-active');

            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $(`#mmooc-tab-content-${tabIndex}`).addClass(
              'mmooc-tab-content-active'
            );
          });

          // tabs-mobile

          $('.mmooc-tabs-mobile-header').click(event => {
            let mobileTabIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).hasClass(
                'mmooc-tabs-mobile-header-active'
              )
            ) {
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-content-active'
              );
            } else {
              $('.mmooc-tabs-mobile-header-active').removeClass(
                'mmooc-tabs-mobile-header-active'
              );
              $('.mmooc-tabs-mobile-content-active').removeClass(
                'mmooc-tabs-mobile-content-active'
              );

              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-content-active'
              );
            }
          });
        });
      });
    },
    createHashTags: function() {
        $('span').click(function(e) {
          if ($(this).filter("[data-name='course']")) {
            var courseGroupId = $(this).closest('section').find('button[index=0]').attr('data-title');
            var hashTag = courseGroupId + "::" + e.currentTarget.id;
            window.location.hash = hashTag;
          }
        });

        $("button[data-title]").click(function(e){
          var categoryName = $(this).attr("data-title");
          var firstCourseId = $(this).siblings().find('span').eq(0).attr('id');
          var hashTag = categoryName + "::" + firstCourseId;
          window.location.hash = hashTag;
        })
    },
    scrollToCourse: function () {
      setTimeout(function() {
        var currentHash = window.location.hash.split('::');
        var courses = $('span').filter("[data-name='course']");

        courses.each(function (i, el) {
          var currentElementId = $(el).attr('id');
          if (currentHash[1] === currentElementId) {
            var categoryElement = $(el).closest('section').find('button[index=0]');
            categoryElement.trigger("click");

            $([document.documentElement, document.body]).animate({
              scrollTop: $("#" + currentElementId).offset().top
            }, 500);

            var courseTab = $(el).find('button');
            courseTab.trigger("click");
          }
        })
      },100)
    },
    setCourseEnrolledStatus: function(allCourses, enrolledCourses) {
      var allCoursesWithStatus = [];
      for (var i = 0; i < allCourses.length; i++) {
        allCourses[i].course.enrolled = false;
        for (var j = 0; j < enrolledCourses.length; j++) {
          if (allCourses[i].course.id == enrolledCourses[j].id) {
            allCourses[i].course.enrolled = true;
          }
        }
        allCoursesWithStatus.push(allCourses[i].course);
      }
      return allCoursesWithStatus;
    },
    insertModalAndOverlay: function() {
      $('body').append("

");
      $('body').append("

");
    },
    handleEnrollClick: function(e, html) {
      $('.mmooc-modal').html(html);
      $('.mmooc-modal-overlay').show();
      $('.mmooc-modal').show();
      $('.mmooc-modal .modal-back').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
    },
    setClickHandlers: function() {
      $('.notenrolled').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.all-courses-show-modal').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .parent()
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.mmooc-modal-overlay').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
      $(document).on('keydown', function(e) {
        if (e.keyCode === 27) {
          $('.mmooc-modal-overlay').hide();
          $('.mmooc-modal').hide();
        }
      });
    },
    populateFilter: function(categorys) {
      var options =
        '<option value="Alle">Alle tilgjengelige ' +
        mmooc.i18n.CoursePlural.toLowerCase() +
        '</option>';
      for (var i = 0; i < categorys.length; i++) {
        options +=
          '<option value="' + categorys[i] + '">' + categorys[i] + '</option>';
      }
      $('#filter').append(options);
    },
    applyFilter: function() {
      var value = $('#filter').val();
      if (value == 'Alle') {
        $('.mmooc-all-courses-list').removeClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          $(this).show();
          $(this)
            .next()
            .show();
        });
      } else {
        $('.mmooc-all-courses-list').addClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          if ($(this).text() == value) {
            $(this).show();
            $(this)
              .next()
              .show();
          } else {
            $(this).hide();
            $(this)
              .next()
              .hide();
          }
        });
      }
    }
  };
})();
<|endoftext|>


<commit_before>/**
 * Navigation Plugin
 * @version 2.0.0
 * @author Artus Kolanowski
 * @license The MIT License (MIT)
 */
;(function($, window, document, undefined) {
	'use strict';

	/**
	 * Creates the navigation plugin.
	 * @class The Navigation Plugin
	 * @param {Owl} carousel - The Owl Carousel.
	 */
	var Navigation = function(carousel) {
		/**
		 * Reference to the core.
		 * @protected
		 * @type {Owl}
		 */
		this._core = carousel;

		/**
		 * Indicates whether the plugin is initialized or not.
		 * @protected
		 * @type {Boolean}
		 */
		this._initialized = false;

		/**
		 * The current paging indexes.
		 * @protected
		 * @type {Array}
		 */
		this._pages = [];

		/**
		 * All DOM elements of the user interface.
		 * @protected
		 * @type {Object}
		 */
		this._controls = {};

		/**
		 * Markup for an indicator.
		 * @protected
		 * @type {Array.<String>}
		 */
		this._templates = [];

		/**
		 * The carousel element.
		 * @type {jQuery}
		 */
		this.$element = this._core.$element;

		/**
		 * Overridden methods of the carousel.
		 * @protected
		 * @type {Object}
		 */
		this._overrides = {
			next: this._core.next,
			prev: this._core.prev,
			to: this._core.to
		};

		/**
		 * All event handlers.
		 * @protected
		 * @type {Object}
		 */
		this._handlers = {
			'prepared.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.push('
' +
						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '
');
				}
			}, this),
			'added.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.splice(e.position, 0, this._templates.pop());
				}
			}, this),
			'remove.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.splice(e.position, 1);
				}
			}, this),
			'changed.owl.carousel': $.proxy(function(e) {
				if (e.namespace && e.property.name == 'position') {
					this.draw();
				}
			}, this),
			'initialized.owl.carousel': $.proxy(function(e) {
				if (e.namespace && !this._initialized) {
					this._core.trigger('initialize', null, 'navigation');
					this.initialize();
					this.update();
					this.draw();
					this._initialized = true;
					this._core.trigger('initialized', null, 'navigation');
				}
			}, this),
			'refreshed.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._initialized) {
					this._core.trigger('refresh', null, 'navigation');
					this.update();
					this.draw();
					this._core.trigger('refreshed', null, 'navigation');
				}
			}, this)
		};

		// set default options
		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);

		// register event handlers
		this.$element.on(this._handlers);
	};

	/**
	 * Default options.
	 * @public
	 * @todo Rename `slideBy` to `navBy`
	 */
	Navigation.Defaults = {
		nav: false,
		navText: [ 'prev', 'next' ],
		navSpeed: false,
		navElement: 'div',
		navContainer: false,
		navContainerClass: 'owl-nav',
		navClass: [ 'owl-prev', 'owl-next' ],
		slideBy: 1,
		dotClass: 'owl-dot',
		dotsClass: 'owl-dots',
		dots: true,
		dotsEach: false,
		dotsData: false,
		dotsSpeed: false,
		dotsContainer: false
	};

	/**
	 * Initializes the layout of the plugin and extends the carousel.
	 * @protected
	 */
	Navigation.prototype.initialize = function() {
		var override,
			settings = this._core.settings;

		// create DOM structure for relative navigation
		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
			: $('
').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');

		$('<' + settings.navElement + '>')
			.addClass(settings.navClass[0])
			.html(settings.navText[0])
			.prependTo(this._controls.$relative)
			.on('click', $.proxy(function(e) {
				this.prev(settings.navSpeed);
			}, this));
		$('<' + settings.navElement + '>')
			.addClass(settings.navClass[1])
			.html(settings.navText[1])
			.appendTo(this._controls.$relative)
			.on('click', $.proxy(function(e) {
				this.next(settings.navSpeed);
			}, this));

		// create DOM structure for absolute navigation
		if (!settings.dotsData) {
			this._templates = [ $('
')
				.addClass(settings.dotClass)
				.append($(''))
				.prop('outerHTML') ];
		}

		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
			: $('
').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');

		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
			var index = $(e.target).parent().is(this._controls.$absolute)
				? $(e.target).index() : $(e.target).parent().index();

			e.preventDefault();

			this.to(index, settings.dotsSpeed);
		}, this));

		// override public methods of the carousel
		for (override in this._overrides) {
			this._core[override] = $.proxy(this[override], this);
		}
	};

	/**
	 * Destroys the plugin.
	 * @protected
	 */
	Navigation.prototype.destroy = function() {
		var handler, control, property, override;

		for (handler in this._handlers) {
			this.$element.off(handler, this._handlers[handler]);
		}
		for (control in this._controls) {
			this._controls[control].remove();
		}
		for (override in this.overides) {
			this._core[override] = this._overrides[override];
		}
		for (property in Object.getOwnPropertyNames(this)) {
			typeof this[property] != 'function' && (this[property] = null);
		}
	};

	/**
	 * Updates the internal state.
	 * @protected
	 */
	Navigation.prototype.update = function() {
		var i, j, k,
			lower = this._core.clones().length / 2,
			upper = lower + this._core.items().length,
			maximum = this._core.maximum(true),
			settings = this._core.settings,
			size = settings.center || settings.autoWidth || settings.dotsData
				? 1 : settings.dotsEach || settings.items;

		if (settings.slideBy !== 'page') {
			settings.slideBy = Math.min(settings.slideBy, settings.items);
		}

		if (settings.dots || settings.slideBy == 'page') {
			this._pages = [];

			for (i = lower, j = 0, k = 0; i < upper; i++) {
				if (j >= size || j === 0) {
					this._pages.push({
						start: Math.min(maximum, i - lower),
						end: i - lower + size - 1
					});
					if (Math.min(maximum, i - lower) === maximum) {
						break;
					}
					j = 0, ++k;
				}
				j += this._core.mergers(this._core.relative(i));
			}
		}
	};

	/**
	 * Draws the user interface.
	 * @todo The option `dotsData` wont work.
	 * @protected
	 */
	Navigation.prototype.draw = function() {
		var difference,
			settings = this._core.settings,
			disabled = this._core.items().length <= settings.items,
			index = this._core.relative(this._core.current());

		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);

		if (settings.nav && !settings.loop && !settings.rewind) {
			this._controls.$relative.find(settings.navClass[0])
				.toggleClass('disabled', index <= this._core.minimum(true));
			this._controls.$relative.find(settings.navClass[0])
				.toggleClass('disabled', index >= this._core.maximum(true));
		}

		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);

		if (settings.dots) {
			difference = this._pages.length - this._controls.$absolute.children().length;

			if (settings.dotsData && difference !== 0) {
				this._controls.$absolute.html(this._templates.join(''));
			} else if (difference > 0) {
				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
			} else if (difference < 0) {
				this._controls.$absolute.children().slice(difference).remove();
			}

			this._controls.$absolute.find('.active').removeClass('active');
			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
		}
	};

	/**
	 * Extends event data.
	 * @protected
	 * @param {Event} event - The event object which gets thrown.
	 */
	Navigation.prototype.onTrigger = function(event) {
		var settings = this._core.settings;

		event.page = {
			index: $.inArray(this.current(), this._pages),
			count: this._pages.length,
			size: settings && (settings.center || settings.autoWidth || settings.dotsData
				? 1 : settings.dotsEach || settings.items)
		};
	};

	/**
	 * Gets the current page position of the carousel.
	 * @protected
	 * @returns {Number}
	 */
	Navigation.prototype.current = function() {
		var current = this._core.relative(this._core.current());
		return $.grep(this._pages, $.proxy(function(page, index) {
			return page.start <= current && page.end >= current;
		}, this)).pop();
	};

	/**
	 * Gets the current succesor/predecessor position.
	 * @protected
	 * @returns {Number}
	 */
	Navigation.prototype.getPosition = function(successor) {
		var position, length,
			settings = this._core.settings;

		if (settings.slideBy == 'page') {
			position = $.inArray(this.current(), this._pages);
			length = this._pages.length;
			successor ? ++position : --position;
			position = this._pages[((position % length) + length) % length].start;
		} else {
			position = this._core.relative(this._core.current());
			length = this._core.items().length;
			successor ? position += settings.slideBy : position -= settings.slideBy;
		}

		return position;
	};

	/**
	 * Slides to the next item or page.
	 * @public
	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
	 */
	Navigation.prototype.next = function(speed) {
		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
	};

	/**
	 * Slides to the previous item or page.
	 * @public
	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
	 */
	Navigation.prototype.prev = function(speed) {
		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
	};

	/**
	 * Slides to the specified item or page.
	 * @public
	 * @param {Number} position - The position of the item or page.
	 * @param {Number} [speed] - The time in milliseconds for the transition.
	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
	 */
	Navigation.prototype.to = function(position, speed, standard) {
		var length;

		if (!standard) {
			length = this._pages.length;
			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
		} else {
			$.proxy(this._overrides.to, this._core)(position, speed);
		}
	};

	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;

})(window.Zepto || window.jQuery, window, document);
<commit_msg>Corrects typo in `draw` of navigation plugin<commit_after>/**
 * Navigation Plugin
 * @version 2.0.0
 * @author Artus Kolanowski
 * @license The MIT License (MIT)
 */
;(function($, window, document, undefined) {
	'use strict';

	/**
	 * Creates the navigation plugin.
	 * @class The Navigation Plugin
	 * @param {Owl} carousel - The Owl Carousel.
	 */
	var Navigation = function(carousel) {
		/**
		 * Reference to the core.
		 * @protected
		 * @type {Owl}
		 */
		this._core = carousel;

		/**
		 * Indicates whether the plugin is initialized or not.
		 * @protected
		 * @type {Boolean}
		 */
		this._initialized = false;

		/**
		 * The current paging indexes.
		 * @protected
		 * @type {Array}
		 */
		this._pages = [];

		/**
		 * All DOM elements of the user interface.
		 * @protected
		 * @type {Object}
		 */
		this._controls = {};

		/**
		 * Markup for an indicator.
		 * @protected
		 * @type {Array.<String>}
		 */
		this._templates = [];

		/**
		 * The carousel element.
		 * @type {jQuery}
		 */
		this.$element = this._core.$element;

		/**
		 * Overridden methods of the carousel.
		 * @protected
		 * @type {Object}
		 */
		this._overrides = {
			next: this._core.next,
			prev: this._core.prev,
			to: this._core.to
		};

		/**
		 * All event handlers.
		 * @protected
		 * @type {Object}
		 */
		this._handlers = {
			'prepared.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.push('
' +
						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '
');
				}
			}, this),
			'added.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.splice(e.position, 0, this._templates.pop());
				}
			}, this),
			'remove.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._core.settings.dotsData) {
					this._templates.splice(e.position, 1);
				}
			}, this),
			'changed.owl.carousel': $.proxy(function(e) {
				if (e.namespace && e.property.name == 'position') {
					this.draw();
				}
			}, this),
			'initialized.owl.carousel': $.proxy(function(e) {
				if (e.namespace && !this._initialized) {
					this._core.trigger('initialize', null, 'navigation');
					this.initialize();
					this.update();
					this.draw();
					this._initialized = true;
					this._core.trigger('initialized', null, 'navigation');
				}
			}, this),
			'refreshed.owl.carousel': $.proxy(function(e) {
				if (e.namespace && this._initialized) {
					this._core.trigger('refresh', null, 'navigation');
					this.update();
					this.draw();
					this._core.trigger('refreshed', null, 'navigation');
				}
			}, this)
		};

		// set default options
		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);

		// register event handlers
		this.$element.on(this._handlers);
	};

	/**
	 * Default options.
	 * @public
	 * @todo Rename `slideBy` to `navBy`
	 */
	Navigation.Defaults = {
		nav: false,
		navText: [ 'prev', 'next' ],
		navSpeed: false,
		navElement: 'div',
		navContainer: false,
		navContainerClass: 'owl-nav',
		navClass: [ 'owl-prev', 'owl-next' ],
		slideBy: 1,
		dotClass: 'owl-dot',
		dotsClass: 'owl-dots',
		dots: true,
		dotsEach: false,
		dotsData: false,
		dotsSpeed: false,
		dotsContainer: false
	};

	/**
	 * Initializes the layout of the plugin and extends the carousel.
	 * @protected
	 */
	Navigation.prototype.initialize = function() {
		var override,
			settings = this._core.settings;

		// create DOM structure for relative navigation
		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
			: $('
').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');

		$('<' + settings.navElement + '>')
			.addClass(settings.navClass[0])
			.html(settings.navText[0])
			.prependTo(this._controls.$relative)
			.on('click', $.proxy(function(e) {
				this.prev(settings.navSpeed);
			}, this));
		$('<' + settings.navElement + '>')
			.addClass(settings.navClass[1])
			.html(settings.navText[1])
			.appendTo(this._controls.$relative)
			.on('click', $.proxy(function(e) {
				this.next(settings.navSpeed);
			}, this));

		// create DOM structure for absolute navigation
		if (!settings.dotsData) {
			this._templates = [ $('
')
				.addClass(settings.dotClass)
				.append($(''))
				.prop('outerHTML') ];
		}

		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
			: $('
').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');

		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
			var index = $(e.target).parent().is(this._controls.$absolute)
				? $(e.target).index() : $(e.target).parent().index();

			e.preventDefault();

			this.to(index, settings.dotsSpeed);
		}, this));

		// override public methods of the carousel
		for (override in this._overrides) {
			this._core[override] = $.proxy(this[override], this);
		}
	};

	/**
	 * Destroys the plugin.
	 * @protected
	 */
	Navigation.prototype.destroy = function() {
		var handler, control, property, override;

		for (handler in this._handlers) {
			this.$element.off(handler, this._handlers[handler]);
		}
		for (control in this._controls) {
			this._controls[control].remove();
		}
		for (override in this.overides) {
			this._core[override] = this._overrides[override];
		}
		for (property in Object.getOwnPropertyNames(this)) {
			typeof this[property] != 'function' && (this[property] = null);
		}
	};

	/**
	 * Updates the internal state.
	 * @protected
	 */
	Navigation.prototype.update = function() {
		var i, j, k,
			lower = this._core.clones().length / 2,
			upper = lower + this._core.items().length,
			maximum = this._core.maximum(true),
			settings = this._core.settings,
			size = settings.center || settings.autoWidth || settings.dotsData
				? 1 : settings.dotsEach || settings.items;

		if (settings.slideBy !== 'page') {
			settings.slideBy = Math.min(settings.slideBy, settings.items);
		}

		if (settings.dots || settings.slideBy == 'page') {
			this._pages = [];

			for (i = lower, j = 0, k = 0; i < upper; i++) {
				if (j >= size || j === 0) {
					this._pages.push({
						start: Math.min(maximum, i - lower),
						end: i - lower + size - 1
					});
					if (Math.min(maximum, i - lower) === maximum) {
						break;
					}
					j = 0, ++k;
				}
				j += this._core.mergers(this._core.relative(i));
			}
		}
	};

	/**
	 * Draws the user interface.
	 * @todo The option `dotsData` wont work.
	 * @protected
	 */
	Navigation.prototype.draw = function() {
		var difference,
			settings = this._core.settings,
			disabled = this._core.items().length <= settings.items,
			index = this._core.relative(this._core.current());

		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);

		if (settings.nav && !settings.loop && !settings.rewind) {
			this._controls.$relative.find('.' + settings.navClass[0])
				.toggleClass('disabled', index <= this._core.minimum(true));
			this._controls.$relative.find('.' + settings.navClass[1])
				.toggleClass('disabled', index >= this._core.maximum(true));
		}

		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);

		if (settings.dots) {
			difference = this._pages.length - this._controls.$absolute.children().length;

			if (settings.dotsData && difference !== 0) {
				this._controls.$absolute.html(this._templates.join(''));
			} else if (difference > 0) {
				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
			} else if (difference < 0) {
				this._controls.$absolute.children().slice(difference).remove();
			}

			this._controls.$absolute.find('.active').removeClass('active');
			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
		}
	};

	/**
	 * Extends event data.
	 * @protected
	 * @param {Event} event - The event object which gets thrown.
	 */
	Navigation.prototype.onTrigger = function(event) {
		var settings = this._core.settings;

		event.page = {
			index: $.inArray(this.current(), this._pages),
			count: this._pages.length,
			size: settings && (settings.center || settings.autoWidth || settings.dotsData
				? 1 : settings.dotsEach || settings.items)
		};
	};

	/**
	 * Gets the current page position of the carousel.
	 * @protected
	 * @returns {Number}
	 */
	Navigation.prototype.current = function() {
		var current = this._core.relative(this._core.current());
		return $.grep(this._pages, $.proxy(function(page, index) {
			return page.start <= current && page.end >= current;
		}, this)).pop();
	};

	/**
	 * Gets the current succesor/predecessor position.
	 * @protected
	 * @returns {Number}
	 */
	Navigation.prototype.getPosition = function(successor) {
		var position, length,
			settings = this._core.settings;

		if (settings.slideBy == 'page') {
			position = $.inArray(this.current(), this._pages);
			length = this._pages.length;
			successor ? ++position : --position;
			position = this._pages[((position % length) + length) % length].start;
		} else {
			position = this._core.relative(this._core.current());
			length = this._core.items().length;
			successor ? position += settings.slideBy : position -= settings.slideBy;
		}

		return position;
	};

	/**
	 * Slides to the next item or page.
	 * @public
	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
	 */
	Navigation.prototype.next = function(speed) {
		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
	};

	/**
	 * Slides to the previous item or page.
	 * @public
	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
	 */
	Navigation.prototype.prev = function(speed) {
		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
	};

	/**
	 * Slides to the specified item or page.
	 * @public
	 * @param {Number} position - The position of the item or page.
	 * @param {Number} [speed] - The time in milliseconds for the transition.
	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
	 */
	Navigation.prototype.to = function(position, speed, standard) {
		var length;

		if (!standard) {
			length = this._pages.length;
			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
		} else {
			$.proxy(this._overrides.to, this._core)(position, speed);
		}
	};

	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;

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