<commit_before>'use strict';

var DragDropActionCreators = require('../actions/DragDropActionCreators'),
    DragDropStore = require('../stores/DragDropStore'),
    HorizontalDragAnchors = require('../constants/HorizontalDragAnchors'),
    VerticalDragAnchors = require('../constants/VerticalDragAnchors'),
    bindAll = require('../utils/bindAll'),
    invariant = require('react/lib/invariant'),
    merge = require('react/lib/merge'),
    union = require('lodash-node/modern/arrays/union'),
    without = require('lodash-node/modern/arrays/without'),
    isObject = require('lodash-node/modern/objects/isObject');

function endsWith(str, suffix) {
  return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

function isFirefox() {
  return /firefox/i.test(navigator.userAgent);
}

function isSafari() {
  return !!window.safari;
}

function isSafari8OrNewer() {
  return isSafari() && parseInt(navigator.appVersion.match(/Version\/(\d+)\./)[1], 10) >= 8;
}

function shouldUseDragPreview(dragPreview) {
  if (!dragPreview) {
    return false;
  }

  if (isSafari() && dragPreview instanceof Image && endsWith(dragPreview.src, '.gif')) {
    // GIFs crash Safari
    return false;
  }

  return true;
}

/**
 * Returns offset to be used as arguments for `dataTransfer.setDragImage(dragImage, x, y)`.
 * Attempts to work around browser differences, especially on high-DPI screens.
 */
function getDragImageOffset(containerNode, dragPreview, dragAnchors, e) {
  dragAnchors = dragAnchors || {};

  var containerWidth = containerNode.offsetWidth,
      containerHeight = containerNode.offsetHeight,
      isImage = dragPreview instanceof Image,
      previewWidth = isImage ? dragPreview.width : containerWidth,
      previewHeight = isImage ? dragPreview.height : containerHeight,
      horizontalAnchor = dragAnchors.horizontal || HorizontalDragAnchors.CENTER,
      verticalAnchor = dragAnchors.vertical || VerticalDragAnchors.CENTER,
      { offsetX, offsetY } = e;

  // Work around @2x coordinate discrepancies in browsers
  if (isFirefox()) {
    offsetX = e.layerX * window.devicePixelRatio;
    offsetY = e.layerY * window.devicePixelRatio;
  } else if (isSafari8OrNewer()) {
    previewHeight /= window.devicePixelRatio;
    previewWidth /= window.devicePixelRatio;
  }

  switch (horizontalAnchor) {
  case HorizontalDragAnchors.LEFT:
    break;
  case HorizontalDragAnchors.CENTER:
    offsetX *= (previewWidth / containerWidth);
    break;
  case HorizontalDragAnchors.RIGHT:
    offsetX = previewWidth - previewWidth * (1 - offsetX / containerWidth);
    break;
  }

  switch (verticalAnchor) {
  case VerticalDragAnchors.TOP:
    break;
  case VerticalDragAnchors.CENTER:
    offsetY *= (previewHeight / containerHeight);
    break;
  case VerticalDragAnchors.BOTTOM:
    offsetY = previewHeight - previewHeight * (1 - offsetY / containerHeight);
    break;
  }

  // Work around Safari 8 positioning bug
  if (isSafari8OrNewer()) {
    // We'll have to wait for @3x to see if this is entirely correct
    offsetY += (window.devicePixelRatio - 1) * previewHeight;
  }

  return {
    x: offsetX,
    y: offsetY
  };
}

function calculateDragPreviewSize(desiredSize) {
  var size = {
    width: desiredSize.width,
    height: desiredSize.height
  };

  if (isFirefox() || isSafari8OrNewer()) {
    size.width *= window.devicePixelRatio;
    size.height *= window.devicePixelRatio;
  }

  return size;
}

function configureDataTransfer(containerNode, nativeEvent, dragOptions) {
  var { dataTransfer } = nativeEvent,
      { dragPreview, effectAllowed, dragAnchors } = dragOptions;

  try {
    // Firefox won't drag without setting data
    dataTransfer.setData('application/json', {});
  } catch (err) {
    // IE doesn't support MIME types in setData
  }

  if (shouldUseDragPreview(dragPreview) && dataTransfer.setDragImage) {
    var dragOffset = getDragImageOffset(containerNode, dragPreview, dragAnchors, nativeEvent);
    dataTransfer.setDragImage(dragPreview, dragOffset.x, dragOffset.y);
  }

  dataTransfer.effectAllowed = effectAllowed;
}

var DragDropMixin = {
  getInitialState() {
    var state = {
      ownDraggedItemType: null,
      hasDragEntered: false
    };

    return merge(state, this.getStateFromDragDropStore());
  },

  getStateFromDragDropStore() {
    return {
      draggedItem: DragDropStore.getDraggedItem(),
      draggedItemType: DragDropStore.getDraggedItemType()
    };
  },

  getDragState(type) {
    invariant(this._dragSources[type], 'No drag source for %s', type);

    return {
      isDragging: this.state.ownDraggedItemType === type
    };
  },

  getDropState(type) {
    invariant(this._dropTargets[type], 'No drop target for %s', type);

    var isDragging = this.state.draggedItemType === type,
        acceptsType = this._dropTargets.hasOwnProperty(type) && type !== this.state.ownDraggedItemType,
        hasDragEntered = this.state.hasDragEntered;

    return {
      isDragging: isDragging && acceptsType,
      isHovering: isDragging && acceptsType && hasDragEntered
    };
  },

  componentWillMount() {
    this._dragEntered = [];
    this._dragSources = {};
    this._dropTargets = {};
    this.configureDragDrop(this.registerDragDropItemTypeHandlers);
  },

  componentDidMount() {
    DragDropStore.addChangeListener(this.handleDragDropStoreChange);
  },

  componentWillUnmount() {
    DragDropStore.removeChangeListener(this.handleDragDropStoreChange);
  },

  calculateDragPreviewSize: calculateDragPreviewSize,

  registerDragDropItemTypeHandlers(type, handlers) {
    var { dragSource, dropTarget } = handlers;

    if (dragSource) {
      invariant(!this._dragSources[type], 'Drag source for %s specified twice', type);
      this._dragSources[type] = bindAll(dragSource, this);
    }

    if (dropTarget) {
      invariant(!this._dropTargets[type], 'Drop target for %s specified twice', type);
      this._dropTargets[type] = bindAll(dropTarget, this);
    }
  },

  handleDragDropStoreChange() {
    this.setState(this.getStateFromDragDropStore());
  },

  dragSourceFor(type) {
    invariant(this._dragSources[type], 'No drag source for %s', type);

    // TODO: optimize by caching binds
    return {
      draggable: true,
      onDragStart: this.handleDragStart.bind(this, type),
      onDragEnd: this.handleDragEnd.bind(this, type)
    };
  },

  handleDragStart(type, e) {
    var { canDrag, beginDrag } = this._dragSources[type];

    if (canDrag && !canDrag(e)) {
      e.preventDefault();
      return;
    }

    var dragOptions = beginDrag(e),
        { item } = dragOptions;

    configureDataTransfer(this.getDOMNode(), e.nativeEvent, dragOptions);
    invariant(isObject(item), 'Expected return value of beginDrag to contain "item" object');

    this.setState({
      ownDraggedItemType: type
    });

    DragDropActionCreators.startDragging(type, item);
  },

  handleDragEnd(type, e) {
    this.setState({
      ownDraggedItemType: null
    });

    var { endDrag } = this._dragSources[type],
        didDrop = DragDropStore.didDrop();

    DragDropActionCreators.endDragging();

    if (endDrag) {
      endDrag(didDrop, e);
    }
  },

  dropTargetFor(...types) {
    types.forEach(type => {
      invariant(this._dropTargets[type], 'No drop target for %s', type);
    });

    // TODO: optimize by caching binds
    return {
      onDragEnter: this.handleDragEnter.bind(this, types),
      onDragOver: this.handleDragOver.bind(this, types),
      onDragLeave: this.handleDragLeave.bind(this, types),
      onDrop: this.handleDrop.bind(this, types)
    };
  },

  isDropTargetActive(types) {
    var { draggedItemType, ownDraggedItemType } = this.state;

    return types.indexOf(draggedItemType) > -1 &&
           draggedItemType !== ownDraggedItemType;
  },

  handleDragOver(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    e.preventDefault();

    var { over } = this._dropTargets[this.state.draggedItemType];
    if (over) {
      over(this.state.draggedItem, e);
    }
  },

  handleDragEnter(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    if (!this._dragEntered.length) {
      this.setState({
        hasDragEntered: true
      });

      var { enter } = this._dropTargets[this.state.draggedItemType];
      if (enter) {
        enter(this.state.draggedItem, e);
      }
    }

    this._dragEntered = union(this._dragEntered, [e.target]);
  },

  handleDragLeave(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    this._dragEntered = without(this._dragEntered, e.target);

    if (!this._dragEntered.length) {
      this.setState({
        hasDragEntered: false
      });

      var { leave } = this._dropTargets[this.state.draggedItemType];
      if (leave) {
        leave(this.state.draggedItem, e);
      }
    }
  },

  handleDrop(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    e.preventDefault();

    var item = DragDropStore.getDraggedItem(),
        { acceptDrop } = this._dropTargets[this.state.draggedItemType];

    this._dragEntered = [];
    this.setState({
      hasDragEntered: false
    });

    if (acceptDrop) {
      acceptDrop(item, e);
    }

    DragDropActionCreators.recordDrop();
  }
};

module.exports = DragDropMixin;<commit_msg>Fix cross-browser discrepancies (works on Chrome, Safari, FF, IE, both retina and not)<commit_after>'use strict';

var DragDropActionCreators = require('../actions/DragDropActionCreators'),
    DragDropStore = require('../stores/DragDropStore'),
    HorizontalDragAnchors = require('../constants/HorizontalDragAnchors'),
    VerticalDragAnchors = require('../constants/VerticalDragAnchors'),
    bindAll = require('../utils/bindAll'),
    invariant = require('react/lib/invariant'),
    merge = require('react/lib/merge'),
    union = require('lodash-node/modern/arrays/union'),
    without = require('lodash-node/modern/arrays/without'),
    isObject = require('lodash-node/modern/objects/isObject');

function endsWith(str, suffix) {
  return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

function isFirefox() {
  return /firefox/i.test(navigator.userAgent);
}

function isSafari() {
  return !!window.safari;
}

function shouldUseDragPreview(dragPreview) {
  if (!dragPreview) {
    return false;
  }

  if (isSafari() && dragPreview instanceof Image && endsWith(dragPreview.src, '.gif')) {
    // GIFs crash Safari
    return false;
  }

  return true;
}

/**
 * Returns offset to be used as arguments for `dataTransfer.setDragImage(dragImage, x, y)`.
 * Attempts to work around browser differences, especially on high-DPI screens.
 */
function getDragImageOffset(containerNode, dragPreview, dragAnchors, e) {
  dragAnchors = dragAnchors || {};

  var containerWidth = containerNode.offsetWidth,
      containerHeight = containerNode.offsetHeight,
      isImage = dragPreview instanceof Image,
      previewWidth = isImage ? dragPreview.width : containerWidth,
      previewHeight = isImage ? dragPreview.height : containerHeight,
      horizontalAnchor = dragAnchors.horizontal || HorizontalDragAnchors.CENTER,
      verticalAnchor = dragAnchors.vertical || VerticalDragAnchors.CENTER,
      { offsetX, offsetY } = e;

  // Work around @2x coordinate discrepancies in browsers
  if (isFirefox()) {
    offsetX = e.layerX;
    offsetY = e.layerY;
  } else if (isSafari()) {
    previewHeight /= window.devicePixelRatio;
    previewWidth /= window.devicePixelRatio;
  }

  switch (horizontalAnchor) {
  case HorizontalDragAnchors.LEFT:
    break;
  case HorizontalDragAnchors.CENTER:
    offsetX *= (previewWidth / containerWidth);
    break;
  case HorizontalDragAnchors.RIGHT:
    offsetX = previewWidth - previewWidth * (1 - offsetX / containerWidth);
    break;
  }

  switch (verticalAnchor) {
  case VerticalDragAnchors.TOP:
    break;
  case VerticalDragAnchors.CENTER:
    offsetY *= (previewHeight / containerHeight);
    break;
  case VerticalDragAnchors.BOTTOM:
    offsetY = previewHeight - previewHeight * (1 - offsetY / containerHeight);
    break;
  }

  // Work around Safari 8 positioning bug
  if (isSafari()) {
    // We'll have to wait for @3x to see if this is entirely correct
    offsetY += (window.devicePixelRatio - 1) * previewHeight;
  }

  return {
    x: offsetX,
    y: offsetY
  };
}

function calculateDragPreviewSize(desiredSize) {
  var size = {
    width: desiredSize.width,
    height: desiredSize.height
  };

  if (isFirefox() || isSafari()) {
    size.width *= window.devicePixelRatio;
    size.height *= window.devicePixelRatio;
  }

  return size;
}

function configureDataTransfer(containerNode, nativeEvent, dragOptions) {
  var { dataTransfer } = nativeEvent,
      { dragPreview, effectAllowed, dragAnchors } = dragOptions;

  try {
    // Firefox won't drag without setting data
    dataTransfer.setData('application/json', {});
  } catch (err) {
    // IE doesn't support MIME types in setData
  }

  if (shouldUseDragPreview(dragPreview) && dataTransfer.setDragImage) {
    var dragOffset = getDragImageOffset(containerNode, dragPreview, dragAnchors, nativeEvent);
    dataTransfer.setDragImage(dragPreview, dragOffset.x, dragOffset.y);
  }

  dataTransfer.effectAllowed = effectAllowed;
}

var DragDropMixin = {
  getInitialState() {
    var state = {
      ownDraggedItemType: null,
      hasDragEntered: false
    };

    return merge(state, this.getStateFromDragDropStore());
  },

  getStateFromDragDropStore() {
    return {
      draggedItem: DragDropStore.getDraggedItem(),
      draggedItemType: DragDropStore.getDraggedItemType()
    };
  },

  getDragState(type) {
    invariant(this._dragSources[type], 'No drag source for %s', type);

    return {
      isDragging: this.state.ownDraggedItemType === type
    };
  },

  getDropState(type) {
    invariant(this._dropTargets[type], 'No drop target for %s', type);

    var isDragging = this.state.draggedItemType === type,
        acceptsType = this._dropTargets.hasOwnProperty(type) && type !== this.state.ownDraggedItemType,
        hasDragEntered = this.state.hasDragEntered;

    return {
      isDragging: isDragging && acceptsType,
      isHovering: isDragging && acceptsType && hasDragEntered
    };
  },

  componentWillMount() {
    this._dragEntered = [];
    this._dragSources = {};
    this._dropTargets = {};
    this.configureDragDrop(this.registerDragDropItemTypeHandlers);
  },

  componentDidMount() {
    DragDropStore.addChangeListener(this.handleDragDropStoreChange);
  },

  componentWillUnmount() {
    DragDropStore.removeChangeListener(this.handleDragDropStoreChange);
  },

  calculateDragPreviewSize: calculateDragPreviewSize,

  registerDragDropItemTypeHandlers(type, handlers) {
    var { dragSource, dropTarget } = handlers;

    if (dragSource) {
      invariant(!this._dragSources[type], 'Drag source for %s specified twice', type);
      this._dragSources[type] = bindAll(dragSource, this);
    }

    if (dropTarget) {
      invariant(!this._dropTargets[type], 'Drop target for %s specified twice', type);
      this._dropTargets[type] = bindAll(dropTarget, this);
    }
  },

  handleDragDropStoreChange() {
    this.setState(this.getStateFromDragDropStore());
  },

  dragSourceFor(type) {
    invariant(this._dragSources[type], 'No drag source for %s', type);

    // TODO: optimize by caching binds
    return {
      draggable: true,
      onDragStart: this.handleDragStart.bind(this, type),
      onDragEnd: this.handleDragEnd.bind(this, type)
    };
  },

  handleDragStart(type, e) {
    var { canDrag, beginDrag } = this._dragSources[type];

    if (canDrag && !canDrag(e)) {
      e.preventDefault();
      return;
    }

    var dragOptions = beginDrag(e),
        { item } = dragOptions;

    configureDataTransfer(this.getDOMNode(), e.nativeEvent, dragOptions);
    invariant(isObject(item), 'Expected return value of beginDrag to contain "item" object');

    this.setState({
      ownDraggedItemType: type
    });

    DragDropActionCreators.startDragging(type, item);
  },

  handleDragEnd(type, e) {
    this.setState({
      ownDraggedItemType: null
    });

    var { endDrag } = this._dragSources[type],
        didDrop = DragDropStore.didDrop();

    DragDropActionCreators.endDragging();

    if (endDrag) {
      endDrag(didDrop, e);
    }
  },

  dropTargetFor(...types) {
    types.forEach(type => {
      invariant(this._dropTargets[type], 'No drop target for %s', type);
    });

    // TODO: optimize by caching binds
    return {
      onDragEnter: this.handleDragEnter.bind(this, types),
      onDragOver: this.handleDragOver.bind(this, types),
      onDragLeave: this.handleDragLeave.bind(this, types),
      onDrop: this.handleDrop.bind(this, types)
    };
  },

  isDropTargetActive(types) {
    var { draggedItemType, ownDraggedItemType } = this.state;

    return types.indexOf(draggedItemType) > -1 &&
           draggedItemType !== ownDraggedItemType;
  },

  handleDragOver(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    e.preventDefault();

    var { over } = this._dropTargets[this.state.draggedItemType];
    if (over) {
      over(this.state.draggedItem, e);
    }
  },

  handleDragEnter(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    if (!this._dragEntered.length) {
      this.setState({
        hasDragEntered: true
      });

      var { enter } = this._dropTargets[this.state.draggedItemType];
      if (enter) {
        enter(this.state.draggedItem, e);
      }
    }

    this._dragEntered = union(this._dragEntered, [e.target]);
  },

  handleDragLeave(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    this._dragEntered = without(this._dragEntered, e.target);

    if (!this._dragEntered.length) {
      this.setState({
        hasDragEntered: false
      });

      var { leave } = this._dropTargets[this.state.draggedItemType];
      if (leave) {
        leave(this.state.draggedItem, e);
      }
    }
  },

  handleDrop(types, e) {
    if (!this.isDropTargetActive(types)) {
      return;
    }

    e.preventDefault();

    var item = DragDropStore.getDraggedItem(),
        { acceptDrop } = this._dropTargets[this.state.draggedItemType];

    this._dragEntered = [];
    this.setState({
      hasDragEntered: false
    });

    if (acceptDrop) {
      acceptDrop(item, e);
    }

    DragDropActionCreators.recordDrop();
  }
};

module.exports = DragDropMixin;<|endoftext|>


<commit_before>/**
 * @module ol/source/Zoomify
 */
import {DEFAULT_TILE_SIZE} from '../tilegrid/common.js';

import ImageTile from '../ImageTile.js';
import TileState from '../TileState.js';
import {expandUrl, createFromTileUrlFunctions} from '../tileurlfunction.js';
import {assert} from '../asserts.js';
import {createCanvasContext2D} from '../dom.js';
import {getTopLeft} from '../extent.js';
import {toSize} from '../size.js';
import TileImage from './TileImage.js';
import TileGrid from '../tilegrid/TileGrid.js';

/**
 * @enum {string}
 */
const TierSizeCalculation = {
  DEFAULT: 'default',
  TRUNCATED: 'truncated'
};

export class CustomTile extends ImageTile {

  /**
   * @param {import("../tilegrid/TileGrid.js").default} tileGrid TileGrid that the tile belongs to.
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {TileState} state State.
   * @param {string} src Image source URI.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @param {import("../Tile.js").Options=} opt_options Tile options.
   */
  constructor(tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {

    super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);

    /**
     * @private
     * @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
     */
    this.zoomifyImage_ = null;

    /**
     * @private
     * @type {import("../size.js").Size}
     */
    this.tileSize_ = toSize(tileGrid.getTileSize(tileCoord[0]));

  }

  /**
   * @inheritDoc
   */
  getImage() {
    if (this.zoomifyImage_) {
      return this.zoomifyImage_;
    }
    const image = super.getImage();
    if (this.state == TileState.LOADED) {
      const tileSize = this.tileSize_;
      if (image.width == tileSize[0] && image.height == tileSize[1]) {
        this.zoomifyImage_ = image;
        return image;
      } else {
        const context = createCanvasContext2D(tileSize[0], tileSize[1]);
        context.drawImage(image, 0, 0);
        this.zoomifyImage_ = context.canvas;
        return context.canvas;
      }
    } else {
      return image;
    }
  }

}

/**
 * @typedef {Object} Options
 * @property {import("./Source.js").AttributionLike} [attributions] Attributions.
 * @property {number} [cacheSize=2048] Cache size.
 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images.  Note that
 * you must provide a `crossOrigin` value  you want to access pixel data with the Canvas renderer.
 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
 * @property {import("../proj.js").ProjectionLike} [projection] Projection.
 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
 * Higher values can increase reprojection performance, but decrease precision.
 * @property {string} [url] URL template or base URL of the Zoomify service.
 * A base URL is the fixed part
 * of the URL, excluding the tile group, z, x, and y folder structure, e.g.
 * `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
 * `{TileGroup}`, `{x}`, `{y}`, and `{z}` placeholders, e.g.
 * `http://my.zoomify.info/IMAGE.TIF/{TileGroup}/{z}-{x}-{y}.jpg`.
 * Internet Imaging Protocol (IIP) with JTL extension can be also used with
 * `{tileIndex}` and `{z}` placeholders, e.g.
 * `http://my.zoomify.info?FIF=IMAGE.TIF&JTL={z},{tileIndex}`.
 * A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
 * used instead of defining each one separately in the `urls` option.
 * @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
 * @property {import("../size.js").Size} [size] Size of the image.
 * @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
 * Default sets the TileGrid in the
 * fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
 * extent to the first quadrant (the default for OpenLayers 2) set the extent
 * as `[0, 0, width, height]`.
 * @property {number} [transition] Duration of the opacity transition for rendering.
 * To disable the opacity transition, pass `transition: 0`.
 * @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
 */

/**
 * @classdesc
 * Layer source for tile data in Zoomify format (both Zoomify and Internet
 * Imaging Protocol are supported).
 * @api
 */
class Zoomify extends TileImage {

  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    const options = opt_options || {};

    const size = options.size;
    const tierSizeCalculation = options.tierSizeCalculation !== undefined ?
      options.tierSizeCalculation :
      TierSizeCalculation.DEFAULT;

    const imageWidth = size[0];
    const imageHeight = size[1];
    const extent = options.extent || [0, -size[1], size[0], 0];
    const tierSizeInTiles = [];
    const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
    let tileSizeForTierSizeCalculation = tileSize;

    switch (tierSizeCalculation) {
      case TierSizeCalculation.DEFAULT:
        while (imageWidth > tileSizeForTierSizeCalculation || imageHeight > tileSizeForTierSizeCalculation) {
          tierSizeInTiles.push([
            Math.ceil(imageWidth / tileSizeForTierSizeCalculation),
            Math.ceil(imageHeight / tileSizeForTierSizeCalculation)
          ]);
          tileSizeForTierSizeCalculation += tileSizeForTierSizeCalculation;
        }
        break;
      case TierSizeCalculation.TRUNCATED:
        let width = imageWidth;
        let height = imageHeight;
        while (width > tileSizeForTierSizeCalculation || height > tileSizeForTierSizeCalculation) {
          tierSizeInTiles.push([
            Math.ceil(width / tileSizeForTierSizeCalculation),
            Math.ceil(height / tileSizeForTierSizeCalculation)
          ]);
          width >>= 1;
          height >>= 1;
        }
        break;
      default:
        assert(false, 53); // Unknown `tierSizeCalculation` configured
        break;
    }

    tierSizeInTiles.push([1, 1]);
    tierSizeInTiles.reverse();

    const resolutions = [1];
    const tileCountUpToTier = [0];
    for (let i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
      resolutions.push(1 << i);
      tileCountUpToTier.push(
        tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
          tileCountUpToTier[i - 1]
      );
    }
    resolutions.reverse();

    const tileGrid = new TileGrid({
      tileSize: tileSize,
      extent: extent,
      origin: getTopLeft(extent),
      resolutions: resolutions
    });

    let url = options.url;
    if (url && url.indexOf('{TileGroup}') == -1 && url.indexOf('{tileIndex}') == -1) {
      url += '{TileGroup}/{z}-{x}-{y}.jpg';
    }
    const urls = expandUrl(url);

    /**
     * @param {string} template Template.
     * @return {import("../Tile.js").UrlFunction} Tile URL function.
     */
    function createFromTemplate(template) {

      return (
        /**
         * @param {import("../tilecoord.js").TileCoord} tileCoord Tile Coordinate.
         * @param {number} pixelRatio Pixel ratio.
         * @param {import("../proj/Projection.js").default} projection Projection.
         * @return {string|undefined} Tile URL.
         */
        function(tileCoord, pixelRatio, projection) {
          if (!tileCoord) {
            return undefined;
          } else {
            const tileCoordZ = tileCoord[0];
            const tileCoordX = tileCoord[1];
            const tileCoordY = tileCoord[2];
            const tileIndex =
                tileCoordX +
                tileCoordY * tierSizeInTiles[tileCoordZ][0];
            const tileSize = tileGrid.getTileSize(tileCoordZ);
            const tileWidth = Array.isArray(tileSize) ? tileSize[0] : tileSize;
            const tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / tileWidth) | 0;
            const localContext = {
              'z': tileCoordZ,
              'x': tileCoordX,
              'y': tileCoordY,
              'tileIndex': tileIndex,
              'TileGroup': 'TileGroup' + tileGroup
            };
            return template.replace(/\{(\w+?)\}/g, function(m, p) {
              return localContext[p];
            });
          }
        }
      );
    }

    const tileUrlFunction = createFromTileUrlFunctions(urls.map(createFromTemplate));

    const ZoomifyTileClass = CustomTile.bind(null, tileGrid);

    super({
      attributions: options.attributions,
      cacheSize: options.cacheSize,
      crossOrigin: options.crossOrigin,
      projection: options.projection,
      tilePixelRatio: options.tilePixelRatio,
      reprojectionErrorThreshold: options.reprojectionErrorThreshold,
      tileClass: ZoomifyTileClass,
      tileGrid: tileGrid,
      tileUrlFunction: tileUrlFunction,
      transition: options.transition
    });

  }

}

