<commit_before>/* @flow */

// TODO: Uncomment this
// import { Buffer } from 'buffer'

// NOTE: The reason we have encodeArray option is because redis protocol
// does not support nested arrays
export function encode(request: any, encodeArray: boolean = true) {
  if (request === null) {
    return '$-1\r\n'
  }
  if (Array.isArray(request) && encodeArray) {
    const content = [`*${request.length}\r\n`]
    for (let i = 0, length = request.length; i < length; i++) {
      content.push(encode(request[i], false))
    }
    return content.join('')
  }
  let value
  if (typeof request === 'object' || typeof request === 'function') {
    value = {}.toString.call(request)
  } else {
    value = String(value)
  }
  return `$${value.length}\r\n${value}\r\n`
}

export function decodeProgressive(content: Buffer, startIndex: number): { index: number, value: any } {
  let currentIndex = startIndex
  const type = content.toString('utf8', currentIndex, currentIndex + 1)
  // +1 because type takes 1 character
  currentIndex++

  if (type === '*') {
    // Array
    const lengthEnd = content.indexOf('\r\n', currentIndex)
    const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10)
    // +2 because of \r\n after length ends
    currentIndex = lengthEnd + 2

    const value = []
    for (let i = 0; i < length; i++) {
      const entry = decodeProgressive(content, currentIndex)
      currentIndex = entry.index
      value.push(entry.value)
    }
    return { index: currentIndex, value }
  }

  if (type === '$') {
    // String or Null
    const lengthEnd = content.indexOf('\r\n', currentIndex)
    const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10)
    // +2 because of \r\n after length ends
    currentIndex = lengthEnd + 2

    let value
    if (length === -1) {
      // Null
      value = null
    } else {
      // String
      value = content.toString('utf8', currentIndex, currentIndex + length)
      // +2 because of \r\n at the end of string
      currentIndex += length + 2
    }

    return { index: currentIndex, value }
  }

  if (type === '+') {
    // Simple string
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = content.toString('utf8', currentIndex, valueEnd)
    // +2 because of \r\n at the end of simple string
    currentIndex = valueEnd + 2

    return { index: currentIndex, value }
  }

  if (type === ':') {
    // Integer
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = parseInt(content.toString('utf8', currentIndex, valueEnd), 10)
    // +2 because of \r\n at the end of simple string
    currentIndex = valueEnd + 2

    return { index: currentIndex, value }
  }

  if (type === '-') {
    // Error
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = content.toString('utf8', currentIndex, valueEnd)
    throw new Error(value)
  }

  throw new Error('Malformed Input')
}

export function *decodeGen(givenContent: Buffer | string): Generator<any, void, void> {
  let index = 0
  const content = Buffer.from(givenContent)

  for (;;) {
    const entry = decodeProgressive(content, index)
    index = entry.index
    yield entry.value
    if (index === content.length) {
      // We have read it all!
      break
    }
  }
}

export function decode(givenContent: Buffer | string): Array<any> {
  let index = 0
  const value = []
  const content = Buffer.from(givenContent)

  for (;;) {
    const entry = decodeProgressive(content, index)
    index = entry.index
    value.push(entry.value)
    if (index === content.length) {
      // We have read it all!
      break
    }
  }

  return value
}
<commit_msg>:bug: Fix a typo<commit_after>/* @flow */

// TODO: Uncomment this
// import { Buffer } from 'buffer'

// NOTE: The reason we have encodeArray option is because redis protocol
// does not support nested arrays
export function encode(request: any, encodeArray: boolean = true) {
  if (request === null) {
    return '$-1\r\n'
  }
  if (Array.isArray(request) && encodeArray) {
    const content = [`*${request.length}\r\n`]
    for (let i = 0, length = request.length; i < length; i++) {
      content.push(encode(request[i], false))
    }
    return content.join('')
  }
  let value
  if (typeof request === 'object' || typeof request === 'function') {
    value = {}.toString.call(request)
  } else {
    value = String(request)
  }
  return `$${value.length}\r\n${value}\r\n`
}

export function decodeProgressive(content: Buffer, startIndex: number): { index: number, value: any } {
  let currentIndex = startIndex
  const type = content.toString('utf8', currentIndex, currentIndex + 1)
  // +1 because type takes 1 character
  currentIndex++

  if (type === '*') {
    // Array
    const lengthEnd = content.indexOf('\r\n', currentIndex)
    const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10)
    // +2 because of \r\n after length ends
    currentIndex = lengthEnd + 2

    const value = []
    for (let i = 0; i < length; i++) {
      const entry = decodeProgressive(content, currentIndex)
      currentIndex = entry.index
      value.push(entry.value)
    }
    return { index: currentIndex, value }
  }

  if (type === '$') {
    // String or Null
    const lengthEnd = content.indexOf('\r\n', currentIndex)
    const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10)
    // +2 because of \r\n after length ends
    currentIndex = lengthEnd + 2

    let value
    if (length === -1) {
      // Null
      value = null
    } else {
      // String
      value = content.toString('utf8', currentIndex, currentIndex + length)
      // +2 because of \r\n at the end of string
      currentIndex += length + 2
    }

    return { index: currentIndex, value }
  }

  if (type === '+') {
    // Simple string
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = content.toString('utf8', currentIndex, valueEnd)
    // +2 because of \r\n at the end of simple string
    currentIndex = valueEnd + 2

    return { index: currentIndex, value }
  }

  if (type === ':') {
    // Integer
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = parseInt(content.toString('utf8', currentIndex, valueEnd), 10)
    // +2 because of \r\n at the end of simple string
    currentIndex = valueEnd + 2

    return { index: currentIndex, value }
  }

  if (type === '-') {
    // Error
    const valueEnd = content.indexOf('\r\n', currentIndex)
    const value = content.toString('utf8', currentIndex, valueEnd)
    throw new Error(value)
  }

  throw new Error('Malformed Input')
}

export function *decodeGen(givenContent: Buffer | string): Generator<any, void, void> {
  let index = 0
  const content = Buffer.from(givenContent)

  for (;;) {
    const entry = decodeProgressive(content, index)
    index = entry.index
    yield entry.value
    if (index === content.length) {
      // We have read it all!
      break
    }
  }
}

export function decode(givenContent: Buffer | string): Array<any> {
  let index = 0
  const value = []
  const content = Buffer.from(givenContent)

  for (;;) {
    const entry = decodeProgressive(content, index)
    index = entry.index
    value.push(entry.value)
    if (index === content.length) {
      // We have read it all!
      break
    }
  }

  return value
}
<|endoftext|>


<commit_before>javascript:
function crcl(){
  var d=document,
      z=d.createElement('scr'+'ipt'),
      b=d.body,
      l=d.location,
      //development === localhost || production === //www.caracol.azurewebsites.net
      u='127.0.0.1:3000';
  try{
    if(!b)
      throw(0);

    d.title='(Saving...) '
      +d.title;

    z.setAttribute('src',l.protocol
      +u
      +'/uri/'
      +encodeURIComponent(l.href));

    b.appendChild(z);
    }
  catch(e){
    alert('Please wait until the page has loaded.');
  }
}crcl();
void(0)<commit_msg>added date and time stamp to uri passed up<commit_after>javascript:
function crcl(){
  var d=document,
      z=d.createElement('scr'+'ipt'),
      b=d.body,
      l=d.location,
      //development === localhost || production === //www.caracol.azurewebsites.net
      u='127.0.0.1:3000';
  try{
    if(!b)
      throw(0);

    d.title='(Saving...) '
      +d.title;

    z.setAttribute('src',l.protocol
      +u
      +'/app/' + encodeURIComponent(l.href)
      +'&t=' + (new Date().getTime()));

    b.appendChild(z);
    }
  catch(e){
    alert('Please wait until the page has loaded.');
  }
}crcl();
void(0)<|endoftext|>


<commit_before>import omit from 'lodash/omit';
import partial from 'lodash/'
import PresenterActions from '../actionTypes/PresenterActionTypes';

function parseEventData(data = {}) {
  try {
    data = JSON.parse(data);
  } catch(error) {
    data = { error };
  }
  return data;
}

// Initializes the Presenter View's app state so that its in sync with the
// Client Window. Omits the `meta` reducer to avoid circular references.
function initPresenterState(win, store) {
  const state = store.getState();
  state.meta.presenterWin.postMessage(JSON.stringify({
    type: PresenterActions.PRESENTER_STATE_CHANGED,
    payload: omit(state, 'meta')
  }), win.location.origin);
}

export function handlePresenterMessage(win, store, event) {
  if(event.origin !== win.location.origin) {
    return;
  }
  const data = parseEventData(event.data);
  switch(data.type) {
    case PresenterActions.PRESENTER_WINDOW_READY:
      return initPresenterState(win, store);
    default:
      // Dispatch all other postMessage events into the Redux store
      return store.dispatch(data);
  }
}

function presenterClosed(clientWin, presenterWin) {
  clientWin.postMessage(JSON.stringify({
    type: PresenterActions.PRESENTER_WINDOW_CLOSED,
    payload: {}
  }), presenterWin.location.origin);
}

// Tells the Client Window that the Presenter app has mounted and is ready to
// receive state and messages
export function presenterReady(presenterWin) {
  const clientWin = presenterWin.opener;
  const msg = {
    type: PresenterActions.PRESENTER_WINDOW_READY,
    payload: {}
  };
  presenterWin.addEventListener('beforeunload', function onPresenterUnload(event) {
    clientWin.postMessage(JSON.stringify({
      type: PresenterActions.PRESENTER_WINDOW_CLOSED,
      payload: {}
    }), presenterWin.location.origin);
    presenterWin.removeEventListener('beforeunload', onPresenterUnload);
  });
  clientWin.postMessage(JSON.stringify(msg), presenterWin.location.origin);
  // Dispatch an event that can keep track of the Client Window object
  return {
    type: PresenterActions.PRESENTER_WINDOW_READY,
    payload: {
      clientWin: presenterWin.opener
    }
  };
}

// Spawns a new window that contains the "Presenter" view of the clock display
export function spawnPresenterWindow() {
  return (dispatch, getState) => {
    const { meta } = getState();
    if(meta.presenterWin) {
      console.warn('Presenter Window already spawned. If closed, it was not cleaned up properly.');
      return;
    }
    const presenterWin = window.open('/presenter.html');
    dispatch({
      type: PresenterActions.PRESENTER_WINDOW_SPAWNED,
      payload: { presenterWin }
    });
    window.addEventListener('beforeunload', function handleClientClose() {
      if(!presenterWin.closed) {
        presenterWin.close();
      }
    });
  };
}
<commit_msg>Fix one more path issue on GH Pages<commit_after>import omit from 'lodash/omit';
import partial from 'lodash/'
import PresenterActions from '../actionTypes/PresenterActionTypes';

