<commit_before>import Garnish from 'garnish'

import Tab from './BlockTypeTab'

const _defaults = {
	id: -1,
	sortOrder: 0,
	name: '',
	handle: '',
	maxBlocks: 0,
	childBlocks: false,
	tabs: []
}

export default Garnish.Base.extend({

	init(settings = {})
	{
		settings = Object.assign({}, _defaults, settings)

		this._id = settings.id|0
		this._sortOrder = settings.sortOrder|0
		this._name = settings.name
		this._handle = settings.handle
		this._maxBlocks = settings.maxBlocks|0
		this._childBlocks = settings.childBlocks
		this._tabs = settings.tabs.map(tab => new Tab(tab))
	},

	getType() { return 'blockType' },
	getId() { return this._id },
	getSortOrder() { return this._sortOrder },
	getName() { return this._name },
	getHandle() { return this._handle },
	getMaxBlocks() { return this._maxBlocks },
	getChildBlocks() { return this._childBlocks },
	getTabs() { return Array.from(this._tabs) },

	getChildBlockItems(items)
	{
		return items.filter(item => item.getType() === 'group' || this.hasChildBlock(item.getHandle()))
	},

	isParent()
	{
		const cb = this.getChildBlocks()
		return cb === true || cb === '*' || (Array.isArray(cb) && cb.length > 0)
	},

	hasChildBlock(handle)
	{
		const cb = this.getChildBlocks()
		return cb === true || cb === '*' || (Array.isArray(cb) && cb.includes(handle))
	}
})
<commit_msg>Empty groups now removed on child block buttons<commit_after>import Garnish from 'garnish'

import Tab from './BlockTypeTab'

const _defaults = {
	id: -1,
	sortOrder: 0,
	name: '',
	handle: '',
	maxBlocks: 0,
	childBlocks: false,
	tabs: []
}

export default Garnish.Base.extend({

	init(settings = {})
	{
		settings = Object.assign({}, _defaults, settings)

		this._id = settings.id|0
		this._sortOrder = settings.sortOrder|0
		this._name = settings.name
		this._handle = settings.handle
		this._maxBlocks = settings.maxBlocks|0
		this._childBlocks = settings.childBlocks
		this._tabs = settings.tabs.map(tab => new Tab(tab))
	},

	getType() { return 'blockType' },
	getId() { return this._id },
	getSortOrder() { return this._sortOrder },
	getName() { return this._name },
	getHandle() { return this._handle },
	getMaxBlocks() { return this._maxBlocks },
	getChildBlocks() { return this._childBlocks },
	getTabs() { return Array.from(this._tabs) },

	getChildBlockItems(items)
	{
		const firstPass = items.filter(item => item.getType() === 'group' || this.hasChildBlock(item.getHandle()))
		return firstPass.filter((item, i) =>
		{
			if(item.getType() === 'group')
			{
				const nextItem = firstPass[i + 1]
				return nextItem && nextItem.getType() !== 'group'
			}

			return true
		})
	},

	isParent()
	{
		const cb = this.getChildBlocks()
		return cb === true || cb === '*' || (Array.isArray(cb) && cb.length > 0)
	},

	hasChildBlock(handle)
	{
		const cb = this.getChildBlocks()
		return cb === true || cb === '*' || (Array.isArray(cb) && cb.includes(handle))
	}
})
<|endoftext|>


<commit_before>/* eslint prefer-reflect: "off" */

import { select } from 'd3';
import isEqual from 'lodash-es/isEqual';
import { controlBar } from '@scola/d3-control';
import { scroller } from '@scola/d3-scroller';

export default class Table {
  constructor() {
    this._enter = (s) => s;
    this._exit = (s) => s;

    this._headerNames = [];
    this._headerModifier = (s) => s;
    this._headerCells = null;

    this._gesture = null;
    this._rootMedia = null;
    this._bodyMedia = null;
    this._scrollerMedia = null;

    this._header = null;
    this._footer = null;
    this._scroller = null;
    this._message = null;

    this._data = null;
    this._key = null;

    this._inset = false;
    this._maximized = false;
    this._over = false;
    this._swiped = false;

    this._root = select('body')
      .append('div')
      .remove()
      .classed('scola table', true)
      .styles({
        'padding-bottom': '3em'
      });

    this._body = this._root
      .append('div')
      .classed('scola body', true)
      .styles({
        'background': '#FFF',
        'border-color': '#CCC',
        'border-style': 'solid',
        'border-width': '1px 0',
        'display': 'flex',
        'flex-direction': 'column',
        'position': 'relative'
      });

    this._container = this._body
      .append('div')
      .classed('scola scroller', true)
      .styles({
        'background': 'rgba(0, 0, 0, 0.2)',
        'display': 'flex',
        'height': '100%',
        'justify-content': 'center',
        'opacity': 0,
        'padding': '0.25em 0',
        'position': 'absolute',
        'right': 0,
        'top': 0,
        'width': '1.5em'
      });

    this._table = this._body
      .append('table')
      .styles({
        'border-collapse': 'collapse',
        'table-layout': 'fixed',
        'width': '100%'
      });

    this._tableHead = this._table
      .append('thead');

    this._headerRow = this._tableHead
      .append('tr');

    this._tableBody = this._table
      .append('tbody');

    this._handleSet = (e) => this._set(e);
    this._bindTable();
  }

  destroy() {
    this._unbindTable();

    this._deleteInset();
    this._deleteHeader();
    this._deleteFooter();
    this._deleteScroller();
    this._deleteMessage();

    this._root.dispatch('destroy');
    this._root.remove();
    this._root = null;
  }

  root() {
    return this._root;
  }

  model(value = null) {
    if (value === null) {
      return this._model;
    }

    this._model = value;
    this._bindModel();

    return this;
  }

  enter(value = null) {
    if (value === null) {
      return this._enter;
    }

    this._enter = value;
    return this;
  }

  exit(value = null) {
    if (value === null) {
      return this._exit;
    }

    this._exit = value;
    return this;
  }

  inset(width = '48em') {
    if (width === null) {
      return this._inset;
    }

    if (width === false) {
      return this._deleteInset();
    }

    if (!this._rootMedia) {
      this._insertInset(width);
    }

    return this;
  }

  header(action = true) {
    if (action === false) {
      return this._deleteHeader();
    }

    if (!this._header) {
      this._insertHeader();
    }

    return this._header;
  }

  footer(action = true) {
    if (action === false) {
      return this._deleteFooter();
    }

    if (!this._footer) {
      this._insertFooter();
    }

    return this._footer;
  }

  scroller(width = '48em') {
    if (width === null) {
      return this._scroller;
    }

    if (width === false) {
      return this._deleteScroller();
    }

    if (!this._scroller) {
      this._insertScroller(width);
    }

    return this._scroller;
  }

  maximize() {
    this._maximized = true;

    this._root.styles({
      'height': '100%',
      'left': 0,
      'padding': 0,
      'position': 'absolute',
      'top': 0,
      'width': '100%'
    });

    this._body.styles({
      'border': 0,
      'height': '100%',
      'overflow': 'hidden'
    });

    return this;
  }

  headers(names = null, modifier = null) {
    if (names === null) {
      return this._headerNames;
    }

    this._headerNames = names;
    this._headerCells = this._headerRow
      .selectAll('th')
      .data((d) => this._columns(d))
      .enter()
      .append('th')
      .styles({
        'border-bottom': '1px solid #CCC',
        'color': '#AAA',
        'font-weight': 'normal',
        'font-size': '0.9em',
        'padding': '0.5em 0 0.5em 1em',
        'text-align': 'left',
        'text-transform': 'uppercase',
        'vertical-align': 'center'
      });

    if (modifier) {
      this._headerModifier = modifier;
    }

    this._headerModifier(this._headerCells
      .transition(), this);

    return this;
  }

  message(value = null, delay = null) {
    if (value === null) {
      return this._message;
    }

    clearTimeout(this._timeout);

    if (value === false) {
      return this._deleteMessage();
    }

    if (delay !== null) {
      return this._delayMessage(value, delay);
    }

    this._data = null;

    if (this._message) {
      return this._updateMessage(value);
    }

    return this._insertMessage(value);
  }

  resize() {
    if (this._maximized === true) {
      const height = parseFloat(this._body.style('height'));
      this._model.set('count', Math.ceil(height / (3 * 16)));
    } else {
      const height = (this._model.get('count') * 3) + 1.875;
      this._body.style('height', height + 'em');

      if (this._scroller) {
        this._scroller.resize();
      }
    }

    this.render();
    return this;
  }

  render(data = null, key = null) {
    if (data === null) {
      data = this._data;
      key = this._key;

      this._data = null;
      this._key = null;
    }

    if (isEqual(data, this._data)) {
      return;
    }

    this._data = data;
    this._key = key;

    if (this._headerCells) {
      this._headerModifier(this._headerCells
        .transition(), this);
    }

    const row = this._tableBody
      .selectAll('tr')
      .data(this._data, this._key);

    const cell = row.selectAll('td')
      .data((d) => this._columns(d));

    const exit = this._exit(row
      .exit()
      .transition(), this);

    exit.remove();

    const enter = row
      .enter()
      .append('tr')
      .merge(row)
      .selectAll('td')
      .data((d) => this._columns(d))
      .enter()
      .append('td')
      .merge(cell)
      .styles({
        'border-top': '1px solid #CCC',
        'height': '3em',
        'overflow': 'hidden',
        'padding': '0 0 0 1em',
        'text-overflow': 'ellipsis',
        'white-space': 'nowrap'
      });

    this._enter(enter.transition(), this);
  }

