<commit_before>import React from 'react';

import Component from '../Component';
import Item from '../Item';
import Group from '../Group';
import MenuItem from './MenuItem';

class Menu extends Component {
    constructor(props) {
        super(props);

        const newValue = this._validValue(props.value);
        this.state = {
            ...this.state,
            hoveredIndex: null,
            value: this._validValue(props.value)
        };

        this._cachedItems = null;
        this._savedIndex = null;

        this.onMouseUp = this.onMouseUp.bind(this);
        this.onMouseDown = this.onMouseDown.bind(this);
        this.onFocus = this.onFocus.bind(this);
        this.onBlur = this.onBlur.bind(this);
        this.onKeyDown = this.onKeyDown.bind(this);
        this.onItemClick = this.onItemClick.bind(this);
        this.onItemHover = this.onItemHover.bind(this);
    }

    componentWillMount() {
        //  Если мы как-то поменяли value (внутри _validValue),
        //  то нужно сообщить про это наверх.
        if (this.props.value !== this.state.value) {
            this.props.onChange(this.state.value, this.props);
        }

        if (this.props.focused) {
            this.onFocus();
        }
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.children !== this.props.children) {
            this._cachedItems = null;
        }

        if (nextProps.value !== this.props.value) {
            this.setState({
                value: this._validValue(nextProps.value)
            });
        }

        if (nextProps.focused && !this.props.focused) {
            this.onFocus();

        } else if (!nextProps.focused && this.props.focused) {
            this.onBlur();
        }
    }

    _getItems() {
        let items = this._cachedItems;

        if (!items) {
            let values = [];
            let statuses = [];
            items = this._cachedItems = { values, statuses };

            const doChild = function(child) {
                values.push(child.props.value);
                statuses.push(child.props.disabled);
            };

            React.Children.forEach(this.props.children, child => {
                if (Component.is(child, Item)) {
                    doChild(child);

                } else if (Component.is(child, Group)) {
                    //  Предполагаем, что ничего, кроме Item внутри Group уже нет.
                    React.Children.forEach(child.props.children, doChild);
                }
            });
        }

        return items;
    }

    _getFirstEnabledIndex() {
        const statuses = this._getItems().statuses;
        for (let i = 0; i < statuses.length; i++) {
            if (!statuses[i]) {
                return i;
            }
        }

        return null;
    }

    _getFirstEnabledValue() {
        const index = this._getFirstEnabledIndex();

        return (index === null) ? null : this._getItems().values[index];
    }

    _validValue(value) {
        let newValue;
        if (value == null) {
            newValue = [];

        } else if (Array.isArray(value)) {
            newValue = value;

        } else {
            newValue = [value];
        }

        const values = this._getItems().values;
        const filteredValue = newValue.filter(aValue => (values.indexOf(aValue) !== -1));
        if (filteredValue.length !== newValue.length) {
            newValue = filteredValue;
        }

        if (this.props.mode === 'radio') {
            if (newValue.length === 0) {
                const firstValue = this._getFirstEnabledValue();
                newValue = (firstValue === null) ? [] : [firstValue];

            } else if (newValue.length > 1) {
                newValue = [newValue[0]];
            }

        } else if (this.props.mode === 'radio-check' && newValue.length > 1) {
            newValue = [newValue[0]];
        }

        //  Раз уж начал упарываться, то остановиться уже сложно.
        //  Теперь в newValue:
        //
        //    * Массив;
        //    * В котором значения из переданного value (массива или просто значения);
        //    * И которые при этом есть в values самого меню.
        //    * При этом, если в value был массив, в котором были только валидные значения,
        //      подходящие к данному mode, то вернется именно этот массив.
        //      Что позволит сравнить исходное value с вот этим новым.
        //
        //  Но, увы, это сравнение все равно даст неверный результат,
        //  если в value передать не массив или ничего не передать :(
        //  Но так уже заморачиваться не хочется. Проще эксепшен кинуть на невалидный value.
        //
        return newValue;
    }

    render() {
        const { theme, size, mode, disabled } = this.props;
        const { value, hoveredIndex } = this.state;

        const onItemClick = this.onItemClick;
        const onItemHover = this.onItemHover;
        const checkable = Boolean(mode);

        let index = 0;
        const children = React.Children.map(this.props.children, child => {
            if (Component.is(child, Group)) {
                return mapGroup(child);

            } else if (Component.is(child, Item)) {
                return mapItem(child);

            } else {
                //  FIXME: Или тут бросать ошибку?
                return child;
            }
        });

        function mapItem(item) {
            const r = React.createElement(
                MenuItem,
                {
                    theme,
                    size,
                    checked: checkable && (value.indexOf(item.props.value) !== -1),
                    hovered: (index === hoveredIndex),
                    disabled: disabled || item.props.disabled,
                    index,
                    onClick: onItemClick,
                    onHover: onItemHover
                },
                item.props.children
            );
            index++;

            return r;
        }

        function mapGroup(group) {
            const items = React.Children.map(group.props.children, mapItem);

            let title;
            if (group.props.title) {
                title = (

{group.props.title}

                );
            }

            return (

                    {title}
                    {items}

            );
        }

        const tabIndex = disabled ? -1 : 0;

        return (

                {children}

        );
    }

    className() {
        var className = 'menu';

        const theme = this.props.theme || this.context.theme;
        if (theme) {
            className += ' menu_theme_' + theme;
        }
        if (this.props.size) {
            className += ' menu_size_' + this.props.size;
        }
        if (this.props.mode) {
            className += ' menu_mode_' + this.props.mode;
        }
        if (this.props.disabled) {
            className += ' menu_disabled';
        }

        if (this.props.className) {
            className += ' ' + this.props.className;
        }

        return className;
    }

    onItemHover(hovered, itemProps) {
        this.setState({
            hoveredIndex: hovered ? itemProps.index : null
        });
    }

    onItemClick(e, itemProps) {
        this._savedIndex = itemProps.index;
        this.onItemCheck(itemProps.index);

        this.props.onItemClick(e, itemProps, this.props);
    }

    onMouseDown() {
        this._mousePressed = true;
    }

    onMouseUp() {
        this._mousePressed = false;
    }

    //  TODO: Если меню в фокусе, то по ховеру тоже нужно менять _savedIndex.

    onFocus() {
        document.addEventListener('keydown', this.onKeyDown, true);

        if (!this._mousePressed) {
            let hoveredIndex = this._savedIndex;
            if (hoveredIndex === null) {
                hoveredIndex = this._getFirstEnabledIndex();
            }
            if (hoveredIndex !== this.state.hoveredIndex) {
                this._savedIndex = hoveredIndex;
                this.setState({ hoveredIndex });
            }
        }
    }

    onBlur() {
        document.removeEventListener('keydown', this.onKeyDown, true);

        this.setState({
            hoveredIndex: null
        });
    }

    onKeyDown(e) {
        if (this.props.disabled) {
            //  Кажется, тут нет нужды проверять focused, так как
            //  иначе этот обработчик и не сработает.
            return;
        }

        if (e.code === 'ArrowDown' || e.code === 'ArrowUp') {
            e.preventDefault();

            const statuses = this._getItems().statuses;
            const len = statuses.length;
            if (!len) {
                return;
            }

            const dir = (e.code === 'ArrowDown' ? 1 : -1);
            let nextIndex;
            if (this.state.hoveredIndex === null) {
                nextIndex = this._getFirstEnabledIndex();

            } else {
                nextIndex = this.state.hoveredIndex;
                do {
                    nextIndex = (nextIndex + len + dir) % len;
                    if (nextIndex === this.state.hoveredIndex) {
                        return;
                    }
                } while (statuses[nextIndex]);
            }

            if (nextIndex !== null) {
                this._savedIndex = nextIndex;
                this.setState({hoveredIndex: nextIndex});
            }

        } else if (e.code === 'Space' || e.code === 'Enter') {
            e.preventDefault();

            if (this.state.hoveredIndex !== null) {
                this.onItemCheck(this.state.hoveredIndex);
            }
        }
    }

    onItemCheck(index) {
        const { mode } = this.props;
        if (!mode) {
            return;
        }

        const items = this._getItems();
        const itemValue = items.values[index];
        const menuValue = this.state.value;

        const checked = (menuValue.indexOf(itemValue) !== -1);
        let newMenuValue;
        if (mode === 'radio') {
            if (checked) {
                return;
            }

            newMenuValue = [itemValue];

        } else if (mode === 'radio-check') {
            newMenuValue = (checked) ? [] : [itemValue];

        } else {
            newMenuValue = (checked) ? menuValue.filter(value => (value !== itemValue)) : menuValue.concat(itemValue);
        }

        if (newMenuValue) {
            this.setState({ value: newMenuValue });

            this.props.onChange(newMenuValue, this.props);
        }
    }

}

Menu.contextTypes = {
    theme: React.PropTypes.string
};

Menu.propTypes = {
    theme: React.PropTypes.string,
    size: React.PropTypes.string,
    mode: React.PropTypes.string,
    disabled: React.PropTypes.bool,
    onChange: React.PropTypes.func,
    onItemClick: React.PropTypes.func
};

Menu.defaultProps = {
    onChange() {},
    onItemClick() {}
};

export default Menu;
<commit_msg>menu: Лишняя переменная<commit_after>import React from 'react';

import Component from '../Component';
import Item from '../Item';
import Group from '../Group';
import MenuItem from './MenuItem';

class Menu extends Component {
    constructor(props) {
        super(props);

        this.state = {
            ...this.state,
            hoveredIndex: null,
            value: this._validValue(props.value)
        };

        this._cachedItems = null;
        this._savedIndex = null;

        this.onMouseUp = this.onMouseUp.bind(this);
        this.onMouseDown = this.onMouseDown.bind(this);
        this.onFocus = this.onFocus.bind(this);
        this.onBlur = this.onBlur.bind(this);
        this.onKeyDown = this.onKeyDown.bind(this);
        this.onItemClick = this.onItemClick.bind(this);
        this.onItemHover = this.onItemHover.bind(this);
    }

    componentWillMount() {
        //  Если мы как-то поменяли value (внутри _validValue),
        //  то нужно сообщить про это наверх.
        if (this.props.value !== this.state.value) {
            this.props.onChange(this.state.value, this.props);
        }

        if (this.props.focused) {
            this.onFocus();
        }
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.children !== this.props.children) {
            this._cachedItems = null;
        }

        if (nextProps.value !== this.props.value) {
            this.setState({
                value: this._validValue(nextProps.value)
            });
        }