function parseEventData(data = {}) {
  try {
    data = JSON.parse(data);
  } catch(error) {
    data = { error };
  }
  return data;
}

// Initializes the Presenter View's app state so that its in sync with the
// Client Window. Omits the `meta` reducer to avoid circular references.
function initPresenterState(win, store) {
  const state = store.getState();
  state.meta.presenterWin.postMessage(JSON.stringify({
    type: PresenterActions.PRESENTER_STATE_CHANGED,
    payload: omit(state, 'meta')
  }), win.location.origin);
}

export function handlePresenterMessage(win, store, event) {
  if(event.origin !== win.location.origin) {
    return;
  }
  const data = parseEventData(event.data);
  switch(data.type) {
    case PresenterActions.PRESENTER_WINDOW_READY:
      return initPresenterState(win, store);
    default:
      // Dispatch all other postMessage events into the Redux store
      return store.dispatch(data);
  }
}

function presenterClosed(clientWin, presenterWin) {
  clientWin.postMessage(JSON.stringify({
    type: PresenterActions.PRESENTER_WINDOW_CLOSED,
    payload: {}
  }), presenterWin.location.origin);
}

// Tells the Client Window that the Presenter app has mounted and is ready to
// receive state and messages
export function presenterReady(presenterWin) {
  const clientWin = presenterWin.opener;
  const msg = {
    type: PresenterActions.PRESENTER_WINDOW_READY,
    payload: {}
  };
  presenterWin.addEventListener('beforeunload', function onPresenterUnload(event) {
    clientWin.postMessage(JSON.stringify({
      type: PresenterActions.PRESENTER_WINDOW_CLOSED,
      payload: {}
    }), presenterWin.location.origin);
    presenterWin.removeEventListener('beforeunload', onPresenterUnload);
  });
  clientWin.postMessage(JSON.stringify(msg), presenterWin.location.origin);
  // Dispatch an event that can keep track of the Client Window object
  return {
    type: PresenterActions.PRESENTER_WINDOW_READY,
    payload: {
      clientWin: presenterWin.opener
    }
  };
}

// Spawns a new window that contains the "Presenter" view of the clock display
export function spawnPresenterWindow() {
  return (dispatch, getState) => {
    const { meta } = getState();
    if(meta.presenterWin) {
      console.warn('Presenter Window already spawned. If closed, it was not cleaned up properly.');
      return;
    }
    const presenterWin = window.open('presenter.html');
    dispatch({
      type: PresenterActions.PRESENTER_WINDOW_SPAWNED,
      payload: { presenterWin }
    });
    window.addEventListener('beforeunload', function handleClientClose() {
      if(!presenterWin.closed) {
        presenterWin.close();
      }
    });
  };
}
<|endoftext|>


<commit_before>(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		define([], factory);
	} else if (typeof module === 'object' && module.exports) {
		module.exports = factory();
	} else {
		root.FilterAny = factory();
	}
}(this, function () {
	var defaults = {
		debounceTimeout: 200,
		highlightedClass: 'filter-highlighted',
		inputSelector: 'input[type=search]',
		itemContainerSelector: 'ul',
		itemSelector: 'li',
		itemTextSelector: '',
		onSearch: function() {}
	};
	function highlightNode(node, startIndex, length, classList) {
		var highlightedNode = document.createElement('mark');
		highlightedNode.classList.add(classList);
		var highlight = document.createRange();
		var nodes = node.childNodes;
		var index = 0;
		for (var i = 0; i <= nodes.length - 1; i++) {
			var localIndex = startIndex - index;
			if ( localIndex < 0 ) {
				break;
			}
			if ( isTextNode(nodes[i]) && localIndex <= nodes[i].textContent.length - 1) {
				highlight.selectNodeContents(nodes[i]);
				highlight.setStart(nodes[i], localIndex);
				highlight.setEnd(nodes[i], localIndex + length);
				highlight.surroundContents(highlightedNode);
				break;
			}
			index += nodes[i].textContent.length;
		};
	}

	function isTextNode(node) {
		return node.nodeType === 3 && /\S/.test(node.textContent);
	}

	function findTextNode(node) {
		var children = node.childNodes,
			child = null,
			textNode = null;
		for (var i = 0; i < children.length; i++) {
			child = children[i];
			if ( isTextNode(child) ) {
				return child;
			}
			else {
				textNode = findTextNode(child);
				if ( textNode ) {
					return textNode;
				}
			}
		}
		return null;
	}
	function cleanItems(containers) {
		for (var i = containers.length - 1; i >= 0; i--) {
			var container = containers[i];
			cleanNodes(container.nodes);
		};
	}

	function cleanNodes(nodes) {
		for (var i = nodes.length - 1; i >= 0; i--) {
			var node = nodes[i];
			node.style.display = '';
			var previouslyHighlighted = node.querySelectorAll('mark');
			if ( !previouslyHighlighted.length ) {
				continue;
			}
			for (var j = previouslyHighlighted.length - 1; j >= 0; j--) {
				var el = previouslyHighlighted[j];
				el.parentNode.replaceChild(el.childNodes[0], el);	//unwrapping
			};
			node.normalize();	//concat textNodes
		};
	}

	function arrayFromNodeList(nodeList) {
		var result = new Array(nodeList.length);
		for (var i = result.length - 1; i >= 0; i--) {
			result[i] = nodeList[i];
		}
		return result;
	}

	function FilterAny(element, options) {
		if (!element) {
			throw new Error('FilterAny: firts argument expected to be Node');
		}

		this.element = element;
		this.settings = {};
		for (var prop in defaults) {
			this.settings[prop] = (options && options[prop]) ? options[prop] : defaults[prop];
		}
		this.init();
	}

	FilterAny.prototype.onInput = function() {
		var instance = this;
		return function() {
			clearTimeout(instance.triggerTimer);
			instance.triggerTimer = setTimeout(function(){
				instance.search(instance.input.value);
			}, instance.settings.debounceTimeout);
		}
	}

	FilterAny.prototype.onReset = function() {
		var instance = this;
		return function(e) {
			instance.search(instance.input.getAttribute('value'));
		}
	}

	FilterAny.prototype.init = function() {
		var instance = this;
		instance.triggerTimer;
		instance.input = instance.element.querySelector(instance.settings.inputSelector);
		if (!instance.input) {
			throw new Error('FilterAny: no input found (refer to option `inputSelector`)');
		}
		instance.itemContainerList = instance.element.querySelectorAll(instance.settings.itemContainerSelector);
		if (!instance.itemContainerList) {
			throw new Error('FilterAny: no input found (refer to option `itemContainerSelector`)');
		}
		var itemContainers = arrayFromNodeList(instance.itemContainerList);

		instance.containers = [];
		itemContainers.forEach(function(itemContainer, index){
			var nodeList = itemContainer.querySelectorAll(instance.settings.itemSelector);
			var nodes = arrayFromNodeList(nodeList);

			cleanNodes(nodes);
			var textNodes = nodes.map(function(node){
				return instance.settings.itemTextSelector ? node.querySelector(instance.settings.itemTextSelector) : node;
			});
			var strings = textNodes.map(function(textNode){
				return textNode.textContent;
			});
			instance.containers.push({
				'containerElement': this,
				'strings': strings,
				'nodes': nodes,
				'textNodes': textNodes
			});
		});
		var inputHandler = this.onInput(instance);
		var resetHandler = this.onReset(instance);
		instance.input.removeEventListener('input', inputHandler);
		instance.input.addEventListener('input', inputHandler);
		var form = instance.input.form;
		if ( form ) {
			form.removeEventListener('reset', resetHandler);
			form.addEventListener('reset', resetHandler);
		}

		if (this.input.value) {
			this.search(instance.input.value);
		}
	}

	FilterAny.prototype.search = function(query) {
		var instance = this;
		var itemsFound = [];
		cleanItems(instance.containers)
		if ( !query ) {
			instance.settings.onSearch.call(instance, null);
			return;
		}

		for (var i = instance.containers.length - 1; i >= 0; i--) {
			var container = instance.containers[i];
			var containerElement = container.containerElement;
			var nodes = container.nodes;

			// remembering container position in DOM before detaching
			// var containerParent = containerElement.parentNode;
			// var containerIndex = Array.prototype.indexOf.call(containerParent.childNodes, containerElement);
			// if ( containerElement.nextSibling ) {
			// 	var containerNextSibling = containerElement.nextSibling;
			// }
			// containerParent.removeChild(containerElement);

			for (var j = container.strings.length - 1; j >= 0; j--) {
				var node = container.nodes[j];
				var textNode = container.textNodes[j];

				var occurenceIndex = container.strings[j].toLowerCase().indexOf(query.toLowerCase());
				if ( occurenceIndex === -1 ) {
					node.style.display = 'none';
					continue;
				}
				else {
					itemsFound.push(node);
				}

				// highlighting all occurences
				if ( instance.settings.highlightedClass ) {
					while (occurenceIndex != -1) {
						highlightNode(textNode, occurenceIndex, query.length, instance.settings.highlightedClass);
						occurenceIndex = container.strings[j].toLowerCase().indexOf(query.toLowerCase(), occurenceIndex + 1);
					}
				}
			};
			//appending container back to it's origin
			// if ( containerNextSibling ) {
			// 	containerParent.insertBefore(containerElement, containerNextSibling);
			// }
			// else {
			// 	containerParent.appendChild(containerElement)
			// }
		}

		instance.settings.onSearch.call(this, itemsFound);
	}

	return FilterAny;
}));<commit_msg>fixed: eslint warnings<commit_after>(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		define([], factory);
	} else if (typeof module === 'object' && module.exports) {
		module.exports = factory();
	} else {
		root.FilterAny = factory();
	}
}(this, function () {
	var defaults = {
		debounceTimeout: 200,
		highlightedClass: 'filter-highlighted',
		inputSelector: 'input[type=search]',
		itemContainerSelector: 'ul',
		itemSelector: 'li',
		itemTextSelector: '',
		onSearch: function() {}
	};
	function highlightNode(node, startIndex, length, classList) {
		var highlightedNode = document.createElement('mark');
		highlightedNode.classList.add(classList);
		var highlight = document.createRange();
		var nodes = node.childNodes;
		var index = 0;
		for (var i = 0; i <= nodes.length - 1; i++) {
			var localIndex = startIndex - index;
			if ( localIndex < 0 ) {
				break;
			}
			if ( isTextNode(nodes[i]) && localIndex <= nodes[i].textContent.length - 1) {
				highlight.selectNodeContents(nodes[i]);
				highlight.setStart(nodes[i], localIndex);
				highlight.setEnd(nodes[i], localIndex + length);
				highlight.surroundContents(highlightedNode);
				break;
			}
			index += nodes[i].textContent.length;
		}
	}

	function isTextNode(node) {
		return node.nodeType === 3 && /\S/.test(node.textContent);
	}

	function findTextNode(node) {
		var children = node.childNodes,
			child = null,
			textNode = null;
		for (var i = 0; i < children.length; i++) {
			child = children[i];
			if ( isTextNode(child) ) {
				return child;
			}
			else {
				textNode = findTextNode(child);
				if ( textNode ) {
					return textNode;
				}
			}
		}
		return null;
	}
	function cleanItems(containers) {
		for (var i = containers.length - 1; i >= 0; i--) {
			var container = containers[i];
			cleanNodes(container.nodes);
		}
	}

	function cleanNodes(nodes) {
		for (var i = nodes.length - 1; i >= 0; i--) {
			var node = nodes[i];
			node.style.display = '';
			var previouslyHighlighted = node.querySelectorAll('mark');
			if ( !previouslyHighlighted.length ) {
				continue;
			}
			for (var j = previouslyHighlighted.length - 1; j >= 0; j--) {
				var el = previouslyHighlighted[j];
				el.parentNode.replaceChild(el.childNodes[0], el);	//unwrapping
			}
			node.normalize();	//concat textNodes
		}
	}

	function arrayFromNodeList(nodeList) {
		var result = new Array(nodeList.length);
		for (var i = result.length - 1; i >= 0; i--) {
			result[i] = nodeList[i];
		}
		return result;
	}

	function FilterAny(element, options) {
		if (!element) {
			throw new Error('FilterAny: firts argument expected to be Node');
		}

		this.element = element;
		this.settings = {};
		for (var prop in defaults) {
			this.settings[prop] = (options && options[prop]) ? options[prop] : defaults[prop];
		}
		this.init();
	}

	FilterAny.prototype.onInput = function() {
		var instance = this;
		return function() {
			clearTimeout(instance.triggerTimer);
			instance.triggerTimer = setTimeout(function(){
				instance.search(instance.input.value);
			}, instance.settings.debounceTimeout);
		}
	}

	FilterAny.prototype.onReset = function() {
		var instance = this;
		return function(e) {
			instance.search(instance.input.getAttribute('value'));
		}
	}

	FilterAny.prototype.init = function() {
		var instance = this;
		instance.input = instance.element.querySelector(instance.settings.inputSelector);
		if (!instance.input) {
			throw new Error('FilterAny: no input found (refer to option `inputSelector`)');
		}
		instance.itemContainerList = instance.element.querySelectorAll(instance.settings.itemContainerSelector);
		if (!instance.itemContainerList) {
			throw new Error('FilterAny: no input found (refer to option `itemContainerSelector`)');
		}
		var itemContainers = arrayFromNodeList(instance.itemContainerList);

		instance.containers = [];
		itemContainers.forEach(function(itemContainer, index){
			var nodeList = itemContainer.querySelectorAll(instance.settings.itemSelector);
			var nodes = arrayFromNodeList(nodeList);

			cleanNodes(nodes);
			var textNodes = nodes.map(function(node){
				return instance.settings.itemTextSelector ? node.querySelector(instance.settings.itemTextSelector) : node;
			});
			var strings = textNodes.map(function(textNode){
				return textNode.textContent;
			});
			instance.containers.push({
				'containerElement': this,
				'strings': strings,
				'nodes': nodes,
				'textNodes': textNodes
			});
		});
		var inputHandler = this.onInput(instance);
		var resetHandler = this.onReset(instance);
		instance.input.removeEventListener('input', inputHandler);
		instance.input.addEventListener('input', inputHandler);
		var form = instance.input.form;
		if ( form ) {
			form.removeEventListener('reset', resetHandler);
			form.addEventListener('reset', resetHandler);
		}

		if (this.input.value) {
			this.search(instance.input.value);
		}
	}

	FilterAny.prototype.search = function(query) {
		var instance = this;
		var itemsFound = [];
		cleanItems(instance.containers)
		if ( !query ) {
			instance.settings.onSearch.call(instance, null);
			return;
		}

		instance.input.value = query;

		for (var i = instance.containers.length - 1; i >= 0; i--) {
			var container = instance.containers[i];
			var containerElement = container.containerElement;
			var nodes = container.nodes;

			// remembering container position in DOM before detaching
			// var containerParent = containerElement.parentNode;
			// var containerIndex = Array.prototype.indexOf.call(containerParent.childNodes, containerElement);
			// if ( containerElement.nextSibling ) {
			// 	var containerNextSibling = containerElement.nextSibling;
			// }
			// containerParent.removeChild(containerElement);

			for (var j = container.strings.length - 1; j >= 0; j--) {
				var node = container.nodes[j];
				var textNode = container.textNodes[j];

				var occurenceIndex = container.strings[j].toLowerCase().indexOf(query.toLowerCase());
				if ( occurenceIndex === -1 ) {
					node.style.display = 'none';
					continue;
				}
				else {
					itemsFound.push(node);
				}

				// highlighting all occurences
				if ( instance.settings.highlightedClass ) {
					while (occurenceIndex !== -1) {
						highlightNode(textNode, occurenceIndex, query.length, instance.settings.highlightedClass);
						occurenceIndex = container.strings[j].toLowerCase().indexOf(query.toLowerCase(), occurenceIndex + 1);
					}
				}
			}
			//appending container back to it's origin
			// if ( containerNextSibling ) {
			// 	containerParent.insertBefore(containerElement, containerNextSibling);
			// }
			// else {
			// 	containerParent.appendChild(containerElement)
			// }
		}

		instance.settings.onSearch.call(this, itemsFound);
	}

	return FilterAny;
}));<|endoftext|>