export default Zoomify;
<commit_msg>Update Zoomify.js<commit_after>/**
 * @module ol/source/Zoomify
 */
import {DEFAULT_TILE_SIZE} from '../tilegrid/common.js';

import ImageTile from '../ImageTile.js';
import TileState from '../TileState.js';
import {expandUrl, createFromTileUrlFunctions} from '../tileurlfunction.js';
import {assert} from '../asserts.js';
import {createCanvasContext2D} from '../dom.js';
import {getTopLeft} from '../extent.js';
import {toSize} from '../size.js';
import TileImage from './TileImage.js';
import TileGrid from '../tilegrid/TileGrid.js';

/**
 * @enum {string}
 */
const TierSizeCalculation = {
  DEFAULT: 'default',
  TRUNCATED: 'truncated'
};

export class CustomTile extends ImageTile {

  /**
   * @param {import("../tilegrid/TileGrid.js").default} tileGrid TileGrid that the tile belongs to.
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {TileState} state State.
   * @param {string} src Image source URI.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @param {import("../Tile.js").Options=} opt_options Tile options.
   */
  constructor(tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {

    super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);

    /**
     * @private
     * @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
     */
    this.zoomifyImage_ = null;

    /**
     * @private
     * @type {import("../size.js").Size}
     */
    this.tileSize_ = toSize(tileGrid.getTileSize(tileCoord[0]));

  }