        if (nextProps.focused && !this.props.focused) {
            this.onFocus();

        } else if (!nextProps.focused && this.props.focused) {
            this.onBlur();
        }
    }

    _getItems() {
        let items = this._cachedItems;

        if (!items) {
            let values = [];
            let statuses = [];
            items = this._cachedItems = { values, statuses };

            const doChild = function(child) {
                values.push(child.props.value);
                statuses.push(child.props.disabled);
            };

            React.Children.forEach(this.props.children, child => {
                if (Component.is(child, Item)) {
                    doChild(child);

                } else if (Component.is(child, Group)) {
                    //  Предполагаем, что ничего, кроме Item внутри Group уже нет.
                    React.Children.forEach(child.props.children, doChild);
                }
            });
        }

        return items;
    }

    _getFirstEnabledIndex() {
        const statuses = this._getItems().statuses;
        for (let i = 0; i < statuses.length; i++) {
            if (!statuses[i]) {
                return i;
            }
        }

        return null;
    }

    _getFirstEnabledValue() {
        const index = this._getFirstEnabledIndex();

        return (index === null) ? null : this._getItems().values[index];
    }

    _validValue(value) {
        let newValue;
        if (value == null) {
            newValue = [];

        } else if (Array.isArray(value)) {
            newValue = value;

        } else {
            newValue = [value];
        }

        const values = this._getItems().values;
        const filteredValue = newValue.filter(aValue => (values.indexOf(aValue) !== -1));
        if (filteredValue.length !== newValue.length) {
            newValue = filteredValue;
        }

        if (this.props.mode === 'radio') {
            if (newValue.length === 0) {
                const firstValue = this._getFirstEnabledValue();
                newValue = (firstValue === null) ? [] : [firstValue];

            } else if (newValue.length > 1) {
                newValue = [newValue[0]];
            }

        } else if (this.props.mode === 'radio-check' && newValue.length > 1) {
            newValue = [newValue[0]];
        }

        //  Раз уж начал упарываться, то остановиться уже сложно.
        //  Теперь в newValue:
        //
        //    * Массив;
        //    * В котором значения из переданного value (массива или просто значения);
        //    * И которые при этом есть в values самого меню.
        //    * При этом, если в value был массив, в котором были только валидные значения,
        //      подходящие к данному mode, то вернется именно этот массив.
        //      Что позволит сравнить исходное value с вот этим новым.
        //
        //  Но, увы, это сравнение все равно даст неверный результат,
        //  если в value передать не массив или ничего не передать :(
        //  Но так уже заморачиваться не хочется. Проще эксепшен кинуть на невалидный value.
        //
        return newValue;
    }

    render() {
        const { theme, size, mode, disabled } = this.props;
        const { value, hoveredIndex } = this.state;

        const onItemClick = this.onItemClick;
        const onItemHover = this.onItemHover;
        const checkable = Boolean(mode);

        let index = 0;
        const children = React.Children.map(this.props.children, child => {
            if (Component.is(child, Group)) {
                return mapGroup(child);

            } else if (Component.is(child, Item)) {
                return mapItem(child);

            } else {
                //  FIXME: Или тут бросать ошибку?
                return child;
            }
        });

        function mapItem(item) {
            const r = React.createElement(
                MenuItem,
                {
                    theme,
                    size,
                    checked: checkable && (value.indexOf(item.props.value) !== -1),
                    hovered: (index === hoveredIndex),
                    disabled: disabled || item.props.disabled,
                    index,
                    onClick: onItemClick,
                    onHover: onItemHover
                },
                item.props.children
            );
            index++;

            return r;
        }

        function mapGroup(group) {
            const items = React.Children.map(group.props.children, mapItem);

            let title;
            if (group.props.title) {
                title = (

{group.props.title}

                );
            }

            return (

                    {title}
                    {items}

            );
        }

        const tabIndex = disabled ? -1 : 0;

        return (

                {children}

        );
    }

    className() {
        var className = 'menu';

        const theme = this.props.theme || this.context.theme;
        if (theme) {
            className += ' menu_theme_' + theme;
        }
        if (this.props.size) {
            className += ' menu_size_' + this.props.size;
        }
        if (this.props.mode) {
            className += ' menu_mode_' + this.props.mode;
        }
        if (this.props.disabled) {
            className += ' menu_disabled';
        }

        if (this.props.className) {
            className += ' ' + this.props.className;
        }

        return className;
    }

    onItemHover(hovered, itemProps) {
        this.setState({
            hoveredIndex: hovered ? itemProps.index : null
        });
    }

    onItemClick(e, itemProps) {
        this._savedIndex = itemProps.index;
        this.onItemCheck(itemProps.index);

        this.props.onItemClick(e, itemProps, this.props);
    }

    onMouseDown() {
        this._mousePressed = true;
    }

    onMouseUp() {
        this._mousePressed = false;
    }

    //  TODO: Если меню в фокусе, то по ховеру тоже нужно менять _savedIndex.

    onFocus() {
        document.addEventListener('keydown', this.onKeyDown, true);

        if (!this._mousePressed) {
            let hoveredIndex = this._savedIndex;
            if (hoveredIndex === null) {
                hoveredIndex = this._getFirstEnabledIndex();
            }
            if (hoveredIndex !== this.state.hoveredIndex) {
                this._savedIndex = hoveredIndex;
                this.setState({ hoveredIndex });
            }
        }
    }

    onBlur() {
        document.removeEventListener('keydown', this.onKeyDown, true);

        this.setState({
            hoveredIndex: null
        });
    }

    onKeyDown(e) {
        if (this.props.disabled) {
            //  Кажется, тут нет нужды проверять focused, так как
            //  иначе этот обработчик и не сработает.
            return;
        }

        if (e.code === 'ArrowDown' || e.code === 'ArrowUp') {
            e.preventDefault();

            const statuses = this._getItems().statuses;
            const len = statuses.length;
            if (!len) {
                return;
            }

            const dir = (e.code === 'ArrowDown' ? 1 : -1);
            let nextIndex;
            if (this.state.hoveredIndex === null) {
                nextIndex = this._getFirstEnabledIndex();

            } else {
                nextIndex = this.state.hoveredIndex;
                do {
                    nextIndex = (nextIndex + len + dir) % len;
                    if (nextIndex === this.state.hoveredIndex) {
                        return;
                    }
                } while (statuses[nextIndex]);
            }

            if (nextIndex !== null) {
                this._savedIndex = nextIndex;
                this.setState({hoveredIndex: nextIndex});
            }

        } else if (e.code === 'Space' || e.code === 'Enter') {
            e.preventDefault();

            if (this.state.hoveredIndex !== null) {
                this.onItemCheck(this.state.hoveredIndex);
            }
        }
    }

    onItemCheck(index) {
        const { mode } = this.props;
        if (!mode) {
            return;
        }

        const items = this._getItems();
        const itemValue = items.values[index];
        const menuValue = this.state.value;

        const checked = (menuValue.indexOf(itemValue) !== -1);
        let newMenuValue;
        if (mode === 'radio') {
            if (checked) {
                return;
            }

            newMenuValue = [itemValue];

        } else if (mode === 'radio-check') {
            newMenuValue = (checked) ? [] : [itemValue];

        } else {
            newMenuValue = (checked) ? menuValue.filter(value => (value !== itemValue)) : menuValue.concat(itemValue);
        }

        if (newMenuValue) {
            this.setState({ value: newMenuValue });

            this.props.onChange(newMenuValue, this.props);
        }
    }

}

Menu.contextTypes = {
    theme: React.PropTypes.string
};

Menu.propTypes = {
    theme: React.PropTypes.string,
    size: React.PropTypes.string,
    mode: React.PropTypes.string,
    disabled: React.PropTypes.bool,
    onChange: React.PropTypes.func,
    onItemClick: React.PropTypes.func
};

Menu.defaultProps = {
    onChange() {},
    onItemClick() {}
};

export default Menu;
<|endoftext|>


<commit_before>/**
 * @fileoverview upload function handler
 */

'use strict'

var path;
var fs = require('fs');
var child = require('child_process');
var rl = require('readline');
var mkdirp = require('mkdirp');

var utils = require('./utils.js');
var segtree = require('./segtree.js');

module.exports = {

  /**
   * Uploads a file or a directory to server.
   * @param {{
   *   type: string,
   *   name: string,
   *   description: string
   * }} desc File description.
   * @param {Object} file File object received from multer.
   * @param {string} prefix The destination folder to upload the file to.
   * @param {string} bigWigToWigAddr Directory of script of UCSC bigWigToWig.
   * @returns {Object} Success or not as a JS Object.
   */
  uploadFile: function(desc, file, prefix, bigWigToWigAddr) {
    var fileType = desc.type;
    var source = fs.createReadStream(file.path);
    var dest = fs.createWriteStream(prefix + desc.name);
    source.pipe(dest);
    source.on('end', function() {
      fs.unlink(file.path);
      if (desc.type == 'binding') {
        this.bigwigtoBcwig(prefix, desc.name, bigWigToWigAddr);
      } else if (desc.type == 'bed') {
        this.bedSort(prefix, desc.name);
      }
    }.bind(this));
    source.on('err', function(err){});

    // write down the network name and description
    var fd = fs.openSync(prefix + desc.name + ".txt", 'w');
    fs.writeSync(fd, desc.description);
    fs.closeSync(fd);

    return {
      success: true
    };

  },

  /**
   * Converts bigwig file to bcwig file and construct segment trees.
   * @param {string} prefix Folder that contains the bw file.
   * @param {string} bwFile Name of the bigwig file (without prefix).
   * @param {string} bigwigtoWigAder The convention script path.
   */
  bigwigtoBcwig: function(prefix, bwFile, bigWigWoWigAddr) {
    // convert *.bw into *.wig
    var wigFileName = bwFile + '.wig';
    console.log('start transfer');
    child.execSync(bigWigWoWigAddr + ' ' + prefix + bwFile + ' ' + prefix + wigFileName);
    console.log(bigWigWoWigAddr + ' ' + prefix + bwFile + ' ' + prefix + wigFileName);

    // convert *.wig into *.bcwig
    var seg = {};  // for segment tree

    // solve each line
    var lines = rl.createInterface({
      input: fs.createReadStream(prefix + wigFileName),
      terminal: false
    });
    var lastxr = -1;
    lines.on('line', function(line) {
      if (line.indexOf('#') == -1) {
        var linePart = line.split(RegExp(/\s+/));
        var chName = linePart[0];
        var xl = parseInt(linePart[1]);
        var xr = parseInt(linePart[2]);
        var val = parseFloat(linePart[3]);
        //console.log(seg);
        if (!seg.hasOwnProperty(linePart[0])) {
          seg[linePart[0]] = [];
        }
        if (xl != lastxr && lastxr > -1) {
          seg[chName].push({
            x: lastxr,
            val: 0
          });
        }
        seg[chName].push({
          x: xl,
          val: val
        });
        lastxr = xr;
      }
    });

    lines.on('close', function() {
      // write to *.bcwig file
      console.log('start log it');
      // if the folder already exists, then delete it
      var folder = prefix + bwFile + '_chr';
      var stats = fs.lstatSync(folder);
      if (stats.isDirectory()) {
        fs.rmdirSync(folder);
        console.log('Wiggle file ' + bwFile + ' is replaced.');
      }
      mkdirp(folder);

      for (var chr in seg) {
        var bcwigFile = folder + '/' + bwFile + '_' + chr + '.bcwig';
        var fd = fs.openSync(bcwigFile, 'w');
        for (var i = 0; i < seg[chr].length; i++) {
          var bcwigBuf = new Buffer(8 * seg[chr].length);
          bcwigBuf.writeInt32LE(seg[chr][i].x, i * 4);
          bcwigBuf.writeFloatLE(seg[chr][i].val, i * 4 + 4);
        }
        fs.writeSync(fd, bcwigBuf, 0, 8 * seg[chr].length, 0);
        fs.closeSync(fd);
      }

      // build segment tree and save
      for (var chr in seg) {
        var segFile = folder + '/' + bwFile + '_' + chr + '.seg';
        var nodes = [];
        segtree.buildSegmentTree(nodes, seg[chr]);
        var segBuf = new Buffer(4 + 4 * nodes.length);
          segBuf.writeInt32LE(nodes.length, 0);
        for (var i = 0, offset = 4; i < nodes.length; i++, offset += 2) {
          segBuf.writeFloatLE(nodes[i], offset);
        }
        var fd = fs.openSync(segFile, 'w');
        fs.writeSync(fd, segBuf, 0, offset, 0);
        fs.closeSync(fd);
      }

    });

  },

  /**
   * Sort bed data segments and write it into separate files.
   * @param {string} prefix Folder to the bed files.
   * @param {string} bedFile File name of the bed file.
   */
  bedSort: function(prefix, bedFile) {
    var lines = rl.createInterface({
      input: fs.createReadStream(prefix + bedFile),
      terminal: false
    });
    var data = {};
    lines.on('line', function(line) {
      var parts = line.split('\t');
      if (parts[0].indexOf('track') != -1) return;
      if (!data.hasOwnProperty(parts[0])) {
        data[parts[0]] = [];
      }
      data[parts[0]].push({
        chrStart: parts[1],
        chrEnd: parts[2]
      })
    });
    lines.on('close', function() {
      console.log('writing bed data...');
      console.log(data);
      var folder = prefix + bedFile + '_chr';
      fs.mkdirSync(folder)
      for (var chr in data) {
        data[chr].sort(function(a, b) {
          if (a.chrStart < b.chrStart) return false;
          if (a.chrStart > b.chrStart) return true;
          return a.chrEnd < b.chrEnd;
        });
        var chrFileName = folder + '/' + bedFile + "_" + chr;
        var fd = fs.openSync(chrFileName, 'w');
        for (var i = 0; i < data[chr].length; i++) {
          fs.writeSync(fd, data[chr][i].chrStart + '\t' + data[chr][i].chrEnd + '\n');
        }
        fs.closeSync(fd);
      }
    });
  }

};
<commit_msg>finish converted binding data and test for bed data upload<commit_after>/**
 * @fileoverview upload function handler
 */