<commit_before>var api_url = "http://knetminer.rothamsted.ac.uk/ws/wheat/";
//var data_url = "http://knetminer.rothamsted.ac.uk/wheat_data/";
//var data_url = "http://qtlnetminer-test.rothamsted.ac.uk/wheat_data/"; // now, using HTTP instead of HTTPS
//var data_url = "http://maize-dev.rothamsted.ac.uk/wheat_data/";
var species = 'Wheat Genome (IWGSP1, MIPSv2.1)';
var reference_genome = true/*false*/; //true if you are providing a reference genome, false to disable MapView
var multiorganisms = false; //true if you specified more than one taxid in the server file config.xml (ie: <entry key="SpeciesTaxId">4113,4081</entry>)
var longest_chr = 850000000;
var species_name = 'Triticum aestivum';<commit_msg>apir_url test wheat port<commit_after>//var api_url = "http://knetminer.rothamsted.ac.uk/ws/wheat";
var api_url = "http://babvs57.rothamsted.ac.uk:8443/ws/wheat";
//var data_url = "http://knetminer.rothamsted.ac.uk/wheat_data/";
//var data_url = "http://maize-dev.rothamsted.ac.uk/wheat_data/";
var species = 'Wheat Genome (IWGSP1, MIPSv2.1)';
var reference_genome = true/*false*/; //true if you are providing a reference genome, false to disable MapView
var multiorganisms = false; //true if you specified more than one taxid in the server file config.xml (ie: <entry key="SpeciesTaxId">4113,4081</entry>)
var longest_chr = 850000000;
var species_name = 'Triticum aestivum';<|endoftext|>


<commit_before>/*
    InfinityScroller

    Create the Google Reader-type of endless scrolling on (almost) any page.

    (c) Copyright 2008 Gyula László. All Rights Reserved.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/**
    See README for more info or go to

        http://psinc.wordpress.com/cscroller_js

        or

        http://github.com/gyulalaszlo/csscroller

    to obtain your copy.

    Usage by example:

	new thepaw.ContinousScroller("recommended_programs",{ url:"/top10/$page_num$" }, {
		loading_placeholder:'
Blah-blah
',
		check_interval:0.5,
		failiure_message:'Something terrible happened.
'+
		    'We cannot help you get any more content. Check your internet connection.'
	})

*/

thepaw = {}