  /**
   * @inheritDoc
   */
  getImage() {
    if (this.zoomifyImage_) {
      return this.zoomifyImage_;
    }
    const image = super.getImage();
    if (this.state == TileState.LOADED) {
      const tileSize = this.tileSize_;
      if (image.width == tileSize[0] && image.height == tileSize[1]) {
        this.zoomifyImage_ = image;
        return image;
      } else {
        const context = createCanvasContext2D(tileSize[0], tileSize[1]);
        context.drawImage(image, 0, 0);
        this.zoomifyImage_ = context.canvas;
        return context.canvas;
      }
    } else {
      return image;
    }
  }

}

/**
 * @typedef {Object} Options
 * @property {import("./Source.js").AttributionLike} [attributions] Attributions.
 * @property {number} [cacheSize=2048] Cache size.
 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images.  Note that
 * you must provide a `crossOrigin` value  you want to access pixel data with the Canvas renderer.
 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
 * @property {import("../proj.js").ProjectionLike} [projection] Projection.
 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
 * Higher values can increase reprojection performance, but decrease precision.
 * @property {string} [url] URL template or base URL of the Zoomify service.
 * A base URL is the fixed part
 * of the URL, excluding the tile group, z, x, and y folder structure, e.g.
 * `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
 * `{TileGroup}`, `{x}`, `{y}`, and `{z}` placeholders, e.g.
 * `http://my.zoomify.info/IMAGE.TIF/{TileGroup}/{z}-{x}-{y}.jpg`.
 * Internet Imaging Protocol (IIP) with JTL extension can be also used with
 * `{tileIndex}` and `{z}` placeholders, e.g.
 * `http://my.zoomify.info?FIF=IMAGE.TIF&JTL={z},{tileIndex}`.
 * A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
 * used instead of defining each one separately in the `urls` option.
 * @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
 * @property {import("../size.js").Size} [size] Size of the image.
 * @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
 * Default sets the TileGrid in the
 * fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
 * extent to the first quadrant (the default for OpenLayers 2) set the extent
 * as `[0, 0, width, height]`.
 * @property {number} [transition] Duration of the opacity transition for rendering.
 * To disable the opacity transition, pass `transition: 0`.
 * @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
 */

/**
 * @classdesc
 * Layer source for tile data in Zoomify format (both Zoomify and Internet
 * Imaging Protocol are supported).
 * @api
 */
class Zoomify extends TileImage {

  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    const options = opt_options || {};

    const size = options.size;
    const tierSizeCalculation = options.tierSizeCalculation !== undefined ?
      options.tierSizeCalculation :
      TierSizeCalculation.DEFAULT;

    const imageWidth = size[0];
    const imageHeight = size[1];
    const extent = options.extent || [0, -size[1], size[0], 0];
    const tierSizeInTiles = [];
    const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
    let tileSizeForTierSizeCalculation = tileSize;

    switch (tierSizeCalculation) {
      case TierSizeCalculation.DEFAULT:
        while (imageWidth > tileSizeForTierSizeCalculation || imageHeight > tileSizeForTierSizeCalculation) {
          tierSizeInTiles.push([
            Math.ceil(imageWidth / tileSizeForTierSizeCalculation),
            Math.ceil(imageHeight / tileSizeForTierSizeCalculation)
          ]);
          tileSizeForTierSizeCalculation += tileSizeForTierSizeCalculation;
        }
        break;
      case TierSizeCalculation.TRUNCATED:
        let width = imageWidth;
        let height = imageHeight;
        while (width > tileSizeForTierSizeCalculation || height > tileSizeForTierSizeCalculation) {
          tierSizeInTiles.push([
            Math.ceil(width / tileSizeForTierSizeCalculation),
            Math.ceil(height / tileSizeForTierSizeCalculation)
          ]);
          width >>= 1;
          height >>= 1;
        }
        break;
      default:
        assert(false, 53); // Unknown `tierSizeCalculation` configured
        break;
    }

    tierSizeInTiles.push([1, 1]);
    tierSizeInTiles.reverse();

    const resolutions = [1];
    const tileCountUpToTier = [0];
    for (let i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
      resolutions.push(1 << i);
      tileCountUpToTier.push(
        tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
          tileCountUpToTier[i - 1]
      );
    }
    resolutions.reverse();