'use strict'

var path;
var fs = require('fs');
var child = require('child_process');
var rl = require('readline');
var mkdirp = require('mkdirp');

var utils = require('./utils.js');
var segtree = require('./segtree.js');

module.exports = {

  /**
   * Uploads a file or a directory to server.
   * @param {{
   *   type: string,
   *   name: string,
   *   description: string
   * }} desc File description.
   * @param {Object} file File object received from multer.
   * @param {string} prefix The destination folder to upload the file to.
   * @param {string} bigWigToWigAddr Directory of script of UCSC bigWigToWig.
   * @returns {Object} Success or not as a JS Object.
   */
  uploadFile: function(desc, file, prefix, bigWigToWigAddr) {
    var fileType = desc.type;
    var source = fs.createReadStream(file.path);
    var dest = fs.createWriteStream(prefix + desc.name);
    source.pipe(dest);
    source.on('end', function() {
      fs.unlink(file.path);
      if (desc.type == 'binding') {
        this.bigwigtoBcwig(prefix, desc.name, bigWigToWigAddr);
      } else if (desc.type == 'bed') {
        this.bedSort(prefix, desc.name);
      }
    }.bind(this));
    source.on('err', function(err){});

    // write down the network name and description
    var fd = fs.openSync(prefix + desc.name + ".txt", 'w');
    fs.writeSync(fd, desc.description);
    fs.closeSync(fd);

    return {
      success: true
    };

  },

  /**
   * Converts bigwig file to bcwig file and construct segment trees.
   * @param {string} prefix Folder that contains the bw file.
   * @param {string} bwFile Name of the bigwig file (without prefix).
   * @param {string} bigwigtoWigAder The convention script path.
   */
  bigwigtoBcwig: function(prefix, bwFile, bigWigWoWigAddr) {
    // convert *.bw into *.wig
    var wigFileName = bwFile + '.wig';
    console.log('start transfer');
    child.execSync(bigWigWoWigAddr + ' ' + prefix + bwFile + ' ' + prefix + wigFileName);
    console.log(bigWigWoWigAddr + ' ' + prefix + bwFile + ' ' + prefix + wigFileName);

    // convert *.wig into *.bcwig
    var seg = {};  // for segment tree

    // solve each line
    var lines = rl.createInterface({
      input: fs.createReadStream(prefix + wigFileName),
      terminal: false
    });
    var lastxr = -1;
    lines.on('line', function(line) {
      if (line.indexOf('#') == -1) {
        var linePart = line.split(RegExp(/\s+/));
        var chName = linePart[0];
        var xl = parseInt(linePart[1]);
        var xr = parseInt(linePart[2]);
        var val = parseFloat(linePart[3]);
        //console.log(seg);
        if (!seg.hasOwnProperty(linePart[0])) {
          seg[linePart[0]] = [];
        }
        if (xl != lastxr && lastxr > -1) {
          seg[chName].push({
            x: lastxr,
            val: 0
          });
        }
        seg[chName].push({
          x: xl,
          val: val
        });
        lastxr = xr;
      }
    });

    lines.on('close', function() {
      // write to *.bcwig file
      console.log('start log it');
      // if the folder already exists, then delete it
      var folder = prefix + bwFile + '_chr';
      var stats = fs.lstatSync(folder);
      if (stats.isDirectory()) {
        fs.rmdirSync(folder);
        console.log('Wiggle file ' + bwFile + ' is replaced.');
      }
      mkdirp(folder);

      for (var chr in seg) {
        var bcwigFile = folder + '/' + bwFile + '_' + chr + '.bcwig';
        var fd = fs.openSync(bcwigFile, 'w');
        for (var i = 0; i < seg[chr].length; i++) {
          var bcwigBuf = new Buffer(8 * seg[chr].length);
          bcwigBuf.writeInt32LE(seg[chr][i].x, i * 4);
          bcwigBuf.writeFloatLE(seg[chr][i].val, i * 4 + 4);
        }
        fs.writeSync(fd, bcwigBuf, 0, 8 * seg[chr].length, 0);
        fs.closeSync(fd);
      }

      // build segment tree and save
      for (var chr in seg) {
        var segFile = folder + '/' + bwFile + '_' + chr + '.seg';
        var nodes = [];
        segtree.buildSegmentTree(nodes, seg[chr]);
        var segBuf = new Buffer(4 + 4 * nodes.length);
          segBuf.writeInt32LE(nodes.length, 0);
        for (var i = 0, offset = 4; i < nodes.length; i++, offset += 2) {
          segBuf.writeFloatLE(nodes[i], offset);
        }
        var fd = fs.openSync(segFile, 'w');
        fs.writeSync(fd, segBuf, 0, offset, 0);
        fs.closeSync(fd);
      }

    });

  },

  /**
   * Sort bed data segments and write it into separate files.
   * @param {string} prefix Folder to the bed files.
   * @param {string} bedFile File name of the bed file.
   */
  bedSort: function(prefix, bedFile) {
    var lines = rl.createInterface({
      input: fs.createReadStream(prefix + bedFile),
      terminal: false
    });
    console.log('separating bed data...');
    var data = {};
    lines.on('line', function(line) {
      var parts = line.split('\t');
      if (parts[0].indexOf('track') != -1) return;
      if (!data.hasOwnProperty(parts[0])) {
        data[parts[0]] = [];
      }
      data[parts[0]].push({
        chrStart: parts[1],
        chrEnd: parts[2]
      })
    });
    lines.on('close', function() {
      console.log('writing bed data...');
      var folder = prefix + bedFile + '_chr';
      fs.mkdirSync(folder)
      for (var chr in data) {
        data[chr].sort(function(a, b) {
          return a.chrStart - b.chrStart;
        });
        var chrFileName = folder + '/' + bedFile + "_" + chr;
        var fd = fs.openSync(chrFileName, 'w');
        for (var i = 0; i < data[chr].length; i++) {
          fs.writeSync(fd, data[chr][i].chrStart + '\t' + data[chr][i].chrEnd + '\n');
        }
        fs.closeSync(fd);
      }
      console.log('bed chromosome data finish.');
    });
  }

};
<|endoftext|>