thepaw.ContinousScroller = Class.create()
thepaw.ContinousScroller.prototype = {

    /**
    new thepaw.ContinousScroller(content_div_id, url_generator, options)

    Create a continous scroller. Only one instance per page...

    Parameters:

        content_div_id:
            The div to serve the content into.
        url_generator:
            The url generator to use. See "The default url generator"
            bit bellow.

    */
    initialize: function(content_div_id, url_generator, options) {

        this.options = $H( thepaw.ContinousScroller.DefaultConfiguration ).merge(options)
        this.url_generator = (typeof url_generator.next == 'undefined' ?
            $H(thepaw.ContinousScroller.DefaultUrlGenerator ).merge(url_generator) : url_generator)

        this.div_id = content_div_id
        this.updateInProgress = false

        new Insertion.After( this.div_id,
            "
" +
            options.loading_placeholder + "
")

        this.updater = new PeriodicalExecuter( function(pe) {
            var t = pe.target_obj
            if (t == null) return
            if (!t.updateInProgress &&
                    (thepaw.third_party.getPageHeight() -
                    thepaw.third_party.getScrollHeight()) < t.options.trigger_height) {
            	    t.updateInProgress = true;
            	    t.getMoreContent();
            }
        }, this.options.check_interval );
        this.updater.target_obj = this

    },

    getMoreContent: function(){
        var t = this
        $( this.placeholderDivId ).show()
        new Ajax.Request(this.url_generator.next()  , {
            method: 'get',
            onSuccess: function(transport) {
                // No more elements for us. Stop.
                if (transport.responseText.length < 300) t.updater.stop()

                // Update the content
                new Insertion.Bottom(t.div_id, transport.responseText)
                $( t.placeholderDivId ).hide()
                t.updateInProgress = false;
            },

            onFailure: function(transport) {
                new Insertion.bottom( t.div_id,
                    "
" + t.options.failiure_message
                    + "
"
                )
            }

        })
    },

    placeholderDivId:'continous_scroller_loading_placeholder'

}

/**
    The default options
    =========================

    Options:

        check_interval:
            The interval between checks (seconds). Default is 0.2

        trigger_height:
            The maximum distance from the bottom where the content
            update gets triggered (pixels). Default is 1000

        failiure_message:
            The message to show on the bottom when the scroller
            can't load the next page.

        loading_placeholder:
            The placeholder text to show when the loading is still
            in progress.

*/

thepaw.ContinousScroller.DefaultConfiguration = {
    check_interval:0.2,
    trigger_height:1000,
    failiure_message: "Error while trying to fetch the new items." +
                        "Check your internet connection...",
    loading_placeholder: "Loading newer items...",
    uid:"continous_scroller_uid"
}

/**
    The default url generator
    =========================

    A generator is a hash with a next() function which returns
    the url of the next segment to load. The second parameter of
    the ContinousScroller accepts hash or a custom url generator:

    Examples:

    // Using the default url generator
    // we don't define next()

    {  url:"/pages/$page_num$.html"  }
        // => '/pages/1.html', '/pages/2.html', ....

    {  start_index:10, url:"/pages/$page_num$"  }
        // => '/pages/10', '/pages/11', '/pages/12', ...

    {  start_index:10, default_spacing:20, url:"/pages/$page_num$"  }
        // => '/pages/10', '/pages/20', '/pages/30', ...

    // Using a custom url generator
    // we simply define next()

    {  next:function() { return "?page_idx=" + Math.round(Math.random() * 100) } }
        // => '?page_idx=57', '?page_idx=19', '/pages/81', ...

    {
        idx = 0,
        next:function() {
            return "items?from=" + this.idx + "&until=" + (this.idx += 10)
        }
    }
        // => 'items?from=0&until=10', 'items?from=0&until=10', '/pages/30'

*/

thepaw.ContinousScroller.DefaultUrlGenerator = {
    url:null,
    start_index:1,
    default_spacing:1,

    next: function() {
        if (typeof this.current_index == "undefined") this.current_index = this.start_index
        this.current_index += this.default_spacing

        var tmp_url = ( this.url == null ? "?page=$page_num$" : this.url )
        return tmp_url.replace('$page_num$', this.current_index)
    }

}

// These two functions are based on code from
// http://www.quirksmode.org/viewport/compatibility.html
thepaw.third_party = {

    getPageHeight: function (){
        var y;
        var test1 = document.body.scrollHeight;
        var test2 = document.body.offsetHeight
        if (test1 > test2) // all but Explorer Mac
        {
            y = document.body.scrollHeight;
        }
        else // Explorer Mac;
             //would also work in Explorer 6 Strict, Mozilla and Safari
        {
            y = document.body.offsetHeight;
        }
        return parseInt(y);
    },

    _getWindowHeight: function (){
        if (self.innerWidth)
        {
            frameWidth = self.innerWidth;
            frameHeight = self.innerHeight;
        }
        else if (document.documentElement && document.documentElement.clientWidth)
        {
            frameWidth = document.documentElement.clientWidth;
            frameHeight = document.documentElement.clientHeight;
        }
        else if (document.body)
        {
            frameWidth = document.body.clientWidth;
            frameHeight = document.body.clientHeight;
        }
        return parseInt(frameHeight);
    },

    getScrollHeight: function (){
        var y;
        // all except Explorer
        if (self.pageYOffset)
        {
            y = self.pageYOffset;
        }
        else if (document.documentElement && document.documentElement.scrollTop)
        {
            y = document.documentElement.scrollTop;
        }
        else if (document.body) // all other Explorers
        {
            y = document.body.scrollTop;
        }
        return parseInt(y)+thepaw.third_party._getWindowHeight();
    }

}<commit_msg>Added callbacks for scroll-based events<commit_after>/*
    InfinityScroller

    Create the Google Reader-type of endless scrolling on (almost) any page.

    (c) Copyright 2008 Gyula László. All Rights Reserved.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/**
    See README for more info or go to

        http://psinc.wordpress.com/cscroller_js

        or

        http://github.com/gyulalaszlo/csscroller

    to obtain your copy.

    Usage by example:

	new thepaw.ContinousScroller("recommended_programs",{ url:"/top10/$page_num$" }, {
		loading_placeholder:'
Blah-blah
',
		check_interval:0.5,
		failiure_message:'Something terrible happened.
'+
		    'We cannot help you get any more content. Check your internet connection.'
	})

*/

thepaw = {}

thepaw.ContinousScroller = Class.create()
thepaw.ContinousScroller.prototype = {

    /**
    new thepaw.ContinousScroller(content_div_id, url_generator, options)

    Create a continous scroller. Only one instance per page...

    Parameters:

        content_div_id:
            The div to serve the content into.
        url_generator:
            The url generator to use. See "The default url generator"
            bit bellow.

    */
    initialize: function(content_div_id, url_generator, options) {

        this.options = $H( thepaw.ContinousScroller.DefaultConfiguration ).merge(options)
        this.url_generator = (typeof url_generator.next == 'undefined' ?
            $H(thepaw.ContinousScroller.DefaultUrlGenerator ).merge(url_generator) : url_generator)

        this.div_id = content_div_id
        this.updateInProgress = false

        new Insertion.After( this.div_id,
            "
" +
            options.loading_placeholder + "
")

        this.updater = new PeriodicalExecuter( function(pe) {
            var t = pe.target_obj
            if (t == null) return
            if (!t.updateInProgress &&
                    (thepaw.third_party.getPageHeight() -
                    thepaw.third_party.getScrollHeight()) < t.options.trigger_height) {
            	    t.updateInProgress = true;
            	    t.getMoreContent();
            }
        }, this.options.check_interval );
        this.updater.target_obj = this

    },

    getMoreContent: function(){
        var t = this
		var placeholder_div = $( this.placeholderDivId )
		placeholder_div.show()

		// LoadStart Callback
		this.options.onSegmentLoadStart()

        new Ajax.Request(this.url_generator.next()  , {
            method: 'get',
            onSuccess: function(transport) {
				t.options.onSegmentLoadComplete( transport )

                // No more elements for us. Stop.
                if (transport.responseText.length < 300) t.updater.stop()

                // Update the content
                new Insertion.Bottom(t.div_id, transport.responseText)
                placeholder_div.hide()
                t.updateInProgress = false;
				t.options.onSegmentInsertComplete()

            },

            onFailure: function(transport) {
				t.options.onSegmentLoadFaliure( transport )
                new Insertion.bottom( t.div_id,
                    "
" + t.options.failiure_message
                    + "
"
                )
            }

        })
    },

    placeholderDivId:'continous_scroller_loading_placeholder'

}

/**
    The default options
    =========================

    Options:

        check_interval:
            The interval between checks (seconds). Default is 0.2

        trigger_height:
            The maximum distance from the bottom where the content
            update gets triggered (pixels). Default is 1000

        failiure_message:
            The message to show on the bottom when the scroller
            can't load the next page.

        loading_placeholder:
            The placeholder text to show when the loading is still
            in progress.

	Callbacks:

		onSegmentLoadStart:
			 function() { ... }
			Callback when starting to load a new segment.

		onSegmentLoadComplete:
			 function(transport) { ... }
			Callback when the AJAX request completed. The transport is the
			raw Protype transport. (use transport.responseText
			to get the raw response text)

		onSegmentInsertComplete:
			function() { }
			Callback when the new contents are inserted to the bottom.

		onSegmentLoadFaliure
			 function(transport) { ... }
			Callback when the AJAX request fails. The transport is the
			raw Protype transport. (use transport.responseText
			to get the raw response text)

*/

thepaw.ContinousScroller.DefaultConfiguration = {
    check_interval:0.2,
    trigger_height:1000,
    failiure_message: "Error while trying to fetch the new items." +
                        "Check your internet connection...",
    loading_placeholder: "Loading newer items...",
    uid:"continous_scroller_uid",

	onSegmentLoadStart:function() { },
	onSegmentLoadComplete:function(transport) { },
	onSegmentInsertComplete:function() { },
	onSegmentLoadFaliure:function(transport) { }
}

/**
    The default url generator
    =========================

    A generator is a hash with a next() function which returns
    the url of the next segment to load. The second parameter of
    the ContinousScroller accepts hash or a custom url generator:

    Examples:

    // Using the default url generator
    // we don't define next()

    {  url:"/pages/$page_num$.html"  }
        // => '/pages/1.html', '/pages/2.html', ....

    {  start_index:10, url:"/pages/$page_num$"  }
        // => '/pages/10', '/pages/11', '/pages/12', ...

    {  start_index:10, default_spacing:20, url:"/pages/$page_num$"  }
        // => '/pages/10', '/pages/20', '/pages/30', ...

    // Using a custom url generator
    // we simply define next()

    {  next:function() { return "?page_idx=" + Math.round(Math.random() * 100) } }
        // => '?page_idx=57', '?page_idx=19', '/pages/81', ...

    {
        idx = 0,
        next:function() {
            return "items?from=" + this.idx + "&until=" + (this.idx += 10)
        }
    }
        // => 'items?from=0&until=10', 'items?from=0&until=10', '/pages/30'

*/

thepaw.ContinousScroller.DefaultUrlGenerator = {
    url:null,
    start_index:1,
    default_spacing:1,

    next: function() {
        if (typeof this.current_index == "undefined") this.current_index = this.start_index
        this.current_index += this.default_spacing

        var tmp_url = ( this.url == null ? "?page=$page_num$" : this.url )
        return tmp_url.replace('$page_num$', this.current_index)
    }

}

// These two functions are based on code from
// http://www.quirksmode.org/viewport/compatibility.html
thepaw.third_party = {

    getPageHeight: function (){
        var y;
        var test1 = document.body.scrollHeight;
        var test2 = document.body.offsetHeight
        if (test1 > test2) // all but Explorer Mac
        {
            y = document.body.scrollHeight;
        }
        else // Explorer Mac;
             //would also work in Explorer 6 Strict, Mozilla and Safari
        {
            y = document.body.offsetHeight;
        }
        return parseInt(y);
    },

    _getWindowHeight: function (){
        if (self.innerWidth)
        {
            frameWidth = self.innerWidth;
            frameHeight = self.innerHeight;
        }
        else if (document.documentElement && document.documentElement.clientWidth)
        {
            frameWidth = document.documentElement.clientWidth;
            frameHeight = document.documentElement.clientHeight;
        }
        else if (document.body)
        {
            frameWidth = document.body.clientWidth;
            frameHeight = document.body.clientHeight;
        }
        return parseInt(frameHeight);
    },

    getScrollHeight: function (){
        var y;
        // all except Explorer
        if (self.pageYOffset)
        {
            y = self.pageYOffset;
        }
        else if (document.documentElement && document.documentElement.scrollTop)
        {
            y = document.documentElement.scrollTop;
        }
        else if (document.body) // all other Explorers
        {
            y = document.body.scrollTop;
        }
        return parseInt(y)+thepaw.third_party._getWindowHeight();
    }

}<|endoftext|>


<commit_before>/**
 * @license MIT
 * taksim.io/emitter // @echo VERSION
 * https://github.com/taksim-io/emitter
 * Copyright (c) 2015 taksim.io
*/

;(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    var Emitter = factory(root);
    root.Emitter || (root.Emitter = Emitter);
    root.taksim || (root.taksim = {});
    root.taksim.Emitter = Emitter;
  }
})(this, function() {

  'use strict';

  var uniqueId = 1;
  var namespace = 'emitter';
  var proto = TaksimEmitter.prototype;

  function TaksimEmitter(obj) {
    if (obj) {
      init(mixin(obj, proto));
      return obj;
    }
    init(this);
  }

  proto.emit = function() {
    var on = _t(this).listeners;
    var args = Array.prototype.slice.call(arguments);
    var event = args.shift();
    var result;
    if (on && on[event]) {
      var callbacks = on[event];
      if (typeof callbacks === 'function') {
        result = callbacks.apply(this, args);
      }
      else {
        var len = callbacks.length;
        callbacks = callbacks.slice();
        for (var i = 0; i < len; i++) {
          result = callbacks[i].apply(this, args);
          if (result === false) {
            break;
          }
        }
      }
    }
    return result;
  };

  proto.on = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'on', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      var t = _t(this);
      var on = t.listeners;
      on || (on = t.listeners = {});
      while (i--) {
        event = events[i];
        if (typeof on[event] !== 'function') {
          on[event] || (on[event] = []);
          on[event].push(callback);
        }
      }
    }
    return this;
  };

  proto.once = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'once', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      while (i--) {
        this.on(event, once(this, events[i], callback));
      }
    }
    return this;
  };

  function once(ctx, event, callback) {
    return function before() {
      ctx.off(event, before);
      callback.apply(ctx, arguments);
    };
  }

  proto.only = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'only', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      var t = _t(this);
      var on = t.listeners;
      on || (on = t.listeners = {});
      while (i--) {
        var e = events[i];
        if (typeof on[e] !== 'function') {
          on[e] = callback;
        }
      }
    }
    return this;
  };

  proto.off = function(event, callback) {
    var argsLen = arguments.length;
    var t = _t(this);
    var on = t.listeners;
    if (!on) {
      return this;
    }
    if (argsLen === 0) {
      t.listeners = null;
    }
    else if (!on[event]) {
      var events = event.split(' ');
      var j = events.length;
      if (j > 1) {
        while (j--) {
          this.off(events[j], callback);
        }
      }
    }
    else if (argsLen === 1 || !callback || typeof on[event] === 'function') {
      on[event] = null;
    }
    else {
      var callbacks = on[event];
      var len = callbacks.length;
      for (var i = 0; i < len; i++) {
        var strCallback = String(callbacks[i]);
        if (strCallback === String(callback) ||
            strCallback === String(once(this, event, callback))) {
          callbacks.splice(i, 1);
          break;
        }
      }
    }
    return this;
  };

  proto.offence = function(event, callback) {
    var argsLen = arguments.length;
    var t = _t(this);
    var on = t.listeners;
    var callbacks;
    if (!on) {
      return this;
    }
    if (argsLen === 0) {
      for (var key in on) {
        if (on.hasOwnProperty(key)) {
          this.offence(key);
        }
      }
    }
    else if (!on[event]) {
      var events = event.split(' ');
      var j = events.length;
      if (j > 1) {
        while (j--) {
          this.offence(events[j], callback);
        }
      }
    }
    else if (argsLen === 1 || !callback || typeof callbacks === 'function') {
      callbacks = on[event];
      if (String(callbacks) !== 'function() {on[event] = callbacks;}') {
        on[event] = function() {on[event] = callbacks;};
      }
    }
    else if (callback) {
      callbacks = on[event];
      var len = callbacks.length;
      for (var i = 0; i < len; i++) {
        var strCallback = String(callbacks[i]);
        if (strCallback === String(callback) ||
            strCallback === String(once(this, event, callback))) {
          offence(callbacks, i, callbacks[i]);
          break;
        }
      }
    }
    return this;
  };

  proto.getListeners = function(event) {
    return (_t(this).listeners || {})[event] || [];
  };

  proto.hasListeners = function(event) {
    return !!this.getListeners(event).length;
  };

  function offence(callbacks, i, callback) {
    callbacks[i] = function() {
      callbacks[i] = callback;
    };
  }

  function eachEvent(ctx, method, obj) {
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        ctx[method](key, obj[key]);
      }
    }
  }

  function init(ctx) {
    ctx._t || (ctx._t = {});
    ctx._t[namespace] = {
      listeners: null
    };
    ctx._t.id = uniqueId++;
    return ctx;
  }

  function _t(ctx) {
    return ctx._t[namespace];
  }

  function mixin(base) {
    var len = arguments.length;
    base || (base = {});
    for (var i = 1; i < len; i++) {
      var source = arguments[i];
      if (source) {
        for (var prop in source) {
          if (source.hasOwnProperty(prop)) {
            base[prop] = source[prop];
          }
        }
      }
    }
    return base;
  }

  TaksimEmitter.mixin = mixin;
  TaksimEmitter.extend = function(ctor, extender) {
    if (typeof ctor !== 'function') {
      extender = ctor;
      ctor = null;
    }
    var sup = this;
    var sub;

    if (ctor) {
      sub = ctor;
    }
    else {
      sub = function() {
        return sup.apply(this, arguments);
      };
    }

    var Mirror = function() {
      this.constructor = sub;
    };
    Mirror.prototype = sup.prototype;
    sub.prototype = new Mirror();

    mixin(sub, sup);
    mixin(sub.prototype, extender);

    sub.__super__ = sup.prototype;
    return sub;
  };

  return TaksimEmitter;
});
<commit_msg>Added inherits function and renamed extend method's variables<commit_after>/**
 * @license MIT
 * taksim.io/emitter // @echo VERSION
 * https://github.com/taksim-io/emitter
 * Copyright (c) 2015 taksim.io