    const tileGrid = new TileGrid({
      tileSize: tileSize,
      extent: extent,
      origin: getTopLeft(extent),
      resolutions: resolutions
    });

    let url = options.url;
    if (url && url.indexOf('{TileGroup}') == -1 && url.indexOf('{tileIndex}') == -1) {
      url += '{TileGroup}/{z}-{x}-{y}.jpg';
    }
    const urls = expandUrl(url);

    /**
     * @param {string} template Template.
     * @return {import("../Tile.js").UrlFunction} Tile URL function.
     */
    function createFromTemplate(template) {

      return (
        /**
         * @param {import("../tilecoord.js").TileCoord} tileCoord Tile Coordinate.
         * @param {number} pixelRatio Pixel ratio.
         * @param {import("../proj/Projection.js").default} projection Projection.
         * @return {string|undefined} Tile URL.
         */
        function(tileCoord, pixelRatio, projection) {
          if (!tileCoord) {
            return undefined;
          } else {
            const tileCoordZ = tileCoord[0];
            const tileCoordX = tileCoord[1];
            const tileCoordY = tileCoord[2];
            const tileIndex =
                tileCoordX +
                tileCoordY * tierSizeInTiles[tileCoordZ][0];
            const tileSize = tileGrid.getTileSize(tileCoordZ);
            const tileWidth = Array.isArray(tileSize) ? tileSize[0] : tileSize;
            const tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / tileWidth) | 0;
            const localContext = {
              'z': tileCoordZ,
              'x': tileCoordX,
              'y': tileCoordY,
              'tileIndex': tileIndex,
              'TileGroup': 'TileGroup' + tileGroup
            };
            return template.replace(/\{(\w+?)\}/g, function(m, p) {
              return localContext[p];
            });
          }
        }
      );
    }

    const tileUrlFunction = createFromTileUrlFunctions(urls.map(createFromTemplate));

    const ZoomifyTileClass = CustomTile.bind(null, tileGrid);

    super({
      attributions: options.attributions,
      cacheSize: options.cacheSize,
      crossOrigin: options.crossOrigin,
      projection: options.projection,
      tilePixelRatio: options.tilePixelRatio,
      reprojectionErrorThreshold: options.reprojectionErrorThreshold,
      tileClass: ZoomifyTileClass,
      tileGrid: tileGrid,
      tileUrlFunction: tileUrlFunction,
      transition: options.transition
    });

    console.log("ollll1",this.tilePixelRatio_)
    console.log("ollll2",this._tilePixelRatio)
    console.log("ollll3",this.tilePixelRatio)

  }

}

export default Zoomify;
<|endoftext|>


<commit_before>/*
 * 1) config.js
 * 2) remplacer dans ezseed.json
 * 3) créer tmp
 * 4) installer client ? => ezseed install
 * 5) ajouter admin ?
 * 6) gulp + test + pm2 ??
 */

var p = require('path')
  , logger = require('../lib/logger')
  , fs = require('fs')
  , i18n = require('i18n')
  , config = require('../config/config-sample')
  , config_path = p.join(p.resolve(__dirname, '../config'), 'config.js')

if(process.getuid() !== 0) {
	logger.error('Sorry but this needs to be run as root. Exiting.')
		process.exit(1)
}

require('./helpers/ascii').print()

require('./inquirer/config')
.then(function(answers) {

	for(var answer in answers) {
		config[answer] = answers[answer]
	}

	logger.info('Installing server...')
	return require('./commands/install').server('localhost:'+answers.port)
})
.catch(function(code) {
	logger.error('server.sh bad exit code', code)
})
.then(function() {
	return require('./inquirer/client')
})
.then(function(client) {
	return require('./commands/install').client(client)
})
.then(function() {

	if(fs.existsSync(config_path)) {
		logger.error(i18n.__('%s already exists', config_path))
	} else {
		fs.writeFileSync(config_path, 'module.exports = '+JSON.stringify(config))
		logger.info(i18n.__('Configuration saved in %s', config_path))
	}
	console.log('test')

})<commit_msg>Write permissions config file Wrong upstream<commit_after>/*
 * 1) config.js
 * 2) remplacer dans ezseed.json
 * 3) créer tmp
 * 4) installer client ? => ezseed install
 * 5) ajouter admin ?
 * 6) gulp + test + pm2 ??
 */

var p = require('path')
  , logger = require('../lib/logger')
  , fs = require('fs')
  , i18n = require('i18n')
  , config = require('../config/config-sample')
  , config_path = p.join(p.resolve(__dirname, '../config'), 'config.js')

if(process.getuid() !== 0) {
	logger.error('Sorry but this needs to be run as root. Exiting.')
		process.exit(1)
}

require('./helpers/ascii').print()

require('./inquirer/config')
.then(function(answers) {

	for(var answer in answers) {
		config[answer] = answers[answer]
	}

	logger.info('Installing server...')
	return require('./commands/install').server('http://localhost:'+answers.port)
})
.catch(function(code) {
	logger.error('server.sh bad exit code', code)
})
.then(function() {
	return require('./inquirer/client')
})
.then(function(client) {
	return require('./commands/install').client(client)
})
.then(function() {

	if(fs.existsSync(config_path)) {
		logger.error(i18n.__('%s already exists', config_path))
	} else {
		fs.writeFileSync(config_path, 'module.exports = '+JSON.stringify(config), {mode: 664})
		logger.info(i18n.__('Configuration saved in %s', config_path))
	}
	console.log('test')

})<|endoftext|>