  _bindTable() {
    this._body.on('mouseenter', () => this._mouseenter());
    this._body.on('mouseleave', () => this._mouseleave());

    this._gesture = this._table
      .gesture()
      .on('panstart', (e) => e.stopPropagation())
      .on('panright', (e) => e.stopPropagation())
      .on('panleft', (e) => e.stopPropagation())
      .on('panend', (e) => e.stopPropagation())
      .on('swiperight', (e) => e.stopPropagation())
      .on('swipeleft', (e) => e.stopPropagation())
      .on('swipeup', (e) => this._swipe(e))
      .on('swipedown', (e) => this._swipe(e))
      .on('tap', (e) => this._tap(e));

    this._gesture.get('swipe').set({
      direction: 30
    });
  }

  _unbindTable() {
    this._body.on('mouseenter', null);
    this._body.on('mouseleave', null);

    if (this._gesture) {
      this._gesture.destroy();
      this._gesture = null;
    }
  }

  _bindModel() {
    if (this._model) {
      this._model.setMaxListeners(this._model.getMaxListeners() + 1);
      this._model.addListener('set', this._handleSet);
    }
  }

  _unbindModel() {
    if (this._model) {
      this._model.setMaxListeners(this._model.getMaxListeners() - 1);
      this._model.removeListener('set', this._handleSet);
    }
  }

  _insertInset(width) {
    this._rootMedia = this._root
      .media(`not all and (min-width: ${width})`)
      .call(() => { this._inset = false; })
      .media(`(min-width: ${width})`)
      .call(() => { this._inset = true; })
      .styles({
        'padding-left': '1em',
        'padding-right': '1em'
      })
      .start();

    this._bodyMedia = this._body
      .media(`(min-width: ${width})`)
      .styles({
        'border-radius': '0.5em',
        'border-style': 'none',
        'overflow': 'hidden'
      })
      .start();

    return this;
  }

  _deleteInset() {
    if (this._rootMedia) {
      this._rootMedia.destroy();
      this._rootMedia = null;
    }

    if (this._bodyMedia) {
      this._bodyMedia.destroy();
      this._bodyMedia = null;
    }

    return this;
  }

  _insertHeader() {
    this._header = controlBar();

    this._header.root()
      .classed('scola header', true)
      .styles({
        'border-bottom': '1px solid #CCC'
      });

    this._body.node().insertBefore(this._header.root().node(),
      this._table.node());

    return this;
  }

  _deleteHeader() {
    if (this._header) {
      this._header.destroy();
      this._header = null;
    }

    return this;
  }

  _insertFooter() {
    this._footer = controlBar();

    this._footer.root()
      .classed('scola footer', true)
      .styles({
        'border-top': '1px solid #CCC'
      });

    this._body
      .append(() => this._footer.root().node());

    return this;
  }

  _deleteFooter() {
    if (this._footer) {
      this._footer.destroy();
      this._footer = null;
    }

    return this;
  }

  _insertMessage(text) {
    this._tableBody
      .selectAll('tr')
      .remove();

    this._message = this._tableBody
      .append('tr')
      .classed('scola message', true)
      .append('td')
      .attr('colspan', this._headerNames.length)
      .styles({
        'cursor': 'default',
        'padding': '1em',
        'text-align': 'center'
      })
      .text(text);

    return this;
  }

  _updateMessage(text) {
    this._message.text(text);
    return this;
  }

  _deleteMessage() {
    if (this._message) {
      this._tableBody
        .selectAll('tr')
        .remove();

      this._message = null;
    }

    return this;
  }

  _delayMessage(text, delay) {
    delay = delay === true ? 250 : delay;

    clearTimeout(this._timeout);

    this._timeout = setTimeout(() => {
      this.message(text);
    }, delay);

    return this;
  }

  _insertScroller(width) {
    this._scroller = scroller()
      .vertical('1em')
      .line(false)
      .tabindex(0);

    this._scroller.root().on('end.table', () => {
      this._hideScroller();
    });

    this._container
      .append(() => this._scroller.root().node());

    this._scrollerMedia = this._root
      .media(`not all and (min-width: ${width})`)
      .call(() => this.resize())
      .media(`(min-width: ${width})`)
      .call(() => this.resize())
      .start();

    return this;
  }

  _deleteScroller() {
    if (this._scroller) {
      this._scroller.root().on('end.table', null);
      this._scroller.destroy();
      this._scroller = null;
    }

    if (this._scrollerMedia) {
      this._scrollerMedia.destroy();
      this._scrollerMedia = null;
    }

    return this;
  }

  _hideScroller() {
    const show = !this._scroller ||
      this._over === true ||
      this._swiped === true ||
      this._scroller.scrolling();

    if (show) {
      return;
    }

    this._container
      .transition()
      .style('opacity', 0)
      .on('end', () => {
        this._container
          .style('display', 'none');
      });
  }

  _showScroller() {
    const hide = !this._scroller ||
      this._model.get('total') === 0;

    if (hide) {
      return;
    }

    this._container
      .style('display', 'flex')
      .transition()
      .style('opacity', 1);

    this._scroller.resize();
  }

  _mouseenter() {
    if (this._swiped === true) {
      return;
    }

    this._over = true;
    this._showScroller();
  }

  _mouseleave() {
    this._over = false;
    this._swiped = false;
    this._hideScroller();
  }

  _tap() {
    const swiped = this._swiped;
    this._swiped = false;

    if (swiped === true) {
      this._hideScroller();
    }
  }

  _swipe(event) {
    if (!this._scroller) {
      return;
    }

    this._swiped = true;
    this._showScroller();

    if (event.type === 'swipeup') {
      this._scroller.up();
    } else if (event.type === 'swipedown') {
      this._scroller.down();
    }
  }

  _set(setEvent) {
    const cancel = setEvent.changed === false ||
      setEvent.name !== 'total' &&
      setEvent.name !== 'count';

    if (cancel) {
      if (setEvent.name === 'count') {
        this._scroller.resize();
      }

      return;
    }

    if (!this._model.has('total') || !this._model.has('count')) {
      return;
    }

    const total = this._model.get('total');
    const count = this._model.get('count') -
      (this._maximized === true ? 1 : 0);

    const max = Math.max(0, Math.ceil((total - count) / count));

    this._scroller.domain([0, max]);
    this._scroller.resize();
  }

  _columns(datum) {
    return Array(this._headerNames.length || 1).fill(datum);
  }
}
<commit_msg>Add maximizer/equalizer, remove resize, add row height<commit_after>/* eslint prefer-reflect: "off" */

import { select } from 'd3';
import isEqual from 'lodash-es/isEqual';
import { controlBar } from '@scola/d3-control';
import { scroller } from '@scola/d3-scroller';

export default class Table {
  constructor() {
    this._enter = (s) => s;
    this._exit = (s) => s;

    this._headerNames = [];
    this._headerModifier = (s) => s;
    this._headerCells = null;

    this._gesture = null;
    this._rootMedia = null;
    this._bodyMedia = null;
    this._scrollerMedia = null;

    this._header = null;
    this._footer = null;
    this._scroller = null;
    this._message = null;

    this._maximizer = null;
    this._equalizer = null;

    this._rowHeight = 48;
    this._inset = false;
    this._over = false;
    this._swiped = false;

    this._data = null;
    this._key = null;

    this._root = select('body')
      .append('div')
      .remove()
      .classed('scola table', true)
      .styles({
        'padding-bottom': '3em'
      });

    this._body = this._root
      .append('div')
      .classed('scola body', true)
      .styles({
        'background': '#FFF',
        'border-color': '#CCC',
        'border-style': 'solid',
        'border-width': '1px 0',
        'display': 'flex',
        'flex-direction': 'column',
        'position': 'relative'
      });

    this._container = this._body
      .append('div')
      .classed('scola scroller', true)
      .styles({
        'background': 'rgba(0, 0, 0, 0.2)',
        'display': 'flex',
        'height': '100%',
        'justify-content': 'center',
        'opacity': 0,
        'padding': '0.25em 0',
        'position': 'absolute',
        'right': 0,
        'top': 0,
        'width': '1.5em'
      });

    this._table = this._body
      .append('table')
      .styles({
        'border-collapse': 'collapse',
        'table-layout': 'fixed',
        'width': '100%'
      });

    this._tableHead = this._table
      .append('thead');

    this._headerRow = this._tableHead
      .append('tr');

    this._tableBody = this._table
      .append('tbody');

    this._handleSet = (e) => this._set(e);
    this._bindTable();
  }

  destroy() {
    this._unbindTable();
    this._unbindModel();
    this._unbindEqualizer();
    this._unbindMaximizer();

    this._deleteInset();
    this._deleteHeader();
    this._deleteFooter();
    this._deleteScroller();
    this._deleteMessage();

    this._root.dispatch('destroy');
    this._root.remove();
    this._root = null;
  }

  root() {
    return this._root;
  }

  model(value = null) {
    if (value === null) {
      return this._model;
    }

    this._model = value;
    this._bindModel();

    return this;
  }

  enter(value = null) {
    if (value === null) {
      return this._enter;
    }

    this._enter = value;
    return this;
  }

  exit(value = null) {
    if (value === null) {
      return this._exit;
    }

    this._exit = value;
    return this;
  }

  height(value = null) {
    if (value === null) {
      return this._rowHeight;
    }

    this._rowHeight = value;
    return this;
  }

  inset(width = '48em') {
    if (width === null) {
      return this._inset;
    }

    if (width === false) {
      return this._deleteInset();
    }

    if (!this._rootMedia) {
      this._insertInset(width);
    }

    return this;
  }

  header(action = true) {
    if (action === false) {
      return this._deleteHeader();
    }

    if (!this._header) {
      this._insertHeader();
    }

    return this._header;
  }

  footer(action = true) {
    if (action === false) {
      return this._deleteFooter();
    }

    if (!this._footer) {
      this._insertFooter();
    }

    return this._footer;
  }