*/

;(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    var Emitter = factory(root);
    root.Emitter || (root.Emitter = Emitter);
    root.taksim || (root.taksim = {});
    root.taksim.Emitter = Emitter;
  }
})(this, function() {

  'use strict';

  var uniqueId = 1;
  var namespace = 'emitter';
  var proto = TaksimEmitter.prototype;

  function TaksimEmitter(obj) {
    if (obj) {
      init(mixin(obj, proto));
      return obj;
    }
    init(this);
  }

  proto.emit = function() {
    var on = _t(this).listeners;
    var args = Array.prototype.slice.call(arguments);
    var event = args.shift();
    var result;
    if (on && on[event]) {
      var callbacks = on[event];
      if (typeof callbacks === 'function') {
        result = callbacks.apply(this, args);
      }
      else {
        var len = callbacks.length;
        callbacks = callbacks.slice();
        for (var i = 0; i < len; i++) {
          result = callbacks[i].apply(this, args);
          if (result === false) {
            break;
          }
        }
      }
    }
    return result;
  };

  proto.on = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'on', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      var t = _t(this);
      var on = t.listeners;
      on || (on = t.listeners = {});
      while (i--) {
        event = events[i];
        if (typeof on[event] !== 'function') {
          on[event] || (on[event] = []);
          on[event].push(callback);
        }
      }
    }
    return this;
  };

  proto.once = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'once', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      while (i--) {
        this.on(event, once(this, events[i], callback));
      }
    }
    return this;
  };

  function once(ctx, event, callback) {
    return function before() {
      ctx.off(event, before);
      callback.apply(ctx, arguments);
    };
  }

  proto.only = function(event, callback) {
    if (typeof event === 'object') {
      eachEvent(this, 'only', event);
    }
    else if (typeof callback === 'function') {
      var events = event.split(' ');
      var i = events.length;
      var t = _t(this);
      var on = t.listeners;
      on || (on = t.listeners = {});
      while (i--) {
        var e = events[i];
        if (typeof on[e] !== 'function') {
          on[e] = callback;
        }
      }
    }
    return this;
  };

  proto.off = function(event, callback) {
    var argsLen = arguments.length;
    var t = _t(this);
    var on = t.listeners;
    if (!on) {
      return this;
    }
    if (argsLen === 0) {
      t.listeners = null;
    }
    else if (!on[event]) {
      var events = event.split(' ');
      var j = events.length;
      if (j > 1) {
        while (j--) {
          this.off(events[j], callback);
        }
      }
    }
    else if (argsLen === 1 || !callback || typeof on[event] === 'function') {
      on[event] = null;
    }
    else {
      var callbacks = on[event];
      var len = callbacks.length;
      for (var i = 0; i < len; i++) {
        var strCallback = String(callbacks[i]);
        if (strCallback === String(callback) ||
            strCallback === String(once(this, event, callback))) {
          callbacks.splice(i, 1);
          break;
        }
      }
    }
    return this;
  };

  proto.offence = function(event, callback) {
    var argsLen = arguments.length;
    var t = _t(this);
    var on = t.listeners;
    var callbacks;
    if (!on) {
      return this;
    }
    if (argsLen === 0) {
      for (var key in on) {
        if (on.hasOwnProperty(key)) {
          this.offence(key);
        }
      }
    }
    else if (!on[event]) {
      var events = event.split(' ');
      var j = events.length;
      if (j > 1) {
        while (j--) {
          this.offence(events[j], callback);
        }
      }
    }
    else if (argsLen === 1 || !callback || typeof callbacks === 'function') {
      callbacks = on[event];
      if (String(callbacks) !== 'function() {on[event] = callbacks;}') {
        on[event] = function() {on[event] = callbacks;};
      }
    }
    else if (callback) {
      callbacks = on[event];
      var len = callbacks.length;
      for (var i = 0; i < len; i++) {
        var strCallback = String(callbacks[i]);
        if (strCallback === String(callback) ||
            strCallback === String(once(this, event, callback))) {
          offence(callbacks, i, callbacks[i]);
          break;
        }
      }
    }
    return this;
  };

  proto.getListeners = function(event) {
    return (_t(this).listeners || {})[event] || [];
  };

  proto.hasListeners = function(event) {
    return !!this.getListeners(event).length;
  };

  function offence(callbacks, i, callback) {
    callbacks[i] = function() {
      callbacks[i] = callback;
    };
  }

  function eachEvent(ctx, method, obj) {
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        ctx[method](key, obj[key]);
      }
    }
  }

  function init(ctx) {
    ctx._t || (ctx._t = {});
    ctx._t[namespace] = {
      listeners: null
    };
    ctx._t.id = uniqueId++;
    return ctx;
  }

  function _t(ctx) {
    return ctx._t[namespace];
  }

  function mixin(base) {
    var len = arguments.length;
    base || (base = {});
    for (var i = 1; i < len; i++) {
      var source = arguments[i];
      if (source) {
        for (var prop in source) {
          if (source.hasOwnProperty(prop)) {
            base[prop] = source[prop];
          }
        }
      }
    }
    return base;
  }

  function inherits(child, parent) {
    var Mirror = function() {
      this.constructor = child;
    };
    Mirror.prototype = parent.prototype;
    child.prototype = new Mirror();
    child.__super__ = parent.prototype;
  }

  TaksimEmitter.mixin = mixin;
  TaksimEmitter.inherits = inherits;
  TaksimEmitter.extend = function(ctor, extender) {
    if (typeof ctor !== 'function') {
      extender = ctor;
      ctor = null;
    }
    var parent = this;
    var child;

    if (ctor) {
      child = ctor;
    }
    else {
      child = function() {
        return parent.apply(this, arguments);
      };
    }

    inherits(child, parent);
    mixin(child, parent);
    mixin(parent.prototype, extender);

    return child;
  };

  return TaksimEmitter;
});
<|endoftext|>


