<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import PropTypes from 'prop-types';
import autobind from 'react-autobind';
import { Expansion } from 'react-native-data-table';
import { GenericPage } from './GenericPage';
import { PageInfo } from '../widgets';
import { dataTableStyles } from '../globalStyles';
import { formatExpiryDate, sortDataBy } from '../utilities';
import { tableStrings } from '../localization';

const DATA_TYPES_SYNCHRONISED = ['Item', 'ItemBatch', 'ItemCategory'];

/**
* Renders the page for all Items and their stock, with expansion of further details.
* @prop   {Realm}               database    App wide database.
* @prop   {func}                navigateTo  CallBack for navigation stack.
* @state  {Realm.Results}       items       Contains all Items stored on the local database.
*/
export class StockPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: props.database.objects('Item'),
    };
    this.dataFilters = {
      searchTerm: '',
      sortBy: 'name',
      isAscending: true,
    };
    autobind(this);
  }

  updateDataFilters(newSearchTerm, newSortBy, newIsAscending) {
    // We use != null, which checks for both null or undefined (undefined coerces to null)
    if (newSearchTerm != null) this.dataFilters.searchTerm = newSearchTerm;
    if (newSortBy != null) this.dataFilters.sortBy = newSortBy;
    if (newIsAscending != null) this.dataFilters.isAscending = newIsAscending;
  }

  /**
   * Returns updated data according to searchTerm, sortBy and isAscending.
   */
  refreshData(newSearchTerm, newSortBy, newIsAscending) {
    this.updateDataFilters(newSearchTerm, newSortBy, newIsAscending);
    const { searchTerm, sortBy, isAscending } = this.dataFilters;
    const data = this.state.items.filtered(
      'name BEGINSWITH[c] $0 OR code BEGINSWITH[c] $0',
      searchTerm
    );
    let sortDataType;
    switch (sortBy) {
      case 'totalQuantity':
        sortDataType = 'number';
        break;
      default:
        sortDataType = 'realm';
    }
    this.setState({
      data: sortDataBy(data, sortBy, sortDataType, isAscending),
    });
  }

  renderExpansion(item) {
    const batchInfo = item.batchesWithStock.map((ItemBatch) => {
      const quantityInfo = `  ${tableStrings.quantity}: ${ItemBatch.numberOfPacks}`;
      const expiryInfo = ItemBatch.expiryDate ?
        `  ${tableStrings.batch_expiry}: ${formatExpiryDate(ItemBatch.expiryDate)},`
        : '';
      const nameInfo = ItemBatch.batch ? `  ${ItemBatch.batch},` : '';

      return {
        title: `${tableStrings.batch}:`,
        info: `${nameInfo}${expiryInfo}${quantityInfo}`,
      };
    });

    const dailyUsage = item.dailyUsage;
    const infoColumns = [
      [
        {
          title: `${tableStrings.category}:`,
          info: item.categoryName,
        },
        {
          title: `${tableStrings.department}:`,
          info: item.departmentName,
        },
        dailyUsage && {
          title: 'Montly Usage : ',
          info: Math.round(item.dailyUsage * 30),
        },
      ],
      batchInfo,
    ];

    return (
      <Expansion style={dataTableStyles.expansion}>
        <PageInfo columns={infoColumns} />
      </Expansion>
    );
  }

  render() {
    return (
      <GenericPage
        data={this.state.data}
        refreshData={this.refreshData}
        renderExpansion={this.renderExpansion}
        defaultSortKey={this.dataFilters.sortBy}
        defaultSortDirection={this.dataFilters.isAscending ? 'ascending' : 'descending'}
        columns={[
          {
            key: 'code',
            width: 1,
            title: tableStrings.item_code,
            sortable: true,
          },
          {
            key: 'name',
            width: 5,
            title: tableStrings.item_name,
            sortable: true,
          },
          {
            key: 'totalQuantity',
            width: 1,
            title: tableStrings.stock_on_hand,
            sortable: true,
            alignText: 'right',
          },
        ]}
        dataTypesSynchronised={DATA_TYPES_SYNCHRONISED}
        database={this.props.database}
        {...this.props.genericTablePageStyles}
        topRoute={this.props.topRoute}
      />
    );
  }
}

StockPage.propTypes = {
  database: PropTypes.object,
  genericTablePageStyles: PropTypes.object,
  topRoute: PropTypes.bool,
  navigateTo: PropTypes.func.isRequired,
};
<commit_msg>Reuse constant<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import PropTypes from 'prop-types';
import autobind from 'react-autobind';
import { Expansion } from 'react-native-data-table';
import { GenericPage } from './GenericPage';
import { PageInfo } from '../widgets';
import { dataTableStyles } from '../globalStyles';
import { formatExpiryDate, sortDataBy } from '../utilities';
import { tableStrings } from '../localization';

const DATA_TYPES_SYNCHRONISED = ['Item', 'ItemBatch', 'ItemCategory'];

/**
* Renders the page for all Items and their stock, with expansion of further details.
* @prop   {Realm}               database    App wide database.
* @prop   {func}                navigateTo  CallBack for navigation stack.
* @state  {Realm.Results}       items       Contains all Items stored on the local database.
*/
export class StockPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: props.database.objects('Item'),
    };
    this.dataFilters = {
      searchTerm: '',
      sortBy: 'name',
      isAscending: true,
    };
    autobind(this);
  }

  updateDataFilters(newSearchTerm, newSortBy, newIsAscending) {
    // We use != null, which checks for both null or undefined (undefined coerces to null)
    if (newSearchTerm != null) this.dataFilters.searchTerm = newSearchTerm;
    if (newSortBy != null) this.dataFilters.sortBy = newSortBy;
    if (newIsAscending != null) this.dataFilters.isAscending = newIsAscending;
  }

  /**
   * Returns updated data according to searchTerm, sortBy and isAscending.
   */
  refreshData(newSearchTerm, newSortBy, newIsAscending) {
    this.updateDataFilters(newSearchTerm, newSortBy, newIsAscending);
    const { searchTerm, sortBy, isAscending } = this.dataFilters;
    const data = this.state.items.filtered(
      'name BEGINSWITH[c] $0 OR code BEGINSWITH[c] $0',
      searchTerm
    );
    let sortDataType;
    switch (sortBy) {
      case 'totalQuantity':
        sortDataType = 'number';
        break;
      default:
        sortDataType = 'realm';
    }
    this.setState({
      data: sortDataBy(data, sortBy, sortDataType, isAscending),
    });
  }

  renderExpansion(item) {
    const batchInfo = item.batchesWithStock.map((ItemBatch) => {
      const quantityInfo = `  ${tableStrings.quantity}: ${ItemBatch.numberOfPacks}`;
      const expiryInfo = ItemBatch.expiryDate ?
        `  ${tableStrings.batch_expiry}: ${formatExpiryDate(ItemBatch.expiryDate)},`
        : '';
      const nameInfo = ItemBatch.batch ? `  ${ItemBatch.batch},` : '';

      return {
        title: `${tableStrings.batch}:`,
        info: `${nameInfo}${expiryInfo}${quantityInfo}`,
      };
    });

    const dailyUsage = item.dailyUsage;
    const infoColumns = [
      [
        {
          title: `${tableStrings.category}:`,
          info: item.categoryName,
        },
        {
          title: `${tableStrings.department}:`,
          info: item.departmentName,
        },
        dailyUsage && {
          title: 'Montly Usage : ',
          info: Math.round(dailyUsage * 30),
        },
      ],
      batchInfo,
    ];

    return (
      <Expansion style={dataTableStyles.expansion}>
        <PageInfo columns={infoColumns} />
      </Expansion>
    );
  }

  render() {
    return (
      <GenericPage
        data={this.state.data}
        refreshData={this.refreshData}
        renderExpansion={this.renderExpansion}
        defaultSortKey={this.dataFilters.sortBy}
        defaultSortDirection={this.dataFilters.isAscending ? 'ascending' : 'descending'}
        columns={[
          {
            key: 'code',
            width: 1,
            title: tableStrings.item_code,
            sortable: true,
          },
          {
            key: 'name',
            width: 5,
            title: tableStrings.item_name,
            sortable: true,
          },
          {
            key: 'totalQuantity',
            width: 1,
            title: tableStrings.stock_on_hand,
            sortable: true,
            alignText: 'right',
          },
        ]}
        dataTypesSynchronised={DATA_TYPES_SYNCHRONISED}
        database={this.props.database}
        {...this.props.genericTablePageStyles}
        topRoute={this.props.topRoute}
      />
    );
  }
}

StockPage.propTypes = {
  database: PropTypes.object,
  genericTablePageStyles: PropTypes.object,
  topRoute: PropTypes.bool,
  navigateTo: PropTypes.func.isRequired,
};
<|endoftext|>


<commit_before>/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

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

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

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import React, { Component } from 'react';
import { connect } from 'react-redux';

import ApiClient from '../api/client'
import { API_HOST } from '../config';
import { getStore, setTagPosts } from '../store';

import Header from '../components/header';
import Footer from '../components/footer';
import Sidebar from '../components/sidebar';
import TagCloud from '../components/tag-cloud';
import {  } from '../triggers';
import { defaultSelector } from '../selectors';