  scroller(width = '48em') {
    if (width === null) {
      return this._scroller;
    }

    if (width === false) {
      return this._deleteScroller();
    }

    if (!this._scroller) {
      this._insertScroller(width);
    }

    return this._scroller;
  }

  equalizer(element = null) {
    if (element === null) {
      return this._equalizer;
    }

    this._equalizer = element;
    this._bindEqualizer();

    return this;
  }

  maximizer(element = null) {
    if (element === null) {
      return this._maximizer;
    }

    this._maximizer = element;
    this._bindMaximizer();

    this._root.styles({
      'height': '100%',
      'left': 0,
      'padding': 0,
      'position': 'absolute',
      'top': 0,
      'width': '100%'
    });

    this._body.styles({
      'border': 0,
      'height': '100%',
      'overflow': 'hidden'
    });

    return this;
  }

  headers(names = null, modifier = null) {
    if (names === null) {
      return this._headerNames;
    }

    this._headerNames = names;
    this._headerCells = this._headerRow
      .selectAll('th')
      .data((d) => this._columns(d))
      .enter()
      .append('th')
      .styles({
        'border-bottom': '1px solid #CCC',
        'color': '#AAA',
        'font-weight': 'normal',
        'font-size': '0.9em',
        'padding': '0.5em 0 0.5em 1em',
        'text-align': 'left',
        'text-transform': 'uppercase',
        'vertical-align': 'center'
      });

    if (modifier) {
      this._headerModifier = modifier;
    }

    this._headerModifier(this._headerCells
      .transition(), this);

    return this;
  }

  message(value = null, delay = null) {
    if (value === null) {
      return this._message;
    }

    clearTimeout(this._timeout);

    if (value === false) {
      return this._deleteMessage();
    }

    if (delay !== null) {
      return this._delayMessage(value, delay);
    }

    this._data = null;

    if (this._message) {
      return this._updateMessage(value);
    }

    return this._insertMessage(value);
  }

  render(data = null, key = null) {
    if (data === null) {
      data = this._data;
      key = this._key;

      this._data = null;
      this._key = null;
    }

    if (isEqual(data, this._data)) {
      return;
    }

    if (this._scroller) {
      this._scroller.resize();
    }

    this._data = data;
    this._key = key;

    if (this._headerCells) {
      this._headerModifier(this._headerCells
        .transition(), this);
    }

    const row = this._tableBody
      .selectAll('tr')
      .data(this._data, this._key);

    const cell = row.selectAll('td')
      .data((d) => this._columns(d));

    const exit = this._exit(row
      .exit()
      .transition(), this);

    exit.remove();

    const enter = row
      .enter()
      .append('tr')
      .merge(row)
      .selectAll('td')
      .data((d) => this._columns(d))
      .enter()
      .append('td')
      .merge(cell)
      .styles({
        'border-top': '1px solid #CCC',
        'height': '3em',
        'overflow': 'hidden',
        'padding': '0 0 0 1em',
        'text-overflow': 'ellipsis',
        'white-space': 'nowrap'
      });

    this._enter(enter.transition(), this);
  }

  _bindTable() {
    this._body.on('mouseenter', () => this._mouseenter());
    this._body.on('mouseleave', () => this._mouseleave());

    this._gesture = this._table
      .gesture()
      .on('panstart', (e) => e.stopPropagation())
      .on('panright', (e) => e.stopPropagation())
      .on('panleft', (e) => e.stopPropagation())
      .on('panend', (e) => e.stopPropagation())
      .on('swiperight', (e) => e.stopPropagation())
      .on('swipeleft', (e) => e.stopPropagation())
      .on('swipeup', (e) => this._swipe(e))
      .on('swipedown', (e) => this._swipe(e))
      .on('tap', (e) => this._tap(e));

    this._gesture.get('swipe').set({
      direction: 30
    });
  }

  _unbindTable() {
    this._body.on('mouseenter', null);
    this._body.on('mouseleave', null);

    if (this._gesture) {
      this._gesture.destroy();
      this._gesture = null;
    }
  }

  _bindModel() {
    if (this._model) {
      this._model.setMaxListeners(this._model.getMaxListeners() + 1);
      this._model.addListener('set', this._handleSet);
    }
  }

  _unbindModel() {
    if (this._model) {
      this._model.setMaxListeners(this._model.getMaxListeners() - 1);
      this._model.removeListener('set', this._handleSet);
    }
  }

  _bindEqualizer() {
    if (this._equalizer) {
      this._equalizer.root().on('resize.scola-table', () => {
        this._equalize();
      });
    }
  }

  _unbindEqualizer() {
    if (this._equalizer) {
      this._equalizer.root().on('resize.scola-table', null);
    }
  }

  _bindMaximizer() {
    if (this._maximizer) {
      this._maximizer.root().on('resize.scola-table', () => {
        this._maximize();
      });
    }
  }

  _unbindMaximizer() {
    if (this._maximizer) {
      this._maximizer.root().on('resize.scola-table', null);
    }
  }

  _insertInset(width) {
    this._rootMedia = this._root
      .media(`not all and (min-width: ${width})`)
      .call(() => { this._inset = false; })
      .media(`(min-width: ${width})`)
      .call(() => { this._inset = true; })
      .styles({
        'padding-left': '1em',
        'padding-right': '1em'
      })
      .start();

    this._bodyMedia = this._body
      .media(`(min-width: ${width})`)
      .styles({
        'border-radius': '0.5em',
        'border-style': 'none',
        'overflow': 'hidden'
      })
      .start();

    return this;
  }

  _deleteInset() {
    if (this._rootMedia) {
      this._rootMedia.destroy();
      this._rootMedia = null;
    }

    if (this._bodyMedia) {
      this._bodyMedia.destroy();
      this._bodyMedia = null;
    }

    return this;
  }

  _insertHeader() {
    this._header = controlBar();

    this._header.root()
      .classed('scola header', true)
      .styles({
        'border-bottom': '1px solid #CCC'
      });

    this._body.node().insertBefore(this._header.root().node(),
      this._table.node());

    return this;
  }

  _deleteHeader() {
    if (this._header) {
      this._header.destroy();
      this._header = null;
    }

    return this;
  }

  _insertFooter() {
    this._footer = controlBar();

    this._footer.root()
      .classed('scola footer', true)
      .styles({
        'border-top': '1px solid #CCC'
      });

    this._body
      .append(() => this._footer.root().node());

    return this;
  }

  _deleteFooter() {
    if (this._footer) {
      this._footer.destroy();
      this._footer = null;
    }

    return this;
  }

  _insertMessage(text) {
    this._tableBody
      .selectAll('tr')
      .remove();

    this._message = this._tableBody
      .append('tr')
      .classed('scola message', true)
      .append('td')
      .attr('colspan', this._headerNames.length)
      .styles({
        'cursor': 'default',
        'padding': '1em',
        'text-align': 'center'
      })
      .text(text);

    return this;
  }

  _updateMessage(text) {
    this._message.text(text);
    return this;
  }

  _deleteMessage() {
    if (this._message) {
      this._tableBody
        .selectAll('tr')
        .remove();

      this._message = null;
    }

    return this;
  }

  _delayMessage(text, delay) {
    delay = delay === true ? 250 : delay;

    clearTimeout(this._timeout);

    this._timeout = setTimeout(() => {
      this.message(text);
    }, delay);

    return this;
  }

  _insertScroller(width) {
    this._scroller = scroller()
      .vertical('1em')
      .line(false)
      .tabindex(0);

    this._scroller.root().on('end.table', () => {
      this._hideScroller();
    });

    this._container
      .append(() => this._scroller.root().node());

    this._scrollerMedia = this._root
      .media(`not all and (min-width: ${width})`)
      .call(() => this.render())
      .media(`(min-width: ${width})`)
      .call(() => this.render())
      .start();

    return this;
  }

  _deleteScroller() {
    if (this._scroller) {
      this._scroller.root().on('end.table', null);
      this._scroller.destroy();
      this._scroller = null;
    }

    if (this._scrollerMedia) {
      this._scrollerMedia.destroy();
      this._scrollerMedia = null;
    }

    return this;
  }

  _hideScroller() {
    const show = !this._scroller ||
      this._over === true ||
      this._swiped === true ||
      this._scroller.scrolling();

    if (show) {
      return;
    }

    this._container
      .transition()
      .style('opacity', 0)
      .on('end', () => {
        this._container
          .style('display', 'none');
      });
  }

  _showScroller() {
    const hide = !this._scroller ||
      this._model.get('total') === 0;

    if (hide) {
      return;
    }

    this._container
      .style('display', 'flex')
      .transition()
      .style('opacity', 1);

    this._scroller.resize();
  }

  _mouseenter() {
    if (this._swiped === true) {
      return;
    }

    this._over = true;
    this._showScroller();
  }

  _mouseleave() {
    this._over = false;
    this._swiped = false;
    this._hideScroller();
  }

  _tap() {
    const swiped = this._swiped;
    this._swiped = false;

    if (swiped === true) {
      this._hideScroller();
    }
  }

  _swipe(event) {
    if (!this._scroller) {
      return;
    }

    this._swiped = true;
    this._showScroller();

    if (event.type === 'swipeup') {
      this._scroller.up();
    } else if (event.type === 'swipedown') {
      this._scroller.down();
    }
  }

  _set(setEvent) {
    const cancel = setEvent.changed === false ||
      setEvent.name !== 'total' &&
      setEvent.name !== 'count';

    if (cancel) {
      return;
    }

    if (!this._model.has('total') || !this._model.has('count')) {
      return;
    }

    const total = this._model.get('total');
    let count = this._model.get('count');

    if (this._maximizer) {
      count -= 1;
    } else {
      const height = parseFloat(this._tableHead.style('height')) +
        (count * this._rowHeight);

      this._body.style('height', height + 'px');
    }

    const max = Math.max(0, Math.ceil((total - count) / count));
    this._scroller.domain([0, max]);
  }