<commit_before>$.declare('slider', {
  defaults: {
    page: 1,
    itemsPerPage: 1,
    duration: 500,
    itemClass: 'item',
    containerClass: 'container',
    auto: false,
    autoDelay: 5000,
    wrap: true
  },

  events: {
    'mouseover': 'stop',
    'mouseout': 'start'
  },

  elements: {
    '[data-action=previous]': 'previousButton',
    '[data-action=next]': 'nextButton'
  },

  init: function() {
    var items = this.find('.'+this.itemClass);
    this.pageCount = Math.ceil(items.length/this.itemsPerPage);
    this.pageWidth = items.outerWidth(true)*this.itemsPerPage;
    this.container = this.find('.'+this.containerClass);
    this.container.queue('fx');
    this.el.css('width', this.pageWidth);
    this.go(this.page);
    if (this.auto) {
      this.start();
    }
  },

  getCurrentPage: function() {
    return this.currentPage;
  },

  next: function(cb) {
    this.go(this.currentPage + 1, cb);
    this.emit('next', this.currentPage);
  },

  previous: function(cb) {
    this.go(this.currentPage - 1, cb);
    this.emit('previous', this.currentPage);
  },

  go: function(page, cb) {
    //check if click from data-action
    if (typeof page === 'object')  {
      page = $(page.target).data('page');
    }

    if (page > this.pageCount || page < 1) {
      if (typeof cb == 'function') {
        cb();
      }
      return;
    }
    this.currentPage = page;
    var width = '-'+this.pageWidth * (page - 1);
    this._slide(width, cb);
  },

  first: function(cb) {
    this.go(1, cb);
  },

  last: function(cb) {
    this.go(this.pageCount, cb);
  },

  _slide: function(width, cb) {
    var self = this;
    this.emit('beforeSlide', this.currentPage);
    this.updateButtons();
    this.container.animate({
      left: width
    }, self.duration, function() {
      self.emit('slide', self.currentPage);
      if (typeof cb == 'function') {
        cb();
      }
    });
  },

  updateButtons: function() {
    if (this.currentPage == 1) {
      this.previousButton.hide();
      this.emit('first', this.currentPage);
    } else {
      this.previousButton.show();
    }
    if (this.currentPage == this.pageCount) {
      this.nextButton.hide();
      this.emit('last', this.currentPage);
    } else {
      this.nextButton.show();
    }
  },

  start: function(e) {
    if (e && !this.auto) {
      return;
    }
    this.auto = true;
    if (this.timeout) {
      clearTimeout(this.timeout);
    }
    var self = this;
    this.timeout = setTimeout(function() {
      if (self.wrap && self.currentPage == self.pageCount) {
        self.currentPage = 0;
      }
      self.next();
      self.start();
    }, this.autoDelay);
  },

  stop: function() {
    if (!this.auto) {
      return;
    }
    clearTimeout(this.timeout);
  }
});
<commit_msg>[lib/slider] wrap in jQuery closure<commit_after>(function($) {
  $.declare('slider', {
    defaults: {
      page: 1,
      itemsPerPage: 1,
      duration: 500,
      itemClass: 'item',
      containerClass: 'container',
      auto: false,
      autoDelay: 5000,
      wrap: true
    },

    events: {
      'mouseover': 'stop',
      'mouseout': 'start'
    },

    elements: {
      '[data-action=previous]': 'previousButton',
      '[data-action=next]': 'nextButton'
    },

    init: function() {
      var items = this.find('.'+this.itemClass);
      this.pageCount = Math.ceil(items.length/this.itemsPerPage);
      this.pageWidth = items.outerWidth(true)*this.itemsPerPage;
      this.container = this.find('.'+this.containerClass);
      this.container.queue('fx');
      this.el.css('width', this.pageWidth);
      this.go(this.page);
      if (this.auto) {
        this.start();
      }
    },

    getCurrentPage: function() {
      return this.currentPage;
    },

    next: function(cb) {
      this.go(this.currentPage + 1, cb);
      this.emit('next', this.currentPage);
    },

    previous: function(cb) {
      this.go(this.currentPage - 1, cb);
      this.emit('previous', this.currentPage);
    },

    go: function(page, cb) {
      //check if click from data-action
      if (typeof page === 'object')  {
        page = $(page.target).data('page');
      }

      if (page > this.pageCount || page < 1) {
        if (typeof cb == 'function') {
          cb();
        }
        return;
      }
      this.currentPage = page;
      var width = '-'+this.pageWidth * (page - 1);
      this._slide(width, cb);
    },

    first: function(cb) {
      this.go(1, cb);
    },

    last: function(cb) {
      this.go(this.pageCount, cb);
    },

    _slide: function(width, cb) {
      var self = this;
      this.emit('beforeSlide', this.currentPage);
      this.updateButtons();
      this.container.animate({
        left: width
      }, self.duration, function() {
        self.emit('slide', self.currentPage);
        if (typeof cb == 'function') {
          cb();
        }
      });
    },

    updateButtons: function() {
      if (this.currentPage == 1) {
        this.previousButton.hide();
        this.emit('first', this.currentPage);
      } else {
        this.previousButton.show();
      }
      if (this.currentPage == this.pageCount) {
        this.nextButton.hide();
        this.emit('last', this.currentPage);
      } else {
        this.nextButton.show();
      }
    },

    start: function(e) {
      if (e && !this.auto) {
        return;
      }
      this.auto = true;
      if (this.timeout) {
        clearTimeout(this.timeout);
      }
      var self = this;
      this.timeout = setTimeout(function() {
        if (self.wrap && self.currentPage == self.pageCount) {
          self.currentPage = 0;
        }
        self.next();
        self.start();
      }, this.autoDelay);
    },

    stop: function() {
      if (!this.auto) {
        return;
      }
      clearTimeout(this.timeout);
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Owner: mark@famo.us
 * @license MPL 2.0
 * @copyright Famous Industries, Inc. 2014
 */

define(function(require, exports, module) {
    var Surface = require('famous/core/Surface');

    /**
     * A surface containing image content.
     *   This extends the Surface class.
     *
     * @class ImageSurface
     *
     * @extends Surface
     * @constructor
     * @param {Object} [options] overrides of default options
     */
    function ImageSurface(options) {
        this._imageUrl = undefined;
        Surface.apply(this, arguments);
    }

    ImageSurface.prototype = Object.create(Surface.prototype);
    ImageSurface.prototype.constructor = ImageSurface;
    ImageSurface.prototype.elementType = 'img';
    ImageSurface.prototype.elementClass = 'famous-surface';

    /**
     * Set content URL.  This will cause a re-rendering.
     * @method setContent
     * @param {string} imageUrl
     */
    ImageSurface.prototype.setContent = function setContent(imageUrl) {
        this._imageUrl = imageUrl;
        this._contentDirty = true;
    };

    /**
     * Place the document element that this component manages into the document.
     *
     * @private
     * @method deploy
     * @param {Node} target document parent of this container
     */
    ImageSurface.prototype.deploy = function deploy(target) {
        target.src = this._imageUrl || '';
    };

    /**
     * Remove this component and contained content from the document
     *
     * @private
     * @method recall
     *
     * @param {Node} target node to which the component was deployed
     */
    ImageSurface.prototype.recall = function recall(target) {
        target.src = '';
    };

    module.exports = ImageSurface;
});
<commit_msg>Add functionality for image caching<commit_after>
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Owner: mark@famo.us
 * @license MPL 2.0
 * @copyright Famous Industries, Inc. 2014
 */

define(function(require, exports, module) {
    var Surface = require('famous/core/Surface');

    var imageCache = {};

    /**
     * A surface containing image content.
     *   This extends the Surface class.
     *
     * @class ImageSurface
     *
     * @extends Surface
     * @constructor
     * @param {Object} [options] overrides of default options
     */
    function ImageSurface(options) {
        this._imageUrl = undefined;
        Surface.apply(this, arguments);
    }

    ImageSurface.prototype = Object.create(Surface.prototype);
    ImageSurface.prototype.constructor = ImageSurface;
    ImageSurface.prototype.elementType = 'img';
    ImageSurface.prototype.elementClass = 'famous-surface';

    /**
     * Set content URL.  This will cause a re-rendering.
     * @method setContent
     * @param {string} imageUrl
     */
    ImageSurface.prototype.setContent = function setContent(imageUrl) {
        if (this._imageUrl && this._imageUrl !== imageUrl) {
            if (imageCache[this._imageUrl].count === 1)
                imageCache[this._imageUrl] = null;
            else
                imageCache[this._imageUrl].count--;
        }

        if (!imageCache[imageUrl])
            imageCache[imageUrl] = {count: 1, node: null};
        else
            imageCache[imageUrl].count++;

        this._imageUrl = imageUrl;
        this._contentDirty = true;
    };

    /**
     * Place the document element that this component manages into the document.
     *
     * @private
     * @method deploy
     * @param {Node} target document parent of this container
     */
    ImageSurface.prototype.deploy = function deploy(target) {
        if (!imageCache[this._imageUrl].node) {
            var img = new Image();
            img.src = this._imageUrl;
            imageCache[this._imageUrl].node = img;
        }

        target.src = this._imageUrl || '';
    };

    /**
     * Remove this component and contained content from the document
     *
     * @private
     * @method recall
     *
     * @param {Node} target node to which the component was deployed
     */
    ImageSurface.prototype.recall = function recall(target) {
        target.src = '';
    };

    module.exports = ImageSurface;
});
<|endoftext|>


<commit_before>'use strict';

if (!MODULE) { var MODULE = {}; }

MODULE.Modal = (function() {
    var FADE_IN_TIME = 250;
    var FADE_OUT_TIME = 500;

    var Modal = function() {
        this.$modal = $('#modal');
        this.$content = this.$modal.find('.content');
        this.$buttons = this.$modal.find('.buttons');
    };

    Modal.prototype.show = function(content, buttons) {
        var self = this;

        buttons = buttons || [{
            text: 'Ok'
        }];

        this.empty();
        this.$content.html(content);

        buttons.forEach(function(button) {
            var $button = $('<button>' + button.text + '</button>');

            $button.on('click', function() {
                self.fadeOut();

                if (button.callback) {
                    button.callback();
                }
            });

            self.$buttons.append($button);
        });

        this.$modal.fadeIn(FADE_IN_TIME);
    };

    Modal.prototype.fadeOut = function() {
        this.$modal.fadeOut(FADE_OUT_TIME, function() {
            this.empty();
        }.bind(this));
    };

    Modal.prototype.hide = function() {
        this.$modal.hide();
        this.empty();
    };

    Modal.prototype.empty = function() {
        this.$content.empty();
        this.$buttons.empty();
    };

    return Modal;
}());
<commit_msg>more cleanup<commit_after>'use strict';

if (!MODULE) { var MODULE = {}; }

MODULE.Modal = (function() {
    var MODAL_SHOW_TIME = 250;
    var MODAL_HIDE_TIME = 500;

    var Modal = function() {
        this.$modal = $('#modal');
        this.$content = this.$modal.find('.content');
        this.$buttons = this.$modal.find('.buttons');
    };

    Modal.prototype.show = function(content, buttons) {
        var self = this;

        buttons = buttons || [{
            text: 'Ok'
        }];

        this.empty();
        this.$content.html(content);

        buttons.forEach(function(button) {
            var $button = $('<button>' + button.text + '</button>');

            $button.on('click', function() {
                self.fadeOut();

                if (button.callback) {
                    button.callback();
                }
            });

            self.$buttons.append($button);
        });

        this.$modal.fadeIn(MODAL_SHOW_TIME);
    };

    Modal.prototype.fadeOut = function() {
        this.$modal.fadeOut(MODAL_HIDE_TIME, function() {
            this.empty();
        }.bind(this));
    };

    Modal.prototype.hide = function() {
        this.$modal.hide();
        this.empty();
    };

    Modal.prototype.empty = function() {
        this.$content.empty();
        this.$buttons.empty();
    };

    return Modal;
}());
<|endoftext|>


<commit_before>var five = require("johnny-five");
var Edison = require("edison-io");
var Twitter = require('twitter');
var config = require('./config');

var board = new five.Board({
  io: new Edison()
});

var twit = new Twitter({
    consumer_key: config.twitter.consumerKey,
    consumer_secret: config.twitter.consumerSecret,
    access_token_key: config.twitter.accessTokenKey,
    access_token_secret: config.twitter.accessTokenSecret
});

var ON_DURATION = 2000;

board.on("ready", function() {
  var monkey = new five.Pin("GP44");

    //monitor by topic
    twit.stream('filter', { track: '#tweetmonkey' }, function (stream) {
        stream.on('data', function (data) {
            console.log('Tweet received from ' + data.user.screen_name + ': "' + data.text + '"');
            monkey.high();
            setTimeout(function () { monkey.low(); }, ON_DURATION);
        });
    });

});<commit_msg>add comments to main app.js file<commit_after>var five = require("johnny-five");
var Edison = require("edison-io");
var Twitter = require('twitter');
var config = require('./config');

var board = new five.Board({
  io: new Edison()
});

//configure the Twitter module with our consumer and access keys
//obtain these by going to apps.twitter.com
var twit = new Twitter({
    consumer_key: config.twitter.consumerKey,
    consumer_secret: config.twitter.consumerSecret,
    access_token_key: config.twitter.accessTokenKey,
    access_token_secret: config.twitter.accessTokenSecret
});

var ON_DURATION = 2000;

board.on("ready", function() {
  var monkey = new five.Pin("GP44");

    //monitor tweets by tracking a hash tag
    twit.stream('filter', { track: '#tweetmonkey' }, function (stream) {
        stream.on('data', function (data) {
            //log the tweet to the screen so we can see it if we have a console
            console.log('Tweet received from ' + data.user.screen_name + ': "' + data.text + '"');

            //take the pin high to animate the monkey
            monkey.high();

            //after some time, turn the monkey back off again
            setTimeout(function () { monkey.low(); }, ON_DURATION);
        });
    });

});<|endoftext|>


<commit_before>var Store = {
    asa: {
        name: 'Asa',
        age: 24
    }
};

var Jack = {
    config: {
      0: {
        storage: 'memory',
        life: 5000
      },
      1: {
        storage: 'session',
        life: 20000
      }
    },
    get: function(key) {
        return Store[key];
    },
    set: function(key, value, type) {
      type = type || 0;
      var config = this.config[type];
      Store[key] = value;
      setTimeout(function() {
        delete Store[key];
      }, config.life);
    }
};
<commit_msg>Work on poc<commit_after>var Store = {
  asa: {
      name: 'Asa',
      age: 24
  }
};

var Removers = {};

var Jack = {
    config: {
      0: {
        storage: 'memory',
        life: 1000
      },
      1: {
        storage: 'session',
        life: 5000
      }
    },
    get: function(key) {
        return Store[key];
    },
    set: function(key, value, type) {
      type = type || 0;
      var config = this.config[type];
      Store[key] = value;
      this.setupCleanup(key, config);
    },
    setupCleanup: function(key, config) {
      if(Removers[key]) {
        clearTimeout(Removers[key].id);
      }
      var remove = function() {
        delete Store[key];
        delete Removers[key];
      };
      var id = setTimeout(remove, config.life);
      Removers[key] = {
        id: id,
        callback: remove
      };
    }
};
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var config = require('../../config.js');
var output = config.log.output;
var path = config.log.path;
var outputlevel = config.log.level;

var Logger = function(){
	this.INFO = 'info';
	this.WARN = 'warn';
	this.DEBUG = 'debug';
	this.ERROR = 'error';
}

var LoggerMap = {
	'info'	:1,
	'warn'	:2,
	'debug'	:3,
	'error'	:4
};
Logger.prototype.info  = function(msg){
	this.log(msg,this.INFO);
};
Logger.prototype.warn  = function(msg){
	this.log(msg,this.WARN);
};
Logger.prototype.debug = function(msg){
	this.log(msg,this.DEBUG);
};
Logger.prototype.error = function(msg){
	this.log(msg,this.ERROR);
};
Logger.prototype.log = function(msg,level){
	level = !level ? 'info' : level;
	if (typeof message === 'function' || typeof message === 'object') {
		this.print(msg.toString(),level);
	} else {
		this.print(msg,level);
	}
};

Logger.prototype.print = function(msg,level) {
	if(LoggerMap[outputlevel] && LoggerMap[outputlevel]>  LoggerMap[level]) return ;
	//TODO fix the log level and add file output
	msg = "["+ level.toUpperCase()+"] " + new Date() + " "  + msg + '\n';
	var outs = output.split(',');
	for(var i=0;i<outs.length;i++){
		switch(outs[i]){
			case 'console':
				console.log(msg);
				break;
			case 'file'	  :
				if(!path){
					path = '/tmp/log/music.log';
				}
				fs.appendFileSync(path,msg);
				break;
			default	:
				console.log(msg);
				break;
		}
	}
}

module.exports = new Logger();

<commit_msg>update log<commit_after>'use strict';
var fs = require('fs');
var config = require('../../config.js');
var output = config.log.output;
var path = config.log.path;
var outputlevel = config.log.level;

var Logger = function(){
	this.INFO = 'info';
	this.WARN = 'warn';
	this.DEBUG = 'debug';
	this.ERROR = 'error';
}

var LoggerMap = {
	'info'	:1,
	'warn'	:2,
	'debug'	:3,
	'error'	:4
};
Logger.prototype.info  = function(msg){
	this.log(msg,this.INFO);
};
Logger.prototype.warn  = function(msg){
	this.log(msg,this.WARN);
};
Logger.prototype.debug = function(msg){
	this.log(msg,this.DEBUG);
};
Logger.prototype.error = function(msg){
	this.log(msg,this.ERROR);
};
Logger.prototype.log = function(msg,level){
	level = !level ? 'info' : level;
	if (typeof message === 'function' || typeof message === 'object') {
		this.print(msg.toString(),level);
	} else {
		this.print(msg,level);
	}
};

Logger.prototype.print = function(msg,level) {
	if(LoggerMap[outputlevel] && LoggerMap[outputlevel]>  LoggerMap[level]) return ;
	//TODO fix the log level and add file output
	//TODO add option of date format
	msg = "["+ level.toUpperCase()+"] " + new Date() + " "  + msg + '\n';
	var outs = output.split(',');
	for(var i=0;i<outs.length;i++){
		switch(outs[i]){
			case 'console':
				console.log(msg);
				break;
			case 'file'	  :
				if(!path){
					path = '/tmp/log/music.log';
				}
				fs.appendFileSync(path,msg);
				break;
			default	:
				console.log(msg);
				break;
		}
	}
}

module.exports = new Logger();

<|endoftext|>


<commit_before>/*
---

name: View

description: Provides an entity that handles an area in which a user can
             interract.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Entity

provides:
	- View

...
*/

/**
 * @name  View
 * @class Provides an entity that handles an area in which a user can
 *        interract.
 *
 * @classdesc
 *
 * [TODO: Description]
 * [TODO: Events]
 * [TODO: Roles]
 * [TODO: Styles]
 * [TODO: Options]
 * [TODO: Element Structure]
 *
 * @extends Entity
 *
 * @author  Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @version 0.1
 */
Moobile.View = new Class( /** @lends View.prototype */ {

	Extends: Moobile.Component,

	/**
	 * The view content.
	 * @type   ViewContent
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	content: null,

	/**
	 * The view that owns this view.
	 * @type   View
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	parentView: null,

	willBuild: function() {

		this.parent();

		this.element.addClass('view');

		var content = this.element.getRoleElement('view-content');
		if (content == null) {
			content = new Element('div');
			content.ingest(this.element);
			content.inject(this.element);
			content.setRole('view-content');
		}
	},

	destroy: function() {
		this.content = null;
		this.parent();
	},

	/**
	 * Enables the touch interraction of the view.
	 *
	 * This method will enable the touch interraction of this view by swapping
	 * the CSS class from `disable` to `enable`. This will set the CSS style
	 * `pointer-events` to `auto` thus enabling touch events.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	enableTouch: function() {
		this.element.removeClass('disable').addClass('enable');
		return this;
	},

	/**
	 * Disables the touch interaction of the view.
	 *
	 * This method will disable the touch interraction of this view by swapping
	 * the CSS class from `enable` to `disable`. This will set the CSS style
	 * `pointer-events` to `none` thus disabling touch events.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	disableTouch: function() {
		this.element.removeClass('enable').addClass('disable');
		return this;
	},

	/**
	 * Adds a child entity to this view.
	 *
	 * This method will add a child entity to this view's content entity. You
	 * can add the child entity before or after this view's content entity by
	 * passing `header` or `footer` to the `where` parameter.
	 *
	 * @see Entity#addChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	addChild: function(entity, where, context) {

		if (this.hasChild(entity))
			return false;

		if (entity instanceof Moobile.View)
			entity.setParentView(this);

		if (entity instanceof Moobile.ViewContent)
			return this.parent(entity, where, context);

		if (where == 'header')
			return this.parent(entity, 'top');

		if (where == 'footer')
			return this.parent(entity, 'bottom');

		if (this.content == null)
			return this.parent(entity, where, context);

		// the entity is in the view but not in the view content
		if (this.hasElement(entity) && !this.content.hasElement(entity))
			return this.parent(entity, where, context);

		// the entity will go next to an element that is in the view but not in the view content
		if (this.hasElement(context) && !this.content.hasElement(context))
			return this.parent(entity, where, context);

		return this.content.addChild(entity, where, context);
	},

	/**
	 * Returns a child entity from this view.
	 *
	 * This method will attempt to find the given child entity from this view's
	 * content entity then from the view itself if the former failed.
	 *
	 * @see Entity#getChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getChild: function(name) {
		return this.content
			 ? this.content.getChild(name) || this.parent(name)
			 : this.parent(name);
	},

	/**
	 * Indicates whether an entity is owned by this view.
	 *
	 * This method will attempt to find the given child entity from this view's
	 * content entity then from the view itself if the former failed.
	 *
	 * @see Entity#hasChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	hasChild: function(entity) {
		return this.content
		     ? this.content.hasChild(entity) || this.parent(entity)
		     : this.parent(entity);
	},

	/**
	 * Returns all the child entities from this view.
	 *
	 * This method will return an array that contains both the child entites
	 * from this view and the child entities from this view's content entity.
	 *
	 * @see Entity#getChildren
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getChildren: function(type) {
		return [].concat(this.parent(type), this.content.getChildren(type));
	},

	/**
	 * Replaces a child entity with another within this view.
	 *
	 * This method will attempt to replace the entity from this view's content
	 * entity first then from the view itself if the former failed.
	 *
	 * @see Entity#replaceChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	replaceChild: function(replace, entity) {
		return this.content
		     ? this.content.replaceChild(replace, entity) || this.parent(replace, entity)
		     : this.parent(replace, entity);
	},

	/**
	 * Removes a child entity.
	 *
	 * This method will attempt to remove the entity from this view's content
	 * entity first then from the view itself if the former failed.
	 *
	 * @see Entity#removeChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	removeChild: function(entity) {
		return this.content
		     ? this.content.removeChild(entity) || this.parent(entity)
		     : this.parent(entity);
	},

	/**
	 * Set the view that owns this view.
	 *
	 * This method should be used instead of `setParent` because it will set
	 * an view instead of a view content.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	setParentView: function(parentView) {
		this.parentViewWillChange(parentView);
		this.parentView = parentView;
		this.parentViewDidChange(parentView);
		return this;
	},

	/**
	 * Returns the view that owns this view.
	 *
	 * This method should be used instead of `getParent` because it will return
	 * an view instead of a view content.
	 *
	 * @return {View} The view that owns this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getParentView: function() {
		return this.parentView;
	},

	/**
	 * Sets the view content.
	 *
	 * This method will set the entity that is used as the content of this
	 * view. This entity will contains all child entities except ones in this
	 * view's header or footer.
	 *
	 * @param {ViewContent} content The view content.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	setContent: function(content) {

		if (this.content == content)
			return this;

		if (this.content == null) {
			this.addChild(content);
			this.content = content;
		} else {
			this.replaceChild(this.content, content);
			this.content.destroy();
			this.content = content;
		}

		return this;
	},

	/**
	 * Returns the view content.
	 *
	 * This method will return the entity that is used as the content of this
	 * view. This entity will contains all child entities except ones in this
	 * view's header or footer.
	 *
	 * @return {ViewContent} The view content.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getContent: function() {
		return this.content;
	},

	/**
	 * Tell the view it's about to be moved to a new view.
	 *
	 * The current implementation of this method does nothing. However it's a
	 * good practice to call the parent at the top of your implementation as
	 * the content of this method may change in the future.
	 *
	 * @param {View} parentView The view that will own this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	parentViewWillChange: function(parentView) {

	},

	/**
	 * Tell the view it has been moved to a new view.
	 *
	 * The current implementation of this method does nothing. However it's a
	 * good practice to call the parent at the top of your implementation as
	 * the content of this method may change in the future.
	 *
	 * @param {View} parentView The view that owns this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	parentViewDidChange: function(parentView) {

	}

});

/**
 * Return the view element of a file at a given path.
 *
 * @param {String} path The file path.
 *
 * @return {Element} The element or null if no elements were found.
 *
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since  0.1
 */
Moobile.View.elementAtPath = function(path) {
	return Element.at(path);
};

/**
 * Return the view of a file at a given path.
 *
 * @param {String} path The file path.
 *
 * @return {View} The view or null if no view were found.
 *
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since  0.1
 */
/**
 * Return the view of a file at a given path.
 *
 * @param {String} path The file path.
 *
 * @return {View} The view or null if no view were found.
 *
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since  0.1
 */
Moobile.View.atPath = function(path) {

	var element = Moobile.View.elementAtPath(path);
	if (element) {
		return Moobile.Component.create(Moobile.View, element, 'data-view');
	}

	return null;
};

//------------------------------------------------------------------------------
// Roles
//------------------------------------------------------------------------------

Moobile.Component.defineRole('view', null, function(element) {
	var instance = Moobile.Component.create(Moobile.View, element, 'data-view');
	this.addChild(instance);
});
<commit_msg>Renamed  to  for consistency and removed  since it's a duplication of<commit_after>/*
---

name: View

description: Provides an entity that handles an area in which a user can
             interract.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Entity

provides:
	- View

...
*/

/**
 * @name  View
 * @class Provides an entity that handles an area in which a user can
 *        interract.
 *
 * @classdesc
 *
 * [TODO: Description]
 * [TODO: Events]
 * [TODO: Roles]
 * [TODO: Styles]
 * [TODO: Options]
 * [TODO: Element Structure]
 *
 * @extends Entity
 *
 * @author  Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @version 0.1
 */
Moobile.View = new Class( /** @lends View.prototype */ {

	Extends: Moobile.Component,

	/**
	 * The view content.
	 * @type   ViewContent
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	content: null,

	/**
	 * The view that owns this view.
	 * @type   View
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	parentView: null,

	willBuild: function() {

		this.parent();

		this.element.addClass('view');

		var content = this.element.getRoleElement('view-content');
		if (content == null) {
			content = new Element('div');
			content.ingest(this.element);
			content.inject(this.element);
			content.setRole('view-content');
		}
	},

	destroy: function() {
		this.content = null;
		this.parent();
	},

	/**
	 * Enables the touch interraction of the view.
	 *
	 * This method will enable the touch interraction of this view by swapping
	 * the CSS class from `disable` to `enable`. This will set the CSS style
	 * `pointer-events` to `auto` thus enabling touch events.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	enableTouch: function() {
		this.element.removeClass('disable').addClass('enable');
		return this;
	},

	/**
	 * Disables the touch interaction of the view.
	 *
	 * This method will disable the touch interraction of this view by swapping
	 * the CSS class from `enable` to `disable`. This will set the CSS style
	 * `pointer-events` to `none` thus disabling touch events.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	disableTouch: function() {
		this.element.removeClass('enable').addClass('disable');
		return this;
	},

	/**
	 * Adds a child entity to this view.
	 *
	 * This method will add a child entity to this view's content entity. You
	 * can add the child entity before or after this view's content entity by
	 * passing `header` or `footer` to the `where` parameter.
	 *
	 * @see Entity#addChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	addChild: function(entity, where, context) {

		if (this.hasChild(entity))
			return false;

		if (entity instanceof Moobile.View)
			entity.setParentView(this);

		if (entity instanceof Moobile.ViewContent)
			return this.parent(entity, where, context);

		if (where == 'header')
			return this.parent(entity, 'top');

		if (where == 'footer')
			return this.parent(entity, 'bottom');

		if (this.content == null)
			return this.parent(entity, where, context);

		// the entity is in the view but not in the view content
		if (this.hasElement(entity) && !this.content.hasElement(entity))
			return this.parent(entity, where, context);

		// the entity will go next to an element that is in the view but not in the view content
		if (this.hasElement(context) && !this.content.hasElement(context))
			return this.parent(entity, where, context);

		return this.content.addChild(entity, where, context);
	},

	/**
	 * Returns a child entity from this view.
	 *
	 * This method will attempt to find the given child entity from this view's
	 * content entity then from the view itself if the former failed.
	 *
	 * @see Entity#getChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getChild: function(name) {
		return this.content
			 ? this.content.getChild(name) || this.parent(name)
			 : this.parent(name);
	},

	/**
	 * Indicates whether an entity is owned by this view.
	 *
	 * This method will attempt to find the given child entity from this view's
	 * content entity then from the view itself if the former failed.
	 *
	 * @see Entity#hasChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	hasChild: function(entity) {
		return this.content
		     ? this.content.hasChild(entity) || this.parent(entity)
		     : this.parent(entity);
	},

	/**
	 * Returns all the child entities from this view.
	 *
	 * This method will return an array that contains both the child entites
	 * from this view and the child entities from this view's content entity.
	 *
	 * @see Entity#getChildren
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getChildren: function(type) {
		return [].concat(this.parent(type), this.content.getChildren(type));
	},

	/**
	 * Replaces a child entity with another within this view.
	 *
	 * This method will attempt to replace the entity from this view's content
	 * entity first then from the view itself if the former failed.
	 *
	 * @see Entity#replaceChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	replaceChild: function(replace, entity) {
		return this.content
		     ? this.content.replaceChild(replace, entity) || this.parent(replace, entity)
		     : this.parent(replace, entity);
	},

	/**
	 * Removes a child entity.
	 *
	 * This method will attempt to remove the entity from this view's content
	 * entity first then from the view itself if the former failed.
	 *
	 * @see Entity#removeChild
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	removeChild: function(entity) {
		return this.content
		     ? this.content.removeChild(entity) || this.parent(entity)
		     : this.parent(entity);
	},

	/**
	 * Set the view that owns this view.
	 *
	 * This method should be used instead of `setParent` because it will set
	 * an view instead of a view content.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	setParentView: function(parentView) {
		this.parentViewWillChange(parentView);
		this.parentView = parentView;
		this.parentViewDidChange(parentView);
		return this;
	},

	/**
	 * Returns the view that owns this view.
	 *
	 * This method should be used instead of `getParent` because it will return
	 * an view instead of a view content.
	 *
	 * @return {View} The view that owns this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getParentView: function() {
		return this.parentView;
	},

	/**
	 * Sets the view content.
	 *
	 * This method will set the entity that is used as the content of this
	 * view. This entity will contains all child entities except ones in this
	 * view's header or footer.
	 *
	 * @param {ViewContent} content The view content.
	 *
	 * @return {View} This view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	setContent: function(content) {

		if (this.content == content)
			return this;

		if (this.content == null) {
			this.addChild(content);
			this.content = content;
		} else {
			this.replaceChild(this.content, content);
			this.content.destroy();
			this.content = content;
		}

		return this;
	},

	/**
	 * Returns the view content.
	 *
	 * This method will return the entity that is used as the content of this
	 * view. This entity will contains all child entities except ones in this
	 * view's header or footer.
	 *
	 * @return {ViewContent} The view content.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getContent: function() {
		return this.content;
	},

	/**
	 * Tell the view it's about to be moved to a new view.
	 *
	 * The current implementation of this method does nothing. However it's a
	 * good practice to call the parent at the top of your implementation as
	 * the content of this method may change in the future.
	 *
	 * @param {View} parentView The view that will own this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	parentViewWillChange: function(parentView) {

	},

	/**
	 * Tell the view it has been moved to a new view.
	 *
	 * The current implementation of this method does nothing. However it's a
	 * good practice to call the parent at the top of your implementation as
	 * the content of this method may change in the future.
	 *
	 * @param {View} parentView The view that owns this view.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	parentViewDidChange: function(parentView) {

	}

});

/**
 * Return the view of a file at a given path.
 *
 * @param {String} path The file path.
 *
 * @return {View} The view or null if no view were found.
 *
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since  0.1
 */
Moobile.View.at = function(path) {

	var element = Element.at(path);
	if (element) {
		return Moobile.Component.create(Moobile.View, element, 'data-view');
	}

	return null;
};

//------------------------------------------------------------------------------
// Roles
//------------------------------------------------------------------------------

Moobile.Component.defineRole('view', null, function(element) {
	var instance = Moobile.Component.create(Moobile.View, element, 'data-view');
	this.addChild(instance);
});
<|endoftext|>


<commit_before>var selectedCloudlet = '';

$('.column-left ul li a').click(function(){

   var id    = $(this).attr('name');
   var auth  = $("#session").val();
   var cloud = $("#cloudlet").val();

   $("#id_list").html("");

   $.ajax({
      url: '/api/v1/objects?type=' + id + "&id_only=true&limit=100",
      type: 'GET',
      data: {},
      headers: {
         "Content-Type"  : "application/json",
         "Authorization" : auth
      },
      dataType: 'json',
      success: function (data) {
         for ( var i = 0; i < data.result.length; i++){
            var id = data.result[i]['@id'][1];
            $("#id_list").append('
' + id + '
' );
         }

         $("ul#id_list li a").click(display_object_function)
      },
      error: function (data) {
         console.log(data)
      }
   });

});

$(window).load(function(){
   $('.column-left ul li a').each(function(){
      var obj    = $(this)
      var typeId = obj.attr('name')
      $.ajax({
         url: '/api/v1/types/' + typeId,
         type: 'GET',
         data: {},
         headers: {
            "Content-Type"  : "application/json"
         },
         dataType: 'json',
         success: function (data) {
            obj.html(data['@reference'])
         },
         error: function (data) {
         }
      });
   })
})

var display_object_function = function(){

   var id   = $(this).html();
   var auth = $("#session").val();
   var cloud = $("#cloudlet").val();

   $.ajax({
      url: '/api/v1/objects/' + cloud + "/" + id ,
      type: 'GET',
      data: {},
      headers: {
         "Content-Type"  : "application/json",
         "Authorization" : auth
      },
      dataType: 'json',
      success: function (data) {
         //$("#data").html("asdf")
         $("#displayContainer").show()
         $("#data").html(JSON.stringify(data, undefined, 2))
      },
      error: function (data) {
         console.log(data)
      }
   });

};<commit_msg>fixed bug with object references<commit_after>var selectedCloudlet = '';

$('#typesmain ul li a').click(function(){

   var id    = $(this).attr('name');
   var auth  = $("#session").val();
   var cloud = $("#cloudlet").val();

   $("#id_list").html("");

   $.ajax({
      url: '/api/v1/objects?type=' + id + "&id_only=true&limit=100",
      type: 'GET',
      data: {},
      headers: {
         "Content-Type"  : "application/json",
         "Authorization" : auth
      },
      dataType: 'json',
      success: function (data) {
         for ( var i = 0; i < data.result.length; i++){
            var id = data.result[i]['@id'][1];
            $("#id_list").append('
' + id + '
' );
         }

         $("ul#id_list li a").click(display_object_function)
      },
      error: function (data) {
         console.log(data)
      }
   });

});

$(window).load(function(){
   $('#typesmain ul li a').each(function(){
      var obj    = $(this)
      var typeId = obj.attr('name')
      $.ajax({
         url: '/api/v1/types/' + typeId,
         type: 'GET',
         data: {},
         headers: {
            "Content-Type"  : "application/json"
         },
         dataType: 'json',
         success: function (data) {
            obj.html(data['@reference'])
         },
         error: function (data) {
            obj.html(typeId)
         }
      });
   })
})

var display_object_function = function(){

   var id   = $(this).html();
   var auth = $("#session").val();
   var cloud = $("#cloudlet").val();

   $.ajax({
      url: '/api/v1/objects/' + cloud + "/" + id ,
      type: 'GET',
      data: {},
      headers: {
         "Content-Type"  : "application/json",
         "Authorization" : auth
      },
      dataType: 'json',
      success: function (data) {
         //$("#data").html("asdf")
         $("#displayContainer").show()
         $("#data").html(JSON.stringify(data, undefined, 2))
      },
      error: function (data) {
         console.log(data)
      }
   });

};<|endoftext|>


<commit_before>if (typeof(SJL) == 'undefined' || ( ! SJL instanceof Object)) SJL = new Object();

if (typeof(SJL.SLGoogleMap) == 'undefined' || ( ! SJL.SLGoogleMap instanceof Object)) {

	SJL.SLGoogleMap = function() {

		/**
		 * The Map "class" constructor.
		 * @param 	object 		init 			Initialisation object containing information essential to the construction of the map.
		 * @param 	object 		options		Map UI options.
		 */
		function Map(init, options) {

			// Check that we have the required information.
			if ( ! init instanceof Object ||
				typeof(init.map_container) == 'undefined' ||
				typeof(init.map_lat) == 'undefined' ||
				typeof(init.map_lng) == 'undefined' ||
				typeof(init.map_zoom) == 'undefined' ||
				typeof(init.pin_lat) == 'undefined' ||
				typeof(init.pin_lng) == 'undefined') {
					return false;
				}

			// Set the default map options.
			var map_options = {
				'ui_zoom'					: false,
				'ui_scale' 				: false,
				'ui_overview'			: false,
				'ui_map_type'			: false,
				'map_drag'				: false,
				'map_click_zoom'	: false,
				'map_scroll_zoom'	: false,
				'pin_drag'				: false,
				'background'			: '#FFFFFF',
				'map_types'				: ''
			}

			// An index containing the available map types.
			var valid_map_types = {
				'hybrid'			: G_HYBRID_MAP,
				'normal'			: G_NORMAL_MAP,
				'physical'		: G_PHYSICAL_MAP,
				'satellite'		: G_SATELLITE_MAP
			};

			default_map_type = valid_map_types['normal'];

			// Override the default options.
			for (o in options) {
				if (map_options[o] != 'undefined') {
					map_options[o] = options[o];
				}
			}

			// Create the map.
			this.__map = new GMap2(document.getElementById(init.map_container), {backgroundColor: map_options['background']});
			this.__map.setCenter(new GLatLng(init.map_lat, init.map_lng), init.map_zoom);		// MUST explicitly call setCenter.

			// Customise the map UI.
			ui = this.__map.getDefaultUI();

			// Everything else is controlled by our map_options object.
			// - Zoom / pan controls.
			if (this.__map.getSize().height <= 325) {
				ui.controls.smallzoomcontrol3d = map_options.ui_zoom;
				ui.controls.largemapcontrol3d = false;
			} else {
				ui.controls.smallzoomcontrol3d = false;
				ui.controls.largemapcontrol3d = map_options.ui_zoom;
			}

			// - Map dragging.
			map_options.map_drag ? this.__map.enableDragging() : this.__map.disableDragging();

			// - Map zooming.
			ui.zoom.doubleclick = map_options.map_click_zoom;
			ui.zoom.scrollwheel = map_options.map_scroll_zoom;

			// - Scale control.
			ui.controls.scalecontrol = map_options.ui_scale;

			// - Map type control.
			ui.controls.maptypecontrol = ui.controls.menumaptypecontrol = false;
			if (this.__map.getSize().width <= 475) {
				ui.controls.menumaptypecontrol = map_options.ui_map_type;
			} else {
				ui.controls.maptypecontrol = map_options.ui_map_type;
			}

			// - Explicitly-set available map types.
			if (map_options.map_types) {
				map_types = map_options.map_types.split('|');

				/**
				 * At this point in time we have no idea what we've got.
				 * We assume the worst, and set all the map types to false.
				 * Then we loop through, activating only those that are explicitly
				 * required.
				 *
				 * In the midst of all this, we also determine the default map type.
				 */

				ui.maptypes.normal 			= false;
				ui.maptypes.satellite		= false;
				ui.maptypes.hybrid			= false;
				ui.maptypes.physical		= false;

				map_types_count 	= map_types.length;
				default_map_set		= false;

				for (i = 0; i < map_types_count; i++) {
					map_types[i] = map_types[i].toLowerCase();

					if (valid_map_types[map_types[i]]) {
						ui.maptypes[map_types[i]] = true;

						if (!default_map_set) {
							default_map_type 	= valid_map_types[map_types[i]];
							default_map_set		= true;
						}
					}
				}
			}

			// - Set the default map type.
			this.__map.setMapType(default_map_type);

			// - Set the UI options.
			this.__map.setUI(ui);

			/**
			 * @bug
			 * The overview map always appears as type G_NORMAL_MAP, regardless of the type of the
			 * main map. There doesn't seem to be a way to change this, or force a refresh of the map.
			 */

			// - Overview control (need to do this separately, for reasons best known to Google).
			if (map_options.ui_overview) {
				this.__map.addControl(new GOverviewMapControl());
			}

			// A shortcut variable that we can reference in our function literals below.
			var t = this;

			// Add the map "pin".
			this.__marker = new GMarker(new GLatLng(init.pin_lat, init.pin_lng), {clickable: map_options.pin_drag, draggable: map_options.pin_drag, autoPan: true});
			this.__map.addOverlay(this.__marker);

			// Add an event listener to the map "pin".
			if (map_options.pin_drag) {
				this.__marker_listener = GEvent.addListener(this.__marker, 'dragend', function(latlng) {
					t.set_location(latlng);
				});
			}

			// If we have a "map_field", we need to update it every time our map changes.
			if (typeof(init.map_field) != 'undefined') {
				this.__map_field = jQuery('#' + init.map_field);

				// Add the event listener.
				if (this.__map_field.length) {
					this.__map_listener = GEvent.addListener(this.__map, 'moveend', function() {
						var map_data = t.get_location();
						var pin_data = t.get_marker();
						var field_data = map_data.latlng.lat() + ',' + map_data.latlng.lng() + ',' + map_data.zoom + ',' + pin_data.lat() + ',' + pin_data.lng();
						t.__map_field.val(field_data);
					});
				}
			}

			// If we have an "address_input" field, and an "address_submit" field, we need to
			// link these to our map.
			if (typeof(init.address_input) != 'undefined' && typeof(init.address_submit) != 'undefined') {
				this.__address_input 	= jQuery('#' + init.address_input);
				this.__address_submit	= jQuery('#' + init.address_submit);

				if (this.__address_input.length && this.__address_submit.length) {
					this.__in_lookup = false;

					// Set a flag every time we enter or leave the address_input field.
					this.__address_input.unbind('focus').bind('focus', function(e) {
						t.__in_lookup = true;
					}).unbind('blur').bind('blur', function() {
						t.__in_lookup = false;
					});

					// Find the specified address.
					this.__address_submit.unbind('click').bind('click', function(e) {
						var address = jQuery.trim(t.__address_input.val());
						if (address !== '') t.pinpoint_address(address, function() {
							// Update the map and pin data.
							var map_data = t.get_location();
							var pin_data = t.get_marker();
							var field_data = map_data.latlng.lat() + ',' + map_data.latlng.lng() + ',' + map_data.zoom + ',' + pin_data.lat() + ',' + pin_data.lng();
							t.__map_field.val(field_data);
						});
						return false;
					}).parents('form').submit(function(e) {
						if (t.__in_lookup) {
							t.__address_submit.click();
							return false;
						}
					});
				}
			}

			return this;
		}

		/**
		 * Sets the map location and zoom level.
		 * @param 	int 	latlng 	A GLatLng object containing the marker's latitude and longitude.
		 * @param		int		zoom		The map zoom level.
		 * @return 	object 	An object containing the map's latitude, longitude, and zoom.
		 */
		Map.prototype.set_location = function(latlng, zoom) {
			// Check the parameters.
			if (jQuery.isFunction(latlng.lat) == false) {
				if ((typeof(latlng.lat) == 'undefined') || (typeof(latlng.lng) == 'undefined')) {
					return false;
				} else {
					latlng = new GLatLng(latlng.lat, latlng.lng);
				}
			}

			if (this.__map) {
				this.__map.setZoom(zoom);
				this.__map.panTo(latlng);
			}
			return this.get_location();
		}

		/**
		 * Gets the map location and zoom level.
		 * @return 	object 	An anonymous object with two properties: latlng (GLatLng object); zoom (integer).
		 */
		Map.prototype.get_location = function() {
			if (this.__map) {
				loc = this.__map.getCenter();
				return {
					latlng: loc,
					zoom: this.__map.getZoom()
				};
			} else {
				return false;
			}
		}

		/**
		 * Sets the location of the map marker.
		 * @param 	object		latlng				A GLatLng object, or an anonymous object with the properties lat and lng.
		 * @return 	object 		A GLatLng object containing the marker's latitude and longitude.
		 */
		Map.prototype.set_marker = function(latlng) {
			// Check the parameters.
			if (jQuery.isFunction(latlng.lat) == false) {
				if ((typeof(latlng.lat) == 'undefined') || (typeof(latlng.lng) == 'undefined')) {
					return false;
				} else {
					latlng = new GLatLng(latlng.lat, latlng.lng);
				}
			}

			this.__marker.setLatLng(latlng);
			return this.get_marker();
		}

		/**
		 * Returns the latitude and longitude of the map marker. If no marker exists,
		 * return FALSE.
		 * @return 		object 		A GLatLng object containing the marker's latitude and longitude.
		 */
		Map.prototype.get_marker = function() {
			if (this.__marker) {
				loc = this.__marker.getLatLng();
				return loc;
			} else {
				return false;
			}
		}

		/**
		 * Attempts to locate the given address on the map.
		 * @param 	string		address			The address to locate (can be a postcode).
		 * @param		function	callback		The function to call when we're all done here (optional).
		 */
		Map.prototype.pinpoint_address = function(address, callback) {
			var regexp, geo, map, local;

			if (jQuery.trim(address) == '') return;

			// Google Maps is rather bad at locating UK postcodes, so we need
			// to be sneaky. If we get given a postcode, we use the Google AJAX
			// search API to get its latitude and longitude.
			regexp = new RegExp("(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])[ ]*[0-9][ABD-HJLNP-UW-Z]{2})", "i");

			// Convenience variable.
			t = this;

			if (address.match(regexp)) {
				local = new GlocalSearch();

				// Search callback handler.
				local.setSearchCompleteCallback(null, function() {
					if (local.results[0]) {
						t.set_location({lat: local.results[0].lat, lng: local.results[0].lng});
						t.set_marker({lat: local.results[0].lat, lng: local.results[0].lng});

						if (callback instanceof Function) {
							callback();
						}
					}
				});

				// Execute the postcode search.
				local.execute(address + ", UK");
			} else {
				// Create a new GClientGeocoder object to help us find the address.
				geo = new GClientGeocoder();
				geo.getLatLng(address, function(latlng) {
					if (latlng !== null) {
						t.set_location(latlng);
						t.set_marker(latlng);

						if (callback instanceof Function) {
							callback();
						}
					}
				});
			} // if - else

		}

		// Return our publically-accessible object.
		return ({Map : Map});

	}();
}

// Create the Google Maps.
jQuery(document).ready(function() {
	if (GBrowserIsCompatible() && typeof(SJL.google_maps) !== 'undefined' && SJL.google_maps instanceof Array) {
		for (var i in SJL.google_maps) {
			map = new SJL.SLGoogleMap.Map(SJL.google_maps[i].init, SJL.google_maps[i].options);
		}
	}
});

// Tidy up after ourselves.
jQuery(window).unload(function() {
	if (GBrowserIsCompatible()) {
		GUnload();
	}
});
<commit_msg>Implemented more robust 'is a string' tests, to avoid situations where passing an empty selector to jQuery 1.3.2 throws and exception.<commit_after>if (typeof(SJL) == 'undefined' || ( ! SJL instanceof Object)) SJL = new Object();

if (typeof(SJL.SLGoogleMap) == 'undefined' || ( ! SJL.SLGoogleMap instanceof Object)) {

	SJL.SLGoogleMap = function() {

		/**
		 * The Map "class" constructor.
		 * @param 	object 		init 			Initialisation object containing information essential to the construction of the map.
		 * @param 	object 		options		Map UI options.
		 */
		function Map(init, options) {

			// Check that we have the required information.
			if ( ! init instanceof Object ||
				typeof(init.map_container) == 'undefined' ||
				typeof(init.map_lat) == 'undefined' ||
				typeof(init.map_lng) == 'undefined' ||
				typeof(init.map_zoom) == 'undefined' ||
				typeof(init.pin_lat) == 'undefined' ||
				typeof(init.pin_lng) == 'undefined') {
					return false;
				}

			// Set the default map options.
			var map_options = {
				'ui_zoom'					: false,
				'ui_scale' 				: false,
				'ui_overview'			: false,
				'ui_map_type'			: false,
				'map_drag'				: false,
				'map_click_zoom'	: false,
				'map_scroll_zoom'	: false,
				'pin_drag'				: false,
				'background'			: '#FFFFFF',
				'map_types'				: ''
			}

			// An index containing the available map types.
			var valid_map_types = {
				'hybrid'			: G_HYBRID_MAP,
				'normal'			: G_NORMAL_MAP,
				'physical'		: G_PHYSICAL_MAP,
				'satellite'		: G_SATELLITE_MAP
			};

			default_map_type = valid_map_types['normal'];

			// Override the default options.
			for (o in options) {
				if (map_options[o] != 'undefined') {
					map_options[o] = options[o];
				}
			}

			// Create the map.
			this.__map = new GMap2(document.getElementById(init.map_container), {backgroundColor: map_options['background']});
			this.__map.setCenter(new GLatLng(init.map_lat, init.map_lng), init.map_zoom);		// MUST explicitly call setCenter.

			// Customise the map UI.
			ui = this.__map.getDefaultUI();

			// Everything else is controlled by our map_options object.
			// - Zoom / pan controls.
			if (this.__map.getSize().height <= 325) {
				ui.controls.smallzoomcontrol3d = map_options.ui_zoom;
				ui.controls.largemapcontrol3d = false;
			} else {
				ui.controls.smallzoomcontrol3d = false;
				ui.controls.largemapcontrol3d = map_options.ui_zoom;
			}

			// - Map dragging.
			map_options.map_drag ? this.__map.enableDragging() : this.__map.disableDragging();

			// - Map zooming.
			ui.zoom.doubleclick = map_options.map_click_zoom;
			ui.zoom.scrollwheel = map_options.map_scroll_zoom;

			// - Scale control.
			ui.controls.scalecontrol = map_options.ui_scale;

			// - Map type control.
			ui.controls.maptypecontrol = ui.controls.menumaptypecontrol = false;
			if (this.__map.getSize().width <= 475) {
				ui.controls.menumaptypecontrol = map_options.ui_map_type;
			} else {
				ui.controls.maptypecontrol = map_options.ui_map_type;
			}

			// - Explicitly-set available map types.
			if (map_options.map_types) {
				map_types = map_options.map_types.split('|');

				/**
				 * At this point in time we have no idea what we've got.
				 * We assume the worst, and set all the map types to false.
				 * Then we loop through, activating only those that are explicitly
				 * required.
				 *
				 * In the midst of all this, we also determine the default map type.
				 */

				ui.maptypes.normal 			= false;
				ui.maptypes.satellite		= false;
				ui.maptypes.hybrid			= false;
				ui.maptypes.physical		= false;

				map_types_count 	= map_types.length;
				default_map_set		= false;

				for (i = 0; i < map_types_count; i++) {
					map_types[i] = map_types[i].toLowerCase();

					if (valid_map_types[map_types[i]]) {
						ui.maptypes[map_types[i]] = true;

						if (!default_map_set) {
							default_map_type 	= valid_map_types[map_types[i]];
							default_map_set		= true;
						}
					}
				}
			}

			// - Set the default map type.
			this.__map.setMapType(default_map_type);

			// - Set the UI options.
			this.__map.setUI(ui);

			/**
			 * @bug
			 * The overview map always appears as type G_NORMAL_MAP, regardless of the type of the
			 * main map. There doesn't seem to be a way to change this, or force a refresh of the map.
			 */

			// - Overview control (need to do this separately, for reasons best known to Google).
			if (map_options.ui_overview) {
				this.__map.addControl(new GOverviewMapControl());
			}

			// A shortcut variable that we can reference in our function literals below.
			var t = this;

			// Add the map "pin".
			this.__marker = new GMarker(new GLatLng(init.pin_lat, init.pin_lng), {clickable: map_options.pin_drag, draggable: map_options.pin_drag, autoPan: true});
			this.__map.addOverlay(this.__marker);

			// Add an event listener to the map "pin".
			if (map_options.pin_drag) {
				this.__marker_listener = GEvent.addListener(this.__marker, 'dragend', function(latlng) {
					t.set_location(latlng);
				});
			}

			// If we have a "map_field", we need to update it every time our map changes.
			if (typeof(init.map_field) == 'string' && init.map_field.length) {
				this.__map_field = jQuery('#' + init.map_field);

				// Add the event listener.
				if (this.__map_field.length) {
					this.__map_listener = GEvent.addListener(this.__map, 'moveend', function() {
						var map_data = t.get_location();
						var pin_data = t.get_marker();
						var field_data = map_data.latlng.lat() + ',' + map_data.latlng.lng() + ',' + map_data.zoom + ',' + pin_data.lat() + ',' + pin_data.lng();
						t.__map_field.val(field_data);
					});
				}
			}

			// If we have an "address_input" field, and an "address_submit" field, we need to
			// link these to our map.
			if (typeof(init.address_input) == 'string' && typeof(init.address_submit) == 'string' && init.address_input.length && init.address_submit.length) {
				this.__address_input 	= jQuery('#' + init.address_input);
				this.__address_submit	= jQuery('#' + init.address_submit);

				if (this.__address_input.length && this.__address_submit.length) {
					this.__in_lookup = false;

					// Set a flag every time we enter or leave the address_input field.
					this.__address_input.unbind('focus').bind('focus', function(e) {
						t.__in_lookup = true;
					}).unbind('blur').bind('blur', function() {
						t.__in_lookup = false;
					});

					// Find the specified address.
					this.__address_submit.unbind('click').bind('click', function(e) {
						var address = jQuery.trim(t.__address_input.val());
						if (address !== '') t.pinpoint_address(address, function() {
							// Update the map and pin data.
							var map_data = t.get_location();
							var pin_data = t.get_marker();
							var field_data = map_data.latlng.lat() + ',' + map_data.latlng.lng() + ',' + map_data.zoom + ',' + pin_data.lat() + ',' + pin_data.lng();
							t.__map_field.val(field_data);
						});
						return false;
					}).parents('form').submit(function(e) {
						if (t.__in_lookup) {
							t.__address_submit.click();
							return false;
						}
					});
				}
			}

			return this;
		}

		/**
		 * Sets the map location and zoom level.
		 * @param 	int 	latlng 	A GLatLng object containing the marker's latitude and longitude.
		 * @param		int		zoom		The map zoom level.
		 * @return 	object 	An object containing the map's latitude, longitude, and zoom.
		 */
		Map.prototype.set_location = function(latlng, zoom) {
			// Check the parameters.
			if (jQuery.isFunction(latlng.lat) == false) {
				if ((typeof(latlng.lat) == 'undefined') || (typeof(latlng.lng) == 'undefined')) {
					return false;
				} else {
					latlng = new GLatLng(latlng.lat, latlng.lng);
				}
			}

			if (this.__map) {
				this.__map.setZoom(zoom);
				this.__map.panTo(latlng);
			}
			return this.get_location();
		}

		/**
		 * Gets the map location and zoom level.
		 * @return 	object 	An anonymous object with two properties: latlng (GLatLng object); zoom (integer).
		 */
		Map.prototype.get_location = function() {
			if (this.__map) {
				loc = this.__map.getCenter();
				return {
					latlng: loc,
					zoom: this.__map.getZoom()
				};
			} else {
				return false;
			}
		}

		/**
		 * Sets the location of the map marker.
		 * @param 	object		latlng				A GLatLng object, or an anonymous object with the properties lat and lng.
		 * @return 	object 		A GLatLng object containing the marker's latitude and longitude.
		 */
		Map.prototype.set_marker = function(latlng) {
			// Check the parameters.
			if (jQuery.isFunction(latlng.lat) == false) {
				if ((typeof(latlng.lat) == 'undefined') || (typeof(latlng.lng) == 'undefined')) {
					return false;
				} else {
					latlng = new GLatLng(latlng.lat, latlng.lng);
				}
			}

			this.__marker.setLatLng(latlng);
			return this.get_marker();
		}

		/**
		 * Returns the latitude and longitude of the map marker. If no marker exists,
		 * return FALSE.
		 * @return 		object 		A GLatLng object containing the marker's latitude and longitude.
		 */
		Map.prototype.get_marker = function() {
			if (this.__marker) {
				loc = this.__marker.getLatLng();
				return loc;
			} else {
				return false;
			}
		}

		/**
		 * Attempts to locate the given address on the map.
		 * @param 	string		address			The address to locate (can be a postcode).
		 * @param		function	callback		The function to call when we're all done here (optional).
		 */
		Map.prototype.pinpoint_address = function(address, callback) {
			var regexp, geo, map, local;

			if (jQuery.trim(address) == '') return;

			// Google Maps is rather bad at locating UK postcodes, so we need
			// to be sneaky. If we get given a postcode, we use the Google AJAX
			// search API to get its latitude and longitude.
			regexp = new RegExp("(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])[ ]*[0-9][ABD-HJLNP-UW-Z]{2})", "i");

			// Convenience variable.
			t = this;

			if (address.match(regexp)) {
				local = new GlocalSearch();

				// Search callback handler.
				local.setSearchCompleteCallback(null, function() {
					if (local.results[0]) {
						t.set_location({lat: local.results[0].lat, lng: local.results[0].lng});
						t.set_marker({lat: local.results[0].lat, lng: local.results[0].lng});

						if (callback instanceof Function) {
							callback();
						}
					}
				});

				// Execute the postcode search.
				local.execute(address + ", UK");
			} else {
				// Create a new GClientGeocoder object to help us find the address.
				geo = new GClientGeocoder();
				geo.getLatLng(address, function(latlng) {
					if (latlng !== null) {
						t.set_location(latlng);
						t.set_marker(latlng);

						if (callback instanceof Function) {
							callback();
						}
					}
				});
			} // if - else

		}

		// Return our publically-accessible object.
		return ({Map : Map});

	}();
}

// Create the Google Maps.
jQuery(document).ready(function() {
	if (GBrowserIsCompatible() && typeof(SJL.google_maps) !== 'undefined' && SJL.google_maps instanceof Array) {
		for (var i in SJL.google_maps) {
			map = new SJL.SLGoogleMap.Map(SJL.google_maps[i].init, SJL.google_maps[i].options);
		}
	}
});

// Tidy up after ourselves.
jQuery(window).unload(function() {
	if (GBrowserIsCompatible()) {
		GUnload();
	}
});
<|endoftext|>