<commit_before>import {
  VUEXFIRE_OBJECT_VALUE,
  VUEXFIRE_ARRAY_INITIALIZE,
  VUEXFIRE_ARRAY_ADD,
  VUEXFIRE_ARRAY_CHANGE,
  VUEXFIRE_ARRAY_MOVE,
  VUEXFIRE_ARRAY_REMOVE,
  VUEXFIRE_MUTATION
} from './types.js'

import {
  createRecord,
  getRef,
  indexForKey,
  getKey,
  isObject
} from './utils/index.js'

const oldmutations = {
  [VUEXFIRE_OBJECT_VALUE] (state, payload) {
    state[payload.key] = payload.record
  },

  [VUEXFIRE_ARRAY_INITIALIZE] (state, payload) {
    state[payload.key] = []
  },

  [VUEXFIRE_ARRAY_ADD] (state, payload) {
    state[payload.key].splice(payload.index, 0, payload.record)
  },

  [VUEXFIRE_ARRAY_CHANGE] (state, payload) {
    state[payload.key].splice(payload.index, 1, payload.record)
  },

  [VUEXFIRE_ARRAY_MOVE] (state, payload) {
    const array = state[payload.key]
    array.splice(payload.newIndex, 0, array.splice(payload.index, 1)[0])
  },

  [VUEXFIRE_ARRAY_REMOVE] (state, payload) {
    state[payload.key].splice(payload.index, 1)
  }
}

const firebaseMutations = {
  // the { commit, state, type, ...payload } syntax is not supported by buble...
  [VUEXFIRE_MUTATION] (_, context) {
    oldmutations[context.type](context.state, context)
  }
}

function bindAsObject ({
  key,
  source,
  cancelCallback,
  commit,
  state
}) {
  const cb = source.on('value', function (snapshot) {
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_OBJECT_VALUE,
      key,
      record: createRecord(snapshot),
      state
    })
  }, cancelCallback)

  // return the listeners that have been setup
  return { value: cb }
}

function bindAsArray ({
  key,
  source,
  cancelCallback,
  commit,
  state
}) {
  // Initialise the array to an empty one
  commit(VUEXFIRE_MUTATION, {
    type: VUEXFIRE_ARRAY_INITIALIZE,
    state,
    key
  })
  const onAdd = source.on('child_added', function (snapshot, prevKey) {
    const array = state[key]
    const index = prevKey ? indexForKey(array, prevKey) + 1 : 0
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_ADD,
      state,
      key,
      index,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  const onRemove = source.on('child_removed', function (snapshot) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_REMOVE,
      state,
      key,
      index
    })
  }, cancelCallback)

  const onChange = source.on('child_changed', function (snapshot) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_CHANGE,
      state,
      key,
      index,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  const onMove = source.on('child_moved', function (snapshot, prevKey) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    var newIndex = prevKey ? indexForKey(array, prevKey) + 1 : 0
    // TODO refactor + 1
    newIndex += index < newIndex ? -1 : 0
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_MOVE,
      state,
      key,
      index,
      newIndex,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  // return the listeners that have been setup
  return {
    child_added: onAdd,
    child_changed: onChange,
    child_removed: onRemove,
    child_moved: onMove
  }
}

// Firebase binding
const bindings = new WeakMap()

function bind ({
  state,
  commit,
  key,
  source,
  options: {
    cancelCallback
  }
}) {
  if (!isObject(source)) {
    throw new Error('VuexFire: invalid Firebase binding source.')
  }
  if (!(key in state)) {
    throw new Error(`VuexFire: cannot bind undefined property '${key}'. Define it on the state first.`)
  }
  // Unbind if it already exists
  let binding = bindings.get(commit)
  if (!binding) {
    binding = {
      sources: Object.create(null),
      listeners: Object.create(null)
    }
    bindings.set(commit, binding)
  }
  if (key in binding.sources) {
    unbind({ commit, key })
  }
  binding.sources[key] = getRef(source)

  // Automatically detects if it should be bound as an array or as an object
  let listener
  if (state[key] && 'length' in state[key]) {
    listener = bindAsArray({ key, source, cancelCallback, commit, state })
  } else {
    listener = bindAsObject({ key, source, cancelCallback, commit, state })
  }

  binding.listeners[key] = listener
}

function unbind ({ commit, key }) {
  let binding = bindings.get(commit)
  if (!binding) {
    binding = {
      sources: Object.create(null),
      listeners: Object.create(null)
    }
    bindings.set(commit, binding)
  }
  if (!(key in binding.sources)) {
    throw new Error(`VuexFire: cannot unbind '${key}' because it wasn't bound.`)
  }
  const oldSource = binding.sources[key]
  const oldListeners = binding.listeners[key]
  for (let event in oldListeners) {
    oldSource.off(event, oldListeners[event])
  }
  // clean up
  delete binding.sources[key]
  delete binding.listeners[key]
}

export function firebaseAction (action) {
  return function firebaseEnhancedActionFn (context, payload) {
    // get the local state and commit. These may be bound to a module
    const { state, commit } = context
    context.bindFirebaseRef = (key, source, options = {}) => {
      bind({ state, commit, key, source, options })
    }
    context.unbindFirebaseRef = (key) => {
      unbind({ commit, key })
    }
    action(context, payload)
  }
}

export { firebaseMutations }
<commit_msg>🔨 Use spread parameters and simplify exports<commit_after>import {
  VUEXFIRE_OBJECT_VALUE,
  VUEXFIRE_ARRAY_INITIALIZE,
  VUEXFIRE_ARRAY_ADD,
  VUEXFIRE_ARRAY_CHANGE,
  VUEXFIRE_ARRAY_MOVE,
  VUEXFIRE_ARRAY_REMOVE,
  VUEXFIRE_MUTATION
} from './types.js'

import {
  createRecord,
  getRef,
  indexForKey,
  getKey,
  isObject
} from './utils/index.js'

const mutations = {
  [VUEXFIRE_OBJECT_VALUE] (state, { key, record }) {
    state[key] = record
  },

  [VUEXFIRE_ARRAY_INITIALIZE] (state, { key }) {
    state[key] = []
  },

  [VUEXFIRE_ARRAY_ADD] (state, { key, index, record }) {
    state[key].splice(index, 0, record)
  },

  [VUEXFIRE_ARRAY_CHANGE] (state, { key, index, record }) {
    state[key].splice(index, 1, record)
  },

  [VUEXFIRE_ARRAY_MOVE] (state, { key, index, record, newIndex }) {
    const array = state[key]
    array.splice(newIndex, 0, array.splice(index, 1)[0])
  },

  [VUEXFIRE_ARRAY_REMOVE] (state, { key, index }) {
    state[key].splice(index, 1)
  }
}

export const firebaseMutations = {
  // the { commit, state, type, ...payload } syntax is not supported by buble...
  [VUEXFIRE_MUTATION] (_, context) {
    mutations[context.type](context.state, context)
  }
}

function bindAsObject ({
  key,
  source,
  cancelCallback,
  commit,
  state
}) {
  const cb = source.on('value', function (snapshot) {
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_OBJECT_VALUE,
      key,
      record: createRecord(snapshot),
      state
    })
  }, cancelCallback)

  // return the listeners that have been setup
  return { value: cb }
}

function bindAsArray ({
  key,
  source,
  cancelCallback,
  commit,
  state
}) {
  // Initialise the array to an empty one
  commit(VUEXFIRE_MUTATION, {
    type: VUEXFIRE_ARRAY_INITIALIZE,
    state,
    key
  })
  const onAdd = source.on('child_added', function (snapshot, prevKey) {
    const array = state[key]
    const index = prevKey ? indexForKey(array, prevKey) + 1 : 0
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_ADD,
      state,
      key,
      index,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  const onRemove = source.on('child_removed', function (snapshot) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_REMOVE,
      state,
      key,
      index
    })
  }, cancelCallback)

  const onChange = source.on('child_changed', function (snapshot) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_CHANGE,
      state,
      key,
      index,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  const onMove = source.on('child_moved', function (snapshot, prevKey) {
    const array = state[key]
    const index = indexForKey(array, getKey(snapshot))
    var newIndex = prevKey ? indexForKey(array, prevKey) + 1 : 0
    // TODO refactor + 1
    newIndex += index < newIndex ? -1 : 0
    commit(VUEXFIRE_MUTATION, {
      type: VUEXFIRE_ARRAY_MOVE,
      state,
      key,
      index,
      newIndex,
      record: createRecord(snapshot)
    })
  }, cancelCallback)

  // return the listeners that have been setup
  return {
    child_added: onAdd,
    child_changed: onChange,
    child_removed: onRemove,
    child_moved: onMove
  }
}

// Firebase binding
const bindings = new WeakMap()

function bind ({
  state,
  commit,
  key,
  source,
  options: {
    cancelCallback
  }
}) {
  if (!isObject(source)) {
    throw new Error('VuexFire: invalid Firebase binding source.')
  }
  if (!(key in state)) {
    throw new Error(`VuexFire: cannot bind undefined property '${key}'. Define it on the state first.`)
  }
  // Unbind if it already exists
  let binding = bindings.get(commit)
  if (!binding) {
    binding = {
      sources: Object.create(null),
      listeners: Object.create(null)
    }
    bindings.set(commit, binding)
  }
  if (key in binding.sources) {
    unbind({ commit, key })
  }
  binding.sources[key] = getRef(source)

  // Automatically detects if it should be bound as an array or as an object
  let listener
  if (state[key] && 'length' in state[key]) {
    listener = bindAsArray({ key, source, cancelCallback, commit, state })
  } else {
    listener = bindAsObject({ key, source, cancelCallback, commit, state })
  }

  binding.listeners[key] = listener
}