  _equalize() {
    const height = parseFloat(this._equalizer.body().style('height')) -
      parseFloat(this._tableHead.style('height')) -
      parseFloat(this._table.style('padding-bottom'));

    this._model.set('count', Math.floor(height / this._rowHeight));
    this.render();
  }

  _maximize() {
    const height = parseFloat(this._body.style('height')) -
      parseFloat(this._tableHead.style('height'));

    this._model.set('count', Math.ceil(height / this._rowHeight));
    this.render();
  }

  _columns(datum) {
    return Array(this._headerNames.length || 1).fill(datum);
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import { Link, withRouter } from 'react-router';
import $ from 'jquery';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import CircularProgress from 'material-ui/CircularProgress';
import LinearProgress from 'material-ui/LinearProgress';
import FlatButton from 'material-ui/FlatButton';

import IconMenu from 'material-ui/IconMenu';
import IconButton from 'material-ui/IconButton';
import NavigationExpandMoreIcon from 'material-ui/svg-icons/navigation/expand-more';
import MenuItem from 'material-ui/MenuItem';
import RaisedButton from 'material-ui/RaisedButton';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Avatar from 'material-ui/Avatar';

import {
  blue300,
  indigo900,
  orange200,
  deepOrange300,
  pink400,
  purple500,
} from 'material-ui/styles/colors';

const injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();

const fecha = require('fecha');
const vex = require('vex-js');

vex.registerPlugin(require('vex-dialog'));
vex.defaultOptions.className = 'vex-theme-os';

let fileName = '';
let filePath = '';
let picDescrip = '';
let currentImgs = [];

const getAllPhotos = () => {
  // console.log('Trying to get topPics ...');
  $.get({
    url: '/topPics',
    success: (data) => {
      // console.log(data, data.length);
    },
    error: (error) => {
      console.error('error in get upload', error);
      $('.error').show();
    },
  });
};

const uploadFile = (props) => {
  $(function () {
    const imageIsLoaded = e => {
      $('#myImg').attr('src', e.target.result);
      filePath = e.target.result;

      if (!currentImgs.includes(fileName)) {
        currentImgs.push(fileName);
        props.uploadBar();
        $.post({
          url: '/upload',
          data: JSON.stringify({
            fileName: fileName,
            filePath: filePath,
            description: picDescrip
          }),
          contentType: 'application/json',
          success: data => {
            props.uploadBar();
            // console.log('Found user\'s uploaded photo from DB', data);
            $('#profilePicUp').val('');
            vex.dialog.alert('Uploaded!');
            $('button.vex-dialog-button-primary.vex-dialog-button.vex-first').click(() => window.location.reload());
          },
          error: error => {
            console.error('error in get upload', error);
            $('.error').show();
          },
        });
      }
    };

    $('#fileUp').change(function () {
      // console.log('file ATTEMPT');
      if (this.files && this.files[0]) {
        const reader = new FileReader();
        picDescrip = $('#description').val();
        fileName = this.files[0].name;
        // console.log(fileName);
        reader.onload = imageIsLoaded;
        reader.readAsDataURL(this.files[0]);
      }
    });

    $('#profilePicUp').change(function () {
      if (this.files && this.files[0]) {
        const reader = new FileReader();
        // picDescrip = $('#description').val();
        fileName = this.files[0].name;
        // console.log(fileName);
        reader.onload = imageIsLoaded;
        reader.readAsDataURL(this.files[0]);
      }
    });
  });
};

const signOut = () => {
  // console.log('in sign out function');
  $.get({
    url: '/signOut',
    success: (data) => {
      // console.log(data);
      window.location.reload();
    },
    error: (error) => {
      console.error('error in get bookmarks', error);
      $('.error').show();
    },
  });
};

const styles = {
  button: {
    margin: 12,
    fontFamily: 'Orbitron !important',
    backgroundColor: '#e8e8e8',
    color: 'black !important'
  },
  exampleImageInput: {
    cursor: 'pointer',
    position: 'absolute',
    top: 0,
    bottom: 0,
    right: 0,
    left: 0,
    width: '100%',
    opacity: 0,
  },
  exploreButton: {
    fontFamily: 'Orbitron',
    color: 'white',
    top: '25%',
    left: '15%',
    // position: 'absolute'
  },
};

const style = {
  margin: 12,
};

const backgroundStyle = {
  // backgroundImage: 'url("http://i.imgur.com/uTYax11.jpg")',
  // backgroundSize: 'cover',
  // backgroundRepeat: 'no-repeat',
  // backgroundPosition: '50% 50%',
  backgroundSize: 'cover',
  position: 'fixed',
  flex: 1,
  height: '100%',
  width: '100%',
}

const overlayStyle = {
  // position: 'fixed',
  top: '50%',
  left: '25%',
}

//

export default props => {
  uploadFile(props);

  return (

        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <Toolbar >
          <ToolbarGroup>
            <Avatar src={props.profilePic} style={{right: '15%'}} />
          </ToolbarGroup>
          <ToolbarGroup>
            <ToolbarTitle className="fancyText" text={"Welcome, " + props.currentUser} style={{ top: '-10px', color: 'white'}}/>
          </ToolbarGroup>

        </Toolbar>
        </MuiThemeProvider>

        <MuiThemeProvider muiTheme={getMuiTheme()}>
            <LinearProgress color='#FF3D00' className={props.shouldHide ? 'hidden' : ''} mode="indeterminate" />
        </MuiThemeProvider>

 Immerse

        <Link to="/lobby">
        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <RaisedButton buttonStyle={styles.exploreButton} label="Explore" primary={true}  />
        </MuiThemeProvider>
        </Link>

        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <RaisedButton
        label="Upload"
        labelPosition="before"
        style={styles.button}
        containerElement="label"
        buttonStyle={styles.exploreButton}>
        <input id="fileUp" type="file" style={styles.exampleImageInput} />
        </RaisedButton>
        </MuiThemeProvider>

          <MuiThemeProvider muiTheme={getMuiTheme()}>
          <FlatButton label="Sign Out" labelStyle={styles.exploreButton} onClick={() => { signOut(); }} />
          </MuiThemeProvider>

  );
};

/*
        <input type='file' id='profilePicUp' />
 */<commit_msg>Change headline to be consistent with domain name<commit_after>import React from 'react';
import { Link, withRouter } from 'react-router';
import $ from 'jquery';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import CircularProgress from 'material-ui/CircularProgress';
import LinearProgress from 'material-ui/LinearProgress';
import FlatButton from 'material-ui/FlatButton';

import IconMenu from 'material-ui/IconMenu';
import IconButton from 'material-ui/IconButton';
import NavigationExpandMoreIcon from 'material-ui/svg-icons/navigation/expand-more';
import MenuItem from 'material-ui/MenuItem';
import RaisedButton from 'material-ui/RaisedButton';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Avatar from 'material-ui/Avatar';

import {
  blue300,
  indigo900,
  orange200,
  deepOrange300,
  pink400,
  purple500,
} from 'material-ui/styles/colors';

const injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();

const fecha = require('fecha');
const vex = require('vex-js');

vex.registerPlugin(require('vex-dialog'));
vex.defaultOptions.className = 'vex-theme-os';

let fileName = '';
let filePath = '';
let picDescrip = '';
let currentImgs = [];

const getAllPhotos = () => {
  // console.log('Trying to get topPics ...');
  $.get({
    url: '/topPics',
    success: (data) => {
      // console.log(data, data.length);
    },
    error: (error) => {
      console.error('error in get upload', error);
      $('.error').show();
    },
  });
};

const uploadFile = (props) => {
  $(function () {
    const imageIsLoaded = e => {
      $('#myImg').attr('src', e.target.result);
      filePath = e.target.result;

      if (!currentImgs.includes(fileName)) {
        currentImgs.push(fileName);
        props.uploadBar();
        $.post({
          url: '/upload',
          data: JSON.stringify({
            fileName: fileName,
            filePath: filePath,
            description: picDescrip
          }),
          contentType: 'application/json',
          success: data => {
            props.uploadBar();
            // console.log('Found user\'s uploaded photo from DB', data);
            $('#profilePicUp').val('');
            vex.dialog.alert('Uploaded!');
            $('button.vex-dialog-button-primary.vex-dialog-button.vex-first').click(() => window.location.reload());
          },
          error: error => {
            console.error('error in get upload', error);
            $('.error').show();
          },
        });
      }
    };

    $('#fileUp').change(function () {
      // console.log('file ATTEMPT');
      if (this.files && this.files[0]) {
        const reader = new FileReader();
        picDescrip = $('#description').val();
        fileName = this.files[0].name;
        // console.log(fileName);
        reader.onload = imageIsLoaded;
        reader.readAsDataURL(this.files[0]);
      }
    });

    $('#profilePicUp').change(function () {
      if (this.files && this.files[0]) {
        const reader = new FileReader();
        // picDescrip = $('#description').val();
        fileName = this.files[0].name;
        // console.log(fileName);
        reader.onload = imageIsLoaded;
        reader.readAsDataURL(this.files[0]);
      }
    });
  });
};

const signOut = () => {
  // console.log('in sign out function');
  $.get({
    url: '/signOut',
    success: (data) => {
      // console.log(data);
      window.location.reload();
    },
    error: (error) => {
      console.error('error in get bookmarks', error);
      $('.error').show();
    },
  });
};

const styles = {
  button: {
    margin: 12,
    fontFamily: 'Orbitron !important',
    backgroundColor: '#e8e8e8',
    color: 'black !important'
  },
  exampleImageInput: {
    cursor: 'pointer',
    position: 'absolute',
    top: 0,
    bottom: 0,
    right: 0,
    left: 0,
    width: '100%',
    opacity: 0,
  },
  exploreButton: {
    fontFamily: 'Orbitron',
    color: 'white',
    top: '25%',
    left: '15%',
    // position: 'absolute'
  },
};

const style = {
  margin: 12,
};

const backgroundStyle = {
  // backgroundImage: 'url("http://i.imgur.com/uTYax11.jpg")',
  // backgroundSize: 'cover',
  // backgroundRepeat: 'no-repeat',
  // backgroundPosition: '50% 50%',
  backgroundSize: 'cover',
  position: 'fixed',
  flex: 1,
  height: '100%',
  width: '100%',
}

const overlayStyle = {
  // position: 'fixed',
  top: '50%',
  left: '25%',
}

//

export default props => {
  uploadFile(props);

  return (

        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <Toolbar >
          <ToolbarGroup>
            <Avatar src={props.profilePic} style={{right: '15%'}} />
          </ToolbarGroup>
          <ToolbarGroup>
            <ToolbarTitle className="fancyText" text={"Welcome, " + props.currentUser} style={{ top: '-10px', color: 'white'}}/>
          </ToolbarGroup>

        </Toolbar>
        </MuiThemeProvider>

        <MuiThemeProvider muiTheme={getMuiTheme()}>
            <LinearProgress color='#FF3D00' className={props.shouldHide ? 'hidden' : ''} mode="indeterminate" />
        </MuiThemeProvider>

 ImmerseVR

        <Link to="/lobby">
        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <RaisedButton buttonStyle={styles.exploreButton} label="Explore" primary={true}  />
        </MuiThemeProvider>
        </Link>

        <MuiThemeProvider muiTheme={getMuiTheme()}>
        <RaisedButton
        label="Upload"
        labelPosition="before"
        style={styles.button}
        containerElement="label"
        buttonStyle={styles.exploreButton}>
        <input id="fileUp" type="file" style={styles.exampleImageInput} />
        </RaisedButton>
        </MuiThemeProvider>

          <MuiThemeProvider muiTheme={getMuiTheme()}>
          <FlatButton label="Sign Out" labelStyle={styles.exploreButton} onClick={() => { signOut(); }} />
          </MuiThemeProvider>

  );
};

/*
        <input type='file' id='profilePicUp' />
 */<|endoftext|>


<commit_before>'use strict';

import { authors } from './authorData';
import _ from 'lodash';

const _generateId = function(author) {
	return author.firstName.toLowerCase().trim() + '-' + author.lastName.toLowerCase().trim();
};

const AuthorApi = {
	getAllAuthors() {
		return authors;
	},

	getAuthorById(id) {
		return _.find(authors, { id: id });
	},

	saveAuthor(author) {
		console.log('Pretend this just saved the author to the DB via AJAX call...');

		if (!author.id) {
			author.id = _generateId(author);
			authors.push(author);
		}

		return author;
	},

	deleteAuthor(id) {
		console.log('Pretend this just deleted the author from the DB via an AJAX call...');
	}
};

module.exports = AuthorApi;
<commit_msg>Update authorsApi.js<commit_after>'use strict'

import {authors} from './authorData'
import _ from 'lodash'

const _generateId = function (author) {
	return author.firstName.toLowerCase().trim() + '-' + author.lastName.toLowerCase().trim()
}

const AuthorApi = {
	getAllAuthors () {
		return authors
	},

	getAuthorById (id) {
		return _.find(authors, { id: id })
	},

	saveAuthor (author) {
		console.log('Pretend this just saved the author to the DB via AJAX call...')

		if (!author.id) {
			author.id = _generateId(author)
			authors.push(author)
		}

		return author
	},

	deleteAuthor (id) {
		console.log('Pretend this just deleted the author from the DB via an AJAX call...')
	}
}

module.exports = AuthorApi
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name PlacedItem
 *
 * @class The PlacedItem class is the base for any items that have a matrix
 * associated with them, describing their placement in the project, such as
 * {@link Raster} and {@link PlacedSymbol}.
 *
 * @extends Item
 */
var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
	// PlacedItem uses strokeBounds for bounds
	_boundsType: { bounds: 'strokeBounds' },

	_hitTest: function(point, options, matrix) {
		point = point.transform(this.matrix);
		var hitResult = this._symbol._definition.hitTest(point, options, matrix);
		// TODO: When the symbol's definition is a path, should hitResult contain
		// information like HitResult#curve?
		if (hitResult)
			hitResult.item = this;
		return hitResult;
	}
});<commit_msg>Optimize PlacedSymbol#_hitTest a bit.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name PlacedItem
 *
 * @class The PlacedItem class is the base for any items that have a matrix
 * associated with them, describing their placement in the project, such as
 * {@link Raster} and {@link PlacedSymbol}.
 *
 * @extends Item
 */