<commit_before>;(function($, window, undefined) {
  'use strict'

  // register namespace
  $.extend(true, window, {
    CADC: {
      RowSelectionModel: CADCRowSelectionModel
    }
  })

  function CADCRowSelectionModel(options) {
    var _grid
    var _ranges = []
    var _self = this
    var _handler = new Slick.EventHandler()
    var _inHandler
    var _options
    var _defaults = {
      selectActiveRow: true,
      selectClickedRow: false,
      propagateEvents: false
    }

    function init(grid) {
      _options = $.extend(true, {}, _defaults, options)
      _grid = grid
      _handler.subscribe(
        _grid.onActiveCellChanged,
        wrapHandler(handleActiveCellChange)
      )
      _handler.subscribe(_grid.onKeyDown, wrapHandler(handleKeyDown))
      _handler.subscribe(_grid.onClick, wrapHandler(handleClick))
    }

    function destroy() {
      _handler.unsubscribeAll()
    }

    function wrapHandler(handler) {
      return function() {
        if (!_inHandler) {
          _inHandler = true
          handler.apply(this, arguments)
          _inHandler = false
        }
      }
    }

    function rangesToRows(ranges) {
      var rows = []
      for (var i = 0; i < ranges.length; i++) {
        for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
          rows.push(j)
        }
      }
      return rows
    }

    function rowsToRanges(rows) {
      var ranges = []
      var lastCell = _grid.getColumns().length - 1
      for (var i = 0; i < rows.length; i++) {
        ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell))
      }
      return ranges
    }

    function getRowsRange(from, to) {
      var i,
        rows = []
      for (i = from; i <= to; i++) {
        rows.push(i)
      }
      for (i = to; i < from; i++) {
        rows.push(i)
      }
      return rows
    }

    function getSelectedRows() {
      return rangesToRows(_ranges)
    }

    function setSelectedRows(rows) {
      setSelectedRanges(rowsToRanges(rows))
    }

    function setSelectedRanges(ranges) {
      _ranges = ranges
      _self.onSelectedRangesChanged.notify(_ranges)
    }

    function getSelectedRanges() {
      return _ranges
    }

    function refreshSelectedRanges() {
      var rowsFromRanges = getSelectedRows()
      setSelectedRows(rowsFromRanges)
    }

    function isCellSelectable(cell) {
      return (
        _grid.getDataItem(cell.row)[cadc.vot.ROW_SELECT_DISABLED_KEY] !== true
      )
    }

    function handleActiveCellChange(e, data) {
      if (_options.selectActiveRow && data.row != null) {
        setSelectedRanges([
          new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)
        ])
      }
    }

    function handleKeyDown(e) {
      var activeRow = _grid.getActiveCell()
      if (
        activeRow &&
        e.shiftKey &&
        !e.ctrlKey &&
        !e.altKey &&
        !e.metaKey &&
        (e.which === 38 || e.which === 40)
      ) {
        var selectedRows = getSelectedRows()
        selectedRows.sort(function(x, y) {
          return x - y
        })

        if (!selectedRows.length) {
          selectedRows = [activeRow.row]
        }

        var top = selectedRows[0]
        var bottom = selectedRows[selectedRows.length - 1]
        var active

        if (e.which === 40) {
          active = activeRow.row < bottom || top == bottom ? ++bottom : ++top
        } else {
          active = activeRow.row < bottom ? --bottom : --top
        }

        if (active >= 0 && active < _grid.getDataLength()) {
          _grid.scrollRowIntoView(active)
          _ranges = rowsToRanges(getRowsRange(top, bottom))
          setSelectedRanges(_ranges)
        }

        e.preventDefault()
        e.stopPropagation()
      }
    }

    function isTargetAllowRowSelection($target) {
      return !$target.hasClass('no-row-select')
    }

    function handleClick(e) {
      // Enable highlighting of the selected row.
      _grid.getOptions().enableCellNavigation = true

      var cell = _grid.getCellFromEvent(e)
      var $target = $(e.target)

      if (
        cell &&
        _grid.canCellBeActive(cell.row, cell.cell) &&
        isCellSelectable(cell)
      ) {
        var selection = rangesToRows(_ranges)
        var idx = $.inArray(cell.row, selection)
        var activeCell = _grid.getActiveCell()

        if (_grid.getOptions().multiSelect) {
          if (idx === -1) {
            // not selected
            if (activeCell && activeCell.row === cell.row && cell.cell !== 0) {
              _grid.resetActiveCell()
            } else {
              selection.push(cell.row)
              _grid.setActiveCell(cell.row, cell.cell)
            }
          } else if (idx !== -1) {
            // un-check the checkbox
            selection = $.grep(selection, function(o, i) {
              return o !== cell.row
            })
            _grid.setActiveCell(cell.row, cell.cell)
          } else if (selection.length) {
            var last = selection.pop()
            var from = Math.min(cell.row, last)
            var to = Math.max(cell.row, last)
            selection = []
            for (var i = from; i <= to; i++) {
              if (i !== last) {
                selection.push(i)
              }
            }
            selection.push(last)
            _grid.setActiveCell(cell.row, cell.cell)
          }
        }

        var shouldNotPropagate =
          _options.propagateEvents === false ||
          $target.is(':checkbox') ||
          $target.hasClass('no-propagate-event')

        if (
          $target.is(':checkbox') ||
          (_options.selectClickedRow && isTargetAllowRowSelection($target))
        ) {
          _ranges = rowsToRanges(selection)
          setSelectedRanges(_ranges)
        }

        if (shouldNotPropagate) {
          e.stopImmediatePropagation()
        }
      } else {
        // Disable highlighting of the selected row.
        _grid.getOptions().enableCellNavigation = false
      }

      return false
    }

    $.extend(this, {
      getSelectedRows: getSelectedRows,
      setSelectedRows: setSelectedRows,

      getSelectedRanges: getSelectedRanges,
      setSelectedRanges: setSelectedRanges,

      refreshSelectedRanges: refreshSelectedRanges,

      init: init,
      destroy: destroy,

      onSelectedRangesChanged: new Slick.Event()
    })
  }
})(jQuery, window)
<commit_msg>Updates to how clicks are passed to the grid.<commit_after>;(function($, window, undefined) {
  'use strict'

  // register namespace
  $.extend(true, window, {
    CADC: {
      RowSelectionModel: CADCRowSelectionModel
    }
  })

  function CADCRowSelectionModel(options) {
    var _grid
    var _ranges = []
    var _self = this
    var _handler = new Slick.EventHandler()
    var _inHandler
    var _options
    var _defaults = {
      selectActiveRow: true,
      selectClickedRow: false,
      propagateEvents: false
    }

    function init(grid) {
      _options = $.extend(true, {}, _defaults, options)
      _grid = grid
      _handler.subscribe(
        _grid.onActiveCellChanged,
        wrapHandler(handleActiveCellChange)
      )
      _handler.subscribe(_grid.onKeyDown, wrapHandler(handleKeyDown))
      _handler.subscribe(_grid.onClick, wrapHandler(handleClick))
    }

    function destroy() {
      _handler.unsubscribeAll()
    }

    function wrapHandler(handler) {
      return function() {
        if (!_inHandler) {
          _inHandler = true
          handler.apply(this, arguments)
          _inHandler = false
        }
      }
    }

    function rangesToRows(ranges) {
      var rows = []
      for (var i = 0; i < ranges.length; i++) {
        for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
          rows.push(j)
        }
      }
      return rows
    }

    function rowsToRanges(rows) {
      var ranges = []
      var lastCell = _grid.getColumns().length - 1
      for (var i = 0; i < rows.length; i++) {
        ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell))
      }
      return ranges
    }

    function getRowsRange(from, to) {
      var i,
        rows = []
      for (i = from; i <= to; i++) {
        rows.push(i)
      }
      for (i = to; i < from; i++) {
        rows.push(i)
      }
      return rows
    }

    function getSelectedRows() {
      return rangesToRows(_ranges)
    }

    function setSelectedRows(rows) {
      setSelectedRanges(rowsToRanges(rows))
    }

    function setSelectedRanges(ranges) {
      _ranges = ranges
      _self.onSelectedRangesChanged.notify(_ranges)
    }

    function getSelectedRanges() {
      return _ranges
    }

    function refreshSelectedRanges() {
      var rowsFromRanges = getSelectedRows()
      setSelectedRows(rowsFromRanges)
    }

    function isCellSelectable(cell) {
      return (
        _grid.getDataItem(cell.row)[cadc.vot.ROW_SELECT_DISABLED_KEY] !== true
      )
    }

    function handleActiveCellChange(e, data) {
      if (_options.selectActiveRow && data.row != null) {
        setSelectedRanges([
          new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)
        ])
      }
    }

    function handleKeyDown(e) {
      var activeRow = _grid.getActiveCell()
      if (
        activeRow &&
        e.shiftKey &&
        !e.ctrlKey &&
        !e.altKey &&
        !e.metaKey &&
        (e.which === 38 || e.which === 40)
      ) {
        var selectedRows = getSelectedRows()
        selectedRows.sort(function(x, y) {
          return x - y
        })

        if (!selectedRows.length) {
          selectedRows = [activeRow.row]
        }

        var top = selectedRows[0]
        var bottom = selectedRows[selectedRows.length - 1]
        var active

        if (e.which === 40) {
          active = activeRow.row < bottom || top == bottom ? ++bottom : ++top
        } else {
          active = activeRow.row < bottom ? --bottom : --top
        }

        if (active >= 0 && active < _grid.getDataLength()) {
          _grid.scrollRowIntoView(active)
          _ranges = rowsToRanges(getRowsRange(top, bottom))
          setSelectedRanges(_ranges)
        }

        e.preventDefault()
        e.stopPropagation()
      }
    }

    function isTargetAllowRowSelection($target) {
      return !$target.hasClass('no-row-select')
    }

    function handleClick(e) {
      // Enable highlighting of the selected row.
      _grid.getOptions().enableCellNavigation = true

      var cell = _grid.getCellFromEvent(e)
      var $target = $(e.target)

      if (
        cell &&
        _grid.canCellBeActive(cell.row, cell.cell) &&
        isCellSelectable(cell)
      ) {
        var selection = rangesToRows(_ranges)
        var idx = $.inArray(cell.row, selection)
        var activeCell = _grid.getActiveCell()

        if (_grid.getOptions().multiSelect) {
          if (idx === -1) {
            // not selected
            if (activeCell && activeCell.row === cell.row && cell.cell !== 0) {
              _grid.resetActiveCell()
            } else {
              selection.push(cell.row)
              _grid.setActiveCell(cell.row, cell.cell)
            }
          } else if (idx !== -1) {
            // un-check the checkbox
            selection = $.grep(selection, function(o, i) {
              return o !== cell.row
            })
            _grid.setActiveCell(cell.row, cell.cell)
          } else if (selection.length) {
            var last = selection.pop()
            var from = Math.min(cell.row, last)
            var to = Math.max(cell.row, last)
            selection = []
            for (var i = from; i <= to; i++) {
              if (i !== last) {
                selection.push(i)
              }
            }
            selection.push(last)
            _grid.setActiveCell(cell.row, cell.cell)
          }
        }

        if ($target.is(':checkbox')) {
          _ranges = rowsToRanges(selection)
          setSelectedRanges(_ranges)
        } else {
          e.stopImmediatePropagation()
        }
      } else {
        // Disable highlighting of the selected row.
        _grid.getOptions().enableCellNavigation = false
      }

      return false
    }

    $.extend(this, {
      getSelectedRows: getSelectedRows,
      setSelectedRows: setSelectedRows,

      getSelectedRanges: getSelectedRanges,
      setSelectedRanges: setSelectedRanges,

      refreshSelectedRanges: refreshSelectedRanges,

      init: init,
      destroy: destroy,

      onSelectedRangesChanged: new Slick.Event()
    })
  }
})(jQuery, window)
<|endoftext|>


<commit_before>var serialport = require("serialport"),				    // include the serialport library
    SerialPort  = serialport.SerialPort,			    // make a local instance of serial
    app = require('express')(),						        // start Express framework
    server = require('http').createServer(app),		// start an HTTP server
    io = require('socket.io').listen(server);	  	// filter the server using socket.io

// /dev/tty.usbmodemfd121
// /dev/tty.usbmodemfd131
var portName = '/dev/tty.usbmodemfd121';
// print out the port you're listening on
console.log("opening serial port: " + portName);

server.listen(8080);
console.log("Listening for new clients on port 8080");
var connected = false;

serialport.list(function (err, ports) {
  ports.forEach(function(port) {
    console.log(port.comName);

      p = new SerialPort(port.comName, {
        baudrate: 9600,
        parser: serialport.parsers.readline("\r\n")
      });

      try {
        p.on('error', function(e) { console.log(e); });
      }
      catch (e) {
        console.log(e);
      }

      p.open(function (error) {
        if (error) {
          console.log("Couldn't connect to: " + port.comName);
        }
        else {
          p.on('data', function (data) {
            console.log(data);
          });
        }
      });
  });
});

// open the serial port. Change the name to the name of your port, just like in Processing and Arduino:
// var myPort = new SerialPort(portName, {
//   // look for return and newline at the end of each data packet:
//   parser: serialport.parsers.readline("\r\n")
// });

// respond to web GET requests with the index.html page:
app.get('/', function (request, response) {
  response.sendfile(__dirname + '/index.html');
});

// listen for new socket.io connections:
io.sockets.on('connection', function (socket) {
  // if the client connects:
  // if (!connected) {
  //   // clear out any old data from the serial bufffer:
  //   myPort.flush();
  //   // send a byte to the serial port to ask for data:
  //   myPort.write('c');
  //   console.log('user connected');
  //   connected = true;
  // }

  // if the client disconnects:
  // socket.on('disconnect', function () {
  //   myPort.write('x');
  //   console.log('user disconnected');
  //   connected = false;
  // });
  //
  // // listen for new serial data:
  // myPort.on('data', function (data) {
  //   // Convert the string into a JSON object:
  //   var serialData = JSON.parse(data);
  //   // for debugging, you should see this in the terminal window:
  //   console.log(data);
  //   // send a serial event to the web client with the data:
  //   socket.emit('serialEvent', serialData);
  // });
});
<commit_msg>Proof-of-concept complete serial <-> arduino handshake<commit_after>var serialport = require("serialport"),				    // include the serialport library
    SerialPort  = serialport.SerialPort,			    // make a local instance of serial
    app = require('express')(),						        // start Express framework
    server = require('http').createServer(app),		// start an HTTP server
    io = require('socket.io').listen(server);	  	// filter the server using socket.io

// /dev/tty.usbmodemfd121
// /dev/tty.usbmodemfd131
var portName = '/dev/tty.usbmodemfd121';
// print out the port you're listening on
console.log("opening serial port: " + portName);

server.listen(8080);
console.log("Listening for new clients on port 8080");
var connected = false;

serialport.list(function (err, ports) {
  ports.forEach(function(port) {
    console.log(port.comName);

      p = new SerialPort(port.comName, {
        baudrate: 9600,
        parser: serialport.parsers.readline("\r\n")
      });

      p.on('error', function(e) { console.log(e); });

      p.open(function (error) {
        if (error) {
          console.log("Couldn't connect to: " + port.comName);
        }
        else {
          p.on('data', function (data) {
            console.log(data);
            if (is_a_scanner(data)) {
              p.flush();
              // send a byte to the serial port to ask for data:
              p.write('$');
            }
          });
        }
      });
  });
});

function is_a_scanner(data) {
  if (data == "connect") {
    return true;
  }
  else {
    return false;
  }
}

// open the serial port. Change the name to the name of your port, just like in Processing and Arduino:
// var myPort = new SerialPort(portName, {
//   // look for return and newline at the end of each data packet:
//   parser: serialport.parsers.readline("\r\n")
// });