function unbind ({ commit, key }) {
  let binding = bindings.get(commit)
  if (!binding) {
    binding = {
      sources: Object.create(null),
      listeners: Object.create(null)
    }
    bindings.set(commit, binding)
  }
  if (!(key in binding.sources)) {
    throw new Error(`VuexFire: cannot unbind '${key}' because it wasn't bound.`)
  }
  const oldSource = binding.sources[key]
  const oldListeners = binding.listeners[key]
  for (let event in oldListeners) {
    oldSource.off(event, oldListeners[event])
  }
  // clean up
  delete binding.sources[key]
  delete binding.listeners[key]
}

export function firebaseAction (action) {
  return function firebaseEnhancedActionFn (context, payload) {
    // get the local state and commit. These may be bound to a module
    const { state, commit } = context
    context.bindFirebaseRef = (key, source, options = {}) => {
      bind({ state, commit, key, source, options })
    }
    context.unbindFirebaseRef = (key) => {
      unbind({ commit, key })
    }
    action(context, payload)
  }
}
<|endoftext|>


<commit_before>import SelectField from 'spectre-canjs/sp-form/fields/sp-select-field/ViewModel';
import DefineList from 'can-define/list/list';

/**
 * The `<sp-multi-check-field />` component viewmodel
 * @class ViewModel
 * @extends Field
 * @memberof sp-multi-check-field
 */
export default SelectField.extend('CheckboxMulti', {
    /** @lends sp-multi-check-field.ViewModel.prototype */

    /**
     * @type {Any}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description The current value of this field. Can be string or a list.
     */
    value: {
        value (props) {
            props.listenTo(this.selectedValues, 'length', () => {
                if (this.valueType === 'string') {
                    props.resolve(this.selectedValues.join(this.valueSeparator));
                } else {
                    props.resolve(this.selectedValues);
                }
                this.dispatch('fieldchange', [this]);
            });
        },
        set (val) {
            if (typeof val === 'string') {
                this.valueType = 'string';
                this.selectedValues.replace(val.split(','));
            }

            return val;
        }
        // Type: DefineList,
        // Default: DefineList
    },
    /**
     * @type {Array<Any>}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description The current array values selected. When this changes, it updates the value
     */
    selectedValues: {
        Type: DefineList,
        Default: DefineList
    },
    /**
     * @type {Array<Any>}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description Type of value. Set this to string to coerce the list to a comma separated list.
     */
    valueType: 'string',
    /**
     * @type {String}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description Separator for the value string. List will be joined using this separator. Default is `,`.
     */
    valueSeparator: {
        type: 'string',
        default: ','
    }
});
<commit_msg>don't join items without a value<commit_after>import SelectField from 'spectre-canjs/sp-form/fields/sp-select-field/ViewModel';
import DefineList from 'can-define/list/list';

/**
 * The `<sp-multi-check-field />` component viewmodel
 * @class ViewModel
 * @extends Field
 * @memberof sp-multi-check-field
 */
export default SelectField.extend('CheckboxMulti', {
    /** @lends sp-multi-check-field.ViewModel.prototype */

    /**
     * @type {Any}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description The current value of this field. Can be string or a list.
     */
    value: {
        value (props) {
            props.listenTo(this.selectedValues, 'length', () => {
                if (this.valueType === 'string') {
                    props.resolve(this.selectedValues.filter((val) => Boolean(val)).join(this.valueSeparator));
                } else {
                    props.resolve(this.selectedValues);
                }
                this.dispatch('fieldchange', [this]);
            });
        },
        set (val) {
            if (typeof val === 'string') {
                this.valueType = 'string';
                this.selectedValues.replace(val.split(','));
            }

            return val;
        }
        // Type: DefineList,
        // Default: DefineList
    },
    /**
     * @type {Array<Any>}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description The current array values selected. When this changes, it updates the value
     */
    selectedValues: {
        Type: DefineList,
        Default: DefineList
    },
    /**
     * @type {Array<Any>}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description Type of value. Set this to string to coerce the list to a comma separated list.
     */
    valueType: 'string',
    /**
     * @type {String}
     * @memberof sp-multi-check-field.ViewModel.prototype
     * @description Separator for the value string. List will be joined using this separator. Default is `,`.
     */
    valueSeparator: {
        type: 'string',
        default: ','
    }
});
<|endoftext|>


<commit_before>import delegate from 'delegate'
import detectie from 'detectie'

// helpers
import Cache from './Cache'
import Link from './Link'
import transitionEnd from './transitionEnd'

// modules
import request from './modules/request'
import getDataFromHtml from './modules/getDataFromHtml'
import loadPage from './modules/loadPage'
import renderPage from './modules/renderPage'
import goBack from './modules/goBack'
import createState from './modules/createState'
import triggerEvent from './modules/triggerEvent'
import getUrl from './modules/getUrl'
import scrollTo from './modules/scrollTo'
import classify from './modules/classify'
import doScrolling from './modules/doScrolling'
import markSwupElements from './modules/markSwupElements'
import updateTransition from './modules/updateTransition'
import preloadPages from './modules/preloadPages'
import usePlugin from './modules/usePlugin'
import log from './modules/log'

export default class Swup {
    constructor(setOptions) {
        // default options
        let defaults = {
            cache: true,
            animationSelector: '[class^="a-"]',
            elements: ['#swup'],
            pageClassPrefix: '',
            debugMode: false,
            scroll: true,

            doScrollingRightAway: false,
            animateScroll: true,
            scrollFriction: .3,
            scrollAcceleration: .04,

            preload: true,
            support: true,
            disableIE: false,
            plugins: [],

            LINK_SELECTOR: 'a[href^="/"]:not([data-no-swup]), a[href^="#"]:not([data-no-swup]), a[xlink\\:href]'
        }

        /**
         * current transition object
         */
        this.transition = {}

        let options = {
            ...defaults,
            ...setOptions
        }

        /**
         * helper variables
         */
        // mobile detection variable
        this.mobile = false
        // id of element to scroll to after render
        this.scrollToElement = null
        // promise used for preload, so no new loading of the same page starts while page is loading
        this.preloadPromise = null
        // save options
        this.options = options
        // plugins array
        this.plugins = []

        /**
         * make modules accessible in instance
         */
        this.getUrl = getUrl
        this.cache = new Cache()
        this.link = new Link()
        this.transitionEndEvent = transitionEnd()
        this.getDataFromHtml = getDataFromHtml
        this.getPage = request
        this.scrollTo = scrollTo
        this.loadPage = loadPage
        this.renderPage = renderPage
        this.goBack = goBack
        this.createState = createState
        this.triggerEvent = triggerEvent
        this.classify = classify
        this.doScrolling = doScrolling
        this.markSwupElements = markSwupElements
        this.updateTransition = updateTransition
        this.preloadPages = preloadPages
        this.usePlugin = usePlugin
        this.log = log
        this.detectie = detectie
        this.enable = this.enable
        this.destroy = this.destroy

        /**
         * detect mobile devices
         */
        if (window.innerWidth <= 767) {
            this.mobile = true
        }

        // attach instance to window in debug mode
        if (this.options.debugMode) {
            window.swup = this
        }

        this.getUrl()
        this.enable()
    }

    enable() {
        /**
         * support check
         */
        if (this.options.support) {
            // check pushState support
            if (!('pushState' in window.history)) {
                console.warn('pushState is not supported')
                return
            }
            // check transitionEnd support
            if (transitionEnd()) {
                this.transitionEndEvent = transitionEnd()
            } else {
                console.warn('transitionEnd detection is not supported')
                return
            }
            // check Promise support
            if(typeof Promise === "undefined" || Promise.toString().indexOf("[native code]") === -1){
                console.warn('Promise is not supported')
                return
            }
        }
        /**
         * disable IE
         */
        if (this.options.disableIE && this.detectie()) {
            return
        }

        // variable to keep event listeners from "delegate"
        this.delegatedListeners = {}

        /**
         * link click handler
         */
        this.delegatedListeners.click = delegate(document, this.options.LINK_SELECTOR, 'click', this.linkClickHandler.bind(this))

        /**
         * link mouseover handler (preload)
         */
        this.delegatedListeners.mouseover = delegate(document.body, this.options.LINK_SELECTOR, 'mouseover', this.linkMouseoverHandler.bind(this))

        /**
         * popstate handler
         */
        window.addEventListener('popstate', this.popStateHandler.bind(this))

        /**
         * initial save to cache
         */
        var page = this.getDataFromHtml(document.documentElement.outerHTML)
        page.url = this.currentUrl
        if (this.options.cache) {
            this.cache.cacheUrl(page, this.options.debugMode)
        }

        /**
         * mark swup blocks in html
         */
        this.markSwupElements(document.documentElement)

        /**
         * enable plugins from options
         */
        this.options.plugins.forEach(item => this.usePlugin(item))

        /**
         * trigger enabled event
         */
        this.triggerEvent('enabled')
        document.documentElement.classList.add('swup-enabled')

        /**
         * trigger page view event
         */
        this.triggerEvent('pageView')

        /**
         * preload pages if possible
         */
        this.preloadPages()
    }

    destroy () {
        // remove delegated listeners
        this.delegatedListeners.click.destroy()
        this.delegatedListeners.mouseover.destroy()

        // remove popstate listener
        window.removeEventListener('popstate', this.popStateHandler.bind(this))

        // empty cache
        this.cache.empty()

        // remove swup data atributes from blocks
        document.querySelectorAll('[data-swup]').forEach(element => {
            delete element.dataset.swup
        })

        this.triggerEvent('disabled')
        document.documentElement.classList.remove('swup-enabled')
    }