var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
	// PlacedItem uses strokeBounds for bounds
	_boundsType: { bounds: 'strokeBounds' },

	_hitTest: function(point, options, matrix) {
		var hitResult = this._symbol._definition.hitTest(
				point._transformPoint(this.matrix), options, matrix);
		// TODO: When the symbol's definition is a path, should hitResult contain
		// information like HitResult#curve?
		if (hitResult)
			hitResult.item = this;
		return hitResult;
	}
});<|endoftext|>


<commit_before>/*
* AUI Base
*/
AUI.add('aui-base', function(A) {

	A.mix(A.Array, {
		remove: function(a, from, to) {
		  var rest = a.slice((to || from) + 1 || a.length);
		  a.length = (from < 0) ? (a.length + from) : from;

		  return a.push.apply(a, rest);
		},

		removeItem: function(a, item) {
			var index = A.Array.indexOf(a, item);

		  	return A.Array.remove(a, index);
		}
	});

}, '@VERSION', { requires: [ 'yui-base' ] });

/*
* AUI Delayed Task
*/

AUI.add('delayed-task', function(A) {

	var DelayedTask = function(fn, scope, args) {
		var instance = this;

		instance._args = args;
		instance._delay = 0;
		instance._fn = fn;
		instance._id = null;
		instance._scope = scope || instance;
		instance._time = 0;

		instance._base = function() {
			var now = instance._getTime();

			if (now - instance._time >= instance._delay) {
				clearInterval(instance._id);

				instance._id = null;

				instance._fn.apply(instance._scope, instance._args || []);
			}
		};
	};

	DelayedTask.prototype = {
		delay: function(delay, newFn, newScope, newArgs) {
			var instance = this;

			if (instance._id && instance._delay != delay) {
				instance.cancel();
			}

			instance._delay = delay || instance._delay;
			instance._time = instance._getTime();

			instance._fn = newFn || instance._fn;
			instance._scope = newScope || instance._scope;
			instance._args = newArgs || instance._args;

			if (!A.Lang.isArray(instance._args)) {
				instance._args = [instance._args];
			}

			if (!instance._id) {
				if (instance._delay > 0) {
					instance._id = setInterval(instance._base, instance._delay);
				}
				else {
					instance._base();
				}
			}
		},

		cancel: function() {
			var instance = this;

			if (instance._id) {
				clearInterval(instance._id);

				instance._id = null;
			}
		},

		_getTime: function() {
			var instance = this;

			return (+new Date());
		}
	};

	A.DelayedTask = DelayedTask;

}, '@VERSION', { requires: [ 'yui-base' ] });

/*
* AUI Node
*/