// respond to web GET requests with the index.html page:
app.get('/', function (request, response) {
  response.sendfile(__dirname + '/index.html');
});

// listen for new socket.io connections:
io.sockets.on('connection', function (socket) {
  // if the client connects:
  // if (!connected) {
  //   // clear out any old data from the serial bufffer:
  //   myPort.flush();
  //   // send a byte to the serial port to ask for data:
  //   myPort.write('c');
  //   console.log('user connected');
  //   connected = true;
  // }

  // if the client disconnects:
  // socket.on('disconnect', function () {
  //   myPort.write('x');
  //   console.log('user disconnected');
  //   connected = false;
  // });
  //
  // // listen for new serial data:
  // myPort.on('data', function (data) {
  //   // Convert the string into a JSON object:
  //   var serialData = JSON.parse(data);
  //   // for debugging, you should see this in the terminal window:
  //   console.log(data);
  //   // send a serial event to the web client with the data:
  //   socket.emit('serialEvent', serialData);
  // });
});
<|endoftext|>


<commit_before>// same example as https://github.com/cujojs/most#simple-example

const { fromEvent, combine } = Servable;

const xInput = document.querySelector('input.x');
const yInput = document.querySelector('input.y');
const resultNode = document.querySelector('.result');

const add = (x, y) => x + y;

const toNumber = e => Number(e.target.value);

const renderResult = result => {
  resultNode.textContent = result
};

const main = () => {
  // x represents the current value of xInput
  const x = fromEvent('input', xInput).map(toNumber);

  // y represents the current value of yInput
  const y = fromEvent('input', yInput).map(toNumber);

  // result is the live current value of adding x and y
  const result = combine(x, y, add);

  // Observe the result value by rendering it to the resultNode
  result.subscribe(renderResult);
};

main();<commit_msg>Update adder example<commit_after>// same example as https://github.com/cujojs/most#simple-example

const { fromEvent, combine } = Servable;

const xInput = document.querySelector('input.x');
const yInput = document.querySelector('input.y');
const resultNode = document.querySelector('.result');

const add = (x, y) => x + y;

const toNumber = e => Number(e.target.value);

const renderResult = result => {
  resultNode.textContent = result
};

const main = () => {
  // x represents the current value of xInput
  const x = fromEvent('input', xInput).map(toNumber);

  // y represents the current value of yInput
  const y = fromEvent('input', yInput).map(toNumber);

  // result is the live current value of adding x and y
  const result = combine([x, y], add);

  // Observe the result value by rendering it to the resultNode
  result.subscribe(renderResult);
};

main();<|endoftext|>


<commit_before>window.onload = function() {
	var messages = [];
	//var socket = io.connect('http://localhost:8080');
	var socket = io.connect("httP://"process.env.OPENSHIFT_NODEJS_IP + ":8080");
	var field = document.getElementById("field");
	var sendButton = document.getElementById("send");
	var content = document.getElementById("content");

	socket.on('message', function (data) {
		if(data.message) {
			messages.push(data.message);
			var html = '';
			for(var i=0; i<messages.length; i++) {
				html += messages[i] + '
';
			}
			content.innerHTML = html;
		} else {
			console.log("There is a problem:", data);
		}
	});

	sendButton.onclick = function() {
		var text = field.value;
		console.log("There is a problem:", text);
		socket.emit('send', { message: text });
	};
}
<commit_msg>fixing typo<commit_after>window.onload = function() {
	var messages = [];
	//var socket = io.connect('http://localhost:8080');
	var socket = io.connect("httP://" + process.env.OPENSHIFT_NODEJS_IP + ":8080");
	var field = document.getElementById("field");
	var sendButton = document.getElementById("send");
	var content = document.getElementById("content");

	socket.on('message', function (data) {
		if(data.message) {
			messages.push(data.message);
			var html = '';
			for(var i=0; i<messages.length; i++) {
				html += messages[i] + '
';
			}
			content.innerHTML = html;
		} else {
			console.log("There is a problem:", data);
		}
	});

	sendButton.onclick = function() {
		var text = field.value;
		console.log("There is a problem:", text);
		socket.emit('send', { message: text });
	};
}
<|endoftext|>


<commit_before>/**
 * @class Oskari.catalogue.bundle.metadataflyout.Flyout
 *
 *
 * This hosts metadata content loaded via ajax from
 * Geonetwork
 *
 * Embeds preformatted (unstyled) tables of metadata information.
 *
 * Style will be forced with CLASS manipulation ?
 *
 * TBD this does way too much logic - logic to be moved to instance
 *
 *
 */
Oskari.clazz.define('Oskari.catalogue.bundle.metadataflyout.Flyout',

/**
 * @method create called automatically on construction
 * @static
 *
 * Always extend this class, never use as is.
 */
function(instance, locale, loader) {

	/* @property instance bundle instance */
	this.instance = instance;

	/* @property locale locale for this */
	this.locale = locale;

	/* @property container the DIV element */
	this.container = null;

	/* element references */
	this.views = {};
	this.titles = {};
	this.tabs = {};
	this.browseGraphic = null;

	/* @Alert for some notifications */
	this.compileTemplates();
	this.alert = Oskari.clazz.create('Oskari.userinterface.component.Alert');

	/**
	 * @property showQueue
	 * request queue to enable postponing ajax loads (TBD)
	 *
	 */
	this.showQueue = [];

	/**
	 * @property state
	 */
	this.state = null;

	/**
	 * @property contentState
	 * what is shown and how
	 */
	this.contentState = {
		metadata : {
			uuid : null,
			RS_Identifier_Code : null,
			RS_Identifier_CodeSpace : null
		},
		view : 'abstract'

	};

}, {
	compileTemplates : function() {

	},
	/**
	 * @property template HTML templates for the User Interface
	 * @static
	 */
	templates : {
		content : "

",
		browseGraphic : "

",
		viewTabs : "

",
		viewTab : "

",
		titles : {
			"abstract" : "

",
			"jhs" : "

",
			"inspire" : "

"

		},
		views : {
			"abstract" : "

",
			"jhs" : "

",
			"inspire" : "

"
		}
	},
	getName : function() {
		return 'Oskari.catalogue.bundle.metadataflyout.Flyout';
	},
	setEl : function(el, width, height) {
		this.container = jQuery(el);
	},
	startPlugin : function() {
		var locale = this.locale;
		var content = jQuery(this.templates.content);

		var me = this;

		/* let's create view selector tabs - and hide them all */

		var viewTabs = jQuery(this.templates.viewTabs);
		var viewTab = jQuery(this.templates.viewTab);

		for(var v in this.templates.views ) {
			var tabs = viewTabs.clone();
			var tabTexts = locale.tabs[v];

			for(var t in tabTexts ) {
				var tab = viewTab.clone();

				if( typeof tabTexts[t] === "string") {

					tab.append(tabTexts[t]);
					tabs.append(tab);
					if(t != v) {

						tab.click({
							viewId : t
						}, function(arg) {
							var data = arg.data;
							me.showMetadataView(data.viewId);
						});
					}
				} else {
					var text = tabTexts[t].text;
					var target = tabTexts[t].target;

					tab.append(text);
					tabs.append(tab);

					tab.click({
						viewId : t,
						target : target
					}, function(arg) {
						var data = arg.data;
						me.openMetadataView(data.viewId, data.target);
					});
				}
			}

			tabs.hide();

			this.tabs[v] = tabs;
			content.append(tabs);
		}

		/*placeholder for browseGrpahics */
		var browseGraphic = jQuery(this.templates.browseGraphic);
		this.browseGraphic = browseGraphic;
		content.append(browseGraphic);

		/*
		 * let's create views - and hide them also
		 */
		for(var v in this.templates.views ) {

			/*
			 * view tabs
			 */

			/*
			 * views
			 */
			this.titles[v] = jQuery(this.templates.titles[v]);
			this.titles[v].append(this.locale[v]);
			this.views[v] = jQuery(this.templates.views[v]);

			content.append(this.titles[v]);
			content.append(this.views[v]);

		}

		/* special handling */
		/* let's add placeholder for browseGraphics */
		content.append(viewTabs);

		this.alert.insertTo(this.container);

		this.container.append(content);

	},
	stopPlugin : function() {
		this.container.empty();
	},
	getTitle : function() {
		return "Metadata";
	},
	getDescription : function() {
	},
	getOptions : function() {

	},
	setState : function(state) {
		this.state = state;

	},
	/**
	 * @method openMetadataView
	 *
	 * opens a view in new window. this will not change state.
	 */
	openMetadataView : function(viewId, target) {
		var me = this;
		var metadata = this.contentState.metadata;

		this.instance.getLoader().openMetadata(viewId, metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace, function(data) {
		}, null, target);
	},
	/**
	 * @method showMetadataView
	 *
	 * shows metadata subset view. this changes state.
	 */
	showMetadataView : function(viewId, target) {
		this.instance.getSandbox().printDebug("ShowMetadataView " + viewId);
		var tabs = this.tabs;
		var views = this.views;
		var titles = this.titles;

		for(var v in views ) {
			if(v != viewId) {
				tabs[v].hide();
				titles[v].hide();
				views[v].hide();
			} else {
				tabs[v].show();
				titles[v].show();
				views[v].hide();
			}

		}

		this.contentState.view = viewId;

		this.loadMetadataForState();

	},
	/**
	 * @method loadMetadataForState
	 */
	loadMetadataForState : function() {
		var me = this;
		var views = this.views;
		var viewId = this.contentState.view;
		var metadata = this.contentState.metadata;
		var url = me.instance.getLoader().getURLForView(viewId, metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace);

		function handler(request) {
			views[viewId].html(request.responseText);
			views[viewId].css("display", "");
		}

		var request = OpenLayers.Request.GET({
			url : url,
			callback : handler
		});

	},
	/**
	 * @method loadMetadataJSONForState
	 */
	loadMetadataJSONForState : function() {

		var me = this;
		var metadata = this.contentState.metadata;

		this.instance.getLoader().loadMetadata('json', metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace, function(data) {
			var metadataJson = data.mdcs[0];
			me.processJSON(metadataJson);
		}, 'json');
	},
	/**
	 * @method processJSON
	 */
	processJSON : function(metadataJson) {
		var browseGraphicUrl = metadataJson.browseGraphic;
		var extentEnvelope = metadataJson.env;

		/*
		 * Let's display the browse graphic image
		 */
		if(browseGraphicUrl) {
			var img = jQuery(this.browseGraphic).children('img');

			if(this.instance.getLoader().dev) {
				img.attr('src', 'espoo_johtokartta_s.png');
			} else {
				img.attr('src', browseGraphicUrl);
			}

		}

		/*
		 * Let's post Envelope to some layer
		 */
		if(extentEnvelope) {
			this.instance.showExtentOnMap(this.contentState.metadata.uuid, extentEnvelope, metadataJson);
		}

	},
	/**
	 * @method showMetadata
	 *
	 * Launches Ajax requestst to embed metadata descriptions
	 * for requested metadata
	 *
	 * Backend provides HTML setups that will be embedded and
	 * styled with bundled CSS.
	 */
	showMetadata : function(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace) {
		this.contentState.metadata.uuid = uuid;
		this.contentState.metadata.RS_Identifier_Code = RS_Identifier_Code;
		this.contentState.metadata.RS_Identifier_CodeSpace = RS_Identifier_CodeSpace;
		this.instance.getSandbox().printDebug("showMetadata { uuid=" + uuid + ", view=" + this.contentState.view + "}");
		this.loadMetadataJSONForState();
		this.showMetadataView(this.contentState.view);
	},
	/**
	 * @method scheduleShowMetadata
	 *
	 * this 'schedules' asyncronous loading
	 * ( calls directly now )
	 * Used to buffer excess calls
	 *
	 */
	scheduleShowMetadata : function(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace) {
		this.showMetadata(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace);
	},
	/**
	 * @method setContentState

	 * restore state from store
	 */
	setContentState : function(contentState) {
		this.contentState = contentState;
		this.loadMetadataJSONForState();
		this.showMetadataView(this.contentState.view);

	},
	/**
	 * @method getContentState
	 *
	 * get state for store
	 */
	getContentState : function() {
		return this.contentState;
	}
}, {
	'protocol' : ['Oskari.userinterface.Flyout']
});
<commit_msg>[PORTTISK-875] metadata now validates the state data before trying to load it<commit_after>/**
 * @class Oskari.catalogue.bundle.metadataflyout.Flyout
 *
 *
 * This hosts metadata content loaded via ajax from
 * Geonetwork
 *
 * Embeds preformatted (unstyled) tables of metadata information.
 *
 * Style will be forced with CLASS manipulation ?
 *
 * TBD this does way too much logic - logic to be moved to instance
 *
 *
 */