    linkClickHandler (event) {
        // no control key pressed
        if (!event.metaKey) {
            this.triggerEvent('clickLink')
            var link = new Link()
            event.preventDefault()
            link.setPath(event.delegateTarget.href)
            if (link.getAddress() == this.currentUrl || link.getAddress() == '') {
                if (link.getHash() != '') {
                    this.triggerEvent('samePageWithHash')
                    var element = document.querySelector(link.getHash())
                    if (element != null) {
                        if (this.options.scroll) {
                            let top = element.getBoundingClientRect().top + window.pageYOffset;
                            this.scrollTo(document.body, top)
                        }
                        history.replaceState(undefined, undefined, link.getHash())
                    } else {
                        console.warn(`Element for offset not found (${link.getHash()})`)
                    }
                } else {
                    this.triggerEvent('samePage')
                    if (this.options.scroll) {
                        this.scrollTo(document.body, 0, 1)
                    }
                }
            } else {
                if (link.getHash() != '') {
                    this.scrollToElement = link.getHash()
                }
                // custom class fro dynamic pages
                var swupClass = event.delegateTarget.dataset.swupClass
                if (swupClass != null) {
                    this.updateTransition(window.location.pathname, link.getAddress(), event.delegateTarget.dataset.swupClass)
                    document.documentElement.classList.add(`to-${swupClass}`)
                } else {
                    this.updateTransition(window.location.pathname, link.getAddress())
                }
                this.loadPage(link.getAddress(), false)
            }
        } else {
            this.triggerEvent('openPageInNewTab')
        }
    }

    linkMouseoverHandler (event) {
        this.triggerEvent('hoverLink')
        if (this.options.preload) {
            var link = new Link()
            link.setPath(event.delegateTarget.href)
            if (link.getAddress() != this.currentUrl && !this.cache.exists(link.getAddress()) && this.preloadPromise == null) {
                this.preloadPromise = new Promise(resolve => {
                    this.getPage(link.getAddress(), response => {
                        if (response === null) {
                            console.warn('Server error.')
                            this.triggerEvent('serverError')
                        } else {
                            // get json data
                            var page = this.getDataFromHtml(response)
                            page.url = link.getAddress()
                            this.cache.cacheUrl(page, this.options.debugMode)
                            this.triggerEvent('pagePreloaded')
                        }
                        resolve()
                        this.preloadPromise = null
                    })
                })
                this.preloadPromise.route = link.getAddress()
            }
        }
    }

    popStateHandler (event)  {
        var link = new Link()
        link.setPath(event.state ? event.state.url : window.location.pathname)
        if (link.getHash() != '') {
            this.scrollToElement = link.getHash()
        } else {
            event.preventDefault()
        }
        this.triggerEvent('popState')
        this.loadPage(link.getAddress(), event)
    }
}
<commit_msg>Add new skipPopStateHandling option for dynamic skip of popState event handling<commit_after>import delegate from 'delegate'
import detectie from 'detectie'

// helpers
import Cache from './Cache'
import Link from './Link'
import transitionEnd from './transitionEnd'

// modules
import request from './modules/request'
import getDataFromHtml from './modules/getDataFromHtml'
import loadPage from './modules/loadPage'
import renderPage from './modules/renderPage'
import goBack from './modules/goBack'
import createState from './modules/createState'
import triggerEvent from './modules/triggerEvent'
import getUrl from './modules/getUrl'
import scrollTo from './modules/scrollTo'
import classify from './modules/classify'
import doScrolling from './modules/doScrolling'
import markSwupElements from './modules/markSwupElements'
import updateTransition from './modules/updateTransition'
import preloadPages from './modules/preloadPages'
import usePlugin from './modules/usePlugin'
import log from './modules/log'

export default class Swup {
    constructor(setOptions) {
        // default options
        let defaults = {
            cache: true,
            animationSelector: '[class^="a-"]',
            elements: ['#swup'],
            pageClassPrefix: '',
            debugMode: false,
            scroll: true,

            doScrollingRightAway: false,
            animateScroll: true,
            scrollFriction: .3,
            scrollAcceleration: .04,

            preload: true,
            support: true,
            disableIE: false,
            plugins: [],

            skipPopStateHandling: function(){ return false; },

            LINK_SELECTOR: 'a[href^="/"]:not([data-no-swup]), a[href^="#"]:not([data-no-swup]), a[xlink\\:href]'
        }

        /**
         * current transition object
         */
        this.transition = {}

        let options = {
            ...defaults,
            ...setOptions
        }

        /**
         * helper variables
         */
        // mobile detection variable
        this.mobile = false
        // id of element to scroll to after render
        this.scrollToElement = null
        // promise used for preload, so no new loading of the same page starts while page is loading
        this.preloadPromise = null
        // save options
        this.options = options
        // plugins array
        this.plugins = []

        /**
         * make modules accessible in instance
         */
        this.getUrl = getUrl
        this.cache = new Cache()
        this.link = new Link()
        this.transitionEndEvent = transitionEnd()
        this.getDataFromHtml = getDataFromHtml
        this.getPage = request
        this.scrollTo = scrollTo
        this.loadPage = loadPage
        this.renderPage = renderPage
        this.goBack = goBack
        this.createState = createState
        this.triggerEvent = triggerEvent
        this.classify = classify
        this.doScrolling = doScrolling
        this.markSwupElements = markSwupElements
        this.updateTransition = updateTransition
        this.preloadPages = preloadPages
        this.usePlugin = usePlugin
        this.log = log
        this.detectie = detectie
        this.enable = this.enable
        this.destroy = this.destroy

        /**
         * detect mobile devices
         */
        if (window.innerWidth <= 767) {
            this.mobile = true
        }

        // attach instance to window in debug mode
        if (this.options.debugMode) {
            window.swup = this
        }

        this.getUrl()
        this.enable()
    }

    enable() {
        /**
         * support check
         */
        if (this.options.support) {
            // check pushState support
            if (!('pushState' in window.history)) {
                console.warn('pushState is not supported')
                return
            }
            // check transitionEnd support
            if (transitionEnd()) {
                this.transitionEndEvent = transitionEnd()
            } else {
                console.warn('transitionEnd detection is not supported')
                return
            }
            // check Promise support
            if(typeof Promise === "undefined" || Promise.toString().indexOf("[native code]") === -1){
                console.warn('Promise is not supported')
                return
            }
        }
        /**
         * disable IE
         */
        if (this.options.disableIE && this.detectie()) {
            return
        }

        // variable to keep event listeners from "delegate"
        this.delegatedListeners = {}

        /**
         * link click handler
         */
        this.delegatedListeners.click = delegate(document, this.options.LINK_SELECTOR, 'click', this.linkClickHandler.bind(this))

        /**
         * link mouseover handler (preload)
         */
        this.delegatedListeners.mouseover = delegate(document.body, this.options.LINK_SELECTOR, 'mouseover', this.linkMouseoverHandler.bind(this))

        /**
         * popstate handler
         */
        window.addEventListener('popstate', this.popStateHandler.bind(this))

        /**
         * initial save to cache
         */
        var page = this.getDataFromHtml(document.documentElement.outerHTML)
        page.url = this.currentUrl
        if (this.options.cache) {
            this.cache.cacheUrl(page, this.options.debugMode)
        }

        /**
         * mark swup blocks in html
         */
        this.markSwupElements(document.documentElement)

        /**
         * enable plugins from options
         */
        this.options.plugins.forEach(item => this.usePlugin(item))

        /**
         * trigger enabled event
         */
        this.triggerEvent('enabled')
        document.documentElement.classList.add('swup-enabled')

        /**
         * trigger page view event
         */
        this.triggerEvent('pageView')

        /**
         * preload pages if possible
         */
        this.preloadPages()
    }

    destroy () {
        // remove delegated listeners
        this.delegatedListeners.click.destroy()
        this.delegatedListeners.mouseover.destroy()

        // remove popstate listener
        window.removeEventListener('popstate', this.popStateHandler.bind(this))

        // empty cache
        this.cache.empty()

        // remove swup data atributes from blocks
        document.querySelectorAll('[data-swup]').forEach(element => {
            delete element.dataset.swup
        })

        this.triggerEvent('disabled')
        document.documentElement.classList.remove('swup-enabled')
    }

    linkClickHandler (event) {
        // no control key pressed
        if (!event.metaKey) {
            this.triggerEvent('clickLink')
            var link = new Link()
            event.preventDefault()
            link.setPath(event.delegateTarget.href)
            if (link.getAddress() == this.currentUrl || link.getAddress() == '') {
                if (link.getHash() != '') {
                    this.triggerEvent('samePageWithHash')
                    var element = document.querySelector(link.getHash())
                    if (element != null) {
                        if (this.options.scroll) {
                            let top = element.getBoundingClientRect().top + window.pageYOffset;
                            this.scrollTo(document.body, top)
                        }
                        history.replaceState(undefined, undefined, link.getHash())
                    } else {
                        console.warn(`Element for offset not found (${link.getHash()})`)
                    }
                } else {
                    this.triggerEvent('samePage')
                    if (this.options.scroll) {
                        this.scrollTo(document.body, 0, 1)
                    }
                }
            } else {
                if (link.getHash() != '') {
                    this.scrollToElement = link.getHash()
                }
                // custom class fro dynamic pages
                var swupClass = event.delegateTarget.dataset.swupClass
                if (swupClass != null) {
                    this.updateTransition(window.location.pathname, link.getAddress(), event.delegateTarget.dataset.swupClass)
                    document.documentElement.classList.add(`to-${swupClass}`)
                } else {
                    this.updateTransition(window.location.pathname, link.getAddress())
                }
                this.loadPage(link.getAddress(), false)
            }
        } else {
            this.triggerEvent('openPageInNewTab')
        }
    }

    linkMouseoverHandler (event) {
        this.triggerEvent('hoverLink')
        if (this.options.preload) {
            var link = new Link()
            link.setPath(event.delegateTarget.href)
            if (link.getAddress() != this.currentUrl && !this.cache.exists(link.getAddress()) && this.preloadPromise == null) {
                this.preloadPromise = new Promise(resolve => {
                    this.getPage(link.getAddress(), response => {
                        if (response === null) {
                            console.warn('Server error.')
                            this.triggerEvent('serverError')
                        } else {
                            // get json data
                            var page = this.getDataFromHtml(response)
                            page.url = link.getAddress()
                            this.cache.cacheUrl(page, this.options.debugMode)
                            this.triggerEvent('pagePreloaded')
                        }
                        resolve()
                        this.preloadPromise = null
                    })
                })
                this.preloadPromise.route = link.getAddress()
            }
        }
    }

    popStateHandler (event)  {
        var link = new Link()
        link.setPath(event.state ? event.state.url : window.location.pathname)
        if (this.options.skipPopStateHandling(link)) return;
        if (link.getHash() != '') {
            this.scrollToElement = link.getHash()
        } else {
            event.preventDefault()
        }
        this.triggerEvent('popState')
        this.loadPage(link.getAddress(), event)
    }
}
<|endoftext|>