AUI.add('aui-node', function(A) {

	var Lang = A.Lang,
		isString = Lang.isString,
		isUndefined = Lang.isUndefined,

		INNER_HTML = 'innerHTML';

	A.mix(A.Node.prototype, {
		after: function(content) {
			var instance = this;

			return instance.insertAfter(content);
		},

		appendTo: function(selector) {
			var instance = this;

			A.get(selector).append(instance);
		},

		attr: function(name, value) {
			var instance = this;

			if (!isUndefined(value)) {
				return instance.setAttribute(name, value);
			}
			else {
				return instance.getAttribute(name);
			}
		},

		before: function(content) {
			var instance = this;

			var parent = instance.get('parentNode');

			if (parent) {
				parent.insertBefore(content, instance);
			}

			return instance;
		},

		empty: function() {
			var instance = this;

			instance.queryAll('>*').remove();

			var el = A.Node.getDOMNode(instance);

			while (el.firstChild) {
				el.removeChild(el.firstChild);
			}

			return instance;
		},

		getDOM: function() {
			var instance = this;

			return A.Node.getDOMNode(instance);
		},

		html: function() {
			var args = arguments, length = args.length;

			if (length) {
				this.set(INNER_HTML, args[0]);
			}
			else {
				return this.get(INNER_HTML);
			}

			return this;
		},

		insertAfter: function(content) {
			var instance = this;

			var parent = instance.get('parentNode');

			if (parent) {
				parent.insertBefore(content, instance.get('nextSibling'));
			}

			return instance;
		},

		prependTo: function(selector) {
			var instance = this;

			A.get(selector).prepend(instance);
		},

		text: function(text) {
			var instance = this;

			if (!isUndefined(text)) {
				text = A.DOM._getDoc(A.Node.getDOMNode(instance)).createTextNode(text);

				return instance.empty().append(text);
			}

			var el = A.Node.getDOMNode(instance);

			return instance._getText(el.childNodes);
		},

		_getText: function(childNodes) {
			var instance = this;

			var length = childNodes.length;
			var childNode;

			var str = [];

			for (var i = 0; i < length; i++) {
				childNode = childNodes[i];

				if (childNode && childNode.nodeType != 8) {
					if (childNode.nodeType != 1) {
						str.push(childNode.nodeValue);
					}

					if (childNode.childNodes) {
						str.push(instance._getText(childNode.childNodes));
					}
				}
			}

			return str.join('');
		}
	}, true);

	A.mix(A.Node, {
		globalEval: function(data) {
			if ( data && /\S/.test(data) ) {
				var head = document.getElementsByTagName("head")[0] || document.documentElement;
				var script = document.createElement("script");

				script.type = "text/javascript";

				if (AUI.support.scriptEval) {
					script.appendChild(document.createTextNode(data));
				}
				else {
					script.text = data;
				}

				head.insertBefore(script, head.firstChild);
				head.removeChild(script);
			}
		},

		evalScript: function(elem) {
			if (elem.src) {
				A.io(elem.src, {
					async: false,
					on: {
						complete: function(i, o) {
							A.Node.globalEval(o.responseText);
						}
					}
				});
			}
			else {
				A.Node.globalEval(elem.text || elem.textContent || elem.innerHTML || "");
			}
		},

		clean: function(html) {
			var TPL_NODE = '

',
				IE_FIX_PADDING_NODE = '
_
',
				SCRIPT = 'script';

			// instead of fix all tags to "XHTML"-style, make the firstChild be a valid non-empty tag
			html = IE_FIX_PADDING_NODE + A.Lang.trim(html);

			delete A.DOM._cloneCache[html];

			// wrap in a nodeType == 1, nodeType 11 (document fragment) does not support getElementsByTagName
			var temp = A.Node.create(TPL_NODE).append(
				A.Node.create(html)
			);

			var scripts = temp.getElementsByTagName(SCRIPT);

			scripts.each(function(elem) {
				elem.remove();
			});

			temp.removeChild(A.Node.getDOMNode(temp).firstChild);

			var html = temp.html();

			// avoid IE6 memory leak
			temp = null;

			return [ html, scripts ];
		},

		domManip: function(html, callback) {
			var clean = A.Node.clean(html);
			var content = clean[0];
			var scripts = clean[1];

			if (callback) {
				callback.apply(this, [ content ]);
			}

			scripts.each(function(elem) {
				A.Node.evalScript( A.Node.getDOMNode(elem) );
			});
		}
	});

	A.Node.ATTRS.innerHTML = {
		setter: function(v) {
			var instance = this;

			var defaultSetter = function(value) {
				A.Node.DEFAULT_SETTER.apply(instance, [ INNER_HTML, value ]);
			};

			if (isString(v)) {
				// eval scripts
				v = A.Node.domManip(v, defaultSetter);
			}
			else {
				defaultSetter(v);
			}
		}
	};

	A.NodeList.importMethod(
		A.Node.prototype,
		[
			'after',

			'appendTo',

			'attr',

			'before',

			'empty',

			'html',

			'insertAfter',

			'prepend',

			'prependTo',

			'text'
		]
	);

	A.NodeList.prototype.getDOM = function() {
		return A.NodeList.getDOMNodes(this);
	};

}, '@VERSION', { requires: [ 'node' ] });<commit_msg>Base .attr() should use .get/.set methods instead of getAttribute/setAttribute<commit_after>/*
* AUI Base
*/
AUI.add('aui-base', function(A) {

	A.mix(A.Array, {
		remove: function(a, from, to) {
		  var rest = a.slice((to || from) + 1 || a.length);
		  a.length = (from < 0) ? (a.length + from) : from;

		  return a.push.apply(a, rest);
		},

		removeItem: function(a, item) {
			var index = A.Array.indexOf(a, item);

		  	return A.Array.remove(a, index);
		}
	});

}, '@VERSION', { requires: [ 'yui-base' ] });

/*
* AUI Delayed Task
*/

AUI.add('delayed-task', function(A) {

	var DelayedTask = function(fn, scope, args) {
		var instance = this;

		instance._args = args;
		instance._delay = 0;
		instance._fn = fn;
		instance._id = null;
		instance._scope = scope || instance;
		instance._time = 0;

		instance._base = function() {
			var now = instance._getTime();

			if (now - instance._time >= instance._delay) {
				clearInterval(instance._id);

				instance._id = null;

				instance._fn.apply(instance._scope, instance._args || []);
			}
		};
	};

	DelayedTask.prototype = {
		delay: function(delay, newFn, newScope, newArgs) {
			var instance = this;

			if (instance._id && instance._delay != delay) {
				instance.cancel();
			}

			instance._delay = delay || instance._delay;
			instance._time = instance._getTime();

			instance._fn = newFn || instance._fn;
			instance._scope = newScope || instance._scope;
			instance._args = newArgs || instance._args;

			if (!A.Lang.isArray(instance._args)) {
				instance._args = [instance._args];
			}

			if (!instance._id) {
				if (instance._delay > 0) {
					instance._id = setInterval(instance._base, instance._delay);
				}
				else {
					instance._base();
				}
			}
		},

		cancel: function() {
			var instance = this;

			if (instance._id) {
				clearInterval(instance._id);

				instance._id = null;
			}
		},

		_getTime: function() {
			var instance = this;

			return (+new Date());
		}
	};

	A.DelayedTask = DelayedTask;

}, '@VERSION', { requires: [ 'yui-base' ] });

/*
* AUI Node
*/

AUI.add('aui-node', function(A) {

	var Lang = A.Lang,
		isString = Lang.isString,
		isUndefined = Lang.isUndefined,

		INNER_HTML = 'innerHTML';

	A.mix(A.Node.prototype, {
		after: function(content) {
			var instance = this;

			return instance.insertAfter(content);
		},

		appendTo: function(selector) {
			var instance = this;

			A.get(selector).append(instance);
		},

		attr: function(name, value) {
			var instance = this;

			if (!isUndefined(value)) {
				return instance.set(name, value);
			}
			else {
				return instance.get(name);
			}
		},

		before: function(content) {
			var instance = this;

			var parent = instance.get('parentNode');

			if (parent) {
				parent.insertBefore(content, instance);
			}

			return instance;
		},

		empty: function() {
			var instance = this;

			instance.queryAll('>*').remove();

			var el = A.Node.getDOMNode(instance);

			while (el.firstChild) {
				el.removeChild(el.firstChild);
			}

			return instance;
		},

		getDOM: function() {
			var instance = this;

			return A.Node.getDOMNode(instance);
		},

		html: function() {
			var args = arguments, length = args.length;

			if (length) {
				this.set(INNER_HTML, args[0]);
			}
			else {
				return this.get(INNER_HTML);
			}

			return this;
		},

		insertAfter: function(content) {
			var instance = this;

			var parent = instance.get('parentNode');

			if (parent) {
				parent.insertBefore(content, instance.get('nextSibling'));
			}

			return instance;
		},

		prependTo: function(selector) {
			var instance = this;

			A.get(selector).prepend(instance);
		},

		text: function(text) {
			var instance = this;

			if (!isUndefined(text)) {
				text = A.DOM._getDoc(A.Node.getDOMNode(instance)).createTextNode(text);

				return instance.empty().append(text);
			}

			var el = A.Node.getDOMNode(instance);

			return instance._getText(el.childNodes);
		},

		_getText: function(childNodes) {
			var instance = this;

			var length = childNodes.length;
			var childNode;

			var str = [];

			for (var i = 0; i < length; i++) {
				childNode = childNodes[i];

				if (childNode && childNode.nodeType != 8) {
					if (childNode.nodeType != 1) {
						str.push(childNode.nodeValue);
					}

					if (childNode.childNodes) {
						str.push(instance._getText(childNode.childNodes));
					}
				}
			}

			return str.join('');
		}
	}, true);

	A.mix(A.Node, {
		globalEval: function(data) {
			if ( data && /\S/.test(data) ) {
				var head = document.getElementsByTagName("head")[0] || document.documentElement;
				var script = document.createElement("script");

				script.type = "text/javascript";

				if (AUI.support.scriptEval) {
					script.appendChild(document.createTextNode(data));
				}
				else {
					script.text = data;
				}

				head.insertBefore(script, head.firstChild);
				head.removeChild(script);
			}
		},

		evalScript: function(elem) {
			if (elem.src) {
				A.io(elem.src, {
					async: false,
					on: {
						complete: function(i, o) {
							A.Node.globalEval(o.responseText);
						}
					}
				});
			}
			else {
				A.Node.globalEval(elem.text || elem.textContent || elem.innerHTML || "");
			}
		},

		clean: function(html) {
			var TPL_NODE = '

',
				IE_FIX_PADDING_NODE = '
_
',
				SCRIPT = 'script';

			// instead of fix all tags to "XHTML"-style, make the firstChild be a valid non-empty tag
			html = IE_FIX_PADDING_NODE + A.Lang.trim(html);

			delete A.DOM._cloneCache[html];

			// wrap in a nodeType == 1, nodeType 11 (document fragment) does not support getElementsByTagName
			var temp = A.Node.create(TPL_NODE).append(
				A.Node.create(html)
			);

			var scripts = temp.getElementsByTagName(SCRIPT);

			scripts.each(function(elem) {
				elem.remove();
			});

			temp.removeChild(A.Node.getDOMNode(temp).firstChild);

			var html = temp.html();

			// avoid IE6 memory leak
			temp = null;

			return [ html, scripts ];
		},

		domManip: function(html, callback) {
			var clean = A.Node.clean(html);
			var content = clean[0];
			var scripts = clean[1];

			if (callback) {
				callback.apply(this, [ content ]);
			}

			scripts.each(function(elem) {
				A.Node.evalScript( A.Node.getDOMNode(elem) );
			});
		}
	});

	A.Node.ATTRS.innerHTML = {
		setter: function(v) {
			var instance = this;

			var defaultSetter = function(value) {
				A.Node.DEFAULT_SETTER.apply(instance, [ INNER_HTML, value ]);
			};

			if (isString(v)) {
				// eval scripts
				v = A.Node.domManip(v, defaultSetter);
			}
			else {
				defaultSetter(v);
			}
		}
	};

	A.NodeList.importMethod(
		A.Node.prototype,
		[
			'after',

			'appendTo',

			'attr',

			'before',

			'empty',

			'html',

			'insertAfter',

			'prepend',

			'prependTo',

			'text'
		]
	);

	A.NodeList.prototype.getDOM = function() {
		return A.NodeList.getDOMNodes(this);
	};

}, '@VERSION', { requires: [ 'node' ] });<|endoftext|>