Oskari.clazz.define('Oskari.catalogue.bundle.metadataflyout.Flyout',

/**
 * @method create called automatically on construction
 * @static
 *
 * Always extend this class, never use as is.
 */
function(instance, locale, loader) {

	/* @property instance bundle instance */
	this.instance = instance;

	/* @property locale locale for this */
	this.locale = locale;

	/* @property container the DIV element */
	this.container = null;

	/* element references */
	this.views = {};
	this.titles = {};
	this.tabs = {};
	this.browseGraphic = null;

	/* @Alert for some notifications */
	this.compileTemplates();
	this.alert = Oskari.clazz.create('Oskari.userinterface.component.Alert');

	/**
	 * @property showQueue
	 * request queue to enable postponing ajax loads (TBD)
	 *
	 */
	this.showQueue = [];

	/**
	 * @property state
	 */
	this.state = null;

	/**
	 * @property contentState
	 * what is shown and how
	 */
	this.contentState = {
		metadata : {
			uuid : null,
			RS_Identifier_Code : null,
			RS_Identifier_CodeSpace : null
		},
		view : 'abstract'

	};

}, {
	compileTemplates : function() {

	},
	/**
	 * @property template HTML templates for the User Interface
	 * @static
	 */
	templates : {
		content : "

",
		browseGraphic : "

",
		viewTabs : "

",
		viewTab : "

",
		titles : {
			"abstract" : "

",
			"jhs" : "

",
			"inspire" : "

"

		},
		views : {
			"abstract" : "

",
			"jhs" : "

",
			"inspire" : "

"
		}
	},
	getName : function() {
		return 'Oskari.catalogue.bundle.metadataflyout.Flyout';
	},
	setEl : function(el, width, height) {
		this.container = jQuery(el);
	},
	startPlugin : function() {
		var locale = this.locale;
		var content = jQuery(this.templates.content);

		var me = this;

		/* let's create view selector tabs - and hide them all */

		var viewTabs = jQuery(this.templates.viewTabs);
		var viewTab = jQuery(this.templates.viewTab);

		for(var v in this.templates.views ) {
			var tabs = viewTabs.clone();
			var tabTexts = locale.tabs[v];

			for(var t in tabTexts ) {
				var tab = viewTab.clone();

				if( typeof tabTexts[t] === "string") {

					tab.append(tabTexts[t]);
					tabs.append(tab);
					if(t != v) {

						tab.click({
							viewId : t
						}, function(arg) {
							var data = arg.data;
							me.showMetadataView(data.viewId);
						});
					}
				} else {
					var text = tabTexts[t].text;
					var target = tabTexts[t].target;

					tab.append(text);
					tabs.append(tab);

					tab.click({
						viewId : t,
						target : target
					}, function(arg) {
						var data = arg.data;
						me.openMetadataView(data.viewId, data.target);
					});
				}
			}

			tabs.hide();

			this.tabs[v] = tabs;
			content.append(tabs);
		}

		/*placeholder for browseGrpahics */
		var browseGraphic = jQuery(this.templates.browseGraphic);
		this.browseGraphic = browseGraphic;
		content.append(browseGraphic);

		/*
		 * let's create views - and hide them also
		 */
		for(var v in this.templates.views ) {

			/*
			 * view tabs
			 */

			/*
			 * views
			 */
			this.titles[v] = jQuery(this.templates.titles[v]);
			this.titles[v].append(this.locale[v]);
			this.views[v] = jQuery(this.templates.views[v]);

			content.append(this.titles[v]);
			content.append(this.views[v]);

		}

		/* special handling */
		/* let's add placeholder for browseGraphics */
		content.append(viewTabs);

		this.alert.insertTo(this.container);

		this.container.append(content);

	},
	stopPlugin : function() {
		this.container.empty();
	},
	getTitle : function() {
		return "Metadata";
	},
	getDescription : function() {
	},
	getOptions : function() {

	},
	setState : function(state) {
		this.state = state;

	},
	/**
	 * @method openMetadataView
	 *
	 * opens a view in new window. this will not change state.
	 */
	openMetadataView : function(viewId, target) {
		var me = this;
		var metadata = this.contentState.metadata;

		this.instance.getLoader().openMetadata(viewId, metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace, function(data) {
		}, null, target);
	},
	/**
	 * @method showMetadataView
	 *
	 * shows metadata subset view. this changes state.
	 */
	showMetadataView : function(viewId, target) {
		this.instance.getSandbox().printDebug("ShowMetadataView " + viewId);
		var tabs = this.tabs;
		var views = this.views;
		var titles = this.titles;

		for(var v in views ) {
			if(v != viewId) {
				tabs[v].hide();
				titles[v].hide();
				views[v].hide();
			} else {
				tabs[v].show();
				titles[v].show();
				views[v].hide();
			}

		}

		this.contentState.view = viewId;

		this.loadMetadataForState();

	},
	/**
	 * @method loadMetadataForState
	 */
	loadMetadataForState : function() {
		var me = this;
		var views = this.views;
		var viewId = this.contentState.view;
		var metadata = this.contentState.metadata;
		var url = me.instance.getLoader().getURLForView(viewId, metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace);

		function handler(request) {
			views[viewId].html(request.responseText);
			views[viewId].css("display", "");
		}

		var request = OpenLayers.Request.GET({
			url : url,
			callback : handler
		});

	},
	/**
	 * @method loadMetadataJSONForState
	 */
	loadMetadataJSONForState : function() {

		var me = this;
        if(!this.contentState ||
            !this.contentState.metadata ||
            !this.contentState.uuid) {
                // nothing to load
            return false;
        }
		var metadata = this.contentState.metadata;

		this.instance.getLoader().loadMetadata('json', metadata.uuid, metadata.RS_Identifier_Code, metadata.RS_Identifier_CodeSpace, function(data) {
			var metadataJson = data.mdcs[0];
			me.processJSON(metadataJson);
		}, 'json');
		return true;
	},
	/**
	 * @method processJSON
	 */
	processJSON : function(metadataJson) {
		var browseGraphicUrl = metadataJson.browseGraphic;
		var extentEnvelope = metadataJson.env;

		/*
		 * Let's display the browse graphic image
		 */
		if(browseGraphicUrl) {
			var img = jQuery(this.browseGraphic).children('img');

			if(this.instance.getLoader().dev) {
				img.attr('src', 'espoo_johtokartta_s.png');
			} else {
				img.attr('src', browseGraphicUrl);
			}

		}

		/*
		 * Let's post Envelope to some layer
		 */
		if(extentEnvelope) {
			this.instance.showExtentOnMap(this.contentState.metadata.uuid, extentEnvelope, metadataJson);
		}

	},
	/**
	 * @method showMetadata
	 *
	 * Launches Ajax requestst to embed metadata descriptions
	 * for requested metadata
	 *
	 * Backend provides HTML setups that will be embedded and
	 * styled with bundled CSS.
	 */
	showMetadata : function(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace) {
		this.contentState.metadata.uuid = uuid;
		this.contentState.metadata.RS_Identifier_Code = RS_Identifier_Code;
		this.contentState.metadata.RS_Identifier_CodeSpace = RS_Identifier_CodeSpace;
		this.instance.getSandbox().printDebug("showMetadata { uuid=" + uuid + ", view=" + this.contentState.view + "}");
		this.loadMetadataJSONForState();
		this.showMetadataView(this.contentState.view);
	},
	/**
	 * @method scheduleShowMetadata
	 *
	 * this 'schedules' asyncronous loading
	 * ( calls directly now )
	 * Used to buffer excess calls
	 *
	 */
	scheduleShowMetadata : function(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace) {
		this.showMetadata(uuid, RS_Identifier_Code, RS_Identifier_CodeSpace);
	},
	/**
	 * @method setContentState

	 * restore state from store
	 */
	setContentState : function(contentState) {
		this.contentState = contentState;
		if(this.loadMetadataJSONForState()) {
            this.showMetadataView(this.contentState.view);
		}
	},
	/**
	 * @method getContentState
	 *
	 * get state for store
	 */
	getContentState : function() {
		return this.contentState;
	}
}, {
	'protocol' : ['Oskari.userinterface.Flyout']
});
<|endoftext|>


<commit_before>// FLUSHALL Redis before starting

var   assert        = require('../support/assert')
    , tests         = module.exports = {}
    , _             = require('underscore')
    , querystring   = require('querystring')
    , fs            = require('fs')
    , redis         = require('redis')
    , th            = require('../support/test_helper')
    , Step          = require('step')
    , mapnik        = require('mapnik')
    , Windshaft     = require('../../lib/windshaft')
    , ServerOptions = require('../support/server_options')
    , http          = require('http');