let SidebarTagCloud = ({ tags, title, ...props }) => {
  if (tags.length == 0) {
    return


<commit_before>define([
    'require',
    '../core/parser',
    '../lib/jquery',
    '../lib/jquery.form'
], function(require) {
    var Parser = require('../core/parser'),
        parser = new Parser("source; target: $source; replace");

    var init = function($el, opts) {
        // XXX: if opts, set them on $el as if defined there

        if ($el.is('a')) $el.click(function(ev) {
            ev.preventDefault();
            trigger($el);
        });

        if ($el.is('form')) $el.submit(function(ev) {
            ev.preventDefault();
            trigger($el);
        });

        if ($el.hasClass('autoLoading-visible')) {
            trigger($el);
        }
    };

    var _injectmethod = function(name, method) {
        var injectwrapper = function($sources, $targets, suppress) {
            // no $targets -> called as a jquery method
            // XXX: is it good to have that here?
            if ($targets === undefined) $targets = this;
            $targets = method($sources, $targets);
            if (!suppress) {
                $targets.trigger('inject', {
                    method: name,
                    $sources: $sources
                });
            }
            return $targets;
        };
        return injectwrapper;
    };

    var content = _injectmethod("content", function($sources, $targets) {
        $targets.each(function() {
            $(this).html($sources.html());
        });
        return $targets;
    });

    var replace = _injectmethod("replace", function($sources, $targets) {
        if ($targets.length === 1) {
            $targets.replaceWith($sources);
            return $sources;
        }
        $targets.each(function() {
            $(this).replaceWith($sources.clone().addClass(replace.marker));
        });
        return $("." + replace.marker).removeClass(replace.marker);
    });
    replace.marker = 'tmp-injection-marker';

    // create an injector to be run on ajax success
    var injector = function($el, method_name, opts, callback) {
        var method = pattern[method_name],
            $targets = $(opts.target);

        if ($targets.length === 0) {
            if (opts.target.slice(0,1) !== '#') {
                console.error('only id supported for non-existing target');
            }
            $targets = $('
').attr({id: opts.target.slice(1)});
            $('body').append($targets);
        }

        var inject = function(data, textStatus, jqXHR) {
            // just copied from old inject code
            data = data
                .replace(/


<commit_before>'use strict';

QForms.inherit(TableFormController, FormController);

////////////////////////////////////////////////////////////////////////////////////////////////////
function TableFormController(model, view, parent) {
    FormController.call(this, model, view, parent);
    this.grid        = null;
    this.framesCount = null;
    this.$goto       = null;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.init = function() {
    TableFormController.super_.prototype.init.call(this);
    this.model.eventRefilled.subscribe(this, 'onRefilled');
    var self = this;
    $(this.view).find('button.refresh').click(function() {
        self.onRefreshClick(this);
    });
    $(this.view).find('button.new').click(function() {
        self.onNewClick(this);
    });
    $(this.view).find('button.delete').click(function() {
        self.onDeleteClick(this);
    });
    $(this.view).find('button.next').click(function() {
        self.onNextClick(this);
    });
    $(this.view).find('button.previous').click(function() {
        self.onPreviousClick(this);
    });
    this.$count = $(this.view).find('span.count');
    this.$goto = $(this.view).find('select.goto');
    this.$goto.change(function() {
        self.onGotoChange(this);
    });
    var gridSelector = '#{pageId}_{formName}_GridWidget'.template({
        pageId  : this.model.page.id,
        formName: this.model.name
    });
    this.grid = new DataGridWidget(this.view.querySelector(gridSelector), this);
    this.grid.init();
    this.model.page.eventHide.subscribe(this, 'onHidePage');
    this.model.page.eventShow.subscribe(this, 'onShowPage');
    this.grid.eventBodyCellDblClick.subscribe(this, 'onGridCellDblClick');
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.deinit = function() {
    this.model.page.eventHide.unsubscribe(this, 'onHidePage');
    this.model.page.eventShow.unsubscribe(this, 'onShowPage');
    this.grid.eventBodyCellDblClick.unsubscribe(this, 'onGridCellDblClick');
    this.grid.deinit();
    this.model.eventRefilled.unsubscribe(this, 'onRefilled');
    TableFormController.super_.prototype.deinit.call(this);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.fill = function() {
    var self = this;
    TableFormController.super_.prototype.fill.call(self);
    if (self.model.dataSource.limit) {
        $(self.view).find('.paging').css('display', 'block');
        self.setCountText();
    }
    self.framesCount = self.model.dataSource.getFramesCount();
    if (self.framesCount) {
        for (var i = 1; i <= self.framesCount; i++) {
            var option = $('<option></option>');
            option.val(i);
            option.html(i);
            self.$goto.append(option);
        }
    }
    self.grid.fill();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.setCountText = function() {
    var self = this;
    var count = '{rowsCount} of {count}'.template({
        rowsCount: self.model.dataSource.length,
        count    : self.model.dataSource.count
    });
    self.$count.text(count);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onRefilled = function(ea) {
    var self = this;
    //console.log('TableFormController.prototype.onRefilled');
    this.grid.clear();
    if (self.model.dataSource.limit) {
        self.setCountText();
    }
    this.framesCount = this.model.dataSource.getFramesCount();
    if (this.framesCount) {
        this.$goto.empty();
        for (var i = 1; i <= this.framesCount; i++) {
            var option = $('<option></option>');
            option.val(i);
            option.html(i);
            this.$goto.append(option);
        }
    }
    this.grid.fill();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onNewClick = function(ctrl) {
    this.model.new();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onRefreshClick = function(ctrl) {
    //console.log('TableFormController.prototype.onRefreshClick', self.name);
    //this.model.refresh();
    this.model.refill();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onDeleteClick = function(ctrl) {
    if (confirm(this.model.page.app.data.text.form.areYouSure)) {
        var key = this.grid.getSelectedKey();
        if (key !== null) {
            this.model.delete(key);
        }
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onNextClick = function(ctrl) {
    var frame = parseInt(this.$goto.val()) + 1;
    if (frame <= this.framesCount) {
        this.$goto.val(frame);
        this.model.frame(frame);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onPreviousClick = function(ctrl) {
    var frame = parseInt(this.$goto.val()) - 1;
    if (frame > 0) {
        this.$goto.val(frame);
        this.model.frame(frame);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onGotoChange = function(ctrl) {
    var frame = parseInt(ctrl.value)
    this.model.frame(frame);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onGridCellDblClick = function(ea) {
    var bodyCell = ea.bodyCell
    var key = bodyCell.bodyRow.qKey;
    switch (this.model.data.editMethod) {
        case 'table':
            if (this.model.dataSource.data.access.update === true) {
                this.grid.gridColumns[bodyCell.qFieldName].beginEdit(bodyCell);
            }
        break;
        case 'form':
            this.model.edit(key);
        break;
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onHidePage = function() {
    this.grid.saveScroll();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onShowPage = function() {
    this.grid.restoreScroll();
};<commit_msg>refresh<commit_after>'use strict';

QForms.inherit(TableFormController, FormController);

////////////////////////////////////////////////////////////////////////////////////////////////////
function TableFormController(model, view, parent) {
    FormController.call(this, model, view, parent);
    this.grid        = null;
    this.framesCount = null;
    this.$goto       = null;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.init = function() {
    TableFormController.super_.prototype.init.call(this);
    this.model.eventRefilled.subscribe(this, 'onRefilled');
    var self = this;
    $(this.view).find('button.refresh').click(function() {
        self.onRefreshClick(this);
    });
    $(this.view).find('button.new').click(function() {
        self.onNewClick(this);
    });
    $(this.view).find('button.delete').click(function() {
        self.onDeleteClick(this);
    });
    $(this.view).find('button.next').click(function() {
        self.onNextClick(this);
    });
    $(this.view).find('button.previous').click(function() {
        self.onPreviousClick(this);
    });
    this.$count = $(this.view).find('span.count');
    this.$goto = $(this.view).find('select.goto');
    this.$goto.change(function() {
        self.onGotoChange(this);
    });
    var gridSelector = '#{pageId}_{formName}_GridWidget'.template({
        pageId  : this.model.page.id,
        formName: this.model.name
    });
    this.grid = new DataGridWidget(this.view.querySelector(gridSelector), this);
    this.grid.init();
    this.model.page.eventHide.subscribe(this, 'onHidePage');
    this.model.page.eventShow.subscribe(this, 'onShowPage');
    this.grid.eventBodyCellDblClick.subscribe(this, 'onGridCellDblClick');
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.deinit = function() {
    this.model.page.eventHide.unsubscribe(this, 'onHidePage');
    this.model.page.eventShow.unsubscribe(this, 'onShowPage');
    this.grid.eventBodyCellDblClick.unsubscribe(this, 'onGridCellDblClick');
    this.grid.deinit();
    this.model.eventRefilled.unsubscribe(this, 'onRefilled');
    TableFormController.super_.prototype.deinit.call(this);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.fill = function() {
    var self = this;
    TableFormController.super_.prototype.fill.call(self);
    if (self.model.dataSource.limit) {
        $(self.view).find('.paging').css('display', 'block');
        self.setCountText();
    }
    self.framesCount = self.model.dataSource.getFramesCount();
    if (self.framesCount) {
        for (var i = 1; i <= self.framesCount; i++) {
            var option = $('<option></option>');
            option.val(i);
            option.html(i);
            self.$goto.append(option);
        }
    }
    self.grid.fill();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.setCountText = function() {
    var self = this;
    var count = '{rowsCount} of {count}'.template({
        rowsCount: self.model.dataSource.length,
        count    : self.model.dataSource.count
    });
    self.$count.text(count);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onRefilled = function(ea) {
    var self = this;
    //console.log('TableFormController.prototype.onRefilled');
    this.grid.clear();
    if (self.model.dataSource.limit) {
        self.setCountText();
    }
    this.framesCount = this.model.dataSource.getFramesCount();
    if (this.framesCount) {
        this.$goto.empty();
        for (var i = 1; i <= this.framesCount; i++) {
            var option = $('<option></option>');
            option.val(i);
            option.html(i);
            this.$goto.append(option);
        }
    }
    this.grid.fill();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onNewClick = function(ctrl) {
    this.model.new();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onRefreshClick = function(ctrl) {
    //console.log('TableFormController.prototype.onRefreshClick', self.name);
    this.model.refresh();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onDeleteClick = function(ctrl) {
    if (confirm(this.model.page.app.data.text.form.areYouSure)) {
        var key = this.grid.getSelectedKey();
        if (key !== null) {
            this.model.delete(key);
        }
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onNextClick = function(ctrl) {
    var frame = parseInt(this.$goto.val()) + 1;
    if (frame <= this.framesCount) {
        this.$goto.val(frame);
        this.model.frame(frame);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onPreviousClick = function(ctrl) {
    var frame = parseInt(this.$goto.val()) - 1;
    if (frame > 0) {
        this.$goto.val(frame);
        this.model.frame(frame);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onGotoChange = function(ctrl) {
    var frame = parseInt(ctrl.value)
    this.model.frame(frame);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onGridCellDblClick = function(ea) {
    var bodyCell = ea.bodyCell
    var key = bodyCell.bodyRow.qKey;
    switch (this.model.data.editMethod) {
        case 'table':
            if (this.model.dataSource.data.access.update === true) {
                this.grid.gridColumns[bodyCell.qFieldName].beginEdit(bodyCell);
            }
        break;
        case 'form':
            this.model.edit(key);
        break;
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onHidePage = function() {
    this.grid.saveScroll();
};

////////////////////////////////////////////////////////////////////////////////////////////////////
TableFormController.prototype.onShowPage = function() {
    this.grid.restoreScroll();
};<|endoftext|>


<commit_before>/*
 *  Manifest - organize a program of songs for an ensemble
 */

function Manifest(manifest) {

	var __Manifest = function(that, manifest) {
		that.manifest = manifest ;
		console.log('Creating manifest ', that.manifest) ;
	}(this, manifest) ;

	this.getBaseUrl = function(song) {

		if ( song.hasOwnProperty('baseUrl') && song.baseUrl !== '' ) {
			return song.baseUrl ;
		}
		if ( this.manifest.hasOwnProperty('baseUrl') && this.manifest.baseUrl !== '' ) {
			return this.manifest.baseUrl ;
		}
		return '' ;
	} ;

    this.displaySong = function(song) {

		var html = '' ;

		if ( song.hasOwnProperty('metadata') ) {
			html += this.displaySongMetadata(song) ;
		}

		if ( song.hasOwnProperty('scores') ) {
			html += this.displaySongScores(song) ;
		}

		if ( song.hasOwnProperty('parts') ) {
			html += this.displaySongParts(song) ;
		}

		if ( song.hasOwnProperty('recordings') ) {
			html += this.displaySongRecordings(song) ;
		}

		return html ;
	} ;

	this.displaySongMetadata = function(song) {

		var html = "\n" +
			"
\n
" + song.metadata.title + "
\n" +
			"
Composed by " + song.metadata.composer ;

		if ( song.metadata.hasOwnProperty('arranger') &&
			 song.metadata.arranger !== '' &&
			 song.metadata.composer !== song.metadata.arranger ) {
			html += ', Arranged by ' + song.metadata.arranger ;
		}

		html += "
\n" ;

		for ( name in song.metadata ) {
			if ( name !== 'title'  &&  name !== 'composer'  &&  name !== 'arranger' ) {
		 		value = song.metadata[name] ;
				html += "
" + name + " " + value + "
\n" ;
			}
		}

		html +=
\n" ;

		return html ;
	} ;

	this.displaySongRecordings = function(song) {

		var name,
			recording,
			description,
			href,
			html = "
\n
Recordings
\n
\n",
			howManyRecordings = 0 ;

		for ( name in song.recordings ) {
	 		recording = song.recordings[name] ;
	 		description = ( recording.description !== '' ) ? recording.description : name ;

			if ( recording.url !== '' ) {
				html += '
' + recording.description + "
\n" ;
				howManyRecordings += 1 ;
			}
		}

		if ( howManyRecordings == 0 ) {
			html = '' ;
		} else {
			html += "
\n

\n
\n" ;
		}

		return html ;
	} ;

	this.displaySongScores = function(song) {

		var name,
			score,
			href,
			html = "
\n
Scores
\n
\n" ;

		for ( name in song.scores ) {
	 		score = song.scores[name] ;
			href = this.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix + score.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}

		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displaySongParts = function(song) {

		var name,
			href,
			html = "
\n
Parts
\n
\n" ;

		for ( name in song.parts ) {
			part = song.parts[name] ;
			href = this.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix + part.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayProgramSummary = function() {

		var programIndex, number, songIndex, song, baseUrl,
			html = "
Songs in program
\n
\n
\n",
			songHtml = ''  ;

		console.log
		for ( programIndex = 0 ; programIndex < this.manifest.programOrder.length ; programIndex++ ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += "
" + song.metadata.title + "
\n";
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayProgramSongs = function() {

		var programIndex, number, songIndex, song, baseUrl,
			html = "
Song Details
\n
\n" ;

		for ( programIndex = 0 ; programIndex < this.manifest.programOrder.length ; programIndex++ ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += this.displaySong(song) ;
		}
		html += "
\n" ;

		return html ;
	} ;

	this.displayPartsInBook = function(chair, partsLists) {

		var songId,
			song,
			partsList,
			partIndex,
			part,
			href,
			that = this,
			manifest = this.manifest,
			html = "\n
" + chair + "
\n
\n
\n" ;

		Object.keys(partsLists).forEach(function(songId) {

	    	song = manifest.songs[songId] ;
			partsList = partsLists[songId] ;
			songUrl = that.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix ;

			if ( partsList.length == 1 ) {
				part = partsList[0] ;
				href = songUrl + song.parts[part].fileSuffix + '.pdf' ;
				html += '
' + song.metadata.title + "
\n" ;
			} else {
				if ( partsList.length > 1 ) {
					html += '
' + song.metadata.title + ' ';
					for ( partIndex = 0 ; partIndex < partsList.length ; partIndex++ ) {
						part = partsList[partIndex] ;
						href = songUrl + song.parts[part].fileSuffix + '.pdf' ;
						html += '    for ' + part + "" ;
						if ( partIndex+1 < partsList.length ) {
							html += ", and \n";
						}
					}
					html += "
\n" ;
				} else {
					console.log('No parts found for song ' + song.title + ' for chair ' + chair) ;
				}
			}
		});

		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayBookSummary= function() {

		var key, name
			books = this.manifest.partsInBooks,
			html = "
Instrumental books
\n
\n" ;

		html += "
Links to the list of pdf files for each instrument
\n
\n" ;

		for ( key in books ) {
			if ( books.hasOwnProperty(key) ) {
				html += '
' + key + "
\n";
			}
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayPartsInBooks = function() {

		var key,
			books = this.manifest.partsInBooks,
			html = "
Instrumental Books
\n
\n" ;

		for ( key in books ) {

			if ( books.hasOwnProperty(key) ) {

				html += this.displayPartsInBook( key, books[key] ) ;

			}
		}
		html += "
\n" ;

		return html ;
	} ;

	this.displayManifest = function() {

		var html = "
Program for " + this.manifest.title + "
\n
\n" ;
		html += "
" + this.manifest.description + "
\n" ;
		html += this.displayProgramSummary() ;
		html += this.displayBookSummary() ;
		html += this.displayProgramSongs() ;
		html += this.displayPartsInBooks() ;
		html += "
\n" ;

		return html ;
	}

	this.placeManifestOnReady = function(content) {

		var entity = this ;

		document.addEventListener(

			'DOMContentLoaded',

				function(){
					var containers = document.querySelectorAll(entity.manifest.selector),
						container ;
					if ( containers.length > 0 ) {
						container = containers[0] ;
						container.innerHTML = content ;
						return ;
					}
					console.log('Could not find elmement with id ' + entity.manifest.selector + 'so addding child.') ;
					document.getElementsByTagName('BODY')[0].innerHTML = content ;
				},

			false
		);
	}

} ;

<commit_msg>first working draft<commit_after>/*
 *  Manifest - organize a program of songs for an ensemble
 */

function Manifest(manifest) {

	var __Manifest = function(that, manifest) {
		that.manifest = manifest ;
		console.log('Creating manifest ', that.manifest) ;
	}(this, manifest) ;

	this.getBaseUrl = function(song) {

		if ( song.hasOwnProperty('baseUrl') && song.baseUrl !== '' ) {
			return song.baseUrl ;
		}
		if ( this.manifest.hasOwnProperty('baseUrl') && this.manifest.baseUrl !== '' ) {
			return this.manifest.baseUrl ;
		}
		return '' ;
	} ;

    this.displaySong = function(song) {

		var html = '' ;

		if ( song.hasOwnProperty('metadata') ) {
			html += this.displaySongMetadata(song) ;
		}

		if ( song.hasOwnProperty('scores') ) {
			html += this.displaySongScores(song) ;
		}

		if ( song.hasOwnProperty('parts') ) {
			html += this.displaySongParts(song) ;
		}

		if ( song.hasOwnProperty('recordings') ) {
			html += this.displaySongRecordings(song) ;
		}

		return html ;
	} ;

	this.displaySongMetadata = function(song) {

		var html = "\n" +
			"
\n
" + song.metadata.title + "
\n" +
			"
Composed by " + song.metadata.composer ;

		if ( song.metadata.hasOwnProperty('arranger') &&
			 song.metadata.arranger !== '' &&
			 song.metadata.composer !== song.metadata.arranger ) {
			html += ', Arranged by ' + song.metadata.arranger ;
		}

		html += "
\n" ;

		for ( name in song.metadata ) {
			if ( name !== 'title'  &&  name !== 'composer'  &&  name !== 'arranger' ) {
		 		value = song.metadata[name] ;
				html += "
" + name + " " + value + "
\n" ;
			}
		}

		html += "
\n" ;

		return html ;
	} ;

	this.displaySongRecordings = function(song) {

		var name,
			recording,
			description,
			href,
			html = "
\n
Recordings
\n
\n",
			howManyRecordings = 0 ;

		for ( name in song.recordings ) {
	 		recording = song.recordings[name] ;
	 		description = ( recording.description !== '' ) ? recording.description : name ;

			if ( recording.url !== '' ) {
				html += '
' + recording.description + "
\n" ;
				howManyRecordings += 1 ;
			}
		}

		if ( howManyRecordings == 0 ) {
			html = '' ;
		} else {
			html += "
\n

\n
\n" ;
		}

		return html ;
	} ;

	this.displaySongScores = function(song) {

		var name,
			score,
			href,
			html = "
\n
Scores
\n
\n" ;

		for ( name in song.scores ) {
	 		score = song.scores[name] ;
			href = this.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix + score.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}

		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displaySongParts = function(song) {

		var name,
			href,
			html = "
\n
Parts
\n
\n" ;

		for ( name in song.parts ) {
			part = song.parts[name] ;
			href = this.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix + part.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayProgramSummary = function() {

		var programIndex, number, songIndex, song, baseUrl,
			html = "
Songs in program
\n
\n
\n",
			songHtml = ''  ;

		console.log
		for ( programIndex = 0 ; programIndex < this.manifest.programOrder.length ; programIndex++ ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += "
" + song.metadata.title + "
\n";
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayProgramSongs = function() {

		var programIndex, number, songIndex, song, baseUrl,
			html = "
Song Details
\n
\n" ;

		for ( programIndex = 0 ; programIndex < this.manifest.programOrder.length ; programIndex++ ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += this.displaySong(song) ;
		}
		html += "
\n" ;

		return html ;
	} ;

	this.displayPartsInBook = function(chair, partsLists) {

		var songId,
			song,
			partsList,
			partIndex,
			part,
			href,
			that = this,
			manifest = this.manifest,
			html = "\n
" + chair + "
\n
\n
\n" ;

		Object.keys(partsLists).forEach(function(songId) {

	    	song = manifest.songs[songId] ;
			partsList = partsLists[songId] ;
			songUrl = that.getBaseUrl(song) +
				song.fileLocation + '/pdf/' +
				song.filePrefix ;

			if ( partsList.length == 1 ) {
				part = partsList[0] ;
				href = songUrl + song.parts[part].fileSuffix + '.pdf' ;
				html += '
' + song.metadata.title + "
\n" ;
			} else {
				if ( partsList.length > 1 ) {
					html += '
' + song.metadata.title + ' ';
					for ( partIndex = 0 ; partIndex < partsList.length ; partIndex++ ) {
						part = partsList[partIndex] ;
						href = songUrl + song.parts[part].fileSuffix + '.pdf' ;
						html += '    for ' + part + "" ;
						if ( partIndex+1 < partsList.length ) {
							html += ", and \n";
						}
					}
					html += "
\n" ;
				} else {
					console.log('No parts found for song ' + song.title + ' for chair ' + chair) ;
				}
			}
		});

		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayBookSummary= function() {

		var key, name
			books = this.manifest.partsInBooks,
			html = "
Instrumental books
\n
\n" ;

		html += "
Links to the list of pdf files for each instrument
\n
\n" ;

		for ( key in books ) {
			if ( books.hasOwnProperty(key) ) {
				html += '
' + key + "
\n";
			}
		}
		html += "
\n

\n
\n" ;

		return html ;
	} ;

	this.displayPartsInBooks = function() {

		var key,
			books = this.manifest.partsInBooks,
			html = "
Instrumental Books
\n
\n" ;

		for ( key in books ) {

			if ( books.hasOwnProperty(key) ) {

				html += this.displayPartsInBook( key, books[key] ) ;

			}
		}
		html += "
\n" ;

		return html ;
	} ;

	this.displayManifest = function() {

		var html = "
Program for " + this.manifest.title + "
\n
\n" ;
		html += "
" + this.manifest.description + "
\n" ;
		html += this.displayProgramSummary() ;
		html += this.displayBookSummary() ;
		html += this.displayProgramSongs() ;
		html += this.displayPartsInBooks() ;
		html += "
\n" ;

		return html ;
	}

	this.placeManifestOnReady = function(content) {

		var entity = this ;

		document.addEventListener(

			'DOMContentLoaded',

				function(){
					var containers = document.querySelectorAll(entity.manifest.selector),
						container ;
					if ( containers.length > 0 ) {
						container = containers[0] ;
						container.innerHTML = content ;
						return ;
					}
					console.log('Could not find elmement with id ' + entity.manifest.selector + 'so addding child.') ;
					document.getElementsByTagName('BODY')[0].innerHTML = content ;
				},

			false
		);
	}

} ;

<|endoftext|>


<commit_before>ZBase.registerView((function() {

  var load = function(url) {
    var qparams = {
      with_categories: true,
      type: "all",
      author: "all"
    };

    var owner_param = UrlUtil.getParamValue(url, "owner");
    if (owner_param) {
      qparams.owner = owner_param;
    }

    var author_param = UrlUtil.getParamValue(url, "author");
    if (author_param) {
      qparams.author = author_param;
    }

    var category_param = UrlUtil.getParamValue(url, "category");
    if (category_param) {
      qparams.category_prefix = category_param;
    }

    var pstatus_param = UrlUtil.getParamValue(url, "publishing_status");
    if (pstatus_param) {
      qparams.publishing_status = pstatus_param;
    }

    $.showLoader();
    ZBaseMainMenu.show();
    HeaderWidget.setBreadCrumbs([
      {href: "/a/", title: "Datastore"},
      {href: "/a/datastore/queries", title: "Queries"}]);

    $.httpGet("/api/v1/documents?" + $.buildQueryString(qparams), function(r) {
      if (r.status == 200) {
        render(JSON.parse(r.response), qparams, url);
      } else {
        $.fatalError();
      }
    });
  }

  var render = function(data, qparams, path) {
    var reports = data.documents;
    var categories = data.categories;

    var page = $.getTemplate(
        "views/datastore_queries",
        "zbase_datastore_queries_main_tpl");

    renderTable(
        page.querySelector(".zbase_datastore_queries tbody"),
        reports);

    $("z-dropdown.create_new_doc", page).addEventListener("change", function(e) {
      $.createNewDocument(this.getValue());
      this.setValue([]);
    });

    $.handleLinks(page);
    $.replaceViewport(page)
    $.hideLoader();
  };

  var renderTable = function(tbody_elem, reports) {
    reports.forEach(function(doc) {
      var url = getPathPrefixForDocType(doc.type) + doc.uuid;

      var tr = document.createElement("tr");
      tr.innerHTML =
          "" + $.escapeHTML(doc.name) + "	" +
          "" + $.escapeHTML(doc.type) + "	" +
          "" + DateUtil.printTimeAgo(doc.mtime) + "	";

      tbody_elem.appendChild(tr);
    });
  };

  var getPathPrefixForDocType = function(doctype) {
    switch (doctype) {
      case "report":
        return "/a/reports/";
      case "sql_query":
        return "/a/sql/";
    }
  }

  return {
    name: "datastore_queries",
    loadView: function(params) { load(params.path); },
    unloadView: function() {},
    handleNavigationChange: load
  };

})());
<commit_msg>doc type whitelisting in queries overview<commit_after>ZBase.registerView((function() {

  var load = function(url) {
    var qparams = {
      with_categories: true,
      type: "all",
      author: "all"
    };

    var owner_param = UrlUtil.getParamValue(url, "owner");
    if (owner_param) {
      qparams.owner = owner_param;
    }

    var author_param = UrlUtil.getParamValue(url, "author");
    if (author_param) {
      qparams.author = author_param;
    }

    var category_param = UrlUtil.getParamValue(url, "category");
    if (category_param) {
      qparams.category_prefix = category_param;
    }

    var pstatus_param = UrlUtil.getParamValue(url, "publishing_status");
    if (pstatus_param) {
      qparams.publishing_status = pstatus_param;
    }

    $.showLoader();
    ZBaseMainMenu.show();
    HeaderWidget.setBreadCrumbs([
      {href: "/a/", title: "Datastore"},
      {href: "/a/datastore/queries", title: "Queries"}]);

    $.httpGet("/api/v1/documents?" + $.buildQueryString(qparams), function(r) {
      if (r.status == 200) {
        render(JSON.parse(r.response), qparams, url);
      } else {
        $.fatalError();
      }
    });
  }

  var render = function(data, qparams, path) {
    var reports = data.documents;
    var categories = data.categories;

    var page = $.getTemplate(
        "views/datastore_queries",
        "zbase_datastore_queries_main_tpl");

    renderTable(
        page.querySelector(".zbase_datastore_queries tbody"),
        reports);

    $("z-dropdown.create_new_doc", page).addEventListener("change", function(e) {
      $.createNewDocument(this.getValue());
      this.setValue([]);
    });

    $.handleLinks(page);
    $.replaceViewport(page)
    $.hideLoader();
  };

  var renderTable = function(tbody_elem, reports) {
    var doc_types = {
      report: true,
      sql_query: true
    };

    reports.forEach(function(doc) {
      if (!doc_types[doc.type]) {
        return;
      }
      var url = getPathPrefixForDocType(doc.type) + doc.uuid;

      var tr = document.createElement("tr");
      tr.innerHTML =
          "" + $.escapeHTML(doc.name) + "	" +
          "" + $.escapeHTML(doc.type) + "	" +
          "" + DateUtil.printTimeAgo(doc.mtime) + "	";

      tbody_elem.appendChild(tr);
    });
  };

  var getPathPrefixForDocType = function(doctype) {
    switch (doctype) {
      case "report":
        return "/a/reports/";
      case "sql_query":
        return "/a/sql/";
    }
  }

  return {
    name: "datastore_queries",
    loadView: function(params) { load(params.path); },
    unloadView: function() {},
    handleNavigationChange: load
  };

})());
<|endoftext|>


<commit_before>require([
    // TODO: remove unused dependencies
    "./rendering/loadimage",
    "./base/time",
    "./base/loop",
    "./game/loadlevel",
    "./game/game",
    "./plugins/pluginloader"
], function main(
    loadImage,
    Time,
    Loop,
    loadLevel,
    Game,
    PluginLoader
) {
    var canvasId = "game",
        game = new Game(canvasId);

    // prepare stats
    var stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild( stats.domElement );

    // main loop
    var time = new Time();
    function animate() {
        stats.update();
        var dt = time.update();
        game.update(dt);
    }
    var loop = new Loop(animate);

    // asset loading
    queue()
        .defer(loadLevel, 0, 'game/0_tutorial.json')
        .defer(loadLevel, 1, 'game/1_movingtank.json')
        .defer(loadLevel, 2, 'demo/2_twotanks.json')
        .defer(loadLevel, 3, 'demo/3_singlehunter.json')
        .defer(loadLevel, 4, 'game/5_borderline.json')
        .defer(loadLevel, 5, 'game/6_hunter2.json')
        .defer(loadLevel, 6, 'demo/7_demo.json')
        .defer(loadLevel, 7, 'game/2_multipletanks.json')
        .defer(loadLevel, 8, 'game/3_grid.json')
        .defer(loadLevel, 9, 'game/4_hunter.json')

        .defer(loadImage, "tileset.png")
        .defer(loadImage, "tank.png")
        .defer(loadImage, "turret.png")
        .defer(loadImage, "bullet.png")
        .defer(loadImage, "target.png")
        .defer(loadImage, "powerups.png")

        .await(function(error) {
            if(error) {
                console.error("error while loading", error);
            } else {
                console.log(arguments[1]);
                game.prepare();
                loop.start();
            }
        });
});
<commit_msg>removed log message<commit_after>require([
    // TODO: remove unused dependencies
    "./rendering/loadimage",
    "./base/time",
    "./base/loop",
    "./game/loadlevel",
    "./game/game",
    "./plugins/pluginloader"
], function main(
    loadImage,
    Time,
    Loop,
    loadLevel,
    Game,
    PluginLoader
) {
    var canvasId = "game",
        game = new Game(canvasId);

    // prepare stats
    var stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild( stats.domElement );

    // main loop
    var time = new Time();
    function animate() {
        stats.update();
        var dt = time.update();
        game.update(dt);
    }
    var loop = new Loop(animate);

    // asset loading
    queue()
        .defer(loadLevel, 0, 'game/0_tutorial.json')
        .defer(loadLevel, 1, 'game/1_movingtank.json')
        .defer(loadLevel, 2, 'demo/2_twotanks.json')
        .defer(loadLevel, 3, 'demo/3_singlehunter.json')
        .defer(loadLevel, 4, 'game/5_borderline.json')
        .defer(loadLevel, 5, 'game/6_hunter2.json')
        .defer(loadLevel, 6, 'demo/7_demo.json')
        .defer(loadLevel, 7, 'game/2_multipletanks.json')
        .defer(loadLevel, 8, 'game/3_grid.json')
        .defer(loadLevel, 9, 'game/4_hunter.json')

        .defer(loadImage, "tileset.png")
        .defer(loadImage, "tank.png")
        .defer(loadImage, "turret.png")
        .defer(loadImage, "bullet.png")
        .defer(loadImage, "target.png")
        .defer(loadImage, "powerups.png")

        .await(function(error) {
            if(error) {
                console.error("error while loading", error);
            } else {
                game.prepare();
                loop.start();
            }
        });
});
<|endoftext|>


<commit_before>const validation_rules = {
    amount: [
        ['req'    , { message: 'The amount is a required field.' }],
        ['number' , { min: 0, type: 'float' }],
    ],
    barrier_1: [
        ['req'    , { condition: store => store.barrier_count && store.form_components.indexOf('barrier') > -1, message: 'The barrier is a required field.' }],
        ['barrier', { condition: store => store.contract_expiry_type !== 'daily' && store.barrier_count }],
        ['number' , { condition: store => store.contract_expiry_type === 'daily' && store.barrier_count, type: 'float' }],
        ['custom' , { func: (value, options, store) => store.barrier_count > 1 ? +value > +store.barrier_2 : true, message: 'The higher barrier must be higher than the lower barrier.' }],
    ],
    barrier_2: [
        ['req'    , { condition: store => store.barrier_count > 1 && store.form_components.indexOf('barrier') > -1, message: 'The barrier is a required field.' }],
        ['barrier', { condition: store => store.contract_expiry_type !== 'daily' && store.barrier_count }],
        ['number' , { condition: store => store.contract_expiry_type === 'daily' && store.barrier_count, type: 'float' }],
        ['custom' , { func: (value, options, store) => +store.barrier_1 > +value, message: 'The lower barrier must be lower than the higher barrier.' }],
    ],
    duration: [
        ['req'    , { message: 'The duration is a required field.' }],
    ],
};

export default validation_rules;
<commit_msg>simplify messages (remove THE)<commit_after>const validation_rules = {
    amount: [
        ['req'    , { message: 'Amount is a required field.' }],
        ['number' , { min: 0, type: 'float' }],
    ],
    barrier_1: [
        ['req'    , { condition: store => store.barrier_count && store.form_components.indexOf('barrier') > -1, message: 'Barrier is a required field.' }],
        ['barrier', { condition: store => store.contract_expiry_type !== 'daily' && store.barrier_count }],
        ['number' , { condition: store => store.contract_expiry_type === 'daily' && store.barrier_count, type: 'float' }],
        ['custom' , { func: (value, options, store) => store.barrier_count > 1 ? +value > +store.barrier_2 : true, message: 'Higher barrier must be higher than lower barrier.' }],
    ],
    barrier_2: [
        ['req'    , { condition: store => store.barrier_count > 1 && store.form_components.indexOf('barrier') > -1, message: 'Barrier is a required field.' }],
        ['barrier', { condition: store => store.contract_expiry_type !== 'daily' && store.barrier_count }],
        ['number' , { condition: store => store.contract_expiry_type === 'daily' && store.barrier_count, type: 'float' }],
        ['custom' , { func: (value, options, store) => +store.barrier_1 > +value, message: 'Lower barrier must be lower than higher barrier.' }],
    ],
    duration: [
        ['req'    , { message: 'Duration is a required field.' }],
    ],
};

export default validation_rules;
<|endoftext|>


<commit_before>'use strict';

describe('xlsService', function(){
    var xlsService;
    var mixedData = {
        "headers": [
            [
                {
                    "title": "Female",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                },
                {
                    "title": "Male",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                },
                {
                    "title": "Number of Deaths",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                }
            ]
        ],
        "rowHeaders": [],
        "data": [
            [
                {
                    "title": "50,390",
                    "percentage": "31.9",
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1
                },
                {
                    "title": "107,460",
                    "percentage": "68.1",
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1
                },
                {
                    "title": "157,850",
                    "percentage": 1.2358582892934038,
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1,
                    "isBold": true
                }
            ]
        ],
        "calculatePercentage":true
    };
    beforeEach(module('owh'));

    beforeEach(inject(function ($injector) {
        xlsService = $injector.get('xlsService');
    }));

    describe('getSheetFromArray', function() {
        it('should return proper xls worksheet object', function () {
            var sheetArray = [[{title: 1}, {title: 2}, {title: 3}], [{title: 'data1'}, null, {title: 'data3'}], [{title: 'data4'}, {title: 'data5'}, {title: 'data6'}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            expect(ws['A1'].v).toEqual(1);
            expect(ws['B2']).toBeUndefined();
            expect(ws['C3'].v).toEqual('data6');
        });

        it('should properly account for horizontally merged cells', function () {
            /*
            [   1   ]
            [2][3][4]
             */
            var sheetArray = [[{title: 1, colspan: 3, rowspan: 1}], [{title: 2, colspan: 1, rowspan: 1}, {title: 3, colspan: 1, rowspan: 1}, {title: 4, colspan: 1, rowspan: 1}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            var mergedCell = {s: {c: 0, r: 0}, e: {c: 2, r: 0}};
            expect(ws['!merges']).toContain(mergedCell);
        });

        it('should properly account for vertically merged cells', function () {
           /*
            |  |[2]
            | 1|[3]
            |  |[4]
             */
            var sheetArray = [[{title: 1, colspan: 1, rowspan: 3}, {title: 2, colspan: 1, rowspan: 1}], [{title: 3, colspan: 1, rowspan: 1}], [{title: 4, colspan: 1, rowspan: 1}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            var mergedCell = {s: {c: 0, r: 0}, e: {c: 0, r: 2}};
            expect(ws['!merges']).toContain(mergedCell);
        });

        it('should convert strings to numbers if possible when the flag is passed', function () {
            var sheetArray = [[{title: 1}, {title: 2}, {title: 3}], [{title: 'data1'}, null, {title: 'data3'}], [{title: 'data4'}, {title: 'data5'}, {title: '12,420'}]];
            var ws = xlsService.getSheetFromArray(sheetArray, true);

            expect(ws['A1'].v).toEqual(1);
            expect(ws['B2']).toBeUndefined();
            expect(ws['C3'].v).toEqual(12420);
            expect(ws['C3'].t).toEqual('n');
        });
    });

    it('getSheetArrayFromMixedTable should return the proper sheet json from a mixed table object', function () {
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
              [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
              [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ]
        };
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedTable);

        expect(sheetArray[0]).toEqual([{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]);
        expect(sheetArray[2]).toEqual([{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]);
    });

    describe('getCSVFromSheet', function () {
        it('should return the proper csv string from xls worksheet object', function () {
            var ws = {'A1': {v: 1, t: 'n'}, 'A2': {v: 'test', t: 's'}, '!ref': 'A1:A2'};
            var csv = xlsService.getCSVFromSheet(ws);

            expect(csv).toEqual('1\ntest\n');
        });

        it('should repeat horizontally merged cells in the csv', function () {
            /*
              [   1   ]
              [2][3][4]
             */
            var ws = {'A1': {v: 1, t: 'n'}, 'A2': {v: 2, t: 'n'}, 'B2': {v: 3, t: 'n'}, 'C2': {v: 4, t: 'n'}, '!ref': 'A1:C2', '!merges': [{s: {c: 0, r: 0}, e: {c: 2, r: 0}}]};
            var csv = xlsService.getCSVFromSheet(ws, [[]]);

            expect(csv).toEqual('1,1,1\n2,3,4\n');
        });

        it('should repeat vertically merged cells in the csv', function () {
            /*
             |  |[2]
             | 1|[3]
             |  |[4]
             */
            var ws = {'A1': {v: 1, t: 'n'}, 'B1': {v: 2, t: 'n'}, 'B2': {v: 3, t: 'n'}, 'B3': {v: 4, t: 'n'}, '!ref': 'A1:B3', '!merges': [{s: {c: 0, r: 0}, e: {c: 0, r: 2}}]};
            var csv = xlsService.getCSVFromSheet(ws, [[], [], []]);

            expect(csv).toEqual('1,2\n1,3\n1,4\n');
        });

        it('should repeat merged cells marked as row headers without repeating data cells', function () {
            /*
            [1][2][3][ 9]
            | |[4][5][10]
            |a|[6][7][11]
            | |[  8 ][12]
             */
            var ws = {
                'A1': {v: 1, t: 'n'},
                'B1': {v: 2, t: 'n'},
                'C1': {v: 3, t: 'n'},
                'D1': {v: 9, t: 'n'},
                'A2': {v: 'a', t: 's'},
                'B2': {v: 4, t: 'n'},
                'C2': {v: 5, t: 'n'},
                'D2': {v: 10, t: 'n'},
                'B3': {v: 6, t: 'n'},
                'C3': {v: 7, t: 'n'},
                'D3': {v: 11, t: 'n'},
                'B4': {v: 8, t: 'n'},
                'D4': {v: 12, t: 'n'},
                '!ref': 'A1:D4',
                '!merges': [{s: {c: 0, r: 1}, e: {c: 0, r: 3}}, {s: {c: 1, r: 3}, e: {c: 2, r: 3}}]
            }
            var csv = xlsService.getCSVFromSheet(ws, [[]], [{}, {}]);

            expect(csv).toEqual('1,2,3,9\na,4,5,10\na,6,7,11\na,8,,12\n');
        })
    });

    it('exportCSVFromMixedTable should call out to saveAs with the proper filename', function () {
        spyOn(window, 'saveAs');
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
                [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
                [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ]
        };
        var filename = 'testname';
        xlsService.exportCSVFromMixedTable(mixedTable, filename);

        expect(window.saveAs).toHaveBeenCalled();
        expect(window.saveAs.calls.argsFor(0)[1]).toEqual(filename + '.csv');
    });

    it('exportXLSFromMixedTable should call out to saveAs with the proper filename', function () {
        spyOn(window, 'saveAs');
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
                [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
                [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ]
        };
        var filename = 'testnameXLS';
        xlsService.exportXLSFromMixedTable(mixedTable, filename);

        expect(window.saveAs).toHaveBeenCalled();
        expect(window.saveAs.calls.argsFor(0)[1]).toEqual(filename + '.xlsx');
    });

    it('should show numbers and percentages in exported csv', function () {
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('% of Female Deaths');
        expect(result['C1'].v).toEqual('Male');
        expect(result['D1'].v).toEqual('% of Male Deaths');
        expect(result['E1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual('50,390');
        expect(result['A2'].t).toEqual('s');
        expect(result['B2'].v).toEqual('31.9');
        expect(result['B2'].t).toEqual('s');
        expect(result['C2'].v).toEqual('107,460');
        expect(result['C2'].t).toEqual('s');
        expect(result['D2'].v).toEqual('68.1');
        expect(result['D2'].t).toEqual('s');
        expect(result['E2'].v).toEqual('157,850');
        expect(result['E2'].t).toEqual('s');
    });

    it('should show numbers and percentages in exported xsl', function () {
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray, true);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('% of Female Deaths');
        expect(result['C1'].v).toEqual('Male');
        expect(result['D1'].v).toEqual('% of Male Deaths');
        expect(result['E1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual(50390);
        expect(result['A2'].t).toEqual('n');
        expect(result['B2'].v).toEqual(31.9);
        expect(result['B2'].t).toEqual('n');
        expect(result['C2'].v).toEqual(107460);
        expect(result['C2'].t).toEqual('n');
        expect(result['D2'].v).toEqual(68.1);
        expect(result['D2'].t).toEqual('n');
        expect(result['E2'].v).toEqual(157850);
        expect(result['E2'].t).toEqual('n');
    });

    it('should show numbers only in exported csv if calculatepercentage set to false', function () {
        mixedData.calculatePercentage = false;
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('Male');
        expect(result['C1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual('50,390');
        expect(result['A2'].t).toEqual('s');
        expect(result['B2'].v).toEqual('107,460');
        expect(result['B2'].t).toEqual('s');
        expect(result['C2'].v).toEqual('157,850');
        expect(result['C2'].t).toEqual('s');
    });

    it('should show numbers only in exported xsl if calculatepercentage set to false', function () {
        mixedData.calculatePercentage = false;
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray, true);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('Male');
        expect(result['C1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual(50390);
        expect(result['A2'].t).toEqual('n');
        expect(result['B2'].v).toEqual(107460);
        expect(result['B2'].t).toEqual('n');
        expect(result['C2'].v).toEqual(157850);
        expect(result['C2'].t).toEqual('n');
    });

});
<commit_msg>OWH-59: fix xls unit tests<commit_after>'use strict';

describe('xlsService', function(){
    var xlsService;
    var mixedData = {
        "headers": [
            [
                {
                    "title": "Female",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                },
                {
                    "title": "Male",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                },
                {
                    "title": "Number of Deaths",
                    "colspan": 1,
                    "rowspan": 1,
                    "isData": true
                }
            ]
        ],
        "rowHeaders": [],
        "data": [
            [
                {
                    "title": "50,390",
                    "percentage": "31.9",
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1
                },
                {
                    "title": "107,460",
                    "percentage": "68.1",
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1
                },
                {
                    "title": "157,850",
                    "percentage": 1.2358582892934038,
                    "isCount": true,
                    "rowspan": 1,
                    "colspan": 1,
                    "isBold": true
                }
            ]
        ],
        "calculatePercentage":true
    };
    beforeEach(module('owh'));

    beforeEach(inject(function ($injector) {
        xlsService = $injector.get('xlsService');
    }));

    describe('getSheetFromArray', function() {
        it('should return proper xls worksheet object', function () {
            var sheetArray = [[{title: 1}, {title: 2}, {title: 3}], [{title: 'data1'}, null, {title: 'data3'}], [{title: 'data4'}, {title: 'data5'}, {title: 'data6'}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            expect(ws['A1'].v).toEqual(1);
            expect(ws['B2']).toBeUndefined();
            expect(ws['C3'].v).toEqual('data6');
        });

        it('should properly account for horizontally merged cells', function () {
            /*
            [   1   ]
            [2][3][4]
             */
            var sheetArray = [[{title: 1, colspan: 3, rowspan: 1}], [{title: 2, colspan: 1, rowspan: 1}, {title: 3, colspan: 1, rowspan: 1}, {title: 4, colspan: 1, rowspan: 1}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            var mergedCell = {s: {c: 0, r: 0}, e: {c: 2, r: 0}};
            expect(ws['!merges']).toContain(mergedCell);
        });

        it('should properly account for vertically merged cells', function () {
           /*
            |  |[2]
            | 1|[3]
            |  |[4]
             */
            var sheetArray = [[{title: 1, colspan: 1, rowspan: 3}, {title: 2, colspan: 1, rowspan: 1}], [{title: 3, colspan: 1, rowspan: 1}], [{title: 4, colspan: 1, rowspan: 1}]];
            var ws = xlsService.getSheetFromArray(sheetArray);

            var mergedCell = {s: {c: 0, r: 0}, e: {c: 0, r: 2}};
            expect(ws['!merges']).toContain(mergedCell);
        });

        it('should convert strings to numbers if possible when the flag is passed', function () {
            var sheetArray = [[{title: 1}, {title: 2}, {title: 3}], [{title: 'data1'}, null, {title: 'data3'}], [{title: 'data4'}, {title: 'data5'}, {title: '12,420'}]];
            var ws = xlsService.getSheetFromArray(sheetArray, true);

            expect(ws['A1'].v).toEqual(1);
            expect(ws['B2']).toBeUndefined();
            expect(ws['C3'].v).toEqual(12420);
            expect(ws['C3'].t).toEqual('n');
        });
    });

    it('getSheetArrayFromMixedTable should return the proper sheet json from a mixed table object', function () {
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
              [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
              [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ],
            rowHeaders: [{}]
        };
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedTable);

        expect(sheetArray[0]).toEqual([{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]);
        expect(sheetArray[2]).toEqual([{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]);
    });

    describe('getCSVFromSheet', function () {
        it('should return the proper csv string from xls worksheet object', function () {
            var ws = {'A1': {v: 1, t: 'n'}, 'A2': {v: 'test', t: 's'}, '!ref': 'A1:A2'};
            var csv = xlsService.getCSVFromSheet(ws);

            expect(csv).toEqual('1\ntest\n');
        });

        it('should repeat horizontally merged cells in the csv', function () {
            /*
              [   1   ]
              [2][3][4]
             */
            var ws = {'A1': {v: 1, t: 'n'}, 'A2': {v: 2, t: 'n'}, 'B2': {v: 3, t: 'n'}, 'C2': {v: 4, t: 'n'}, '!ref': 'A1:C2', '!merges': [{s: {c: 0, r: 0}, e: {c: 2, r: 0}}]};
            var csv = xlsService.getCSVFromSheet(ws, [[]]);

            expect(csv).toEqual('1,1,1\n2,3,4\n');
        });

        it('should repeat vertically merged cells in the csv', function () {
            /*
             |  |[2]
             | 1|[3]
             |  |[4]
             */
            var ws = {'A1': {v: 1, t: 'n'}, 'B1': {v: 2, t: 'n'}, 'B2': {v: 3, t: 'n'}, 'B3': {v: 4, t: 'n'}, '!ref': 'A1:B3', '!merges': [{s: {c: 0, r: 0}, e: {c: 0, r: 2}}]};
            var csv = xlsService.getCSVFromSheet(ws, [[], [], []]);

            expect(csv).toEqual('1,2\n1,3\n1,4\n');
        });

        it('should repeat merged cells marked as row headers without repeating data cells', function () {
            /*
            [1][2][3][ 9]
            | |[4][5][10]
            |a|[6][7][11]
            | |[  8 ][12]
             */
            var ws = {
                'A1': {v: 1, t: 'n'},
                'B1': {v: 2, t: 'n'},
                'C1': {v: 3, t: 'n'},
                'D1': {v: 9, t: 'n'},
                'A2': {v: 'a', t: 's'},
                'B2': {v: 4, t: 'n'},
                'C2': {v: 5, t: 'n'},
                'D2': {v: 10, t: 'n'},
                'B3': {v: 6, t: 'n'},
                'C3': {v: 7, t: 'n'},
                'D3': {v: 11, t: 'n'},
                'B4': {v: 8, t: 'n'},
                'D4': {v: 12, t: 'n'},
                '!ref': 'A1:D4',
                '!merges': [{s: {c: 0, r: 1}, e: {c: 0, r: 3}}, {s: {c: 1, r: 3}, e: {c: 2, r: 3}}]
            }
            var csv = xlsService.getCSVFromSheet(ws, [[]], [{}, {}]);

            expect(csv).toEqual('1,2,3,9\na,4,5,10\na,6,7,11\na,8,,12\n');
        })
    });

    it('exportCSVFromMixedTable should call out to saveAs with the proper filename', function () {
        spyOn(window, 'saveAs');
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
                [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
                [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ],
            rowHeaders: [{}]
        };
        var filename = 'testname';
        xlsService.exportCSVFromMixedTable(mixedTable, filename);

        expect(window.saveAs).toHaveBeenCalled();
        expect(window.saveAs.calls.argsFor(0)[1]).toEqual(filename + '.csv');
    });

    it('exportXLSFromMixedTable should call out to saveAs with the proper filename', function () {
        spyOn(window, 'saveAs');
        var mixedTable = {
            headers: [[{title: 'header1', colspan: 1, rowspan: 1}, {title: 'header2', colspan: 1, rowspan: 1}]],
            data: [
                [{title: 'data1', colspan: 1, rowspan: 1}, {title: 'data2', colspan: 1, rowspan: 1}],
                [{title: 'data3', colspan: 1, rowspan: 1}, {title: 'data4', colspan: 1, rowspan: 1}]
            ],
            rowHeaders: [{}]
        };
        var filename = 'testnameXLS';
        xlsService.exportXLSFromMixedTable(mixedTable, filename);

        expect(window.saveAs).toHaveBeenCalled();
        expect(window.saveAs.calls.argsFor(0)[1]).toEqual(filename + '.xlsx');
    });

    it('should show numbers and percentages in exported csv', function () {
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('% of Female Deaths');
        expect(result['C1'].v).toEqual('Male');
        expect(result['D1'].v).toEqual('% of Male Deaths');
        expect(result['E1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual('50,390');
        expect(result['A2'].t).toEqual('s');
        expect(result['B2'].v).toEqual('31.9');
        expect(result['B2'].t).toEqual('s');
        expect(result['C2'].v).toEqual('107,460');
        expect(result['C2'].t).toEqual('s');
        expect(result['D2'].v).toEqual('68.1');
        expect(result['D2'].t).toEqual('s');
        expect(result['E2'].v).toEqual('157,850');
        expect(result['E2'].t).toEqual('s');
    });

    it('should show numbers and percentages in exported xsl', function () {
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray, true);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('% of Female Deaths');
        expect(result['C1'].v).toEqual('Male');
        expect(result['D1'].v).toEqual('% of Male Deaths');
        expect(result['E1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual(50390);
        expect(result['A2'].t).toEqual('n');
        expect(result['B2'].v).toEqual(31.9);
        expect(result['B2'].t).toEqual('n');
        expect(result['C2'].v).toEqual(107460);
        expect(result['C2'].t).toEqual('n');
        expect(result['D2'].v).toEqual(68.1);
        expect(result['D2'].t).toEqual('n');
        expect(result['E2'].v).toEqual(157850);
        expect(result['E2'].t).toEqual('n');
    });

    it('should show numbers only in exported csv if calculatepercentage set to false', function () {
        mixedData.calculatePercentage = false;
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('Male');
        expect(result['C1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual('50,390');
        expect(result['A2'].t).toEqual('s');
        expect(result['B2'].v).toEqual('107,460');
        expect(result['B2'].t).toEqual('s');
        expect(result['C2'].v).toEqual('157,850');
        expect(result['C2'].t).toEqual('s');
    });

    it('should show numbers only in exported xsl if calculatepercentage set to false', function () {
        mixedData.calculatePercentage = false;
        var sheetArray = xlsService.getSheetArrayFromMixedTable(mixedData)
        var result = xlsService.getSheetFromArray(sheetArray, true);
        expect(result['A1'].v).toEqual('Female');
        expect(result['B1'].v).toEqual('Male');
        expect(result['C1'].v).toEqual('Number of Deaths');
        expect(result['A2'].v).toEqual(50390);
        expect(result['A2'].t).toEqual('n');
        expect(result['B2'].v).toEqual(107460);
        expect(result['B2'].t).toEqual('n');
        expect(result['C2'].v).toEqual(157850);
        expect(result['C2'].t).toEqual('n');
    });

});
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { toQueryString } from './utils.js';

window.retrieveSimulations = retrieveSimulations; // Add function to global scope.

/**
 * Fetch url and retrieve a JSON object storing simulations' metadata,
 * and display as an html table.
 */
function retrieveSimulations() {
    fetch('/list-simulations')
    .then(response => response.json())
    .then(simulations => {
        displaySimulationAsTable(simulations);
    });
}

function retrieveSortedSimulations(sortProperty) {
    const queryString = toQueryString({ sortProperty : sortProperty });
    fetch(`/list-simulations?${queryString}`)
    .then(response => response.json())
    .then(simulations => {
        displaySimulationAsTable(simulations);
    });
}

/**
 * Given a json object storing simulations' metadata, write all data to an html table.
 * @param {Object} simulations is an object storing simulations' unique id and metadata.
 */
function displaySimulationAsTable(simulations) {
    const allSimulationIds = Object.keys(simulations);
    if (allSimulationIds.length === 0) { return; }

    const firstSimulationId = allSimulationIds[0];
    const firstSimulation = simulations[firstSimulationId];
    const simulationProperties = Object.keys(firstSimulation);

    var table = document.getElementById("simulations-table");
    table.innerHTML = '';
    addSimulationHeader(table, simulationProperties);
    addSimulationRows(table, simulations);
}

/**
 * Given a table and an array of strings, add a header based on the array's items.
 * @param {HTMLElement} table is the html table to be updated.
 * @param {String[]} properties is an array of header properties.
 */
function addSimulationHeader(table, properties) {
    var header = table.createTHead();
    var row = header.insertRow(0);
    // cell 0 contains the simulation button, therefore header starts at cell 1.
    row.insertCell(0).innerHTML = '';
    for (var i = 0; i < properties.length; i++) {
        row.insertCell(i + 1).appendChild(createSortButton(properties[i]));
    }
}

/**
 * Given a table and an object storing simulations' metadata, add a row for each simulation.
 * @param {HTMLElement} table is the table to be updated.
 * @param {Object} simulations is an object storing simulations' id and metadata.
 */
function addSimulationRows(table, simulations) {
    for (const id in simulations) {
        const simulation = simulations[id];
        var row = table.insertRow(-1);
        const visualizeSimulationButton = createVisualizationButton(simulation, id);
        const deleteSimulationButton = createDeletionButton(id);
        const cell = row.insertCell(0);
        cell.appendChild(visualizeSimulationButton);
        cell.appendChild(deleteSimulationButton);
        var i = 1; // cell index (cell 0 is a button).
        for (const property in simulation) {
            row.insertCell(i++).innerHTML = simulation[property];
        }
    }
}

/**
 * Create a button for simulation visualization.
 * @param {Object} simulation is the simulation object.
 * @param {String} id is the simulation id.
 */
function createVisualizationButton(simulation, id) {
    var visualizeSimulationButton = document.createElement('button');
    visualizeSimulationButton.innerText = 'Visualize Simulation';
    visualizeSimulationButton.addEventListener('click', () => {
        var simulationWithId = JSON.parse(JSON.stringify(simulation)); // Deep copy.
        simulationWithId['id'] = id;
        window.location.replace('simulation_visualization.html?' + toQueryString(simulationWithId));
    });

    return visualizeSimulationButton;
}

/**
 * Create a button for simulation deletion.
 * @param {String} id is the simulation id.
 */
function createDeletionButton(id) {
    var deleteSimulationButton = document.createElement('button');
    deleteSimulationButton.innerText = 'Delete Simulation';
    deleteSimulationButton.addEventListener('click', () => {
        var confirmed = confirm('Do you want to delete this simulation?');
        if (confirmed) {
            var params = new URLSearchParams();
            params.append('simulationId', id);
            fetch('/delete-simulation', {method: 'POST', body: params})
            .then(response => response.text())
            .then(message => window.alert(message))
            .then(() => location.reload())
        }
    });

    return deleteSimulationButton;
}

function createSortButton(sortProperty) {
    var sortButton = document.createElement('button');
    sortButton.innerText = sortProperty;
    sortButton.addEventListener('click', () => {
        retrieveSortedSimulations(sortProperty);
    });

    return sortButton;
}<commit_msg>add documentation.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { toQueryString } from './utils.js';

window.retrieveSimulations = retrieveSimulations; // Add function to global scope.

/**
 * Fetch url and retrieve a JSON object storing simulations' metadata,
 * and display as an html table.
 */
function retrieveSimulations() {
    fetch('/list-simulations')
    .then(response => response.json())
    .then(simulations => {
        displaySimulationAsTable(simulations);
    });
}

/**
 * Fetch url and retrieve a JSON object storing sorted simulations' metadata,
 * and display as an html table.
 * @param {String} sortProperty is the name of the property to sort by.
 */
function retrieveSortedSimulations(sortProperty) {
    const queryString = toQueryString({ sortProperty : sortProperty });
    fetch(`/list-simulations?${queryString}`)
    .then(response => response.json())
    .then(simulations => {
        displaySimulationAsTable(simulations);
    });
}

/**
 * Given a json object storing simulations' metadata, write all data to an html table.
 * @param {Object} simulations is an object storing simulations' unique id and metadata.
 */
function displaySimulationAsTable(simulations) {
    const allSimulationIds = Object.keys(simulations);
    if (allSimulationIds.length === 0) { return; }

    const firstSimulationId = allSimulationIds[0];
    const firstSimulation = simulations[firstSimulationId];
    const simulationProperties = Object.keys(firstSimulation);

    var table = document.getElementById("simulations-table");
    table.innerHTML = '';
    addSimulationHeader(table, simulationProperties);
    addSimulationRows(table, simulations);
}

/**
 * Given a table and an array of strings, add a header based on the array's items.
 * @param {HTMLElement} table is the html table to be updated.
 * @param {String[]} properties is an array of header properties.
 */
function addSimulationHeader(table, properties) {
    var header = table.createTHead();
    var row = header.insertRow(0);
    // cell 0 contains the simulation button, therefore header starts at cell 1.
    row.insertCell(0).innerHTML = '';
    for (var i = 0; i < properties.length; i++) {
        row.insertCell(i + 1).appendChild(createSortButton(properties[i]));
    }
}

/**
 * Given a table and an object storing simulations' metadata, add a row for each simulation.
 * @param {HTMLElement} table is the table to be updated.
 * @param {Object} simulations is an object storing simulations' id and metadata.
 */
function addSimulationRows(table, simulations) {
    for (const id in simulations) {
        const simulation = simulations[id];
        var row = table.insertRow(-1);
        const visualizeSimulationButton = createVisualizationButton(simulation, id);
        const deleteSimulationButton = createDeletionButton(id);
        const cell = row.insertCell(0);
        cell.appendChild(visualizeSimulationButton);
        cell.appendChild(deleteSimulationButton);
        var i = 1; // cell index (cell 0 is a button).
        for (const property in simulation) {
            row.insertCell(i++).innerHTML = simulation[property];
        }
    }
}

/**
 * Create a button for simulation visualization.
 * @param {Object} simulation is the simulation object.
 * @param {String} id is the simulation id.
 */
function createVisualizationButton(simulation, id) {
    var visualizeSimulationButton = document.createElement('button');
    visualizeSimulationButton.innerText = 'Visualize Simulation';
    visualizeSimulationButton.addEventListener('click', () => {
        var simulationWithId = JSON.parse(JSON.stringify(simulation)); // Deep copy.
        simulationWithId['id'] = id;
        window.location.replace('simulation_visualization.html?' + toQueryString(simulationWithId));
    });

    return visualizeSimulationButton;
}

/**
 * Create a button for simulation deletion.
 * @param {String} id is the simulation id.
 */
function createDeletionButton(id) {
    var deleteSimulationButton = document.createElement('button');
    deleteSimulationButton.innerText = 'Delete Simulation';
    deleteSimulationButton.addEventListener('click', () => {
        var confirmed = confirm('Do you want to delete this simulation?');
        if (confirmed) {
            var params = new URLSearchParams();
            params.append('simulationId', id);
            fetch('/delete-simulation', {method: 'POST', body: params})
            .then(response => response.text())
            .then(message => window.alert(message))
            .then(() => location.reload())
        }
    });

    return deleteSimulationButton;
}

/**
 * Create a button for simulations sort.
 * @param {String} sortProperty is the name of the property to sort by.
 */
function createSortButton(sortProperty) {
    var sortButton = document.createElement('button');
    sortButton.innerText = sortProperty;
    sortButton.addEventListener('click', () => {
        retrieveSortedSimulations(sortProperty);
    });

    return sortButton;
}<|endoftext|>


<commit_before>var express = require('express');
var cors = require('cors');
var https = require('https');
var bodyParser = require('body-parser');
var morgan = require('morgan'); // logging
var winston = require('winston');
var basicAuth = require('basic-auth-connect');
var fs = require('fs');
var mkdirp = require('mkdirp');

var config = require('./config');
var manifest = require('./src/manifest')

// LOGGING (to a file in addition to the console)
winston.add(winston.transports.File, { filename: config.LOG_FILE });

// create the folder where the data will be stored
mkdirp.sync(config.DATA_FOLDER);

// CHECK IF THE RESULT ALREADY EXISTS
var cmdlineOption = process.argv[2];
var resultFileExists = fs.existsSync(config.RESULT_FILE);
if (resultFileExists && cmdlineOption !== '--serveResult') {
    console.log('ERROR: The file with result (%s) already exists.', config.RESULT_FILE);
    console.log('Remove this file or run the server with --serveResult option.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}
if (cmdlineOption === '--serveResult' && !resultFileExists) {
    console.log('ERROR: The file with result does not exist.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}

// CHECK IF THE LOG WITH ACCEPTED BALLOTS EXISTS
var logFileExists = fs.existsSync(config.ACCEPTED_BALLOTS_LOG_FILE);
if (logFileExists && !resultFileExists && cmdlineOption !== '--resume') {
    console.log('ERROR: Log file with accepted ballots (%s) exists.', config.ACCEPTED_BALLOTS_LOG_FILE);
    console.log('Remove this file or run the server with --resume option.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}
if (cmdlineOption === '--resume' && !logFileExists) {
    console.log('ERROR: Log file with accepted ballots does not exist');
    console.log('Server cannot be resumed.');
    process.exit(1);
}

// CHECK FOR WRONG OPTIONS
if (cmdlineOption && cmdlineOption!=='--resume' && cmdlineOption!=='--serveResult') {
    console.log('ERROR: Wrong option');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}

// CREATE AND CONFIGURE THE APP
var routes = require('./src/routes');
var app = express();
app.use(cors()); // enable all CORS request
app.set('views', './src/views');    // location of the views
app.set('view engine', 'ejs');  // view engine
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use(express.static('./public')); // static content
app.use( morgan('*** :remote-addr [:date] :method :url :status / :referrer [:response-time ms]', {}) ); // logging
app.use('/admin/*', basicAuth('admin', config.serverAdminPassword)); // authentication for the admin panel only

// Insert some delay (for testing only):
// app.use(function(req, res, next) { setTimeout(next, 300); });

// ROUTES
app.post('/otp', routes.otp);
app.post('/cast', routes.cast);

app.get('/', routes.info);
app.get('/status', routes.info);
app.get('/admin/panel', routes.controlPanel);
app.get('/admin/close', routes.close);
app.get('/result.msg', routes.serveFile(config.RESULT_FILE));
app.get('/votersList.msg', routes.serveFile(config.VOTERSLIST_FILE));
app.get('/manifest', routes.serveFile(config.MANIFEST_FILE));

// STARTING THE SERVER

if (config.useTLS) {
	key = fs.readFileSync(config.TLS_KEY_FILE, 'utf8');
	cert = fs.readFileSync(config.TLS_CERT_FILE, 'utf8');
    var tls_options = {
			key:  key,
			cert: cert
    	};
    app = https.createServer(tls_options, app);
}
var server = app.listen(config.port, function() {
    console.log('Collecting Server running for election "%s" [%s]', manifest.title, manifest.hash);
    winston.info('SERVER STARTED');
    console.log('Server listening on %s, port %d', server.address().address, server.address().port);
    if (config.useTLS)
        console.log('Using TLS');
});

<commit_msg>comment useless checking out<commit_after>var express = require('express');
var cors = require('cors');
var https = require('https');
var bodyParser = require('body-parser');
var morgan = require('morgan'); // logging
var winston = require('winston');
var basicAuth = require('basic-auth-connect');
var fs = require('fs');
var mkdirp = require('mkdirp');

var config = require('./config');
var manifest = require('./src/manifest')

// LOGGING (to a file in addition to the console)
winston.add(winston.transports.File, { filename: config.LOG_FILE });

// create the folder where the data will be stored
mkdirp.sync(config.DATA_FOLDER);

/*
// CHECK IF THE RESULT ALREADY EXISTS
var cmdlineOption = process.argv[2];

var resultFileExists = fs.existsSync(config.RESULT_FILE);
if (resultFileExists && cmdlineOption !== '--serveResult') {
    console.log('ERROR: The file with result (%s) already exists.', config.RESULT_FILE);
    console.log('Remove this file or run the server with --serveResult option.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}
if (cmdlineOption === '--serveResult' && !resultFileExists) {
    console.log('ERROR: The file with result does not exist.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}

// CHECK IF THE LOG WITH ACCEPTED BALLOTS EXISTS
var logFileExists = fs.existsSync(config.ACCEPTED_BALLOTS_LOG_FILE);
if (logFileExists && !resultFileExists && cmdlineOption !== '--resume') {
    console.log('ERROR: Log file with accepted ballots (%s) exists.', config.ACCEPTED_BALLOTS_LOG_FILE);
    console.log('Remove this file or run the server with --resume option.');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}
if (cmdlineOption === '--resume' && !logFileExists) {
    console.log('ERROR: Log file with accepted ballots does not exist');
    console.log('Server cannot be resumed.');
    process.exit(1);
}

// CHECK FOR WRONG OPTIONS
if (cmdlineOption && cmdlineOption!=='--resume' && cmdlineOption!=='--serveResult') {
    console.log('ERROR: Wrong option');
    console.log('SERVER NOT STARTED.');
    process.exit(1);
}
*/

// CREATE AND CONFIGURE THE APP
var routes = require('./src/routes');
var app = express();
app.use(cors()); // enable all CORS request
app.set('views', './src/views');    // location of the views
app.set('view engine', 'ejs');  // view engine
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use(express.static('./public')); // static content
app.use( morgan('*** :remote-addr [:date] :method :url :status / :referrer [:response-time ms]', {}) ); // logging
app.use('/admin/*', basicAuth('admin', config.serverAdminPassword)); // authentication for the admin panel only

// Insert some delay (for testing only):
// app.use(function(req, res, next) { setTimeout(next, 300); });

// ROUTES
app.post('/otp', routes.otp);
app.post('/cast', routes.cast);

app.get('/', routes.info);
app.get('/status', routes.info);
app.get('/admin/panel', routes.controlPanel);
app.get('/admin/close', routes.close);
app.get('/result.msg', routes.serveFile(config.RESULT_FILE));
app.get('/votersList.msg', routes.serveFile(config.VOTERSLIST_FILE));
app.get('/manifest', routes.serveFile(config.MANIFEST_FILE));

// STARTING THE SERVER

if (config.useTLS) {
	key = fs.readFileSync(config.TLS_KEY_FILE, 'utf8');
	cert = fs.readFileSync(config.TLS_CERT_FILE, 'utf8');
    var tls_options = {
			key:  key,
			cert: cert
    	};
    app = https.createServer(tls_options, app);
}
var server = app.listen(config.port, function() {
    console.log('Collecting Server running for election "%s" [%s]', manifest.title, manifest.hash);
    winston.info('SERVER STARTED');
    console.log('Server listening on %s, port %d', server.address().address, server.address().port);
    if (config.useTLS)
        console.log('Using TLS');
});

<|endoftext|>