<commit_before>/**
 * ToolsJs provides some frequently used functions to
 * improve your development efficiency and reduce the amount of your code.
 * @author victor.li
 * @date 2015/01/22
 * @version 1.0.0
 * Released under terms of MIT lincense.
 */
'use strict';

var Tools = (function(global, undefined) {

    /**
     * get object's actual runtime type
     */
    function _typeof(obj) {

        if (!Object.constructor.name)
            return _compatibleTypeof(obj);

        return _modernTypeof(obj);

    };

    /**
     * typeof function for modern internet explorer
     */
    function _modernTypeof(obj) {

        if (typeof obj === 'undefined')
            return 'undefined';
        if (obj === null)
            return 'null';
        var _obj = obj,
            type = _obj.constructor.name;
        if (type === 'Number' && isNaN(_obj))
            return 'NaN';

        return type;

    };

    /**
     * IE compatible
     */
    function _compatibleTypeof(obj) {

        if (typeof obj === 'undefined')
            return 'undefined';
        if (obj === null)
            return 'null';
        var _obj = obj,
            type = {}.toString.call(_obj);
        if (type.search(/Array/) > -1)
            return 'Array';
        if (type.search(/String/) > -1)
            return 'String';
        if (type.search(/Number/) > -1 && isNaN(_obj)) {
            return 'NaN';
        } else if (type.search(/Number/) > -1) {
            return 'Number';
        }
        if (type.search(/Date/) > -1)
            return 'Date';
        if (type.search(/RegExp/) > -1)
            return 'RegExp';

    };

    /**
     * find each index of keyword in a string
     */
    function _mark_str(substr, str, case_sensitive) {

        var index = [],
            sublen = substr.length,
            regexp = new RegExp(substr, 'g');
        if (!case_sensitive) regexp = new RegExp(substr, 'gi');
        while (regexp.exec(str)) {
            index.push(regexp.lastIndex - sublen);
        }

        return index;

    };

    /**
     * find each index of keyword in array in a string
     */
    function _mark_str_arr(substr_arr, str, case_sensitive) {

        var index = [];
        for (var i = 0; i < substr_arr.length; i++) {
            var _index = {key: substr_arr[i], index: []},
                sublen = substr_arr[i].length,
                regexp = new RegExp(substr_arr[i], 'g');
            if (!case_sensitive) regexp = new RegExp(substr_arr[i], 'gi');
            while (regexp.exec(str)) {
                _index.index.push(regexp.lastIndex - sublen);
            }
            index.push(_index);
        }

        return index;

    };

    /**
     * determines whether the input string is numeric
     * @param string
     * @return boolean
     */
    function isNumeric(string) {
        var numeric = new RegExp(/^(\d+|\d+\.\d+)$/);
        return numeric.test(string);
    };

    /**
     * determines whether the input string is percentage
     * @param string
     * @return boolean
     */
    function isPercentage(string) {
        var percentage = new RegExp(/^(\d+|\d+\.\d+)\%{1}$/);
        return percentage.test(string);
    };

    /**
     * determines whether the specified element is in the specified array
     * if the specified element is in the specified array, return true,
     * otherwise return false
     */
    function inArray(arr, ele) {

        try {
            getIEVersion();
            var i = 0, len = arr.length;
            for (; i < len; i++) {
                if (arr[i] === ele)
                    return true;
            }
        } catch (e) {
            return (arr.indexOf(ele) !== -1);
        }

        return false;
    };

    /**
     * gets version of Microsoft Internet Explorer
     * this function will throw an error if the current browser
     *  is not a Microsoft Internet Explorer
     */
    function getIEVersion() {

        if (!document.documentMode)
            throw new Error('The current browser is
                    not a microsoft internet explorer');

        return 'IE' + document.documentMode;

    };

    return {

        mark: function(substr, str, case_sensitive) {

            if (_typeof(substr) === 'Array')
                return _mark_str_arr(substr, str, case_sensitive);
            if (_typeof(substr) === 'String')
                return _mark_str(substr, str, case_sensitive);

        },
        _typeof: _typeof,
        inArray: inArray,
        isNumeric: isNumeric,
        isPercentage: isPercentage,
        getIEVersion: getIEVersion

    };

})(window);

<commit_msg>added a function<commit_after>/**
 * ToolsJs provides some frequently used functions to
 * improve your development efficiency and reduce the amount of your code.
 * @author victor.li
 * @date 2015/01/22
 * @version 1.0.0
 * Released under terms of MIT lincense.
 */
'use strict';

var Tools = (function(global, undefined) {

    /**
     * get object's actual runtime type
     */
    function _typeof(obj) {

        if (!Object.constructor.name)
            return _compatibleTypeof(obj);

        return _modernTypeof(obj);

    };

    /**
     * typeof function for modern internet explorer
     */
    function _modernTypeof(obj) {

        if (typeof obj === 'undefined')
            return 'undefined';
        if (obj === null)
            return 'null';
        var _obj = obj,
            type = _obj.constructor.name;
        if (type === 'Number' && isNaN(_obj))
            return 'NaN';

        return type;

    };

    /**
     * IE compatible
     */
    function _compatibleTypeof(obj) {

        if (typeof obj === 'undefined')
            return 'undefined';
        if (obj === null)
            return 'null';
        var _obj = obj,
            type = {}.toString.call(_obj);
        if (type.search(/Array/) > -1)
            return 'Array';
        if (type.search(/String/) > -1)
            return 'String';
        if (type.search(/Number/) > -1 && isNaN(_obj)) {
            return 'NaN';
        } else if (type.search(/Number/) > -1) {
            return 'Number';
        }
        if (type.search(/Date/) > -1)
            return 'Date';
        if (type.search(/RegExp/) > -1)
            return 'RegExp';

    };

    /**
     * find each index of keyword in a string
     */
    function _mark_str(substr, str, case_sensitive) {

        var index = [],
            sublen = substr.length,
            regexp = new RegExp(substr, 'g');
        if (!case_sensitive) regexp = new RegExp(substr, 'gi');
        while (regexp.exec(str)) {
            index.push(regexp.lastIndex - sublen);
        }

        return index;

    };

    /**
     * find each index of keyword in array in a string
     */
    function _mark_str_arr(substr_arr, str, case_sensitive) {

        var index = [];
        for (var i = 0; i < substr_arr.length; i++) {
            var _index = {key: substr_arr[i], index: []},
                sublen = substr_arr[i].length,
                regexp = new RegExp(substr_arr[i], 'g');
            if (!case_sensitive) regexp = new RegExp(substr_arr[i], 'gi');
            while (regexp.exec(str)) {
                _index.index.push(regexp.lastIndex - sublen);
            }
            index.push(_index);
        }

        return index;

    };

    /**
     * determines whether the input string is numeric
     * @param string
     * @return boolean
     */
    function isNumeric(string) {

        var numeric = new RegExp(/^(\d+|\d+\.\d+)$/);
        return numeric.test(string);

    };

    /**
     * determines whether the input string is percentage
     * @param string
     * @return boolean
     */
    function isPercentage(string) {

        var percentage = new RegExp(/^(\d+|\d+\.\d+)\%{1}$/);
        return percentage.test(string);

    };

    /**
     * determines whether the input value is decimal
     * @param input
     * @return boolean
     */
    function isDecimal(input) {

        var type = _typeof(input);
        if ('String' !== type && 'Number' !== type) {
            throw new Error('the inputted value cannot be converted to valid number');
        }

        var decimal = new RegExp(/^\d+\.\d+$/);
        if ('Number' === _typeof(input)) {
            input += '';
        }

        return decimal.test(input);

    };

    /**
     * determines whether the specified element is in the specified array
     * if the specified element is in the specified array, return true,
     * otherwise return false
     */
    function inArray(arr, ele) {

        try {
            getIEVersion();
            var i = 0, len = arr.length;
            for (; i < len; i++) {
                if (arr[i] === ele)
                    return true;
            }
        } catch (e) {
            return (arr.indexOf(ele) !== -1);
        }

        return false;
    };

    /**
     * gets version of Microsoft Internet Explorer
     * this function will throw an error if the current browser
     *  is not a Microsoft Internet Explorer
     */
    function getIEVersion() {

        if (!document.documentMode)
            throw new Error('The current browser is
                    not a microsoft internet explorer');

        return 'IE' + document.documentMode;

    };

    return {

        mark: function(substr, str, case_sensitive) {

            if (_typeof(substr) === 'Array')
                return _mark_str_arr(substr, str, case_sensitive);
            if (_typeof(substr) === 'String')
                return _mark_str(substr, str, case_sensitive);

        },
        _typeof: _typeof,
        inArray: inArray,
        isNumeric: isNumeric,
        isPercentage: isPercentage,
        getIEVersion: getIEVersion

    };

})(window);

<|endoftext|>


<commit_before>/**
 * Defines custom events for touch related gusters.
 * Following events are defined:
 * tap, dbltap, taphold, swipe, swipeleft, swiperight
 * @author aniketn3@gmail.com
 */
/**
 * Tap event definition
 */
(function($, undefn) {
   var undef = undefn, state = {/* id, x, y, target */};

   function clearState() {
      state.id = state.x = state.y = state.moved = state.target = undef;
   }

   function hasMoved(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2;
      return Math.abs(dx) > 30 || Math.abs(dy) > 30;
   }

   function handler(te) {
      var type = te.type, touch, touches = te.touches, cTouches = te.changedTouches, target = te.target;
      switch(type) {
         case "touchstart":
            if(touches.length !== 1) {
               return;
            }
            touch = touches[0];
            state.id = touch.identifier;
            state.x = touch.pageX;
            state.y = touch.pageY;
            state.target = target;
            break;
         case "touchmove":
            touch = cTouches[0];
            if(!state.moved && touch.identifier === state.id) {
               state.moved = hasMoved(state.x, state.y, touch.pageX, touch.pageY);
            }
            break;
         case "touchend":
            if(cTouches.length === 0 || state.moved) {
               clearState();
               return;
            }
            touch = cTouches[0];
            if(touch.identifier === state.id &&
                  !hasMoved(state.x, state.y, touch.pageX, touch.pageY) &&
                  state.target === target) {
               $(target).dispatch("tap");
            }
            break;
         case "touchcancel":
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "tap",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler)
            .on("touchend", handler).on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler)
            .un("touchend", handler).un("touchcancel", handler);
      }
   });
})(h5);