suite('torque', function() {

    ////////////////////////////////////////////////////////////////////
    //
    // SETUP
    //
    ////////////////////////////////////////////////////////////////////

    var server = new Windshaft.Server(ServerOptions);
    server.setMaxListeners(0);
    var redis_client = redis.createClient(ServerOptions.redis.port);

    checkCORSHeaders = function(res) {
      var h = res.headers['access-control-allow-headers'];
      assert.ok(h);
      assert.equal(h, 'X-Requested-With, X-Prototype-Version, X-CSRF-Token');
      var h = res.headers['access-control-allow-origin'];
      assert.ok(h);
      assert.equal(h, '*');
    };

    suiteSetup(function(done) {

      // Check that we start with an empty redis db
      redis_client.keys("*", function(err, matches) {
          if ( err ) { done(err); return; }
          assert.equal(matches.length, 0, "redis keys present at setup time:\n" + matches.join("\n"));
          done();
      });

    });

    test("missing required property from torque layer", function(done) {

      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select cartodb_id, the_geom from test_table',
               cartocss: 'Map { marker-fill:blue; }'
             } }
        ]
      };

      Step(
        function do_post1()
        {
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          console.log("ERRRRRR", error);
          assert.equal(error,
            "Missing required property '-torque-frame-count' in torque layer CartoCSS");
          return null;
        },
        function do_post2(err)
        {
          if ( err ) throw err;
          var next = this;
          var css = 'Map { -torque-frame-count: 2; }';
          layergroup.layers[0].options.cartocss = css;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse2(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          assert.equal(error,
            "Missing required property '-torque-resolution' in torque layer CartoCSS");
          return null;
        },
        function do_post3(err)
        {
          if ( err ) throw err;
          var next = this;
          var css = 'Map { -torque-frame-count: 2; -torque-resolution: 3; }'
          layergroup.layers[0].options.cartocss = css;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse3(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          assert.equal(error,
            "Missing required property '-torque-aggregation-function' in torque layer CartoCSS");
          return null;
        },
        function finish(err) {
          done(err);
        }
      );
    });

    test("can render tile for valid mapconfig", function(done) {

      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 1 as id, now() as d, 'SRID=4326;POINT(0 0)'::geometry as the_geom, 'SRID=3785;POINT(0 0)'::geometry as the_geom_webmercator",
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; -torque-aggregation-function:\'count(id)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };

      var expected_token;
      Step(
        function do_post()
        {
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(mapconfig)
          }, {}, function(res, err) { next(err, res); });
        },
        function checkPost(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
          // CORS headers should be sent with response
          // from layergroup creation via POST
          checkCORSHeaders(res);
          var parsedBody = JSON.parse(res.body);
          if ( expected_token ) assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2});
          else expected_token = parsedBody.layergroupid;
          return null;
        },
        function do_get_tile(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token + '/0/0/0.png',
              method: 'GET',
              encoding: 'binary'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_mapnik_error_1(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode != 200 ? (': ' + res.body) : '' ));
          var parsed = JSON.parse(res.body);
          assert.equal(parsed.error, "No 'mapnik' layers in MapConfig");
          return null;
        },
        function do_get_grid0(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token
                 + '/0/0/0/0.grid.json',
              method: 'GET'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_mapnik_error_2(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode != 200 ? (': ' + res.body) : '' ));
          var parsed = JSON.parse(res.body);
          assert.equal(parsed.error, "No 'mapnik' layers in MapConfig");
          return null;
        },
        function do_get_torque0(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token
                 + '/0/0/0/0.json.torque',
              method: 'GET'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_torque_response(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 200, res.body);
          assert.equal(res.headers['content-type'], "application/json; charset=utf-8");
          // TODO: check actual torque tile content
          return null;
        },
        function finish(err) {
          var errors = [];
          if ( err ) errors.push(err.message);
          redis_client.exists("map_cfg|" +  expected_token, function(err, exists) {
              if ( err ) errors.push(err.message);
              //assert.ok(exists, "Missing expected token " + expected_token + " from redis");
              redis_client.del("map_cfg|" +  expected_token, function(err) {
                if ( err ) errors.push(err.message);
                if ( errors.length ) done(new Error(errors));
                else done(null);
              });
          });
        }
      );
    });

    ////////////////////////////////////////////////////////////////////
    //
    // TEARDOWN
    //
    ////////////////////////////////////////////////////////////////////

    suiteTeardown(function(done) {

      // Check that we left the redis db empty
      redis_client.keys("*", function(err, matches) {
          try {
            assert.equal(matches.length, 0, "Left over redis keys:\n" + matches.join("\n"));
          } catch (err2) {
            if ( err ) err.message += '\n' + err2.message;
            else err = err2;
          }
          redis_client.flushall(function() {
            done(err);
          });
      });

    });

});

<commit_msg>added test comparison for tile in torque specs<commit_after>// FLUSHALL Redis before starting

var   assert        = require('../support/assert')
    , tests         = module.exports = {}
    , _             = require('underscore')
    , querystring   = require('querystring')
    , fs            = require('fs')
    , redis         = require('redis')
    , th            = require('../support/test_helper')
    , Step          = require('step')
    , mapnik        = require('mapnik')
    , Windshaft     = require('../../lib/windshaft')
    , ServerOptions = require('../support/server_options')
    , http          = require('http');

suite('torque', function() {

    ////////////////////////////////////////////////////////////////////
    //
    // SETUP
    //
    ////////////////////////////////////////////////////////////////////

    var server = new Windshaft.Server(ServerOptions);
    server.setMaxListeners(0);
    var redis_client = redis.createClient(ServerOptions.redis.port);

    checkCORSHeaders = function(res) {
      var h = res.headers['access-control-allow-headers'];
      assert.ok(h);
      assert.equal(h, 'X-Requested-With, X-Prototype-Version, X-CSRF-Token');
      var h = res.headers['access-control-allow-origin'];
      assert.ok(h);
      assert.equal(h, '*');
    };

    suiteSetup(function(done) {

      // Check that we start with an empty redis db
      redis_client.keys("*", function(err, matches) {
          if ( err ) { done(err); return; }
          assert.equal(matches.length, 0, "redis keys present at setup time:\n" + matches.join("\n"));
          done();
      });

    });

    test("missing required property from torque layer", function(done) {

      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select cartodb_id, the_geom from test_table',
               cartocss: 'Map { marker-fill:blue; }'
             } }
        ]
      };

      Step(
        function do_post1()
        {
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          console.log("ERRRRRR", error);
          assert.equal(error,
            "Missing required property '-torque-frame-count' in torque layer CartoCSS");
          return null;
        },
        function do_post2(err)
        {
          if ( err ) throw err;
          var next = this;
          var css = 'Map { -torque-frame-count: 2; }';
          layergroup.layers[0].options.cartocss = css;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse2(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          assert.equal(error,
            "Missing required property '-torque-resolution' in torque layer CartoCSS");
          return null;
        },
        function do_post3(err)
        {
          if ( err ) throw err;
          var next = this;
          var css = 'Map { -torque-frame-count: 2; -torque-resolution: 3; }'
          layergroup.layers[0].options.cartocss = css;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(layergroup)
          }, {}, function(res) { next(null, res); });
        },
        function checkResponse3(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed.errors, parsed);
          var error = parsed.errors[0];
          assert.equal(error,
            "Missing required property '-torque-aggregation-function' in torque layer CartoCSS");
          return null;
        },
        function finish(err) {
          done(err);
        }
      );
    });

    test("can render tile for valid mapconfig", function(done) {

      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 1 as id, now() as d, 'SRID=4326;POINT(0 0)'::geometry as the_geom, 'SRID=3785;POINT(0 0)'::geometry as the_geom_webmercator",
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; -torque-aggregation-function:\'count(id)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };

      var expected_token;
      Step(
        function do_post()
        {
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup',
              method: 'POST',
              headers: {'Content-Type': 'application/json' },
              data: JSON.stringify(mapconfig)
          }, {}, function(res, err) { next(err, res); });
        },
        function checkPost(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
          // CORS headers should be sent with response
          // from layergroup creation via POST
          checkCORSHeaders(res);
          var parsedBody = JSON.parse(res.body);
          if ( expected_token ) assert.deepEqual(parsedBody, {layergroupid: expected_token, layercount: 2});
          else expected_token = parsedBody.layergroupid;
          return null;
        },
        function do_get_tile(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token + '/0/0/0.png',
              method: 'GET',
              encoding: 'binary'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_mapnik_error_1(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode != 200 ? (': ' + res.body) : '' ));
          var parsed = JSON.parse(res.body);
          assert.equal(parsed.error, "No 'mapnik' layers in MapConfig");
          return null;
        },
        function do_get_grid0(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token
                 + '/0/0/0/0.grid.json',
              method: 'GET'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_mapnik_error_2(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 400, res.statusCode + ( res.statusCode != 200 ? (': ' + res.body) : '' ));
          var parsed = JSON.parse(res.body);
          assert.equal(parsed.error, "No 'mapnik' layers in MapConfig");
          return null;
        },
        function do_get_torque0(err)
        {
          if ( err ) throw err;
          var next = this;
          assert.response(server, {
              url: '/database/windshaft_test/layergroup/' + expected_token
                 + '/0/0/0/0.json.torque',
              method: 'GET'
          }, {}, function(res, err) { next(err, res); });
        },
        function check_torque_response(err, res) {
          if ( err ) throw err;
          assert.equal(res.statusCode, 200, res.body);
          assert.equal(res.headers['content-type'], "application/json; charset=utf-8");
          // TODO: check actual torque tile content
          var tile_content = [{"x__uint8":42.6666666666667,"y__uint8":42.6666666666667,"vals__uint8":[1],"dates__uint16":[0]}];
          var parsed = JSON.parse(res.body);
          assert.ok(_.isEqual(tile_content, parsed));
          return null;
        },
        function finish(err) {
          var errors = [];
          if ( err ) errors.push(err.message);
          redis_client.exists("map_cfg|" +  expected_token, function(err, exists) {
              if ( err ) errors.push(err.message);
              //assert.ok(exists, "Missing expected token " + expected_token + " from redis");
              redis_client.del("map_cfg|" +  expected_token, function(err) {
                if ( err ) errors.push(err.message);
                if ( errors.length ) done(new Error(errors));
                else done(null);
              });
          });
        }
      );
    });

    ////////////////////////////////////////////////////////////////////
    //
    // TEARDOWN
    //
    ////////////////////////////////////////////////////////////////////

    suiteTeardown(function(done) {

      // Check that we left the redis db empty
      redis_client.keys("*", function(err, matches) {
          try {
            assert.equal(matches.length, 0, "Left over redis keys:\n" + matches.join("\n"));
          } catch (err2) {
            if ( err ) err.message += '\n' + err2.message;
            else err = err2;
          }
          redis_client.flushall(function() {
            done(err);
          });
      });

    });

});

<|endoftext|>