/**
 * Double Tap event definition
 */
(function($) {
   var state = {/* last, target */};

   function handler(te) {
      var now = Date.now(), elapsed = now - (state.last || now), target = te.target;
      if(elapsed > 0 && elapsed < 300 && state.target === target) {
         $(target).dispatch("dbltap");
         state.last = state.target = null;
      }else {
         state.last = now;
         state.target = te.target;
      }
   }

   $.defineEvent({
      type: "dbltap",
      setup: function() {
         $(document).on("tap", handler);
      },
      destroy: function() {
         $(document).un("tap", handler);
      }
   });
})(h5);

/**
 * Tap hold event
 */
(function($, undefn) {
      var undef = undefn, state = {/* moved, x, y */}, timer;

   function hasMoved(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2;
      return Math.abs(dx) > 30 || Math.abs(dy) > 30;
   }

   function clearState() {
      state.moved = state.x = state.y = undef;
   }

   function handler(te) {
      var type = te.type, target = te.target;
      switch(type) {
         case "touchstart":
            if(te.touches.length !== 1) {
               return;
            }
            state.x = te.pageX;
            state.y = te.pageY;
            timer = setTimeout(function() {
               if(!state.moved) {
                  $(target).dispatch("taphold");
               }
            }, 700);
            break;
         case "touchmove":
            if(!state.moved) {
               state.moved = hasMoved(state.x, state.y, te.pageX, te.pageY);
            }
            break;
         case "touchend":
         case "touchcancel":
         default:
            clearTimeout(timer);
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "taphold",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler).on("touchend", handler)
            .on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler).un("touchend", handler)
            .un("touchcancel", handler);
      }
   });
})(h5);

/**
 * Swipe event
 */
(function($, undefn) {
   var undef = undefn, state = {};

   /**
    * Calculate the delta difference between two points (x1,y1) and (x2,y2)
    * @return A delta object {x: xdelta, y: ydelta} if the difference is more
    * than 30 pixels or null if its less. The values x and y can be -ve
    */
   function getMovement(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2, xa, ya;
      if((xa = Math.abs(dx)) < 30 & (ya = Math.abs(dy)) < 30) {
         return null;
      }
      return {
         x: dx,
         y: dy,
         dir: xa >= ya ? (dx < 0 ? "left" : "right") : (dy < 0 ? "up" : "down")
      };
   }

   function clearState() {
      state.id = state.x = state.y = state.movement = undef;
   }

   function handler(te) {
      var type = te.type, touches = te.touches, touch, target, m, evtData;

      switch(type) {
         case "touchstart":
            touches = te.touches;
            if(touches.length > 1) {
               return;
            }
            touch = touches[0];
            state.id = touch.identifier;
            state.x = touch.pageX;
            state.y = touch.pageY;
            break;
         case "touchmove":
            touches = te.changedTouches;
            touch = touches[0];
            if(touch.identifier === state.id && te.touches.length === 1) {
               state.movement = getMovement(touch.pageX, touch.pageY, state.x, state.y);
            }
            break;
         case "touchend":
            touches = te.changedTouches;
            touch = touches[0];
            if(state.id === touch.identifier && (m = state.movement)) {
               evtData = {movement: m};
               $(te.target).dispatch("swipe", evtData);
               clearState();
            }
            break;
         default:
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "swipe",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler).on("touchend", handler)
            .on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler).un("touchend", handler)
            .un("touchcancel", handler);
      }
   });
})(h5);

<commit_msg>Added comments<commit_after>/**
 * Defines custom events for touch related gusters.
 * Following events are defined:
 * tap, dbltap, taphold, swipe, swipeleft, swiperight
 * @author aniketn3@gmail.com
 */
/**
 * Tap event definition
 */
(function($, undefn) {
   var undef = undefn, state = {/* id, x, y, target */};

   function clearState() {
      state.id = state.x = state.y = state.moved = state.target = undef;
   }

   function hasMoved(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2;
      return Math.abs(dx) > 30 || Math.abs(dy) > 30;
   }

   function handler(te) {
      var type = te.type, touch, touches = te.touches, cTouches = te.changedTouches, target = te.target;
      switch(type) {
         case "touchstart":
            if(touches.length !== 1) {
               return;
            }
            touch = touches[0];
            state.id = touch.identifier;
            state.x = touch.pageX;
            state.y = touch.pageY;
            state.target = target;
            break;
         case "touchmove":
            touch = cTouches[0];
            if(!state.moved && touch.identifier === state.id) {
               state.moved = hasMoved(state.x, state.y, touch.pageX, touch.pageY);
            }
            break;
         case "touchend":
            if(cTouches.length === 0 || state.moved) {
               clearState();
               return;
            }
            touch = cTouches[0];
            if(touch.identifier === state.id &&
                  !hasMoved(state.x, state.y, touch.pageX, touch.pageY) &&
                  state.target === target) {
               $(target).dispatch("tap");
            }
            break;
         case "touchcancel":
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "tap",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler)
            .on("touchend", handler).on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler)
            .un("touchend", handler).un("touchcancel", handler);
      }
   });
})(h5);

/**
 * Double Tap event definition
 */
(function($) {
   var state = {/* last, target */};

   function handler(te) {
      var now = Date.now(), elapsed = now - (state.last || now), target = te.target;
      if(elapsed > 0 && elapsed < 300 && state.target === target) {
         $(target).dispatch("dbltap");
         state.last = state.target = null;
      }else {
         state.last = now;
         state.target = te.target;
      }
   }

   $.defineEvent({
      type: "dbltap",
      setup: function() {
         $(document).on("tap", handler);
      },
      destroy: function() {
         $(document).un("tap", handler);
      }
   });
})(h5);

/**
 * Tap hold event
 */
(function($, undefn) {
      var undef = undefn, state = {/* moved, x, y */}, timer;

   function hasMoved(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2;
      return Math.abs(dx) > 30 || Math.abs(dy) > 30;
   }

   function clearState() {
      state.moved = state.x = state.y = undef;
   }

   function handler(te) {
      var type = te.type, target = te.target;
      switch(type) {
         case "touchstart":
            if(te.touches.length !== 1) {
               return;
            }
            state.x = te.pageX;
            state.y = te.pageY;
            timer = setTimeout(function() {
               if(!state.moved) {
                  $(target).dispatch("taphold");
               }
            }, 700);
            break;
         case "touchmove":
            if(!state.moved) {
               state.moved = hasMoved(state.x, state.y, te.pageX, te.pageY);
            }
            break;
         case "touchend":
         case "touchcancel":
         default:
            clearTimeout(timer);
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "taphold",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler).on("touchend", handler)
            .on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler).un("touchend", handler)
            .un("touchcancel", handler);
      }
   });
})(h5);

/**
 * Swipe event
 */
(function($, undefn) {
   var undef = undefn, state = {};

   /**
    * Calculate the delta difference between two points (x1,y1) and (x2,y2)
    * @return A delta object {x: xdelta, y: ydelta} if the difference is more
    * than 30 pixels or null if its less. The values x and y can be -ve
    */
   function getMovement(x1, y1, x2, y2) {
      var dx = x1 - x2, dy = y1 - y2, xa, ya;
      if((xa = Math.abs(dx)) < 30 & (ya = Math.abs(dy)) < 30) {
         return null;
      }
      return {
         x: dx,
         y: dy,
         dir: xa >= ya ? (dx < 0 ? "left" : "right") : (dy < 0 ? "up" : "down")
      };
   }

   function clearState() {
      state.id = state.x = state.y = state.movement = undef;
   }

   function handler(te) {
      var type = te.type, touches = te.touches, touch, target, m, evtData;

      switch(type) {
         case "touchstart":
            touches = te.touches;
            if(touches.length > 1) {
               return;
            }
            touch = touches[0];
            state.id = touch.identifier;
            state.x = touch.pageX;
            state.y = touch.pageY;
            break;
         case "touchmove":
            touches = te.changedTouches;
            touch = touches[0];
            if(touch.identifier === state.id && te.touches.length === 1) {
               state.movement = getMovement(touch.pageX, touch.pageY, state.x, state.y);
            }
            break;
         case "touchend":
            touches = te.changedTouches;
            touch = touches[0];
            if(state.id === touch.identifier && (m = state.movement)) {
               evtData = {movement: m};
               $(te.target).dispatch("swipe", evtData); // available as event.movement
               clearState();
            }
            break;
         default:
            clearState();
            break;
      }
   }

   $.defineEvent({
      type: "swipe",
      setup: function() {
         $(document).on("touchstart", handler).on("touchmove", handler).on("touchend", handler)
            .on("touchcancel", handler);
      },
      destroy: function() {
         $(document).un("touchstart", handler).un("touchmove", handler).un("touchend", handler)
            .un("touchcancel", handler);
      }
   });
})(h5);

<|endoftext|>